SFML community forums

Help => Graphics => Topic started by: gop_t3r on February 06, 2014, 04:13:47 pm

Title: Help with Tile collisions
Post by: gop_t3r on February 06, 2014, 04:13:47 pm
So far I got collisions between sprites that are of type sf::Sprite; but my tiles are not of type sf::Sprite so the collisions do not work. My tiles are of sf::VertexArray type, and I used the tile-map as a base from

http://www.sfml-dev.org/tutorials/2.1/graphics-vertex-array.php

I can get my player to check for collisions with the tile-map, but the only problem is that because all the numbers represent a tile the collision check returns true.

Using the code from the tutorial above, how can I implement a simple tile collision with a player that has a type sf::Sprite? Thanks for reading.
Title: Re: Help with Tile collisions
Post by: eXpl0it3r on February 06, 2014, 04:26:23 pm
Not sure what you've already been using, but since you want a simple way to detect collision, you can just go with sf::Rect<T>::contains() function.

The sf::Sprite provides you a handy function to get it's global bounds: getGlobalBounds(), it returns a sf::FloatRect. All you now need to do is write a function to retrieve the global bounds of your tile. If there's no scaling or rotation involved with your vertex array, you can simply go and use the four vertices of your tile to construct the global bounds.
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 06, 2014, 04:52:42 pm
That could work, but again, it will always return true because the player is in the tile map to begin with. How can I discriminate so that only some of the tiles are collidable and others aren't?
Title: Re: Help with Tile collisions
Post by: AN71 on February 06, 2014, 05:48:11 pm
Well, I, for one, am now confused.

