Jump to content

  • Log In with Google      Sign In   
  • Create Account


2D Multiple Collision Response SAT


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
6 replies to this topic

#1 mwkenna   Members   -  Reputation: 143

Like
0Likes
Like

Posted 25 October 2013 - 03:45 AM

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.

Attached Thumbnails

  • Before.png
  • After.png


Sponsor:

#2 serumas   Members   -  Reputation: 712

Like
0Likes
Like

Posted 25 October 2013 - 07:48 AM

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



#3 mwkenna   Members   -  Reputation: 143

Like
0Likes
Like

Posted 25 October 2013 - 07:54 AM

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);
}


#4 serumas   Members   -  Reputation: 712

Like
0Likes
Like

Posted 26 October 2013 - 01:08 AM

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;

}

}



#5 mwkenna   Members   -  Reputation: 143

Like
0Likes
Like

Posted 26 October 2013 - 03:31 AM

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.



#6 mwkenna   Members   -  Reputation: 143

Like
0Likes
Like

Posted 27 October 2013 - 04:12 AM

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);
        }


#7 serumas   Members   -  Reputation: 712

Like
0Likes
Like

Posted 28 October 2013 - 12:00 PM

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...






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS