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!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, 1Alright 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=10neat. 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+1If 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, 4and 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: