LoginLogin
Nintendo shutting down 3DS + Wii U online services, see our post

Could someone help me with programming Sprite Collision with BG Tiles?

Root / Programming Questions / [.]

ElzoBroCreated:
Just give me a crash course on it all, I dont know almost nothing about sprite collision, but I mainly want to know stuff with BG Tiles and such. Thanks!

Just give me a crash course on it all, I dont know almost nothing about sprite collision, but I mainly want to know stuff with BG Tiles and such. Thanks!
Hey. I can help you. Here's the basic run down. A sprite is just four lines connected together. To collide with a bg tile you need to actually use bgget at location. If you REALLY want to use sphit It's pretty simple but you won't get GOOD results. unless you know a bit more about the mechanics of movement in games. For instance if your sprite moves forward 4 pixels but was only 3 pixels away from the tile which is meant to be solid and then SPHIT detects the collision you may FIND that all of a sudden your sprite is 1 pixel past the 'solid' tile. If you had code that checks if the player is against solid tile and you didn't take care to detect what SIDE of the player was touching that solid tile or where it was happening (in relation to the player's four sides) and you were lazy and basically said "The player can't move if touching any solid tile ever or if stuck inside any solid tile) you would end up either trapping the player forever until they glitch themselves back out of it OR you could do the inverse and say "allow the player to move on solid tile as long as they are landed" but if the player ends up landing BETWEEN a solid and non solid tile sideways then your player will end up smushed and unable to move (so long as part of the solid tile is detected as them landing) So if you are reckless about how, where, and why the collision happened then your engine is going to have bugs like you wouldn't believe. You would use BGCHECK or something. Nope that isn't right. Let's set up something very very simple.
DIM MAP[7, 7] 'THIS IS ACTUALLY 8 x 8 BUT SMILEBASIC COUNTS FROM 0
FOR TX=0 TO 7
FOR TY=0 TO 7
MAP[TX, TY]=READ ' THIS STORES THE DATA IN THE EASY TO READ ARRAY IN OUR ACTUAL MAP
NEXT
NEXT


'THS SUBROUTINE MAKES THE TILES IN THE ARRAY GO ONTO THE BGSCREEN
@DRAWMAP
BGLAYER=0 'CHANGE THIS TO CHANGE WHAT BG LAYER IT GOES ON BUT ALL TILES WILL BE PUT THERE
FOR TX=0 TO 7
FOR TY=0 TO 7
'THE LINE BELOW THESE COMMENTS PUTS THE MAP DATA AT X, Y INTO TILEVALUE SO IT CAN BE USED IN BGPUT
'THE SHORTCUT IS TO JUST PUT MAP[TX, TY] IN PLACE OF TILEVALUE IN THE LINE COMMENTED *TILEPLACEMENT*
TILEVALUE = MAP[TX, TY]
BGPUT BGLAYER, TX, TY,  TILEVALUE '*TILEPLACEMENT*
NEXT NEXT
RETURN

