SFML community forums

Help => Graphics => Topic started by: dotty on February 21, 2012, 01:16:09 pm

Title: Collision with FloatRect
Post by: dotty on February 21, 2012, 01:16:09 pm
Hello, I need some advice on collisions. I have setup 2 RectangleShapes and setup up 2 FloatRect around them. One of the shapes is moved around using this code

Code: [Select]

if (sf::Keyboard::IsKeyPressed( sf::Keyboard::W )) {
      this->velocity.y -= this->deltatime;
   }

   if (sf::Keyboard::IsKeyPressed( sf::Keyboard::S )) {
      this->velocity.y += this->deltatime;
   }

if (sf::Keyboard::IsKeyPressed( sf::Keyboard::A )) {
      this->velocity.x -= this->deltatime;
   }

   if (sf::Keyboard::IsKeyPressed( sf::Keyboard::D )) {
      this->velocity.x += this->deltatime;
   }


(Thanks Laurent!).

The FloatRect also move with the moveable box. I've modified the code so that when the 2 boxes intersect the movable box is no longer movable in that direction. The problem is that this code is only run once the boxes intersect, meaning I'm already inside the box and cannot get out.

This must be an obvious issue, but how would one go about fixing it?
Title: Collision with FloatRect
Post by: Ptlomej on February 21, 2012, 03:44:47 pm
I use to detect Physiks with Box2d! if you want to use it to i can Teach you ;)!
Title: Collision with FloatRect
Post by: unranked86 on February 21, 2012, 05:22:58 pm
When the boxes intersect, move the movable box back by 1 pixel.
Title: Collision with FloatRect
Post by: dotty on February 21, 2012, 05:42:48 pm
Sometimes because my movement is timed by deltatime the box doesn't move by 1px and could intersect by 3-4 pixels.
Title: Collision with FloatRect
Post by: texus on February 21, 2012, 05:57:07 pm
Quote from: "dotty"
Sometimes because my movement is timed by deltatime the box doesn't move by 1px and could intersect by 3-4 pixels.

Move it 1 pixel, check the collision again.
If it still collides then you move another pixel until the boxes no longer collide.
Title: Collision with FloatRect
Post by: jmcmorris on February 22, 2012, 08:46:40 am
You'll need some slightly more complicated collision handling. I have recently been working on my own and this is what I am doing.

Set entity's previous position to position
Add gravity to the entity's velocity
Add velocity to the entity's position (multiply time delta if this is not a fixed time loop)
Check for collision with other entities
if collision then calculate the overlap between the two entities
if both entities are movable then divide the overlap between the two and move both away from one another by overlap amount.
if only one entity is movable then move the entity back overlap amount

Things can be a little trickier than that and there are a few ways do deal with them. I'm honestly still figuring them out but this should give you a good start.
Title: Collision with FloatRect
Post by: Haze on February 22, 2012, 02:48:49 pm
During the movement step, store the previous position of each object before computing its new position.
Then, in the collision detection step, if two objects are overlapping, assign their previous position (before collision), so you can ensure objects are never overlapping.
Title: Collision with FloatRect
Post by: jmcmorris on February 22, 2012, 07:02:33 pm
Quote from: "Haze"
During the movement step, store the previous position of each object before computing its new position.
Then, in the collision detection step, if two objects are overlapping, assign their previous position (before collision), so you can ensure objects are never overlapping.


While this is a very simple means to get collision working, it would also mean that if an object has high velocity it would appear to not move at all even though it should have moved 20 out of the 21 pixels that it should have.
Title: Collision with FloatRect
Post by: dotty on February 24, 2012, 02:33:17 pm
Thanks everyone, all the answer were insightful.

I do have another question though. Should my main player's object be checking for collisions with all intrects in my scene? Or should all colliderable objects be checking for collisions with the main player?

If it's the former then what happens if I have 500+ colliderable "tiles" in my scene? Every frame my main player would have to loop around ALL the tiles and do it's collision checking.

How do people go about doings this?
Title: Collision with FloatRect
Post by: unranked86 on February 24, 2012, 04:30:12 pm
Well, I was "researching" (using google :) ) the very same thing, and in general, you have two options. Implement your own Quad-tree, or the grid-based collision detection. In my personal opinion, it all depends on your game, whether you want to use quad-trees or the grid. I mean, if you have a tile-map then the quad-tree seems a better choice.
Title: Collision with FloatRect
Post by: jmcmorris on February 24, 2012, 07:11:28 pm
If you have a tile-based map then the only tiles you need to check to see if the player is colliding with a tile are the tiles that the player is on. Here is my function for detecting if a player is overlapping a tile.

