this is my first time doing this and im sorry if im doing this wrong but for the last couple of weeks i've been working on a little project with xna and c# while following a book
i made a simple platformer game with enemies and collectibales and traps
but i ran into an issue...
You see i have struggled to find (and to write) a good collision detection function to use. I ultimately used one from the Microsoft platformer project in addition to the function found in the book i was reading everything was fine but i noticed that the game character was lagging (sort of moving in bursts instead of smooth motion) while moving. The frame rate was stable and well above 400 (i turned off fixed time step).
So my question is if someone can take a look at my code and tell me whats the problem..
i think the main problem is in the HandleCollisons function or the horizontal and vertical collision detecting functions
ps: english is not my first language as you might have noticed so sorry for the bad grammer :D/>
anyway thanks in advance
this is the class that does the collision Detection :
public override void Update(GameTime gameTime)
{
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
Vector2 prevLocation = worldLocation;
if (useGravity) { speed.Y += Gravity.Y * elapsed; }
Vector2 moveAmount;
moveAmount.X = speed.X * elapsed;
moveAmount.Y = speed.Y * elapsed;
if (isPlayer)
{
moveAmount = horizontalCollisionTest(moveAmount);
moveAmount = verticalCollisionTest(moveAmount);
}
if (moveAmount == Vector2.Zero)
{
worldLocation = prevLocation;
}
else
{
worldLocation.X += moveAmount.X;
worldLocation.Y += moveAmount.Y;
}
HandleCollisions();
if (limitSpeed)
{
if (speed.X > maxSpeed.X) speed.X = maxSpeed.X;
if (speed.X < -maxSpeed.X) speed.X = -maxSpeed.X;
if (speed.Y > maxSpeed.Y) speed.Y = maxSpeed.Y;
if (speed.Y < -maxSpeed.Y) speed.Y = -maxSpeed.Y;
}
if ((speed.Y > MaxSpeed.Y / 20))
{
onGround = false;
jumping = true;
}
if (!beingMoved)
{
if (speed.X < 0) speed.X += deaccelerationX * elapsed;
if (speed.X > 0) speed.X -= deaccelerationX * elapsed;
if (speed.X > 0 && speed.X < (deaccelerationX * elapsed)) speed.X = 0;
if (speed.X < 0 && speed.X > (-deaccelerationX * elapsed)) speed.X = 0;
}
if (worldLocation.X <= 0)
{
worldLocation.X = 0;
speed.X = 0;
}
if (worldLocation.X >= (Camera.WorldRectangle.Width - FrameWidth))
{
worldLocation.X = Camera.WorldRectangle.Width - FrameWidth;
speed.X = 0;
}
base.Update(gameTime);
}
private void HandleCollisions()
{
Rectangle bounds = CollisionRectangle;
int left = (int)((bounds.Left / TileMap.TileWidth)) * TileMap.TileWidth;
int right = (int)((bounds.Right / TileMap.TileWidth)) * TileMap.TileWidth;
int top = (int)((bounds.Top / TileMap.TileHeight)) * TileMap.TileHeight;
int bottom = (int)((bounds.Bottom / TileMap.TileHeight)) * TileMap.TileHeight;
for (int i = left; i <= right; i += TileMap.TileWidth)
{
for (int j = top; j <= bottom; j += TileMap.TileHeight)
{
Rectangle tile = TileMap.CellWorldRectangle(i / TileMap.TileWidth, j / TileMap.TileHeight);
if (!TileMap.CellIsPassable(TileMap.GetCellByPixel(new Vector2(i, j))))
{
Rectangle tileRect = new Rectangle(i, j, TileMap.TileWidth, TileMap.TileHeight);
Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileRect);
if (depth != Vector2.Zero)
{
float absDepthX = Math.Abs(depth.X);
float absDepthY = Math.Abs(depth.Y);
if (absDepthY <= absDepthX)
{
if (preBottom <= tileRect.Top)
{
onGround = true;
jumping = false;
}
if (onGround)
{
worldLocation = new Vector2(worldLocation.X, worldLocation.Y + depth.Y + 1);
bounds = CollisionRectangle;
speed.Y = 0;
}
}
else
{
worldLocation = new Vector2(worldLocation.X + depth.X, worldLocation.Y);
bounds = CollisionRectangle;
speed.X = 0;
}
}
}
}
}
preBottom = bounds.Bottom;
}
private Vector2 horizontalCollisionTest(Vector2 moveAmount)
{
if (moveAmount.X == 0)
return moveAmount;
Rectangle afterMoveRect = CollisionRectangle;
afterMoveRect.Offset((int)moveAmount.X, -5);
Vector2 corner1, corner2;
if (moveAmount.X < 0)
{
corner1 = new Vector2(afterMoveRect.Left,
afterMoveRect.Top + 1);
corner2 = new Vector2(afterMoveRect.Left,
afterMoveRect.Bottom - 1);
}
else
{
corner1 = new Vector2(afterMoveRect.Right,
afterMoveRect.Top + 1);
corner2 = new Vector2(afterMoveRect.Right,
afterMoveRect.Bottom - 1);
}
Vector2 mapCell1 = TileMap.GetCellByPixel(corner1);
Vector2 mapCell2 = TileMap.GetCellByPixel(corner2);
if (!TileMap.CellIsPassable(mapCell1) ||
!TileMap.CellIsPassable(mapCell2))
{
moveAmount.X = 0;
speed.X = 0;
}
return moveAmount;
}
private Vector2 verticalCollisionTest(Vector2 moveAmount)
{
if (moveAmount.Y == 0)
return moveAmount;
Rectangle afterMoveRect = CollisionRectangle;
afterMoveRect.Offset((int)moveAmount.X, (int)moveAmount.Y + 1);
Vector2 corner1, corner2;
if (moveAmount.Y < 0)
{
corner1 = new Vector2(afterMoveRect.Left + 1,
afterMoveRect.Top);
corner2 = new Vector2(afterMoveRect.Right - 1,
afterMoveRect.Top);
}
else
{
corner1 = new Vector2(afterMoveRect.Left + 1,
afterMoveRect.Bottom);
corner2 = new Vector2(afterMoveRect.Right - 1,
afterMoveRect.Bottom);
}
Vector2 mapCell1 = TileMap.GetCellByPixel(corner1);
Vector2 mapCell2 = TileMap.GetCellByPixel(corner2);
if (!TileMap.CellIsPassable(mapCell1) ||
!TileMap.CellIsPassable(mapCell2))
{
if (moveAmount.Y > 0)
{
onGround = true;
}
moveAmount.Y = 0;
speed.Y = 0;
}
return moveAmount;
}
public override void Draw(SpriteBatch spriteBatch)
{
base.Draw(spriteBatch);
}
}
}
and the code for the rectangle intersection depth is :
public static Vector2 GetIntersectionDepth(this Rectangle rectA, Rectangle rectB)
{
// Calculate half sizes.
float halfWidthA = rectA.Width / 2.0f;
float halfHeightA = rectA.Height / 2.0f;
float halfWidthB = rectB.Width / 2.0f;
float halfHeightB = rectB.Height / 2.0f;
// Calculate centers.
Vector2 centerA = new Vector2(rectA.Left + halfWidthA, rectA.Top + halfHeightA);
Vector2 centerB = new Vector2(rectB.Left + halfWidthB, rectB.Top + halfHeightB);
// Calculate current and minimum-non-intersecting distances between centers.
float distanceX = centerA.X - centerB.X;
float distanceY = centerA.Y - centerB.Y;
float minDistanceX = halfWidthA + halfWidthB;
float minDistanceY = halfHeightA + halfHeightB;
// If we are not intersecting at all, return (0, 0).
if (Math.Abs(distanceX) >= minDistanceX || Math.Abs(distanceY) >= minDistanceY)
return Vector2.Zero;
// Calculate and return intersection depths.
float depthX = distanceX > 0 ? minDistanceX - distanceX : -minDistanceX - distanceX;
float depthY = distanceY > 0 ? minDistanceY - distanceY : -minDistanceY - distanceY;
return new Vector2(depthX, depthY);
}