'IF YOU LOOK AT THIS YOU WILL SEE IT LOOKS SORT OF LIKE A MAP WHERE 1 IS WALLS AND 3 IS 'WALKABLE'
DATA 1, 1, 1, 1, 1, 1, 1, 1
DATA 1, 3, 3, 3, 3, 3, 3, 1
DATA 1, 3, 3, 3, 3, 3, 3, 1
DATA 1, 3, 3, 3, 3, 3, 3, 1
DATA 1, 3, 3, 3, 3, 3, 3, 1
DATA 1, 3, 3, 3, 3, 3, 3, 1
DATA 1, 1, 1, 1, 1, 1, 1, 1
Alright so the above code example should work. If it doesn't let me know. But basically once you test that you see how map data actually works. the for loops go from 0 to however many you define and in this case they have to count for the exact same amount of tiles that your program has reffered to in our case it's 8 but because we count from zero it's 8-1 or just 7 though you could put 8-1 if it makes your life easier (in the actual for x=0 to, y=0 to) loops. Ie: X=0 to 8-1 it might be easier for you to remember. and for addressing the array just visualize it. X is across and Y is down. 0, 0 is the top left corner and 7, 7 is the bottom right corner. All those 1's and 3's don't look too convincing but trust me they do some cool things. Or atleast, they will when we're done here. Alright so what now? I've explained how maps work.. and you can kind of see that a 2d map in smilebasic is similiar to this array that's why the exchange of these two data types works so well. now we can move onto more juicy things. When you have a player sprite it's going to inevitably have two coordinates. X and Y We'll call these playerx and playery like so
playerx=10
playery=10
neat. SO basically the way it works now is you can figure out what tile is at what coordinates. If you had this set up you could easily do this math
TileX = abs(playerx/16)
TileY = abs(playery/16)
this gets us a 16 by 16 offset. okay so now we know roughly the tile. We can't put decimals or big numbers into the array but with this we can get the tile number that the player is most likely touching. Like so:
TileValue = MAP[TileX, TileY]
Lastly , we can check if the TileValue is a 1 or a 3 before letting the player move. So what if we want the tile closest to the player. Simple.
'tile to the left of player
LeftTileX = ABS( (PlayerX-1)/16)
LeftTileY = ABS(PlayerY/16)
'tile to the right of the player
RightTileX = ABS(PlayerX+1) / 16)
RightTileY = ABS(PlayerY/16)
'Tile below the player
BelowTileX = ABS(PlayerX/16)
BelowTileY = ABS( (PlayerY+1)/16 )
'Tile above the player
AboveTileX = ABS(PlayerX/16)
AboveTileY = ABS((PlayerY-1 ) /16)
If you had this code in your main loop or in a subroutine called @getplayertiles you would then be able to establish a system of just quickly checking what tile values are near the player So say this is your player: [L]X[R] [D] In that case you now have all the X and Y coordinates (in map space not pixel space) to be able to check where the player is virtually any time during your game loop. Now this isn't the most acurate but it often times gets the job done (with some overlap) once you can identify what tile *NUMBER* is on either side of the player. You can simply allow or dis-allow movement based on that alone In this case you'd have to check if a tile was solid or not before letting the player move. I'll finish part 2 of this post later but I think it's more than enough info to get you started. however; One last thing. To get the actual tile NUMBER of each position we do this
left_tile = MAP[LeftTileX, LeftTileY]
right_tile=MAP[RightTileX, RightTileY]
below_tile = MAP[BelowTileX, BelowTileY]
above_tile = MAP[AboveTileX, AboveTileY]

With that set up all you'd need to do is this:
B=BUTTON()
'MOVE UP
IF B AND 1 THEN IF ABOVE_TILE>1 THEN PLAYERY=PLAYERY-1
'MOVE DOWN
IF B AND 2 THEN IF BELOW_TILE>1 THEN PLAYERY=PLAYERY+1
'MOVE LEFT
IF B AND 4 THEN IF LEFT_TILE>1 THEN PLAYERX=PLAYERX-1
'MOVE RIGHT
IF B AND 8 THEN IF RIGHT_TILE>1 THEN PLAYERX=PLAYERX+1
If you combine most of these concepts together you will actually have a program structure that lets you move a sprite around the last thing to do of course would be to use spset to set your sprite up and then spofs to move it
'at your start code
spset 1, 507, 0, 0
'in your main loop after movement goes here
SPOFS 1, PLAYERX, PLAYERY, 4

and that wraps up the lesson. If you have any questions or issues regarding this concept let me know and I will help however I can but keep in mind I'm always a bit hard-pressed for time with my busy lifestyle X_X