Code: [Select]
std::vector<Vector2i> TileLayer::overlaps(const sf::FloatRect& rect, const bool solidOnly, const bool includeTouching) {
    std::vector<Vector2i> overlapped;
    float touching = includeTouching ? 0 : 0.001f;
    Int32 startX = std::max<float>(0, rect.Left / TileSystem::TILE_WIDTH);
    Int32 startY = std::max<float>(0, rect.Top / TileSystem::TILE_HEIGHT);
    Int32 endX = std::min<float>((rect.Left + rect.Width - touching) / TileSystem::TILE_WIDTH, m_tiles[0].size() - 1);
    Int32 endY = std::min<float>((rect.Top + rect.Height - touching) / TileSystem::TILE_HEIGHT, m_tiles.size() - 1);
    for (Int32 y = startY; y <= endY; ++y) {
        for (Int32 x = startX; x <= endX; ++x) {
            Int32 tileId = m_tiles[y][x];
            if (tileId != 0 && (!solidOnly || m_tileSystem->getTile(tileId)->isSolid())) {
                overlapped.push_back(Vector2i(x, y));
            }
        }
    }
    return overlapped;
}


This takes a rect (the collidable rect of the player), the solidOnly is to check for only solid tiles (you could quite possibly remove this and related code), and the includeTouching is kind of a hack to specify if a rect should be considered overlapping a tile if it is on the tile border. The return value is a list of tiles that the rect is overlapping.

For my collision algorithm I do
Code: [Select]
std::vector<Vector2i> overlapping = tileLayer->(player.getRect(), true, false);
if (!overlapping.empty()) {
    //Collision detected!
}


Doing the actual collision testing is tricky and I'm still working on that code and not happy enough with it yet to share it. The basic logic is along the lines of what I sent in my first post in this topic. The player is movable while the tiles are not.

I hope this helps some!
Title: Collision with FloatRect
Post by: dotty on February 26, 2012, 02:30:35 pm
I'm having difficulties with getting 2 FloatRects to react to each other.

Can someone write a simple sample showing how to to del with this? Having 2 FloatRects on the screen (displayed with RectangleShapes), one of them movable with WASD keys, the other stationary. The movable one needs to collide with the stationary one and not be able to move through it.

This would be very helpful so I can inspect how this is handled.

Thanks
Title: Collision with FloatRect
Post by: Weeve on February 26, 2012, 11:25:31 pm
err.. I'm not going to build the entire code (I'm still working on my own project), but I will give a little help, if your doing only rectangular collision checking, its easy:

Code: [Select]
for (int i=0;i<tiles.size();++i){
    if (PlayerPosition.x + PlayerSize.x/2 <= TilePosition.x + TileSize.x/2 && PlayerPosition.x - PlayerSize.x/2 >= TilePosition.x - TileSize.x/2) {
        //collision on the x
        PlayerPosition.x += (PlayerPosition.x - TilePosition.x)
    }
    if (PlayerPosition.y + PlayerSize.y/2 <= TilePosition.y + TileSize.y/2 && PlayerPosition.y - PlayerSize.y/2 >= TilePosition.y - TileSize.y/2) {
        //collision on the y
        PlayerPosition.y += (PlayerPosition.y - TilePosition.y)
    }
}


I might have a few signs reversed, cause I havent tested this, I just wrote it for you (I've kinda done this before, but in lua, and not C++), but thats the jist of rectangle collision checking, you can break off the && onto another if to make it more efficient if you want :)
Title: Collision with FloatRect
Post by: unranked86 on February 27, 2012, 09:53:49 am
Why don't you use the Intersects(...) (http://sfml-dev.org/documentation/2.0/classsf_1_1Rect.php#a63ad921f63da1183baa87f9e246cab6b) and Contains(...) (http://sfml-dev.org/documentation/2.0/classsf_1_1Rect.php#a7343feda13d5e005182dc4fd893a6f4b) functions of the sf::FloatRect class ? I guess, that's why they exist, you know, to make our lives easier. :)
Title: Collision with FloatRect
Post by: dotty on February 27, 2012, 05:18:43 pm
sorry, I don't think I explained myself very well. I'm using Intersects and that successfully returns a boolean (true on collision, else false).

I'm having difficulties actually dealing with the FloatRects once they actually collide (making FloatRect A stop moving and revert to the boarder of FloatRect B).
Title: Collision with FloatRect
Post by: dotty on February 27, 2012, 11:22:11 pm
Ok, I'm getting somewhere now.

