Replying to:12Me21
I've never understood the reason that websites have links that take you to the top of a page...
until now.
Actually no, mobile browsers just suck.
MasterR3CORD what browser are you using?
Root / Submissions / [.]
SPSET 1,856 'NEKOOOThis makes sprite 1 into the cat (definition 856). You can use the SmileTool to see what each definition is. Now we need to put it in the middle of the screen. We use SPOFS to move the sprite to an X and Y location. All sprite commands start with the ID of the sprite your want to manipulate. X is pixels across the screen from the left, Y is pixels down from the top:
SPSET 1,856 SPOFS 1,200,120 'The screen is 400x240, so divide by 2 for the middleOh jeez, the sprite isn't actually in the middle. It's a little off. The sprite position is based on the upper-left corner of the sprite, so that CORNER is in the middle of the screen. To fix this, we will use the middle of the sprite as the offset with SPHOME:
SPSET 1,856 SPHOME 1,8,8 'The sprite is 16x16, so we make the position use the center SPOFS 1,200,120 'Across 200, down 120The order of SPHOME and SPOFS doesn't really matter. Cool, we have a player in the middle of the screen.
BGCLR 'Get rid of everything in the BG layers BGSCREEN 0,100,100 'Set BG layer 0 to 100 tiles wide and 100 tiles tall FOR I=0 TO 99 '0 to 99 because size is 100 but it starts at 0 'The 4 perimeter walls: top, bottom, left, and right BGPUT 0,I,0,107 BGPUT 0,I,99,107 BGPUT 0,0,I,107 BGPUT 0,99,I,107 NEXT FOR I=1 TO 98 FOR J=1 TO 98 'Loop over every single tile within the layer IF RND(4)==0 THEN BGPUT 0,J,I,100 'A 1 in 4 chance to put a tree for each space (tree is tile 100) NEXT NEXTIn your game, you can fill the BG your own way. Draw your game map or something. We now have a map to work with.
BGOFS 0,50,100If you add this to the above map code, you can see the new map position. It updates immediately. In a standard RPG, the player stays in the middle of the screen while the map moves around them as they walk. Thus, our program will only move the BG as the player walks and not the sprite. Notice that the 50,100 is once again using the top left corner of the BG layer as the origin. Setting the BGOFS to 0,0 will put the upper left corner of the layer right up against the upper left corner of the screen. But think about this: where is the player when the BGOFS is 0,0? The player is at 200,120 and hovering over some BG tile in the middle, but the BG location is 0,0. We don't want this: the player should line up with BGOFS. So, a BGOFS of 0,0 should put the upper left corner of the BG underneath our player. We want this because there is a magical command that converts screen coordinates to BG coordinates, and it would be easier to check the screen coordinates under the player rather than over in the corner of the screen. There is a BGHOME command that works similarly to SPHOME: we use it to make BGOFS line up with the center of the screen rather than the upper-left corner. Altogether, the setup code is thus:
ACLS 'Clear EVERYTHING (including BG) 'Player sprite setup SPSET 1,856 SPHOME 1,8,8 SPOFS 1,200,120 'Map setup (a random map with perimeter) BGSCREEN 0,100,100 BGHOME 0,200,120 'Make BGOFS line up with center of screen. FOR I=0 TO 99 BGPUT 0,I,0,107 BGPUT 0,I,99,107 BGPUT 0,0,I,107 BGPUT 0,99,I,107 NEXT FOR I=1 TO 98 FOR J=1 TO 98 IF RND(4)==0 THEN BGPUT 0,J,I,100 NEXT NEXTYou should get a cat in the middle of the screen at the top left corner of a randomly generated map with rock walls. If you do not, check your code and try again (or maybe I messed up).
'Insert this after the setup code above PLX=100 PLY=100 'Player X and Y position. SPD=2 'How fast you can move per frame WHILE TRUE VX=0 VY=0 'Player X and Y velocity (assume none) B=BUTTON(0) 'Set player velocity based on directional input. IF B AND #UP THEN VY=-SPD ELSEIF B AND #DOWN THEN VY=SPD IF B AND #LEFT THEN VX=-SPD ELSEIF B AND #RIGHT THEN VX=SPD PLX=PLX+VX PLY=PLY+VY 'Update player position based on current velocity BGOFS 0,PLX,PLY 'Update the map position to reflect the new player position VSYNC 'Waits for the next screen refresh. Makes game run at 60fps rather than sporadically WENDTogether with the setup code, you should be able to "move" the cat around the map (even though you're actually moving the map). You may notice this isn't optimal. We could, for instance, directly update the position in the button checks. However, we need to split position and velocity for the collision code, as you'll see later.
SPSET 1,856 SPHOME 1,8,8 SPOFS 1,200,120 SPCOL 1,-7,-7,14,14,TRUE,&HFFFFFFFFSPCOL takes an ID, X and Y hitbox position, Width and Height of hitbox, Scaling collision, and a Collision Mask. The X and Y position is relative to SPHOME: our home is the sprite's middle but our hitbox should be at the edge, so it's negative. I'm lenient on collision so there's a 1 pixel free zone around the sprite: instead of the hitbox being 16x16 and lining up perfectly with the sprite, it is 14x14 so the outer edge isn't detected. TRUE means the hitbox will scale with SPSCALE. There are very few cases where this will be FALSE. The &HFFFFFFFF is the collision mask. This value is ANDed with the colliding object's mask and collision is detected if the value is nonzero. For instance, if the player had mask &B101 and the colliding object had mask &B100, collision would be detected. However, if the colliding object's mask is &B010, no collision is detected because no bits match up. &HFFFFFFFF has all the bits set, so collision with anything should be detected (unless the other object's mask is 0). Remember, &B is binary and &H is hexadecimal.
BGCOORD 0,200,120,1 OUT PBGX,PBGYThe parameters are BG Layer, X, Y, Mode. It produces a converted X and Y. In this case, we convert Screen coordinates 200,120 (player position on screen) to BG tile coordinates (mode 1) for layer 0. PBGX and PBGY is now the location of the player in BG tile units. You use BGGET to retrieve the ID of a tile on a BG layer. For this example, we'll assume any nonzero tile ID is solid. You can make this check anything you want. You check collision after determining the velocity but before updating the player position. This way, you know the player's movement but you can intercept it and stop it before the actual position update occurs. The code for checking collision with each tile will start like this (within your game loop):
BGCOORD 0,200,120,1 OUT PBGX,PBGY FOR X=-1 TO 1 FOR Y=-1 TO 1 'Don't check collision for empty tiles (make this check anything you want) IF BGGET(0,PBGX+X,PBGY+Y)==0 THEN CONTINUE 'Run SPHITRC here? NEXT NEXTThe FOR loops check the surrounding tiles (-1 to 1, so 3x3). This will skip tiles that are empty on layer 0. Now the actual hard part: SPHITRC detects collisions with rectangles on the screen. But we're working with BG tile coordinates. BGCOORD to the rescue. One of the BGCOORD modes converts BG pixel coordinates to screen coordinates. There isn't one for BG tile coordinates to screen coordinates, but we can figure out the BG pixel coordinate of the top-left of the tile (the start of the rectangle) with a little math. Using BGCOORD, we can get the screen rectangle coordinates for each of the surrounding BG tiles. While we're at it, we can get SPHITRC set up. Basic SPHITRC takes the ID, Rectangle X and Y, and Rectangle Width and Height and returns TRUE if the sprite with ID is colliding with the given rectangle on screen. The SPHITRC we use is more advanced: we also give the collision mask and the movement speed of the rectangle. The rectangle movement speed is negative: the player might be moving forward, but the map moves in reverse. If the player is moving right (positive X velocity), the map is moving left (negative X velocity). The loop now looks like this:
BGCOORD 0,200,120,1 OUT PBGX,PBGY FOR X=-1 TO 1 FOR Y=-1 TO 1 IF BGGET(0,PBGX+X,PBGY+Y)==0 THEN CONTINUE BGCOORD 0,(PBGX+X)*16,(PBGY+Y)*16,0 OUT RCX,RCY IF SPHITRC(1,RCX,RCY,16,16,&H1,-VX,-VY) THEN VX=0:VY=0 NEXT NEXTRCX and RCY is the screen location of the upper left corner of the BG tile we're checking. Each tile is 16x16, so those are the width and height. If a hit is detected, we want to stop the player's movement (solid objects, you know), so we set their velocity to 0. The mask is &H1: it can be anything because our player mask is the full set &HFFFFFFFF.
ACLS 'Player Setup SPSET 1,856 SPHOME 1,8,8 SPOFS 1,200,120 SPCOL 1, -7,-7,14,14,TRUE,&HFFFFFFFF 'Map Setup BGSCREEN 0,100,100 BGHOME 0,200,120 FOR I=0 TO 99 BGPUT 0,I,0,107 BGPUT 0,I,99,107 BGPUT 0,0,I,107 BGPUT 0,99,I,107 NEXT FOR I =1 TO 98 FOR J=1 TO 98 IF RND(4)==0 THEN BGPUT 0,J,I,100 NEXT NEXT 'Movement and Collision (the game) PLX=100 PLY=100 SPD=2 BGOFS 0,PLX,PLY 'Make sure the BG is set to the player's position before starting. WHILE TRUE VX=0 VY=0 B=BUTTON(0) IF B AND #UP THEN VY=-SPD ELSEIF B AND #DOWN THEN VY=SPD IF B AND #LEFT THEN VX=-SPD ELSEIF B AND #RIGHT THEN VX=SPD 'Our collision loop from just earlier: BGCOORD 0,200,120,1 OUT PBGX,PBGY FOR X=-1 TO 1 FOR Y=-1 TO 1 IF BGGET(0,PBGX+X,PBGY+Y)==0 THEN CONTINUE BGCOORD 0,(PBGX+X)*16,(PBGY+Y)*16,0 OUT RCX,RCY IF SPHITRC(1,RCX,RCY,16,16,&H1,-VX,-VY) THEN VX=0:VY=0 NEXT NEXT PLX=PLX+VX PLY=PLY+VY BGOFS 0,PLX,PLY VSYNC WENDYou may notice some... undesired features. For starters, if you spawn in a block (a 1 in 4 chance), you can't move. At all. If this happens while testing, you can restart the program until you're free. Alternatively, you can remove all blocks generated around the player. A bigger problem: you can't move diagonally across a flat surface and slide along it. This feature is present in basically all RPGs but not here. If you are OK with this, you can stop here and use just this code. We're going to complicate this further by overcoming this diagonal sliding limitation.
CORNERS=0 'How many corners we're colliding with ALLHITS=0 'All single directional hits for all tiles BGCOORD 0,200,120,1 OUT PBGX,PBGY FOR X=-1 TO 1 FOR Y=-1 TO 1 IF BGGET(0,PBGX+X,PBGY+Y)==0 THEN CONTINUE BGCOORD 0,(PBGX+X)*16,(PBGY+Y)*16,0 OUT RCX,RCY IF SPHITRC(1,RCX,RCY,16,16,&H1,-VX,-VY) THEN 'Corner hit test HIT=&H3 'Assume hitting from two directions IF SPHITRC(1,RCX,RCY,16,16,&H1,-VX,0) THEN HIT=HIT AND NOT &H2 'If hitting from sides, assume not hitting from top/bottom IF SPHITRC(1,RCX,RCY,16,16,&H1,0,-VY) THEN HIT=HIT AND NOT &H1 'If hitting from top/bottom, assume not hitting from sides IF (HIT AND &H3)==&H3 THEN CORNERS=CORNERS+1 'If no hit directions were removed, this is a pure corner collision ELSE ALLHITS=ALLHITS OR HIT 'A single direction hit. Combine with other detected single hits ENDIF ENDIF NEXT NEXT 'Only update position if no hits in that direction IF !(ALLHITS AND &H1) THEN PLX=PLX+VX IF !(ALLHITS AND &H2) THEN PLY=PLY+VYNotice the single direction collision checks have -VX,0 and 0,-VY as velocities (respectively). That's movement only in X for the first, and movement only in Y for the second.
IF !((Y==0 && X==0) || (VY!=0 && SGN(VY)==SGN(Y) || VX!=0 && SGN(VX)==SGN(X))) THEN CONTINUEIt creates those shapes above. Basically it says "always check the center tile (0,0), then only check tiles in the direction we're moving". SGN returns 1,0, or -1 based on if the parameter is positive, 0 or negative. It means "give me the sign of the number". The "cut corners" code looks like this:
IF CORNERS>0 && ALLHITS==0 THEN IF ABS(VX)>ABS(VY) THEN ALLHITS=&H2 ELSE ALLHITS=&H1 ENDIFRemember, we ONLY want to process corners if there are no alternatives. ALLHITS is all single direction hits for all checked tiles, so if it's 0 there were no single direction hits. ABS removes the sign on the parameter so the value is always positive. It is the "magnitude" of the number, so ABS(6) == 6 and ABS(-5) == 5.
ACLS 'Clear everything 'Player Setup SPSET 1,856 'Set our player (1) to the cat (856) SPHOME 1,8,8 'Set player position relative to center of sprite SPOFS 1,200,120 'Put player in the center of the screen SPCOL 1, -6.99,-6.99,13.98,13.98,TRUE,&HFFFFFFFF 'Set sprite collision boundaries. 'SPCOL is relative to SPHOME (the center), so -6.99,-6.99 is nearly 7 to the left and up from the center, and 13.98,13.98 is the width/height. 'TRUE says the sprite collision scales with SPSCALE. &HFFFFFFFF is the 32 bit collision mask (collide with anything) 'Map Setup BGSCREEN 0,100,100 'Set BG layer 0 to be 100 tiles width and tall BGHOME 0,200,120 'Place BGOFS 0,0 in the middle of the screen 'These FOR loops fill the map for our collision test. You can use your own map here/ FOR I=0 TO 99 'The rock perimeter BGPUT 0,I,0,107 '107 is a weird rock BGPUT 0,I,99,107 BGPUT 0,0,I,107 BGPUT 0,99,I,107 NEXT FOR I =1 TO 98 FOR J=1 TO 98 'Random trees (1 in 4 chance) IF RND(4)==0 THEN BGPUT 0,J,I,100 NEXT NEXT 'Movement and Collision (the game) PLX=100 'Player position (relative to BG pixels) PLY=100 SPD=2 WHILE TRUE VX=0 'Assume no player velocity VY=0 B=BUTTON(0) 'Set player velocity based on directional input. IF B AND #UP THEN VY=-SPD ELSEIF B AND #DOWN THEN VY=SPD IF B AND #LEFT THEN VX=-SPD ELSEIF B AND #RIGHT THEN VX=SPD ALLHITS=0 'Collect all hit directions. &H1 is left/right hit and &H2 is up/down hit CORNERS=0 'Count corner hits. You get stuck on corners if you don't handle them special BGCOORD 0,200,120,1 OUT PBGX,PBGY 'Get the TILE location the player is in. FOR X=-1 TO 1 FOR Y=-1 TO 1 'Scan the 3x3 section of tiles around the player 'Only check tiles in an "arrow" shape pointing towards the movement IF !((Y==0 && X==0) || (VY!=0 && SGN(VY)==SGN(Y) || VX!=0 && SGN(VX)==SGN(X))) THEN CONTINUE 'This is where you'd figure out if a tile is solid. I say any non-zero tile is solid. IF BGGET(0,PBGX+X,PBGY+Y)==0 THEN CONTINUE 'Convert BG pixel coordinates of tile's upper left corner to screen coordinates. BGCOORD 0,(PBGX+X)*16,(PBGY+Y)*16,0 OUT RCX,RCY 'Check collision of tile rectangle with sprite. 'Rectangle shifted by negative velocity (map moves in opposite direction of player). 'Mask (&H1) can be anything set in player mask (so anything) IF SPHITRC(1,RCX,RCY,16,16,&H1,-VX,-VY) THEN HIT=&H3 'Assume hitting from two directions IF SPHITRC(1,RCX,RCY,16,16,&H1,-VX,0) THEN HIT=HIT AND NOT &H2 'If hitting from sides, assume not hitting from top/bottom IF SPHITRC(1,RCX,RCY,16,16,&H1,0,-VY) THEN HIT=HIT AND NOT &H1 'If hitting from top/bottom, assume not hitting from sides IF (HIT AND &H3)==&H3 THEN CORNERS=CORNERS+1 'If no hit directions were removed, this is a pure corner collision ELSE ALLHITS=ALLHITS OR HIT 'A single direction hit. Add it to the "all possible hit directions" ENDIF ENDIF NEXT NEXT 'If the only hit we have is a corner, choose a direction based on velocity magnitude IF CORNERS>0 && ALLHITS==0 THEN IF ABS(VX)>ABS(VY) THEN ALLHITS=&H2 ELSE ALLHITS=&H1 ENDIF 'Only update position if no hits in that direction IF !(ALLHITS AND &H1) THEN PLX=PLX+VX IF !(ALLHITS AND &H2) THEN PLY=PLY+VY BGOFS 0,PLX,PLY 'Update the map position to reflect the new player position VSYNC 'Waits for the next screen refresh. Makes game run at 60fps rather than sporadically WEND
ACLS BGMSTOP XSCREEN 3 LOAD GRP4:E,FALSE SPDEF 0,0,0,48,72,0,0,1 SPSET 0,0 SPSCALE 0,2,2 SPOFS 0,155,40 BEEP 39 BACKCOLOR RGB(0,0,0) WAIT 100 BGMSTOP ACLS BGMPLAY 9 SPSET 0,856 SPOFS 0,190 105 SPSCALE 0,1,1 SPHOME 1,8,8while writing this i noticed i used the wrong management number lol
IF (PLY>=0 AND PLY<=YMIN) OR (PLY>=YMAX AND PLY<=1575) OR (PLX>=0 AND PLX<=XMIN) OR (PLX>=XMAX AND PLX<=1575) THEN MODE=1 ELSE MODE=0Then later on we the velocities get added...
IF !(ALLHITS AND &H1) && MODE==0 THEN PLX=PLX+VX IF !(ALLHITS AND &H2) && MODE==0 THEN PLY=PLY+VY IF !(ALLHITS AND &H1) && MODE==0 THEN PX=PX+VX IF !(ALLHITS AND &H2) && MODE==0 THEN PY=PY+VYI was gonna worry about collision later. As far as what I have, it works to an extent. What do you think I should add or change? Because when I exit the range I am getting atuck and the sprite is forced to a certain position.