Are you using  a grid system? Are you pre-rendering your screen to a buffer that is the size of the screen, and using that as the grid (making the boundaries of tiles unavailable)? I'm rather perplexed by what you mean by
Quote from: gop_t3r
it will always return true because the player is in the tile map to begin with
Isn't this the same for most tile games? Are you using some unusual method that prevents the tile's boundaries from being accessed on an individual basis? The more info given, the easier it is to find a solution :)
Title: Re: Help with Tile collisions
Post by: Assassin0795 on February 07, 2014, 02:32:46 am
Why not just assign a particular state to tiles set by 2 and 3? I.e. If your character goes to move onto a pixel that part of the tile marked by the number 2 (let's say 2 denotes a wall tile), then movement in that particular direction will fail.

Or is this what you're stuck at? I apologize if I'm just rephrasing your question.
Title: AW: Help with Tile collisions
Post by: eXpl0it3r on February 07, 2014, 08:19:13 am
You simply map the numbers to the wanted tile type and actually even construct the bounds from it (it's easy given that all tiles have the same size.

So iterate over the tile map, check if it's a collideable tile type (wall etc), if so construct the bounds, check for collision.

The next step and sometimes harder one, is to properly react to the collision. ;)
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 07, 2014, 08:23:14 pm
Thanks for your responses, I know which tiles I want collidable but I need to know how it can be implemented. Using the code above as to loading a tile, what must I modify in order to make tiles 2 and 3 collidable? Using a finite state in order to control this would be very helpful but I'm open to other ideas. So far I've been able to grep all the tile numbers according to their value using an iterator, but I figure that may not be enough since those are just numbers, not the tiles themselves. Suffice it to say I don't know how I can check if it's a collidable type since it's just a number, unless I say: if the number is 2 or 3, then the tile is collidable. It's the latter that I don't know how to implement. Sorry for the confusion!
Title: Re: Help with Tile collisions
Post by: Hapax on February 07, 2014, 08:40:36 pm
Using the code above...what must I modify in order to make tiles 2 and 3 collidable?
You wouldn't be modifying the code in the TileMap class. That just creates the actual image to display the map. You would be testing again the values in the array that holds the data on which tile should be shown at the tile position.

Do you know which position in the grid that your sprite is in? (i.e. in tile coordinates rather than pixel coordinates)
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 08, 2014, 12:36:03 am
Using the code above...what must I modify in order to make tiles 2 and 3 collidable?
You wouldn't be modifying the code in the TileMap class. That just creates the actual image to display the map. You would be testing again the values in the array that holds the data on which tile should be shown at the tile position.

Do you know which position in the grid that your sprite is in? (i.e. in tile coordinates rather than pixel coordinates)

No, I don't know; how do I find out where my sprite is in tile coordinates?
Title: Re: Help with Tile collisions
Post by: Hapax on February 08, 2014, 01:08:57 am
Do you know which position in the grid that your sprite is in? (i.e. in tile coordinates rather than pixel coordinates)
No, I don't know; how do I find out where my sprite is in tile coordinates?
Starting at the position that you display your tilemap, you just need to work out how many times tileSize has been passed - in both x and y. e.g. (sprite.x - tilemapOrigin.x) / tileSize.x
That is assuming that your tilemap's origin is still located at the top-left corner of the map.
You might also want to round it down to get the exact grid position.
The results will be where in the grid the sprite is and you can then know which tile values (in the array) you need to be checking.
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 08, 2014, 01:27:55 am
Do you know which position in the grid that your sprite is in? (i.e. in tile coordinates rather than pixel coordinates)
No, I don't know; how do I find out where my sprite is in tile coordinates?
Starting at the position that you display your tilemap, you just need to work out how many times tileSize has been passed - in both x and y. e.g. (sprite.x - tilemapOrigin.x) / tileSize.x
That is assuming that your tilemap's origin is still located at the top-left corner of the map.
You might also want to round it down to get the exact grid position.
The results will be where in the grid the sprite is and you can then know which tile values (in the array) you need to be checking.

When you refer to sprite.x, do you mean the player's sprite? How do I get the tilemap origin? There's no get origin function for Vertex Arrays.
Title: Re: Help with Tile collisions
Post by: Hapax on February 08, 2014, 03:01:16 am
When you refer to sprite.x, do you mean the player's sprite? How do I get the tilemap origin? There's no get origin function for Vertex Arrays.
Yes, I just meant the x position of the sprite. By origin I meant the position you draw it at. You should be able to do tilemap.setPosition(x, y) to choose where it goes. I believe that the default position is top-left corner, which is (0, 0).
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 08, 2014, 04:02:17 am
I am no philosopher to be pragmatic as to know what we're supposed to do with tileSize. Right now, am clueless what you're asking for here, and I'd understand better if you elaborated how I'm supposed to use tileSize in order to get a tile collision through code rather than describing what's supposed to happen. I'm following what you're doing but I have no idea where I'm supposed to implement and how it's all coming together; everything's just fragmented.
Title: Re: Help with Tile collisions
Post by: Hapax on February 08, 2014, 04:19:34 am
I was talking only about finding out which tile your sprite is "in" so that you can know which tile it is in the array. That way, you can decide if it's a tile that should be collided with or should be ignored.
Then, when you know whether it should be collided with or not, you can compare the bounding box of the sprite and the tile.

That sort of thing...
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 08, 2014, 05:15:30 am
Okay, I think I understand. You mean I need to create a getTileSize() function wherein I just get the size of the tile and test whether it's been collided with or not?
Title: Re: Help with Tile collisions
Post by: Hapax on February 08, 2014, 05:26:38 am
First, you could use sf::Vector2f for tileSize so it uses float, or you could cast the integers to float to force it to comply.
Second, I don't know why you need a function to work out the size of each tile; it will be in the line that created the tilemap.
This is from the tutorial where you got the tilemap class (this is the code that loads the map):
TileMap map;
    if (!map.load("tileset.png", sf::Vector2u(32, 32), level, 16, 8))
        return -1;
The size of each tile is here in the sf::Vector2u - they're 32 x 32. Which values you used there in that line is the size of your tiles.

The tile size is used to find which tile the sprite is in by using the sprite's position using something like what I posted earlier.

Just to clarify, where is your tilemap? Is it in the top-left corner of your window? Does it fit into the window?
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 08, 2014, 06:06:57 am
You lost me now; where am I supposed to be implementing this? I'm assuming it's in the class implementation file, hence I created a function. My tilemap is actually stored in a file, and I modified my tile loader function to read from it. My tileset is actually 40 x 40; and yes, the origin is in the top-left corner of the window, and it does fit into the window as well.

I think some code could help out here, please; doesn't have to be accurate but I need an idea as to what you're getting at. If it's in main.cpp, then I'm happy to comply. In which case, there should be something like this:

float result = (player.sprite.getPosition().x - map.getPosition().x) / 40;
 

So far so good.
Title: Re: Help with Tile collisions
Post by: Hapax on February 08, 2014, 05:22:16 pm
Since you're map is at (0, 0) - the top-left - it's not necessary to subtract its position from the sprite's.

Please take some time to study this image. I hope you understand it because it's the clearest representation of what I'm trying to explain.
(http://i.imgur.com/RwmvlfR.jpg)

tiles[tileNumber] would then tell you which tile (from your array of tiles) is in under the sprite at its origin. You would then need to decide what to do with that information e.g. Is player in a tile that it can pass through, is the next tile in the direction that the player is moving a tile that the player can pass through.
Title: Re: Help with Tile collisions
Post by: Hapax on February 08, 2014, 09:29:37 pm
You just need to decide which tiles should collide and which ones shouldn't. Then test for those values.

For example, if the player shouldn't collide with tiles 0 or 1 but should collide with 2 or 3, then it would be:
if ((map.pTiles[tileNo] == 2) || (map.pTiles[tileNo] == 3))
{
  // player has collided with something it shouldn't have so move/stop/alter player accordingly.
}
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 09, 2014, 12:08:56 am
You just need to decide which tiles should collide and which ones shouldn't. Then test for those values.

For example, if the player shouldn't collide with tiles 0 or 1 but should collide with 2 or 3, then it would be:
if ((map.pTiles[tileNo] == 2) || (map.pTiles[tileNo] == 3))
{
  // player has collided with something it shouldn't have so move/stop/alter player accordingly.
}

Thanks, the collision test works! What I'm planning to do is simply have platforms 2 and 3 solid, such that the player can't move through them. How can I prevent a player from moving 'through' tiles? I tried a premature method of just subtracting 40 from the position thereof, but it doesn't do what I really want.
Title: Re: Help with Tile collisions
Post by: Hapax on February 09, 2014, 01:17:40 am
Ah good! :)
Well, you now know how to compare tiles in the map with the pixel positions (e.g. sprite origins). What you do with that information, however, is up you. I can't write your code for you :p You should google some tips for dealing with collisions.

FYI, "it's not doing what I want" doesn't give enough information for anyone to help; (most) people aren't mind-readers ;)
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 09, 2014, 05:35:55 am
At least I have tile-collisions, what happens as a result thereof varies; indeed this thread's purpose has thus been satisfied and I hereby declare this issue resolved.