main.cpp - http://pastiebin.com/?page=p&id=4f4c0145b3656
tile.h - http://pastiebin.com/?page=p&id=4f4c0178e3182
tile.cpp - http://pastiebin.com/?page=p&id=4f4c019a11ace

If you set these files up and run them you can move around with WASD

The problem I face is when the block collides it correctly collides, but it also draws the overlapping frame, then the reverted position frame. I'm not sure why this happens, surely the calculations and repositioning is done before the next Draw() is made.

Can anyone lend me a hand on this please?
Title: Collision with FloatRect
Post by: dotty on February 29, 2012, 02:49:35 pm
Pretty please :)
Title: Collision with FloatRect
Post by: Tex Killer on February 29, 2012, 09:14:21 pm
I cannot see any of your .cpp files.
Title: Collision with FloatRect
Post by: dotty on February 29, 2012, 09:58:49 pm
Really? Works for me using Safari.

Try these - main.cpp http://pastie.org/3491192
tile.h http://pastie.org/3491196
tile.cpp http://pastie.org/3491200
Title: Collision with FloatRect
Post by: Tex Killer on February 29, 2012, 10:39:18 pm
Do your Update calls before the CheckCollidingWith ones.
Title: Collision with FloatRect
Post by: dotty on February 29, 2012, 11:43:57 pm
No, the collision checks happen first, then the Update gets called (which Draws the shape).
Title: Collision with FloatRect
Post by: Tex Killer on March 01, 2012, 04:23:21 am
You must change your logic then, because the drawing is being done right after the movement, and the collision step is only done at the begining of the next loop.

I suggest you do your collision calculations inside your update function, or draw your sprites outside of the update function (or both).
Title: Collision with FloatRect
Post by: dotty on March 01, 2012, 02:15:54 pm
Ok I get you, so should I be change my Update() to Update(tiles) and pass the tiles vector?
Title: Collision with FloatRect
Post by: Tex Killer on March 01, 2012, 07:01:29 pm
You can do that, or make the vector global.
Title: Collision with FloatRect
Post by: dotty on March 02, 2012, 01:45:29 pm
The global root sounds better. Is it a good idea to have ALL my "collider FloatRects" stored within a global vector? There could be hundreds.
Title: Collision with FloatRect
Post by: Nexus on March 02, 2012, 07:51:59 pm
Global is never better :P

Why don't you write a class that is responsible for the collision of the rectangles?

And why does the tile class store the RenderWindow? It could provide a Draw() function, this shouldn't be in Update() anyway. Furthermore, especially in the presence of many tiles, it might be better not to store any graphical data in the tiles. You could for example construct sf::RectangleShapes on the fly...

You have to experiment a little, I personally like to separate responsibilities (like graphics and physics), as it makes maintenance and interchangeability easier.
Title: Collision with FloatRect
Post by: dotty on March 03, 2012, 12:49:06 pm
Nexus, I read up on global variables after I posted my reply, and all the articles mentioned why you should never use global variables unless you absolutely need to.

The rectangles will eventually become sf::Sprite's.

The reason I passed a reference of RenderWindow to my tile class was so that I could handle all my logic in tile class, so my main loop would call only the Upate() method, then the Update() method in my tile class would do everything it needs to. Is this a bad idea? I wanted to sort my code that everything is self contained within each class. I guess this way of doing stuff was from moving from Unity3d, where every game object has it's own Draw() and Update() method.

What would the collision class do? Would it take 2 FloatRects then work out collision, or would it take 2 tiles?
Title: Collision with FloatRect
Post by: unranked86 on March 03, 2012, 02:43:21 pm
I think, your collision class should take 2 FloatRects.
And instead of creating the rects "by hand" for your Sprites, take a look at Sprite.GetGlobalBounds (http://sfml-dev.org/documentation/2.0/classsf_1_1Sprite.php#afa4b1d5b02639b700f544b0cc4c172c9)
Title: Re: Collision with FloatRect
Post by: dotty on March 25, 2012, 02:56:34 pm
Sorry to bring this up again. I've got the grasp of checking and dealing with collisions using IntRect now, however I can't seem to handle multiple collection checks.

My project is zipped up at https://legacy.sfmluploads.org/file/112

Bascially move around with WASD if you collide into the upper right box then "slide" to the left (using W and A), the moveable block gets stuck when trying to deal with the collision between 2 boxes.

Can someone please lend me a hand on this, I've been trying to deal with this problem all weekend and just cannot get it working! I think it's the way the blocks are added to the vector.

If you don't want to download the zip file, the files are located at pastie.org

main - http://pastie.org/3654696
player - http://pastie.org/3654701
spriteManager - http://pastie.org/3654702
gameObject - http://pastie.org/3654708