LASooner Posted February 19, 2018 Share Posted February 19, 2018 I'm having trouble wrapping my brain around how to constrain player controlled and CPU controlled sprites through a maze. for the CPU controlled, I originally tried trigger spots, where the monster determines where it is and whether it's coincident with an intersection, then randomly select which direction to go by adjusting sprite velocity. The problem with this is the time it takes to scan through all possible intersections, and act upon it, the coincident detection has usually past. And my monsters just keep moving in that one direction. The player controlled, I can easily keep the player sprite within the confines of the screen, I'm using CALL LOCATE to position the player, and I can set minimum and maximum constraints for the screen, I have then determined where the vertical pathways are and only limit up and down motion through those avenues. But I don't know how to determine when a wall blocks that vertical path. I want to keep all this position polling to a minimum as it affects the animation of the characters because it has to be done during the game loop. I don't see anyway to detect collision with a specific character which would be the easiest way, since the path is all CHR$(32) I was just wondering how others may have tackled the task of moving player and CPU controlled sprites through a maze without clipping through walls using extended basic? My intent is to compress this as I'm using XB256, so RXB is not really an option. Quote Link to comment Share on other sites More sharing options...
Opry99er Posted February 19, 2018 Share Posted February 19, 2018 Since youre compiling, tracking your player by using CALL POSITION and then doing a CALL GCHAR would be fine for speed.... in uncompiled XB, this would be noticeably slow, but GCHAR in the compiler it should be money. 1 Quote Link to comment Share on other sites More sharing options...
Retrospect Posted February 19, 2018 Share Posted February 19, 2018 I think the overlap of sprite into walls maybe comes when we are converting from characters to sprite positions? I noticed with my Agenda99 bomber game the explosions on the walls of the buildings varied in accuracy due to the conversion Quote Link to comment Share on other sites More sharing options...
LASooner Posted February 19, 2018 Author Share Posted February 19, 2018 So if X and Y are the dot values given by CALL POSITION, I would use A=INT(X/8) :: B=INT(Y/8) :: CALL GCHAR (A,B,Z) Am I correct that Z would give me the character value under the SPRITE? Sorry if these question sound newbie, programming isn't my strong suit. 1 Quote Link to comment Share on other sites More sharing options...
Opry99er Posted February 19, 2018 Share Posted February 19, 2018 I cant test it right now, but youve got the right idea there. Quote Link to comment Share on other sites More sharing options...
Asmusr Posted February 20, 2018 Share Posted February 20, 2018 To avoid getting stuck in the walls you probably want to test the position you're moving to rather than the position you're already on. 2 Quote Link to comment Share on other sites More sharing options...
matthew180 Posted February 20, 2018 Share Posted February 20, 2018 So if X and Y are the dot values given by CALL POSITION, I would use A=INT(X/8) :: B=INT(Y/8) :: CALL GCHAR (A,B,Z) Am I correct that Z would give me the character value under the SPRITE? Sorry if these question sound newbie, programming isn't my strong suit. Actually the formula would be: A=INT(X/8)+1 (and the same for Y) since sprite locations between 1 and 7 would return, i.e. INT(7/8) is 0, and tile rows and columns are 1-based. In your example Z would contain the ASCII value of the tile (character) at row A, col B. See pg. 88 of the XB manual (available in PDF form from many places, see the sticky thread at the top of the forum). However, be careful with HCHAR and GCHAR, the parameters are "row, col", and row is the same as the y-axis when thinking about the screen in terms of an X,Y grid. The parameters for sprites are also called "dot-row" and "dot-col", so at least it is consistent. To keep your brain straight, you might want to switch to using R and C instead of Y and X. Actually, the example in the XB manual for CALL POSITION uses an example with X,Y and shows them written in "Y, X" order: CALL POSITION(#1,Y,X) XT=INT(X/8)+1::YT=INT(Y/8)+1 CALL GCHAR(YT,XT,T) or save the intermediate variables: CALL GCHAR(INT(Y/8)+1,INT(X/8)+1,T) Also, if you are in XB and expect to have the 32K expansion, it *might* be faster to keep your maze in an array instead of using GCHAR: DIM MAZE(30,20) T=MAZE(INT(X/8)+1,INT(Y/8)+1) You would load your maze into the array and draw it to the screen once during setup. Then your array is the in memory model of your maze and you use it to know where you can move, etc. What is on the screen is just a reflection of what is in the maze. But the XB gurus will have to chime-in to tell us if this would be faster. Notice in this case that your array is in X,Y format, so you use X,Y instead of Y,X as you would for GCHAR. I would also recommend you keep the "path" part of your maze as a single full tile, and also make the walls a full tile. This will make your wall collision much easier and faster. As for moving, I know auto-sprite motion is nice and all, but you risk having your sprites move right through the walls if you are not careful in the way you set up the motion. You might try a typical game-loop first, using CALL LOCATE to move the sprites, to see if you get satisfactory results. A game-loop goes something like this: while ( user doesn't exit ) check for user input run AI move user move enemies resolve collisions update/draw graphics play sounds end while Although it seems complicated, each step is usually only a few lines of code (that's all the time you have in an environment like XB). For example, your "check for user input" step would be CALL KEY, the "run AI" step is the simple steps your computer player makes to decide how to move. The "move user" step would just be calculating the player's *new* X,Y position (this is a very important distinction) based on the keyboard input. It is the "resolve collisions" step that your original question was concerned with. At this point you would check if the *new* position is in bounds of a maze path, or if it hit a maze wall. If there was a hit, you simply don't update the player's position. If the move is legal then you set the player's real position to the new position calculated previously. Then you draw/update the sprite positions. This might all go something like: SPEED=2 DIM MAZE(30,20) // generate maze in MAZE // draw maze on screen WHILE game_running // user input, note to have the player keep moving when a direction key // is released, remove the "ELSE DY=0" and "ELSE DX=0" parts. CALL KEY ... IF quit or dead or whatever THEN ... IF up THEN DY=-SPEED ELSE IF down THEN DY=SPEED ELSE DY=0 IF left THEN DX=-SPEED ELSE IF right THEN DX=SPEED ELSE DX=0 // run AI, none yet. // move user, PX,PY is the current player location NX=PX+DX :: DY=PY+DY // resolve collisions IF MAZE(INT(NX/8)+1,INT(NY/8)+1)=32 THEN PX=NX :: PY=NY // update graphics CALL LOCATE(#1,PY,PX) // play sounds, maybe if the player hit a wall then make // a bump sound. IF PX<>NX THEN CALL SOUND(bump) END WHILE An alternate resolve collisions if using CALL GCHAR: // resolve collisions CALL GCHAR(INT(NY/8)+1,INT(NX/8)+1,T) IF T=32 THEN PX=NX :: PY=NY Of course this is part pseudo code and part XB, so you will have to sort out the syntax bits to make it all work. Here are a few examples. I like to use W,A,S,D instead of the TI "arrows", and Q is for quit. Avoid the edge of the screen: 100 REM >>> GAMELOOP <<< 110 CALL CLEAR 120 X=16::Y=12 130 DX=0::DY=0 140 C=64:=32::E=42 150 CALL HCHAR(Y,X,C) 160 REM >>> GAME LOOP 170 REM >>> CHECK USER INPUT W,A,S,D,OR Q 180 CALL KEY(0,K,S)::IF S=0 THEN 250 190 IF K=81 THEN EXIT_GAME: 200 IF K=87 THEN DX=0::DY=-1::GOTO 250 210 IF K=83 THEN DX=0::DY=1::GOTO 250 220 IF K=65 THEN DX=-1::DY=0::GOTO 250 230 IF K=68 THEN DX=1::DY=0 240 REM >>> MOVE PLAYER 250 NX=X+DX::NY=Y+DY 260 REM >>> AI 270 REM >>> MOVE ENEMIES 280 REM >>> RESOLVE COLLISIONS 290 IF NX < 1 OR NX > 32 OR NY < 1 OR NY > 24 THEN 380 300 REM >>> DRAW GRAPHICS 310 CALL HCHAR(Y,X,D) 320 X=NX::Y=NY 330 CALL HCHAR(Y,X,C) 340 REM >>> PLAY SOUNDS 350 REM >>> END GAME LOOP 360 GOTO 170 370 REM >>> BLOW UP 380 CALL HCHAR(Y,X,E) 390 DISPLAY AT(12,14):"BOOM" 400 FOR I=1 TO 500::NEXT I 410 GOTO 110 420 END Uses a sprite, avoid the edge of the screen. 100 REM >>> SPRITE GAMELOOP <<< 110 CALL CLEAR 120 X=128::Y=96 130 DX=0::DY=0::SP=2 140 C=64::E=42 150 CALL SPRITE(#1,C,2,Y,X) 160 REM >>> GAME LOOP 170 REM >>> CHECK USER INPUT W,A,S,D, OR Q 180 CALL KEY(0,K,S)::IF S=0 THEN 250 190 IF K=81 THEN 420 200 IF K=87 THEN DX=0::DY=-SP::GOTO 250 210 IF K=83 THEN DX=0::DY=SP::GOTO 250 220 IF K=65 THEN DX=-SP::DY=0::GOTO 250 230 IF K=68 THEN DX=SP::DY=0 240 REM >>> MOVE PLAYER 250 NX=X+DX::NY=Y+DY 260 REM >>> AI 270 REM >>> MOVE ENEMIES 280 REM >>> RESOLVE COLLISIONS 290 IF NX < 8 OR X > 248 OR Y < 8 OR Y > 184 THEN 370 300 X=NX::Y=NY 310 REM >>> DRAW GRAPHICS 320 CALL LOCATE(#1,Y,X) 330 REM >>> PLAY SOUNDS 340 REM >>> END GAME LOOP 350 GOTO 170 360 REM >>> BLOW UP 370 CALL PATTERN(#1,E) 380 DISPLAY AT(12,14):"BOOM" 390 FOR I=1 TO 500::NEXT I 400 GOTO 110 410 REM >>> END GAMELOOP 420 END Uses a sprite, avoid the # 100 REM >>> SPRITE GAMELOOP <<< 110 DIM M(30,22) 120 CALL CLEAR 130 X=128::Y=96 140 DX=0::DY=0::SP=2 150 C=64::E=42::W=35 160 REM >>> BORDER 170 FOR TX=1 TO 30 180 M(TX,1)=W::CALL HCHAR(1,TX,W) 190 M(TX,22)=W::CALL HCHAR(22,TX,W) 200 NEXT TX 210 FOR TY=1 TO 22 220 M(1,TY)=W::CALL HCHAR(TY,1,W) 230 M(30,TY)=W::CALL HCHAR(TY,30,W) 240 NEXT TY 250 REM >>> GENERATE PLAYFIELD 260 FOR TY=2 TO 21 270 FOR TX=2 TO 29::M(TX,TY)=0::NEXT TX 280 TX=INT(RND*28)+2 290 M(TX,TY)=W::CALL HCHAR(TY,TX,W) 300 NEXT TY 310 REM INITIAL PLAYER LOCATION 320 M(INT(X/8)+1,INT(Y/8)+1)=0 330 CALL SPRITE(#1,C,5,Y,X) 340 REM >>> GAME LOOP 350 REM >>> CHECK USER INPUT W,A,S,D, OR Q 360 CALL KEY(0,K,S)::IF S=0 THEN 430 370 IF K=81 THEN 610 380 IF K=87 THEN DX=0::DY=-SP::GOTO 430 390 IF K=83 THEN DX=0::DY=SP::GOTO 430 400 IF K=65 THEN DX=-SP::DY=0::GOTO 430 410 IF K=68 THEN DX=SP::DY=0 420 REM >>> MOVE PLAYER 430 NX=X+DX::NY=Y+DY 440 REM >>> AI 450 REM >>> MOVE ENEMIES 460 REM >>> RESOLVE COLLISIONS 470 IF M(INT(NX/8)+1,INT(NY/8)+1)=W THEN 550 480 X=NX::Y=NY 490 REM >>> DRAW GRAPHICS 500 CALL LOCATE(#1,Y,X) 510 REM >>> PLAY SOUNDS 520 REM >>> END GAME LOOP 530 GOTO 350 540 REM >>> BLOW UP 550 CALL PATTERN(#1,E) 560 DISPLAY AT(12,14):"BOOM" 570 FOR I=1 TO 500::NEXT I 580 CALL LOCATE(#1,192,1) 590 GOTO 120 600 REM >>> END GAMELOOP 610 END 2 Quote Link to comment Share on other sites More sharing options...
LASooner Posted February 20, 2018 Author Share Posted February 20, 2018 (edited) I should mention that I'm using MAGNIFY (3), so the pathways are 2 chars wide. I am having some success, with using GCHAR, I have one for each corner of the sprite. I figured out the need to have it be (X/8)+1 earlier this evening so some brain cells are still kicking. If the character next to sprite is 32 in any direction, I only allow input in those directions. It's getting there. I will move the monsters away from auto motion and use LOCATE as well. But I'm not worrying about those guys yet. I'm a 3D Artist for my day job, so interpolating X and Y is hard wired in my brain. Edited February 20, 2018 by LASooner 1 Quote Link to comment Share on other sites More sharing options...
Airshack Posted February 20, 2018 Share Posted February 20, 2018 (edited) In my limited experience the automatic sprites in XB are fun to mess around with but difficult to manage due to the slow speed of XB -- the main BIG issue. It's like trying to fly a drone with a really slow radio control scheme. By the time you tell the damn thing to turn around it has already flown out of range. Compiling XB fixes most of the speed issues and significantly helps to cleanly manage auto-spites. Still, it's not perfect. Just pretty good. I'd say the 20X+ speed improvement with Compiled BASIC results in GOOD auto-sprite management, not GREAT. The final step is programming in Assembly where you have the speed to accurately manage automatic sprites but may not really need them. Ironic? Edited February 20, 2018 by Airshack Quote Link to comment Share on other sites More sharing options...
unhuman Posted February 20, 2018 Share Posted February 20, 2018 Auto-sprite motion will cause you problems here - because XB is slow and you'd need to stop the bad motion and jump back to the last good space. I'm going to be working on some maze stuff too... I'm making the assumption of no motion + compiler and see if it works. Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted February 20, 2018 Share Posted February 20, 2018 LOCATE is your best option for moving a CPU-controlled sprite through a maze. You can look at "Dark Maze", my short program, as an example of a moving sprite enemy. In general, for XB programming, it's pretty hard to have more than a single CPU controlled enemy. Using compiled XB helps a bit, but you still have the challenge of timing things. You have the opposite problem in assembly. You have to make certain that sprites move at intervals that are actually visible to the user. Generally speaking, there is no excuse there for poor controls short of intensive CPU work, like Parsec with the horizontal scrolling. (TI Invaders annoys me with how your cannon is sluggish to respond to sudden changes in direction.) 1 Quote Link to comment Share on other sites More sharing options...
RXB Posted February 20, 2018 Share Posted February 20, 2018 LOCATE is your best option for moving a CPU-controlled sprite through a maze. You can look at "Dark Maze", my short program, as an example of a moving sprite enemy. In general, for XB programming, it's pretty hard to have more than a single CPU controlled enemy. Using compiled XB helps a bit, but you still have the challenge of timing things. You have the opposite problem in assembly. You have to make certain that sprites move at intervals that are actually visible to the user. Generally speaking, there is no excuse there for poor controls short of intensive CPU work, like Parsec with the horizontal scrolling. (TI Invaders annoys me with how your cannon is sluggish to respond to sudden changes in direction.) I think Invaders is written in GPL and they did not put the SCAN loop in the main loop for checking key input from user. Thus why you get lag in changing direction, it appears they instead called SCAN when not updating the screen. 1 Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted February 20, 2018 Share Posted February 20, 2018 I think Invaders is written in GPL and they did not put the SCAN loop in the main loop for checking key input from user. Thus why you get lag in changing direction, it appears they instead called SCAN when not updating the screen. Yep, that makes sense. It's a bad game design. Given that most of the old TI games were written by college-level CS students, it's not surprising. 1 Quote Link to comment Share on other sites More sharing options...
Retrospect Posted February 20, 2018 Share Posted February 20, 2018 I've tried to write an example code to help with the maze game and sprite, and hit on a problem myself. But in doing so, help with this might help you to make your maze game. Note that I've used only small sprite, magnification 1. ! TREASURE HOUSE EXAMPLE GAME ! NO PROBLEM WITH LEFT OR RIGHT, BUT A PROBLEM OCCURS IN UP AND DOWN MOVEMENT, WHY?? ! DEFINE THE GRAPHICS 10 CALL CHAR(104,"080808FF808080FF") ! WALLS (CHAR) 20 CALL CHAR(96,"1819FFBC3C3C6446") ! THE PLAYER (SPRITE) 25 CALL CHAR(112,"00001C2236363E00") ! TREASURE (CHAR) ! DO THE COLOURS 30 CALL CLEAR::CALL COLOR(10,5,16,11,4,1)::CALL SCREEN(2) ! RESET THE SCORE 35 SCORE=0 ! PLAN THE HOUSE LAYOUT 40 CALL HCHAR(1,1,104,32)::CALL HCHAR(24,1,104,32)::CALL VCHAR(1,1,104,24)::CALL VCHAR(1,32,104,24) 50 FOR Q=3 TO 22 STEP 2::CALL HCHAR(Q,3,104,28)::NEXT Q 60 FOR Q=3 TO 30 STEP 3::CALL HCHAR(22,Q,104)::NEXT Q ! PLACE THE TREASURE CHARS 70 CALL HCHAR(2,2,112)::CALL HCHAR(2,31,112)::CALL HCHAR(23,2,112)::CALL HCHAR(23,31,112) ! GIVE THE PLAYER X AND Y COORDS AND TELL COMPUTER THAT TREASURE=0 80 MX=136 :: MY=128 :: TR=0 ! PLACE THE PLAYER SPRITE 90 CALL SPRITE(#1,96,16,MX,MY) ! NOTE THE JOYSTICK COMMAND WORKS OPPOSITE WITH X AND Y. I KNOW, RIGHT?! 100 CALL JOYST(1,JY,JX) 110 IF JY=-4 THEN 210 120 IF JY=4 THEN 220 130 IF JX=4 THEN 230 140 IF JX=-4 THEN 240 150 goto 100 210 ! MOVE LEFT 211 MY=MY-8::GOSUB 1100::GOTO 90 220 ! MOVE RIGHT 221 MY=MY+8::GOSUB 1200::GOTO 90 230 ! MOVE UP 231 MX=MX-8::GOSUB 1300::GOTO 90 240 ! MOVE DOWN 241 MX=MX+8::GOSUB 1400::GOTO 90 1100 ! CHECK FOR LEFT 1102 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX,CY-1,CH) 1104 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MY=MY+8::GOTO 90 1106 GOTO 90 1200 ! CHECK FOR RIGHT 1202 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX,CY+1,CH) 1204 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MY=MY-8::GOTO 90 1206 GOTO 90 1300 ! CHECK FOR UP 1302 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX-1,CY,CH) 1304 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MX=MX-8::GOTO 90 1306 GOTO 90 1400 ! CHECK FOR DOWN 1402 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX+1,CY,CH) 1404 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MX=MX+8::GOTO 90 1406 GOTO 90 2000 ! GOT TREASURE 2010 CALL SOUND(200,1360,1)::TR=TR+1::IF TR=4 THEN 3000 ELSE 90 3000 ! GOT ALL TREASURE 3010 FOR Q=220 TO 880 STEP 64::CALL SOUND(128,Q,1)::NEXT Q::DISPLAY AT(24,1)ERASE ALL:"GOT ALL THE TREASURE!"::STOP 1 Quote Link to comment Share on other sites More sharing options...
LASooner Posted February 21, 2018 Author Share Posted February 21, 2018 (edited) 1100 ! CHECK FOR LEFT 1102 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX,CY-1,CH) 1104 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MY=MY+8::GOTO 90 1106 GOTO 90 1200 ! CHECK FOR RIGHT 1202 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX,CY+1,CH) 1204 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MY=MY-8::GOTO 90 1206 GOTO 90 1300 ! CHECK FOR UP 1302 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX-1,CY,CH) 1304 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MX=MX-8::GOTO 90 1306 GOTO 90 1400 ! CHECK FOR DOWN 1402 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX+1,CY,CH) 1404 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MX=MX+8::GOTO 90 1406 GOTO 90 That is basically what I'm doing as well, it's not as clean for a 16x16 sprite since I'm doing only 4 checks, I'm going to try adding 4 more and see if that slows it down too much *- GCHAR position point #- Sprite What I'm currently doing * ## *##* * With these 4 checks it works perfectly when colliding with obstacles to the right and down, but left and up causes the character to get stuck, so I've had to include checks to see if the character has gone too far to the left, or too high up and reset their position to the next closest pathway So I'm going to try doing 2 checks on each side. ** *##* *##* ** Which I suspect will yield better collision,without having to check the character's position, but not sure at what cost performance wise doing 8 GCHARs per input loop. Thanks for all the input guys, I appreciate it! Edited February 21, 2018 by LASooner 1 Quote Link to comment Share on other sites More sharing options...
Ed in SoDak Posted February 21, 2018 Share Posted February 21, 2018 Years ago, I wrote a simple two-player tank game. I used CALL COINC, but at any decent sprite speed, XB failed to detect if a cannon shot scored or the two tanks collided, let alone hit any static obstacles. So I just made it into an out of control free for all. Too bad, 'cause I had great graphics and sound for when a tank blew up! -Ed 2 Quote Link to comment Share on other sites More sharing options...
Retrospect Posted February 21, 2018 Share Posted February 21, 2018 Well , performance-wise, if you're compiling the game, just remember take into consideration the heavier the hit on performance your routines are, the lesser the number you'll want in your CALL LINK("DELAY",XX) number ... Just as an example, Eric in Monsterland has around 3 to 4 sprites moving around on screen with programmed movements (not automotion all the time) and I use something like CALL LINK("DELAY",80) ... that is done on every screen update. I think you'll want probably 40 or so. See how it goes. As for the up and down I don't know I'm as stuck as you are on that one Quote Link to comment Share on other sites More sharing options...
LASooner Posted February 21, 2018 Author Share Posted February 21, 2018 I'm actually using a FOR/NEXT loop for my delay and putting the player input loop in that to increase controller sensitivity. I adjust the loop value to adjust the needed delay. 2 Quote Link to comment Share on other sites More sharing options...
RXB Posted February 21, 2018 Share Posted February 21, 2018 I've tried to write an example code to help with the maze game and sprite, and hit on a problem myself. But in doing so, help with this might help you to make your maze game. Note that I've used only small sprite, magnification 1. ! TREASURE HOUSE EXAMPLE GAME ! NO PROBLEM WITH LEFT OR RIGHT, BUT A PROBLEM OCCURS IN UP AND DOWN MOVEMENT, WHY?? ! DEFINE THE GRAPHICS 10 CALL CHAR(104,"080808FF808080FF") ! WALLS (CHAR) 20 CALL CHAR(96,"1819FFBC3C3C6446") ! THE PLAYER (SPRITE) 25 CALL CHAR(112,"00001C2236363E00") ! TREASURE (CHAR) ! DO THE COLOURS 30 CALL CLEAR::CALL COLOR(10,5,16,11,4,1)::CALL SCREEN(2) ! RESET THE SCORE 35 S! PLAN THE HOUSE LAYOUT 40 CALL HCHAR(1,1,104,32)::CALL HCHAR(24,1,104,32)::CALL VCHAR(1,1,104,24)::CALL VCHAR(1,32,104,24) 50 FOR Q=3 TO 22 STEP 2::CALL HCHAR(Q,3,104,28)::NEXT Q 60 FOR Q=3 TO 30 STEP 3::CALL HCHAR(22,Q,104)::NEXT Q ! PLACE THE TREASURE CHARS 70 CALL HCHAR(2,2,112)::CALL HCHAR(2,31,112)::CALL HCHAR(23,2,112)::CALL HCHAR(23,31,112) ! GIVE THE PLAYER X AND Y COORDS AND TELL COMPUTER THAT TREASURE=0 80 MX=136 :: MY=128 :: TR=0 ! PLACE THE PLAYER SPRITE 90 CALL SPRITE(#1,96,16,MX,MY) ! NOTE THE JOYSTICK COMMAND WORKS OPPOSITE WITH X AND Y. I KNOW, RIGHT?! 100 CALL JOYST(1,JY,JX) 110 IF JY=-4 THEN 210 120 IF JY=4 THEN 220 130 IF JX=4 THEN 230 140 IF JX=-4 THEN 240 150 goto 100 210 ! MOVE LEFT 211 MY=MY-8::GOSUB 1100::GOTO 90 220 ! MOVE RIGHT 221 MY=MY+8::GOSUB 1200::GOTO 90 230 ! MOVE UP 231 MX=MX-8::GOSUB 1300::GOTO 90 240 ! MOVE DOWN 241 MX=MX+8::GOSUB 1400::GOTO 90 1100 ! CHECK FOR LEFT 1102 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX,CY-1,CH) 1104 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MY=MY+8::GOTO 90 1106 GOTO 90 1200 ! CHECK FOR RIGHT 1202 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX,CY+1,CH) 1204 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MY=MY-8::GOTO 90 1206 GOTO 90 1300 ! CHECK FOR UP 1302 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX-1,CY,CH) 1304 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MX=MX-8::GOTO 90 1306 GOTO 90 1400 ! CHECK FOR DOWN 1402 CALL POSITION(#1,PX,PY)::CX=INT(PX/8)+1::CY=INT(PY/8)+1::CALL GCHAR(CX+1,CY,CH) 1404 IF CH=112 THEN 2000 ELSE IF CH=104 THEN MX=MX+8::GOTO 90 1406 GOTO 90 2000 ! GOT TREASURE 2010 CALL SOUND(200,1360,1)::TR=TR+1::IF TR=4 THEN 3000 ELSE 90 3000 ! GOT ALL TREASURE 3010 FOR Q=220 TO 880 STEP 64::CALL SOUND(128,Q,1)::NEXT Q::DISPLAY AT(24,1)ERASE ALL:"GOT ALL THE TREASURE!"::STOP RXB has better versions of this XB code for CALL HCHAR and CALL VCHAR 40 CALL HCHAR(1,1,104,32)::CALL HCHAR(24,1,104,32)::CALL VCHAR(1,1,104,24)::CALL VCHAR(1,32,104,24) ! XB 40 CALL HCHAR(1,1,104,32,24,1,104,32)::CALL VCHAR(1,1,104,24,1,32,104,24) ! RXB 70 CALL HCHAR(2,2,112)::CALL HCHAR(2,31,112)::CALL HCHAR(23,2,112)::CALL HCHAR(23,31,112) ! XB 70 CALL HCHAR(2,2,112,1,2,31,112,1,23,2,112,1,23,31,112) ! RXB 1 Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted February 21, 2018 Share Posted February 21, 2018 I've tried to write an example code to help with the maze game and sprite, and hit on a problem myself. But in doing so, help with this might help you to make your maze game. Note that I've used only small sprite, magnification 1. ! TREASURE HOUSE EXAMPLE GAME ... This is only a quick and minor rewrite. I've moved focus from the sprite pixel position to it's row and column position. It makes it easier to evaluate a new position (in this case). Directions are handled in one go instead of splitting the logic into four. Also removing the treasure once you get one. This is of course not a solution for moving a sprite at different speeds (other than 8 pixels per move). ! TREASURE HOUSE EXAMPLE GAME ! DO THE COLOURS 10 CALL CLEAR::CALL COLOR(10,5,16,11,4,1)::CALL SCREEN(2) ! DEFINE THE GRAPHICS 20 CALL CHAR(104,"080808FF808080FF") ! WALLS (CHAR) 25 CALL CHAR(96,"1819FFBC3C3C6446") ! THE PLAYER (SPRITE) 30 CALL CHAR(112,"00001C2236363E00") ! TREASURE (CHAR) ! PLAN THE HOUSE LAYOUT 40 CALL HCHAR(24,1,104,64)::CALL VCHAR(1,32,104,48) 50 FOR Q=3 TO 22 STEP 2::CALL HCHAR(Q,3,104,28)::NEXT Q 60 FOR Q=3 TO 30 STEP 3::CALL HCHAR(22,Q,104)::NEXT Q ! PLACE THE TREASURE CHARS 70 CALL HCHAR(2,2,112)::CALL HCHAR(2,31,112)::CALL HCHAR(23,2,112)::CALL HCHAR(23,31,112) ! GIVE THE PLAYER COORDS 80 C=19 :: R=18 ! PLACE THE PLAYER SPRITE 90 CALL SPRITE(#1,96,16,(R-1)*8+1,(C-1)*8+1) ! READ JOYSTICK 100 CALL JOYST(1,X,Y)::if x=0 and y=0 then 100 ! find new position 110 rn=r-y/4::cn=c+x/4::call gchar(rn,cn,g) ! CHECK FOR WALL 120 if g=104 then 100 ! MOVE OKAY 130 r=rn::c=cn ! CHECK FOR TREASURE 140 if g=112 then 2000 else 90 2000 ! GOT TREASURE 2010 call hchar(r,c,32)::CALL SOUND(200,1360,1)::TR=TR+1::IF TR=4 THEN 3000 ELSE 90 3000 ! GOT ALL TREASURE 3010 FOR Q=220 TO 880 STEP 64::CALL SOUND(128,Q,1)::NEXT Q::DISPLAY AT(24,1)ERASE ALL:"GOT ALL THE TREASURE!"::STOP 1 Quote Link to comment Share on other sites More sharing options...
Retrospect Posted February 21, 2018 Share Posted February 21, 2018 Excellent, sometimes99er. Thankyou. This is something I've always become stuck with! Probably help me with that platformer I need to make and I hope helps LASooner with his game too. 1 Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted February 21, 2018 Share Posted February 21, 2018 Excellent, sometimes99er. Thankyou. This is something I've always become stuck with! Probably help me with that platformer I need to make and I hope helps LASooner with his game too. Thanks. Yep, I hope this may at least bring another perspective (rather than confusion) to the challenge of the topic. Changing focus (from pixel to chars) is not something one has to do, just in this case I think it makes for less code overall. Handling the movement in one go, instead of splitting it up, is universal, even though optimizing XB may indeed lead to "splitting" code. Nice little and cute game that could be taken to the next level. 1 Quote Link to comment Share on other sites More sharing options...
LASooner Posted February 21, 2018 Author Share Posted February 21, 2018 (edited) So after adding 4 more points of character detection, he moves the maze pretty good, the only areas where he's having trouble is the ends of the walls, but I put IF/THEN statements in the movement subroutines to handle those positions and it's working fairly well. If the character gets really close to the wall he's moving slower but not stopping, and I'm not opposed to this behavior as it simulates wall scraping a bit, so I may just leave it. Most importantly adding the extra detection passes hasn't made that much of a speed hit compared to just 4. I took Mathew180's suggestion of removing the interim variable. I use TIdBit so this is my detection pass _MOVERETURN: _COLMAP: CALL GCHAR(INT(MY/8)+1,INT(MX/8)+1,MZ1) IF MZ1=32 THEN GOSUB _LEFT IF MZ1=16 THEN GOSUB _LEFT IF MZ1=17 THEN GOSUB _LEFT IF MZ1=18 THEN GOSUB _LEFT IF MZ1=19 THEN GOSUB _LEFT IF MX>33 AND MY>33 THEN _COLMAP1 FOR A=36 TO 45 IF MZ1=A THEN GOSUB _WEBLEFT NEXT A _COLMAP1: CALL GCHAR(INT(MY/8)+2,INT(MX/8)+1,MZ2) IF MZ2=32 THEN GOSUB _LEFT IF MZ2=16 THEN GOSUB _LEFT IF MZ2=17 THEN GOSUB _LEFT IF MZ2=18 THEN GOSUB _LEFT IF MZ2=19 THEN GOSUB _LEFT IF MX>33 AND MY>33 THEN _COLMAP2 FOR A=36 TO 45 IF MZ2=A THEN GOSUB _WEBLEFT NEXT A _COLMAP2: CALL GCHAR(INT(MY/8)+1,INT(MX/8)+3,MZ3) IF MZ3=32 THEN GOSUB _RIGHT IF MZ3=16 THEN GOSUB _RIGHT IF MZ3=17 THEN GOSUB _RIGHT IF MZ3=18 THEN GOSUB _RIGHT IF MZ3=19 THEN GOSUB _RIGHT IF MX>33 AND MY>33 THEN _COLMAP3 FOR A=36 TO 45 IF MZ3=A THEN GOSUB _WEBRIGHT NEXT A _COLMAP3: CALL GCHAR(INT(MY/8)+2,INT(MX/8)+3,MZ4) IF MZ4=32 THEN GOSUB _RIGHT IF MZ4=16 THEN GOSUB _RIGHT IF MZ4=17 THEN GOSUB _RIGHT IF MZ4=18 THEN GOSUB _RIGHT IF MZ4=19 THEN GOSUB _RIGHT IF MX>33 AND MY>33 THEN _COLMAP4 FOR A=36 TO 45 IF MZ4=A THEN GOSUB _WEBRIGHT NEXT A _COLMAP4: CALL GCHAR(INT(MY/8)+1,INT(MX/8)+1,MZ5) IF MZ5=32 THEN GOSUB _UP IF MZ5=16 THEN GOSUB _UP IF MZ5=17 THEN GOSUB _UP IF MZ5=18 THEN GOSUB _UP IF MZ5=19 THEN GOSUB _UP IF MX>33 AND MY>33 THEN _COLMAP5 FOR A=36 TO 45 IF MZ5=A THEN GOSUB _WEBUP NEXT A _COLMAP5: CALL GCHAR(INT(MY/8)+1,INT(MX/8)+2,MZ6) IF MZ6=32 THEN GOSUB _UP IF MZ6=16 THEN GOSUB _UP IF MZ6=17 THEN GOSUB _UP IF MZ6=18 THEN GOSUB _UP IF MZ6=19 THEN GOSUB _UP IF MX>33 AND MY>33 THEN _COLMAP6 FOR A=36 TO 45 IF MZ6=A THEN GOSUB _WEBUP NEXT A _COLMAP6: CALL GCHAR(INT(MY/8)+3,INT(MX/8)+1,MZ7) IF MZ7=32 THEN GOSUB _DOWN IF MZ7=16 THEN GOSUB _DOWN IF MZ7=17 THEN GOSUB _DOWN IF MZ7=18 THEN GOSUB _DOWN IF MZ7=19 THEN GOSUB _DOWN IF MX>33 AND MY>33 THEN _COLMAP7 FOR A=36 TO 45 IF MZ7=A THEN GOSUB _WEBDOWN NEXT A _COLMAP7: CALL GCHAR(INT(MY/8)+3,INT(MX/8)+2,MZ8) IF MZ8=32 THEN GOSUB _DOWN IF MZ8=16 THEN GOSUB _DOWN IF MZ8=17 THEN GOSUB _DOWN IF MZ8=18 THEN GOSUB _DOWN IF MZ8=19 THEN GOSUB _DOWN IF MX>33 AND MY>33 THEN _LIMITS FOR A=36 TO 45 IF MZ8=A THEN GOSUB _WEBDOWN NEXT A Edited February 22, 2018 by LASooner Quote Link to comment Share on other sites More sharing options...
LASooner Posted February 22, 2018 Author Share Posted February 22, 2018 Time to take the wraps off what I've been farting around with. Here's my test, I have the player moving through the maze, Robot, Bats and Spider randomly moving through the maze, and I can pick up the gun and add bullets. I've only been working on this since last week. It is running CPU Overdrive because it's not compiled yet. But this is all very encouraging. I felt like Night Stalker was good choice, Bomb Squad was a little too ambitious at this time. It only has 1 map, always 4 enemies, so basically once I get the base game working, getting to the finish seems more achievable. With tools like XB256, Magellan and TIdBit, it sure removes the barrier to entry. The next challenge will be shooting and hit detection. But I'll probably clean up the player sticking to walls as much as I can. Thanks again everyone for the help! 9 Quote Link to comment Share on other sites More sharing options...
unhuman Posted February 25, 2018 Share Posted February 25, 2018 That's fantastic. You may need to be mindful of >4 sprites per line. In my head, that's always the biggest challenge, especially when you consider bullets, although perhaps you can use character animations for those. If you do that, then you could just prevent the 2 bats from ever crossing paths. Then you're done. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.