Thanks for your help!
Title: Re: [SOLVED] Help with Tile collisions
Post by: gop_t3r on February 10, 2014, 04:13:28 pm
Hi, I am reopening this thread as an issue has arisen which I have not noticed until today:

The tile collision works, but appears the program thinks there's a collision when I am on the same x-axis as the specified tiles. Say a player collides with a tile at (400, 300), it returns true (there is a collision), but if I move along the x-axis outside the tile to somewhere like (300, 300), it still returns true and thinks that it's on the same tile as the player was on (400, 300).
Title: Re: [SOLVED] Help with Tile collisions
Post by: Hapax on February 10, 2014, 05:51:01 pm
it still returns true and thinks that it's on the same tile as the player was on (400, 300).
How do you know it thinks that? How are you testing to see if it's still true?

I'm using the same information you have given me regarding this collision.
The information I gave you was to detect which tile the origin of the sprite was in (so you could work out whether it was supposed to collide or not). For the actual collision detection, you would need to test the boundary boxes for the sprite against the tiles' boundary boxes.
Title: Re: [SOLVED] Help with Tile collisions
Post by: gop_t3r on February 10, 2014, 06:48:53 pm
it still returns true and thinks that it's on the same tile as the player was on (400, 300).
How do you know it thinks that? How are you testing to see if it's still true?

I'm using the same information you have given me regarding this collision.
The information I gave you was to detect which tile the origin of the sprite was in (so you could work out whether it was supposed to collide or not). For the actual collision detection, you would need to test the boundary boxes for the sprite against the tiles' boundary boxes.

The only way for it to return true is through the if statement provided; I have run the program and even though the player is not at the tile BUT is on the same horizontal axis as the tile, it returns true.

This is what I've concluded from testing, using the coordinates of the player:

Test 1: Where x = 168, y = 228 --> NO collision;
Test 2: Where x = 100, y = 332 --> collision; (this co-ordinate is located to the LEFT of the tile, outside thereof)
Test 3: Where x = 374, y = 320 --> collision; (this co-ordinate is located within the tile)
Test  4: Where x = 740, y = 308 --> collision; (this co-ordinate is located to the RIGHT of the tile, outside thereof)

As you can see, the outlier y value concludes that there is something wrong with the y value in collision detection. I have used the information you gave me to work out which tile the sprite was in, but what's interesting is that in all those three collision detections, REGARDLESS of what's being shown on screen; the tileNumber returns 2. In collision tests 2, 3 and 4: tileNumber returns 2, even though in collision tests 2 and 4 were OUTSIDE the tile. I don't think this is a problem with the actual collisions detection, but rather in how the program is interpreting which tile is which. So far, it only happens to tile numbers 2 and 3 and a collision test on both tiles returns true regardless of where we are on the horizontal axis.

I think a problem lies in this line of code:

float tileNo = (gridPosition.y * gridSize.x) + gridPosition.x;
 
Title: Re: Help with Tile collisions
Post by: Hapax on February 10, 2014, 07:17:52 pm
Do you only have one tile that would be tested for collision? Could it be "colliding" with a different tile that should be collided with?

That code is fine as long as your tile data is an array which goes through each x before y (i.e. like the tutorial tilemap does). It also relies on the fact that your tile map is located at the top-right corner, the tile size you use to calculate the grid sizes is correct, and the grid size is correct.

How are you testing this? Are you placing a sprite in one place explicitly, running the code, checking to see if text is output, and then ending the code. Or, are you moving the sprite without closing the program?
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 10, 2014, 07:39:58 pm
Do you only have one tile that would be tested for collision? Could it be "colliding" with a different tile that should be collided with?

That code is fine as long as your tile data is an array which goes through each x before y (i.e. like the tutorial tilemap does). It also relies on the fact that your tile map is located at the top-right corner, the tile size you use to calculate the grid sizes is correct, and the grid size is correct.

How are you testing this? Are you placing a sprite in one place explicitly, running the code, checking to see if text is output, and then ending the code. Or, are you moving the sprite without closing the program?

My tile-map is located at the top-left hand corner. I am testing this program by having my player moving without closing the program. If it moves to the aforementioned coordinates, the results thereof appear.
Title: Re: Help with Tile collisions
Post by: Hapax on February 10, 2014, 09:00:53 pm
My tile-map is located at the top-left hand corner.
Yeah, I meant top-left :p

The problem is that the computer thinks the tiles are drawn as they appear on the first image.
I'm not sure how you know what your computer is thinking.

I am testing the collision through a simple cout << "collision" << endl; because I need to ensure that a collision is actually happening.
This is the most interesting part. Do you mean that you output "collision" to the console when there is a collision based on whether or not the sprite is in the tile at that time?
If so, what console readout do you get? Is it just one output that stays there?

Also, at the place where it isn't supposed to collide... Does it show collision if you go there without going to the other place first?
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 10, 2014, 09:42:52 pm
The collision check only couts "collision" if and only if a collision has occurred, which should return true WHEN the tile 2 is collided with. The interesting part is this: look back at tests 1-4 in my other post and follow this:

