Jump to content
  • Advertisement
Sign in to follow this  
Ex0Matter

Blocking movement on collision

This topic is 777 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

After implementing a collision detection system (from my last post), I've been trying to find a good way to stop movement after 2 moving entities collide with each other. I've seen multiple people talking about using something like this:

if (entity != collidingEntity && entity->getSprite().getGlobalBounds().intersects(collidingEntity->getSprite().getGlobalBounds()))
{
    entity->setPosition(entity->getLastPosition());
}

After trying this, the problem still stands that my player can still go through objects. The enemies that collide that follow it stop entirely, and only resume movement in certain circumstances.

 

I'm using SFML and C++, by the way.

Edited by Ex0Matter

Share this post


Link to post
Share on other sites
Advertisement

The way I generally do collision is to have objects ask if they can go some place. I use vectors for movement most of the time. So, the vector would be a proposed path of movement. I generally work in 3D, but the principle is the same in 2D.

 

A vector, for anyone that doesn't know, is basically just an arrow. It's used in math (and in game programming) to represent things where an amount needs to be used together with a direction. The direction is the arrows direction. The amount is the length of the arrow. Vectors are really just that simple. The hardest part is understanding doing math with them, and then again vector "multiplication" is really the only difficult part of that. Vectors with a length of 1 are called "normals" and represent a direction that has no actual amount.

 

The actual position of a vector is always irrelevant (well, except in the case of vectors that are not really vectors - like positions where you take a position and shove it in a mathematical vector just so you can then add or subtract it with and actual vector or to get an actual vector as an answer). For that reason, a vector's tail (think arrow again) is always at the origin. Because of this, you only have to store the position of the vector's arrow head to represent the entire arrow. So, a vector is stored as a single point when in reality it is two points, but the second point is always 0,0 in 2D or 0,0,0 in 3D. But it's not a point. It's an arrow. Or rather it's a known point (the origin) which never changes and thus does not need to be stored and a given point that represent an arrow. But you have all this information stores as 2 or 3 floating point values.

 

Anyway, I use vectors for movement.

 

And so my object request to move along a certain path by saying, "This is my current position (point stored as a vector even though it's not one really) and here is the path vector (arrow) that I want to move along." The amount (or length of the arrow) represents how far it can move in a single frame. It's the full possible movement if nothing stops it. The collision manager checks if there would be a collision caused by this. If there would be the collision manager denies permission and the object cannot move.

 

This causes a problem if the object's velocity is significant. For example, if the object is 100 feet from the wall and moving 101 feet was the request. It will collide, or stop, 100 feet short of the wall just because it was not allowed to travel the full 101 feet, because  that would cause a collision.

 

So, my collision manager is usually written so that it does not return permission, but rather returns a compromise. So, the input into the collision manager is current position, and proposed vector path. The output is the granted vector path. So, in the previous example, it would determine that the collision object is 100 feet while the requested path was 101 feet. It would shorten the path vector (easy to do by normalizing the vector then multiplying it times the length of the granted path) to 100 feet and return the same, but shortened vector as the granted path. Applying that vector by adding it to the current position would move the object right up to the wall and stop it. So, it hits the wall with a "thunk" and stops dead in it's track.

 

Future, requests to continue along that path would have a zero distance to the wall and would return a zero length vector which would be added to current position, meaning the position would never change until it requests to go in a different direction.

 

I've also been known to do reflections. Those are a little more complicated, but you basically do the same thing but instead of returning a path, you return the final position. You start out the same way, but whatever part of the path is left over, you reflect it. So, in the previous example, you would calculate the point in space where the object collided with the wall. You get the remainder, which was 1 foot in the example. You calculate a reflection vector off the collision point. You set the reflection vector's length to the remainder. You add the collision point to the reflection vector and return that point. The object is moved to that point, giving the appearance it bounced off the wall.

 

When you do a reflection like that, you probably also do not directly control the object's movement. It instead would have a "velocity" vector to make it travel in a certain direction and certain distance per frame forever until you tell it to change. In this case, the collision manager would tell it to change the direction of the velocity vector to the direction of the reflection vector.

 

But the short answer is that you should have the object request a movement rather than just moving it. Then the movement can be denied if a collision would result.

Share this post


Link to post
Share on other sites
You have two options here.

If you have determined that two shapes do overlap, determine the smallest amount you need to push one of the shapes to correct the overlap. This however, can result in objects passing through each other if they move fast enough.
See separating axis theorem

The second option is to do a raycast aka swept collision detection. You find out how far in a given direction any obstacle is in front of the player and use that distance to determine if the player can move before moving them. Is actual practice, you usually do sphere casting or capsule casting. Its like ray casting except the ray has thickness. In essense it just determines how far a sphere or capsule shape can move before hitting something. Spheres and capsules, apart from being easier to do collision detection with, also have the benefit of not getting stuck on sharp corners. They just slide over them without a problem.
Here is a simple example for a sphere/plane swept collision. http://www.gamasutra.com/view/feature/131790/simple_intersection_tests_for_games.php

Share this post


Link to post
Share on other sites

"Velocity is a physical vector quantity; both magnitude and direction are needed to define it."

 

Basically like it has already been stated, think of it as an arrow that gives both a direction and a magnitude(distance). When using your physics controller or how ever you handle bodies, check that before you even update.

Share this post


Link to post
Share on other sites

So, should I have a separate class to handle all my collisions?


I would move collision logic into its own part of the code, so yes.

Share this post


Link to post
Share on other sites

After implementing a collision detection system (from my last post), I've been trying to find a good way to stop movement after 2 moving entities collide with each other. I've seen multiple people talking about using something like this:

if (entity != collidingEntity && entity->getSprite().getGlobalBounds().intersects(collidingEntity->getSprite().getGlobalBounds()))
{
    entity->setPosition(entity->getLastPosition());
}

After trying this, the problem still stands that my player can still go through objects. The enemies that collide that follow it stop entirely, and only resume movement in certain circumstances.

 

I'm using SFML and C++, by the way.

 

What you can do is, instead of immediately moving an object's position when collision is detected, just mark the colliding objects location of where they should be (ie, the last position). After you check all the entities, then you correct multiple objects at once.

 

It's not elegant, but it should work.  See how it fairs for you if you're still struggling.

 

(BTW, this is a beginner's solution, there are obviously better solutions, but this one is simple).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!