I'm trying to make a character collide with some tiled terrain.
I have an issue with the collision resolution, and after days of shooting in the dark ant not finding any relevant help online, I'm no closer to working collision resolution.
I can detect if the player is colliding with the tiles, but I can't figure out how to properly resolve the collision.
I have is so gravity is only applied when there is no collisions in the downward direction, and I have set it so that the proper velocity resolution, so that if I collide with the ground, I don't go through it, but I still go a few pixels into the tile if going at high velocities, and for some reason, if I'm colliding with a surface whose normal is along the x axis (floors and ceilings) It decides that I'm also colliding on the left and right sides as well, and I don't collide with vertical walls at all.
I should note that I'm using MonoGame 3.4.
Physics update code for character
public void Update()
{
Position += Velocity * TimeHandler.DeltaTime;
//TODO: add tile collision based on the entity.world property
var tiles = entity.World.Tiles;
int minTileX = (int)Math.Floor (Bounds.MinX);
int maxTileX = (int)Math.Ceiling (Bounds.MaxX);
int minTileY = (int)Math.Floor (Bounds.MinY) - 1;
int maxTileY = (int)Math.Ceiling (Bounds.MaxY) - 1;
bool collidedNegY = false;
for (int x = minTileX; x <= maxTileX; x++)
{
for (int y = minTileY; y <= maxTileY; y++)
{
bool kKeyDown = Keyboard.GetState ().IsKeyDown (Keys.K);
if (kKeyDown)
tiles.SetID (1, x, y);
bool jKeyDown = Keyboard.GetState ().IsKeyDown (Keys.J);
if (jKeyDown)
tiles.SetID (0, x, y);
AABB tileAABB = new AABB (new Vector2(x, y), new Vector2(1f, 1f), new Vector2(0f, 1f));
//CollisionInfo info;
if (tileAABB.Check (Bounds))
{
if (tiles.GetID (x, y) == 0)
continue;
Vector2 collisionDirection = tileAABB.Position - Bounds.Position;
bool xIsRight = collisionDirection.X > 0;
bool yIsUp = collisionDirection.Y > 0;
bool differentX = xIsRight == Velocity.X > 0;
bool differentY = yIsUp == Velocity.Y > 0;
if (differentX)
{
Velocity.X *= 0f;
if (Bounds.MaxX > tileAABB.MaxX)
{
}
if (Bounds.MinX < tileAABB.MinX)
{
}
}
if (differentY)
{
Velocity.Y *= 0f;
if (Bounds.MaxY > tileAABB.MaxY)
{
collidedNegY = true;
}
if (Bounds.MinY < tileAABB.MinY)
{
}
}
}
}
}
if(!collidedNegY)
{
//apply gravity
Velocity.Y -= entity.World.Gravity * TimeHandler.DeltaTime;
}
Bounds.Position = Position;
}
AABB class:
public struct AABB
{
private Vector2 min;
private Vector2 max;
private float y;
private float x;
private float width;
private float height;
private Vector2 offset;
//position
public Vector2 Position
{
get
{
return new Vector2 (x, y);
}
set
{
UpdateBounds (value.X, value.Y);
}
}
public Vector2 Size
{
get
{
return new Vector2 (width, height);
}
set
{
UpdateBounds (x, y, value.X, value.Y);
}
}
public float MinX
{
get
{
return min.X;
}
}
public float MinY
{
get
{
return min.Y;
}
}
public float MaxX
{
get
{
return max.X;
}
}
public float MaxY
{
get
{
return max.Y;
}
}
public float Width
{
get
{
return width;
}
set
{
UpdateBounds (min.X, min.Y, value, height);
}
}
public float Height
{
get
{
return height;
}
set
{
UpdateBounds (min.X, min.Y, width, value);
}
}
//update
private void UpdateBounds(float x, float y)
{
this.x = x;
this.y = y;
min = new Vector2 (x + offset.X, y + offset.Y);
max = new Vector2 (min.X + width, min.Y + height);
}
private void UpdateBounds(float x, float y, float width, float height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
min = new Vector2 (x + offset.X, y + offset.Y);
max = new Vector2 (min.X + width, min.Y + height);
}
//constructors
public AABB(Vector2 pos, Vector2 size, Vector2 offset)
{
this.x = pos.X;
this.y = pos.Y;
this.width = size.X;
this.height = size.Y;
this.offset = offset;
this.min = new Vector2(pos.X + offset.X, pos.Y + offset.Y);
this.max = new Vector2 (min.X + size.X, min.Y + size.Y);
}
//checking
public bool Check(AABB b)
{
if (this.max.X < b.min.X || this.min.X > b.max.X)
return false;
if (this.max.Y < b.min.Y || this.min.Y > b.max.Y)
return false;
return true;
}
public static bool Check(AABB a, AABB b)
{
return a.Check (b);
}
}