Do you not see? The computer thinks the tiles that are meant to be 0, are in fact 2. By the way, when I say 'think', it is euphemism for whatever the computer assumes to be right or wrong. (I know the computer doesn't think)

What's funny is that even if I'm not at tile 2, it still returns true for collision IF I AM ON THE SAME HORIZONTAL AXIS as tile 2 or any other tile I want to collide with. So long as I am colliding with the tile, then it will continue to cout << "collision" until I leave the vicinity. Have you tested the code to see if you can detect the issue?
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 10, 2014, 10:18:54 pm
I've just implemented a bounding box collision test from another class I use for it; it appears the issue hasn't been resolved and am convinced that this has definitely something to do with the way tileNo is calculated. Just out of curiosity, what data type do you expect from pTiles or tileNumber? You haven't defined any data types in your example, and I'd like your input as to which data types you expect. Just so you know, pTiles is a vector array of integers.
Title: Re: Help with Tile collisions
Post by: Lee R on February 10, 2014, 10:32:45 pm
Quote from: gop_t3r
it appears the issue hasn't been resolved and am convinced that this has definitely something to do with the way tileNo is calculated [...]

There doesn't seem to be anything wrong with how the tile number is calculated. It's probably the input values to the calculation that are wrong (i.e. you're returning something funky from 'map.getTileSize()' and/or 'map.getDimensions()').

Quote from: gop_t3r
Have you tested the code to see if you can detect the issue?

Where is the code? :/

Title: Re: Help with Tile collisions
Post by: gop_t3r on February 10, 2014, 11:05:23 pm
Quote from: gop_t3r
it appears the issue hasn't been resolved and am convinced that this has definitely something to do with the way tileNo is calculated [...]

There doesn't seem to be anything wrong with how the tile number is calculated. It's probably the input values to the calculation that are wrong (i.e. you're returning something funky from 'map.getTileSize()' and/or 'map.getDimensions()').

Quote from: gop_t3r
Have you tested the code to see if you can detect the issue?

Where is the code? :/

The code is everywhere as far as I'm aware. Suffice it to say that I've tested everything and there is nothing obscure as to the values produced. All the input values are correct and I'm convinced that there's something weird with the way the computer treats where the player is located at on the grid.

What I noticed is that a collision only happens when the player is touching the bottom of the tile. I really just want a collision which returns true if any of the sides are touched by the player.
Title: Re: Help with Tile collisions
Post by: Hapax on February 10, 2014, 11:10:15 pm
I agree that it's a good idea to check your other functions to make sure they are passing x/y values to the relevant x/y.
Your code is in many fragments here. It's impossible to try it. Why not attach it?
Title: Re: Help with Tile collisions
Post by: Lee R on February 10, 2014, 11:10:53 pm
The code is everywhere? Lemme just grab my ethereal debugger :/
Title: Re: Help with Tile collisions
Post by: Hapax on February 10, 2014, 11:28:34 pm
I've tested everything
Obviously not.

I'm convinced that there's something weird with the way the computer treats where the player is located at on the grid.
The calculations that I gave you will only go far as to tell you which tile (0, 1, 2, 3 in your map) is under a specific coordinate. You've been using the player sprite position for this; it's likely that your sprite's origin is at the top-left corner of the sprite so will "be in" a tile when the top-left corner is. To see if the centre is in a tile, you'll need to offset the value.

What I noticed is that a collision only happens when the player is touching the bottom of the tile. I really just want a collision which returns true if any of the sides are touched by the player.
This can also be caused by the effects of the origin being at the top-left. You can either add half of your sprite's size to its position when you calculate it's grid position, or you can just change where its origin is:
player.sprite.setOrigin(player.sprite.getLocalBounds().width / 2, player.sprite.getLocalBounds().height / 2);
You only need to do that once.
Title: Re: Help with Tile collisions
Post by: Lee R on February 11, 2014, 12:02:05 am
There is nothing wrong with that line of code. That is a well known method to convert from a 2D coordinate into a 1D array index. But hey, you just know that all your other code is producing the correct values, right? :/

Edit: except that it shouldn't be a floating point value...
Title: Re: Help with Tile collisions
Post by: Hapax on February 11, 2014, 01:38:03 am
except that it shouldn't be a floating point value...
Oh wow! I didn't even notice that gop was using float there. He did mention later that I should've put said which types to use for the code.

It was supposed to be helpful and point you in the right direction rather than write the program for you. I obviously overlooked the possibility of using floating point numbers for storage of an array index.

I shall punish myself now.

Gop, you should have a look at the tile map class that you said you adapted. You should also check the file itself...  :P

EDIT: If you changed that code, you'll just be getting random tiles to test. This could be any tile so could deceptively look like it's fixed the other, underlining problem. Trust me; keep that and find out what else is making it not work  ;)
Title: Re: Help with Tile collisions
Post by: gop_t3r on February 11, 2014, 04:30:05 pm
There is nothing wrong with that line of code. That is a well known method to convert from a 2D coordinate into a 1D array index. But hey, you just know that all your other code is producing the correct values, right? :/

Edit: except that it shouldn't be a floating point value...

Please tell me you're not assuming pTiles is a 2D array, right? :-/ It's 1D to begin with.
Title: Re: Help with Tile collisions
Post by: Lee R on February 11, 2014, 05:19:03 pm
I am not assuming pTiles is a 2D array. I am assuming that your screen is 2D. You're converting 2D screen coordinates into 2D grid coordinates (the grid is conceptually 2D) and then into a 1D array index.