Sign in to follow this  

Tile-based 2D physics

This topic is 2547 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

I've been working on a simple tile-based 2D physics class and it was working pretty well while I was using the rectangle class. The rectangle class only takes ints as parameters in XNA, so I decided to switch it over to the BoundingBox class, which allows positions to be stored as floating-point numbers. Upon doing that, I noticed that whenever I move to the left to a wall, it shoots me up to the top. Moving to the right is no problem.

I've tried quite a few different things and haven't found a solution. Now I'm wondering whether or not the problem is my approach. What I do is check which objects are the nearest and perform AABB collision on them. If the player would be inside the object after moving, I place it on the side of the object. If my description isn't too bright then I've added the commented code bellow:


class Physics
{
List<Object> objects;
Player player;
int gravity;
float gravconstant;

//would be better to give these from the object
float maxvel;
float maxvelx;
float xdamp;
float ydamp;

/// <summary>
/// Creates a physics handler
/// </summary>
/// <param name="objects">The object list to consider.</param>
/// <param name="enemies">The enemy list to consider.</param>
/// <param name="player">The player.</param>
/// <param name="gravity">0 = gravity off; 1 = gravity on.</param>
public Physics(List<Object> objects, List<Enemy> enemies, Player player, int gravity)
{
this.objects = objects;
this.enemies = enemies;
this.player = player;
this.gravity = gravity;
gravconstant = 1.0f;
maxvel = 1000.0f; //may want to change for testing
maxvelx = 10.0f;
xdamp = 4.0f;
ydamp = 1.0f;
}

public void Update(GameTime gameTime)
{
//move the player
//1. check collisions and move current vel, make sure if the player collides the vel is 0! (done)
//2. if player isn't on platform, accel them down if grav is on (done)
//3. do some dampening (x axis damp and y terminal)

//-- 1. --//

Object testobject = null;
player.onplatform = false;
Vector2 movedistance = new Vector2(player.velocity.X, player.velocity.Y);



Vector3 testvel = new Vector3(player.position.X + player.velocity.X, player.position.Y + player.velocity.Y, 0);

if (player.velocity.X > 0)
{
BoundingBox testrect = new BoundingBox(new Vector3(player.position.X, player.position.Y, 0), new Vector3((player.texture.Width + player.position.X + player.velocity.X), player.position.Y + player.texture.Height, 0));

foreach (Object obj in objects)
{
if (obj.collision)
if (!obj.platform)
{
if (testrect.Intersects(obj.hit_box))
{
if (testobject == null || testobject.position.X - (player.position.X + player.texture.Width) > obj.position.X - (player.position.X + player.texture.Width))
testobject = obj;
}
}
}

if (testobject != null)
{
movedistance.X = testobject.position.X - (player.position.X + player.texture.Width)-0.1f;
player.velocity.X = 0;
}

player.position.X += movedistance.X;

testobject = null;
}

if (player.velocity.X < 0)
{
BoundingBox testrect = new BoundingBox(new Vector3((player.position.X), player.position.Y, 0), new Vector3((player.texture.Width + player.position.X + player.velocity.X), player.position.Y + player.texture.Height, 0));

foreach (Object obj in objects)
{
if (obj.collision)
if (!obj.platform)
{
if (testrect.Intersects(obj.hit_box))
{
if (testobject == null || player.position.X - (testobject.position.X + testobject.texture.Width) > player.position.X - (obj.position.X + obj.texture.Width))
testobject = obj;
}
}
}


if (testobject != null)
{
movedistance.X = (testobject.position.X + testobject.texture.Width - player.position.X + 0.1f);
player.velocity.X = 0;
}

player.position.X += movedistance.X;

testobject = null;
}

if (player.velocity.Y > 0)
{
BoundingBox testrect = new BoundingBox(new Vector3(player.position.X, player.position.Y, 0), new Vector3(player.position.X + player.texture.Width, player.position.Y + player.texture.Height + player.velocity.Y, 0));
foreach (Object obj in objects)
{
if (obj.collision)
if (obj.platform && !player.throughplatform)
{
if (player.position.Y + player.texture.Height <= obj.position.Y)
{
if (testrect.Intersects(obj.hit_box))
{
if (testobject == null || testobject.position.Y - (player.position.Y + player.texture.Height) > obj.position.Y - (player.position.Y + player.texture.Height))
testobject = obj;

player.onplatform = true;
}
}
}
else if (!obj.platform)
{
if (testrect.Intersects(obj.hit_box))
{
if (testobject == null || testobject.position.Y - (player.position.Y + player.texture.Height) > obj.position.Y - (player.position.Y + player.texture.Height))
testobject = obj;

player.onplatform = true;
}
}
}

if (testobject != null)
{
movedistance.Y = testobject.position.Y - (player.position.Y + player.texture.Height) - 0.1f;
player.velocity.Y = 0;
}



player.position.Y += movedistance.Y;


testobject = null;
}


if (player.velocity.Y < 0)
{
BoundingBox testrect = new BoundingBox(new Vector3(player.position.X, player.position.Y, 0), new Vector3(player.position.X + player.texture.Width, player.position.Y + player.texture.Height + player.velocity.Y, 0));

foreach (Object obj in objects)
{
if (obj.collision)
if (!obj.platform)
{
if (testrect.Intersects(obj.hit_box))
{
if (testobject == null || player.position.Y - (testobject.position.Y + testobject.texture.Height) > player.position.Y - (obj.position.Y + obj.texture.Height))
testobject = obj;
}
}
}
if (testobject != null)
{
movedistance.Y = testobject.position.Y + testobject.texture.Height - player.position.Y + 0.1f;
player.velocity.Y = 0;
}

player.position.Y += movedistance.Y;

testobject = null;
}




//player.position = Vector3.Add(player.position, new Vector3(movedistance.X, movedistance.Y, 0));

//-- 2. --//
if (gravity == 1)
{
if (player.velocity.Y < maxvel)
player.velocity.Y += gravconstant;
}

//-- 3. --//

//x dampening
if (player.velocity.X > 0 && player.velocity.X - xdamp > 0)
player.velocity.X -= xdamp;
else if (player.velocity.X > 0 && player.velocity.X - xdamp <= 0)
player.velocity.X = 0;
else if (player.velocity.X < 0 && player.velocity.X + xdamp < 0)
player.velocity.X += xdamp;
else if (player.velocity.X < 0 && player.velocity.X + xdamp >= 0)
player.velocity.X = 0;

if (Math.Abs(player.velocity.X) > maxvelx)
{
if (player.velocity.X < 0)
player.velocity.X = -maxvelx;
if (player.velocity.X > 0)
player.velocity.X = maxvelx;
}

//y dampening (only use if no gravity)
if (gravity == 0)
{
if (player.velocity.Y > 0 && player.velocity.Y - ydamp > 0)
player.velocity.Y -= ydamp;
else if (player.velocity.Y > 0 && player.velocity.Y - ydamp <= 0)
player.velocity.Y = 0;
else if (player.velocity.Y < 0 && player.velocity.Y + ydamp < 0)
player.velocity.Y += ydamp;
else if (player.velocity.Y < 0 && player.velocity.Y + ydamp >= 0)
player.velocity.Y = 0;
}
}
}
}



If anyone notices anything simple that I've missed I'd really appreciate it. I'd also appreciate any criticism towards my approach.
Thanks for reading!

Share this post


Link to post
Share on other sites
I figured the problem out. I was making the boundingboxes backwards for vel.x and vel.y < 0. The new test boxes should be initiated like so:

For vel.x < 0:

BoundingBox testrect = new BoundingBox(new Vector3((player.position.X + player.velocity.X), player.position.Y, 0), new Vector3((player.texture.Width + player.position.X), player.position.Y + player.texture.Height, 0));



For vel.y < 0:

BoundingBox testrect = new BoundingBox(new Vector3(player.position.X, player.position.Y + player.velocity.Y, 0), new Vector3(player.position.X + player.texture.Width, player.position.Y + player.texture.Height, 0));



I'm still open for criticism towards my method, though.

Share this post


Link to post
Share on other sites

This topic is 2547 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this