Alright so, I went ahead and helped ElzoBro with this further. Here is the key and the changelog: KEY 4RXPE4PD Changelog here:
Spoiler [quote = "changelog"] ChangeLog for "COINZEXAMPLE" January 20th, 2017 ===How to read this=== anything with a - in front of it is a change logged. If you see something like ===code starts here=== and ===code ends here=== it is telling you that the last change noted with - is continued in description by that code. I did this so that it's VERY clear what the code is. When you see this code here it's telling you the new code added. If old code like a function or def existed before Then assume it was changed to the new code contained. I'll try to be clear about which code was changed. I won't explain why in every instance. Enjoy. -Delete The following lines: -Deleted line 2: READ MAP[TX ,TY] as it's no longer needed (DEF DRAWMAP Will replace it) -Deleted line 3: NEXT as it was part of the above -Deleted line 4: NEXt as it was part of the above -Wrote @MAPDATA one line above all the data lines. It's used to tell SB how to copy data to an array. -Moved from @mapdata down to the last data statement from the MIDDLE of the program to the very end of it. -Deleted the line "TILEX=ABS(PlayerX/16) as it was meant as an example only -Deleted the line "TILEY=ABS(Playery/16) as it was meant as an example only -Deleted the line "TILEVALUE=MAP[TILEX, TILEY] as it's not useful outside main loop and it wasn't in mainloop -added the FOLLOWING code ABOVE the label @MAPDATA =====code starts here==== DEF DRAWMAP BGLAYER COPY MAP, @MAPDATA, 8*8 BGLOAD BGLAYER, MAP END ======code ends here===== -Moved the line "PlayerX=10" all the way to line 2 -Moved the line "PlayerY=10" all the way to line 3 -changed the line "Playerx=10" to "PlayerX=32" -changed the line "Playery=10" to "playery=32" The above two lines were moved because they aren't part of the main loop (Ever) Do not ever put direct player coordinate assignment in the main loop --As it will over-ride any movement the player actually makes. -Added the following code BELOW the line (line3) which has this code on it "PlayerY=10" ===Code starts here=== While 1 'tile to the left of player LeftTileX = ABS( (PlayerX-1)/16) LeftTileY = ABS(PlayerY/16) 'tile to the right of the player RightTileX = ABS(PlayerX+1) / 16)+1 '+1 extra player tile width RightTileY = ABS(PlayerY/16) 'Tile below the player BelowTileX = ABS(PlayerX/16) BelowTileY = ABS( (PlayerY+1)/16 )+1 '+1 extra player tile height 'Tile above the player AboveTileX = ABS(PlayerX/16) AboveTileY = ABS((PlayerY-1 ) /16) 'THIS GETS THE TILES left_tile = MAP[LeftTileX, LeftTileY] right_tile=MAP[RightTileX, RightTileY] below_tile = MAP[BelowTileX, BelowTileY] above_tile = MAP[AboveTileX, AboveTileY] '=====MOVING CODE===== B=BUTTON() 'MOVE UP IF B AND 1 THEN IF ABOVE_TILE>1 THEN PLAYERY=PLAYERY-1 ENDIF 'MOVE DOWN IF B AND 2 THEN IF BELOW_TILE>1 THEN PLAYERY=PLAYERY+1 ENDIF 'MOVE LEFT IF B AND 4 THEN IF LEFT_TILE>1 THEN PLAYERX=PLAYERX-1 ENDIF 'MOVE RIGHT IF B AND 8 THEN IF RIGHT_TILE>1 THEN PLAYERX=PLAYERX+1 ENDIF SPOFS 1, PLAYERX, PLAYERY, 4 VSYNC 1 wend ===Code ends here===== -Put following code ABOVE WHILE line ==Code starts here 'at your start code BGOFS 0, 0, 0, 1024 SPSET 1, 310 ==code ends here====== -Put the following code before SPSET and BGOFS ===Code starts here=== DRAWMAP 0 ===code ends here=== -Changed the DRAWMAP function code TO THIS: =======def starts here==== DEF DRAWMAP BG COPY MAP, @MAPDATA BGLOAD BGLAYER, 0, 0, 8, 8, MAP END =======def ends here ===== -Put CLS at line 1 of program ABOVE everything else. few notes When someone says delete a 'whole' for loop it means ====delete from here=== FOR X=1 to 10 //some code print "hi" //some more code next ===to here =======