2D Multiple Collision Response SAT

Started by
5 comments, last by serumas 10 years, 5 months ago

Hi All

I'm learning GameDev by developing a tile-based game.

I've implemented swept SAT using the great PolyColly tutorials. My "future-collision" response code is working very well but the "current-collision" response code is having trouble when resolving multiple collisions (like on an inside edge). Note that I am disregarding edges that are marked as "empty" as suggested by the great MetaNet tutorials.

I've included 2 screenshots of the problem.

I can provide code on request.

I would really like to understand what is happening here.

Thanks,

Mark.

Advertisement

There is nothing to say without the code you resolve overlaping.

Here is the collision code that I am using. Note that I am currently trying to understand it so I'm not worried about that fact that it's not very efficient yet. Also note that it's the current collisions which are not working correctly.

Thanks,

Mark.


protected override void Update(GameTime gameTime)
{
	// Allows the game to exit
	if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
		this.Exit();

	//player position update
	float amount = 50;
	Vector2 offset = Vector2.Zero;
	KeyboardState state = Keyboard.GetState();
	if (state.IsKeyDown(Keys.Up))
		offset += new Vector2(0, -amount);
	if (state.IsKeyDown(Keys.Down))
		offset += new Vector2(0, amount);
	if (state.IsKeyDown(Keys.Left))
		offset += new Vector2(-amount, 0);
	if (state.IsKeyDown(Keys.Right))
		offset += new Vector2(amount, 0);
	redPoly.Position += offset;

	//player velocity update
	Vector2 displacement = new Vector2(0, 0);
	MouseState mouseState = Mouse.GetState();
	Vector2 mousePos = Vector2.Zero;

	if (mouseState.LeftButton == ButtonState.Pressed)
	{
		mousePos = new Vector2(mouseState.X - (boxWidth / 2), mouseState.Y - (boxHeight / 2));
		redPoly.Displacement = mousePos - redPoly.Position;
	}

	//get the list of collisions
	List<CollisionResult> collisions = new List<CollisionResult>();
	foreach (Polygon p in polygons)
	{
		var collision = Collide(redPoly, p, redPoly.Position - p.Position, redPoly.Displacement - p.Displacement);
		if (collision != null)
		{
			collisions.Add(collision);
		}
	}

	var futureTimes = (from a in collisions where a.CollisionType == CollisionResultType.Future select a.T).ToList();
	if (futureTimes.Count > 0)
	{
		futureTimes.Sort();
		collPos = redPoly.Position + redPoly.Displacement * futureTimes.First();
	}
	else
	{
		if (mouseState.LeftButton == ButtonState.Pressed)
			collPos = mousePos;
	}

	Vector2 mtd = Vector2.Zero;
	var currentCollisions = (from a in collisions where a.CollisionType == CollisionResultType.Current select a).ToList();
	if (currentCollisions.Count > 0)
	{
		collPos = Vector2.Zero;

		//find the largest  MTD required to push the player out
		foreach (var currentCol in currentCollisions)
		{
			Vector2 a = currentCol.CollisionNormal * currentCol.T;

			if (Math.Abs(a.X) > Math.Abs(mtd.X))
				mtd.X = a.X;
			if (Math.Abs(a.Y) > Math.Abs(mtd.Y))
				mtd.Y = a.Y;
		}
	}

	if (mtd != Vector2.Zero)
		redPoly.Position -= mtd;

	base.Update(gameTime);
}

As I undertood from code you are doing: first find max overlaping and then resolving it.

Try not searching max overlapping, but resolve collision for each overlaping occure and do it not wit mtd but with redPoly.position:

foreach(bluePoly)

{

if(collides(redPoly,cur_bluePoly))

{

a = ...;

redPoly.Position -=a;

}

}

I am trying to accomplish the "Basic Arcade Collision Response" from the PolyColly tutorial, but without the physics. All I want is for it to be basic but correct). This is what I have modified the code to but I'm not getting the functionality that I would expect, the player is sticking to the polygons and sometimes penetrating the surface.

Again.. trying to keep it simple just using the arrow keys to modify the offset of the player (redPoly).


protected override void Update(GameTime gameTime)
{
	// Allows the game to exit
	if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
		this.Exit();

	//player position update
	float amount = 40;
	Vector2 offset = Vector2.Zero;
	KeyboardState state = Keyboard.GetState();
	if (state.IsKeyDown(Keys.Up))
		offset += new Vector2(0, -amount);
	if (state.IsKeyDown(Keys.Down))
		offset += new Vector2(0, amount);
	if (state.IsKeyDown(Keys.Left))
		offset += new Vector2(-amount, 0);
	if (state.IsKeyDown(Keys.Right))
		offset += new Vector2(amount, 0);

	//get the list of collisions
	List<CollisionResult> collisions = new List<CollisionResult>();
	foreach (Polygon p in polygons)
	{
		float t = 1.0f;
		Vector2 N = Vector2.Zero;

		Vector2 relPos = redPoly.Position - p.Position;
		Vector2 relDisplacement = offset;

		if (Collide(redPoly, p, relPos, relDisplacement, ref N, ref t))
		{
			if (t < 0)
			{
				ProcessOverlap(ref redPoly, N, t);
			}
			else
			{
				ProcessCollision(ref redPoly, N, t, ref offset);
			}
		}
	}

	redPoly.Position += offset;

	base.Update(gameTime);
}

Does this look correct to you guys?

Thanks,

Mark.

After debugging the code further I believe the problem is now a case of how to deal with "touching" collisions.

What's happening is that when I detect a future collision and update the players position to "hug" the colliding object, the collision code is continuously detecting the "touching state" and not applying the position offset.

I have attached my code:


protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            //player position update
            float amount = 10;
            Vector2 offset = Vector2.Zero;
            KeyboardState state = Keyboard.GetState();
            if (state.IsKeyDown(Keys.Up))
                offset += new Vector2(0, -amount);
            if (state.IsKeyDown(Keys.Down))
                offset += new Vector2(0, amount);
            if (state.IsKeyDown(Keys.Left))
                offset += new Vector2(-amount, 0);
            if (state.IsKeyDown(Keys.Right))
                offset += new Vector2(amount, 0);

            foreach (Polygon p in polygons)
            {
                float t = 1.0f;
                Vector2 N = Vector2.Zero;

                Vector2 relPos = redPoly.Position - p.Position;
                Vector2 relDisplacement = offset;

                if (Collide(redPoly, p, relPos, relDisplacement, ref N, ref t))
                {
                    if (t < 0)
                    {
                        //process teh current overlap
                        redPoly.Position -= N * t;
                        offset = Vector2.Zero;
                    }
                    else
                    {
                        if (t == 0)
                        {
                            //the objects are just touching
                        }
                        else
                        {
                            //process an overlap forward in time
                            redPoly.Position += offset * t;
                            offset = Vector2.Zero;
                        }
                    }
                }
            }

            redPoly.Position += offset;

            base.Update(gameTime);
        }

I dont understand why you need these multiple t checks offset, p reldisplacement....

if there are only quads just check how much red object overlaps the one blue you are checking at the moment and push back red object that overlaping to be gone...

these weird calculations is useless, you dont need process forward in time.

If you still cant make it write to PM...

This topic is closed to new replies.

Advertisement