# One-way platform collision

I hate asking questions that are specific to my own code like this, but I've run into a pesky roadblock and could use some help getting around it. I'm coding floating platforms into my game that will allow a player to jump onto them from underneath, but then will not allow players to fall through them once they are on top, which require some custom collision detection code. The code I have written so far isn't working, the character passes through it on the way up, and on the way down, stops for a moment on the platform, and then falls right through it. Here is the code to handle collisions with floating platforms:

protected void HandleFloatingPlatforms(Vector2 moveAmount)
{
//if character is traveling downward.
if (moveAmount.Y > 0)
{
Rectangle afterMoveRect = collisionRectangle;
afterMoveRect.Offset((int)moveAmount.X, (int)moveAmount.Y);
foreach (World_Objects.GameObject platform in gameplayScreen.Entities)
{
if (platform is World_Objects.Inanimate_Objects.FloatingPlatform)
{
//wideProximityArea is just a rectangle surrounding the collision
//box of an entity to check for nearby entities.
if (wideProximityArea.Intersects(platform.CollisionRectangle) ||
wideProximityArea.Contains(platform.CollisionRectangle))
{
if (afterMoveRect.Intersects(platform.CollisionRectangle))
{
//This, in my mind would denote that after the character is moved, its feet have fallen below the top of the platform, but before he had moved its feet were above it...
if (collisionRectangle.Bottom <= platform.CollisionRectangle.Top)
{
if (afterMoveRect.Bottom > platform.CollisionRectangle.Top)
{
//And then after detecting that he has fallen through the platform, reposition him on top of it...
worldLocation.Y = platform.CollisionRectangle.Y - frameHeight;
hasCollidedVertically = true;

}
}
}
}
}
}
}
}


In case you are curious, the parameter moveAmount is found through this code:

elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

float totalX = 0;
float totalY = 0;

foreach (Vector2 vector in velocities)
{
totalX += vector.X;
totalY += vector.Y;
}

velocities.Clear();

velocity.X = totalX;
velocity.Y = totalY;

velocity.Y = Math.Min(velocity.Y, 1000);

Vector2 moveAmount = velocity * elapsed;

• What if the player is not moving downwards but the floating platform is moving upwards? Does it still check for collision? – wolfdawn Sep 30 '12 at 20:56
• After some thought, I suggest, you check which condition returns false during the time the player falls through the platform. All conditions there are supposed to be true during that instance. That will help clear things up? I did not see any flow in the logic. – wolfdawn Sep 30 '12 at 21:30
• There is a minor logical problem with the collision detector: If the player is falling very fast (max fall speed is 1000 ?) on a slow computer with low frame rate, he could fall theoretically without intersecting with a thin platform, therefore afterMoveRect will be bellow the platform and collisionRectangle will be above it. You would be better off making a 'moveRect' that contains both collisionRect and afterMoveRect. – wolfdawn Oct 1 '12 at 6:19
• Thank you very much, I'm aware of tunneling and intend on adding a few things to handle such possibilities. – TheBroodian Oct 2 '12 at 0:15

## 2 Answers

Sorry for wasting anybody's time; I located my issue, it wasn't actually with my collision resolution code, just where I had placed it in my character's class.

The original code looked like this:

        Vector2 moveAmount = velocity * elapsed;

slopeCollisionMode = false;

moveAmount = horizontalCollision(moveAmount, layer);
moveAmount = verticalCollision(moveAmount, layer);

//The problem exists right here.
HandleFloatingPlatforms(moveAmount);

if (hasCollidedVertically)
{
selfSpeed.Y = 0;
}
if (hasCollidedHorizontally)
{
selfSpeed.X = 0;
}

Location newPosition = new Location((worldLocation.X + (int)moveAmount.X),(worldLocation.Y + (int)moveAmount.Y));

newPosition = new Location(
(int)MathHelper.Clamp(newPosition.X, 0, layer.Map.DisplayWidth - frameWidth),
(int)MathHelper.Clamp(newPosition.Y, -layer.Map.DisplayHeight * 2, layer.Map.DisplayHeight + frameHeight));

oldLocation = worldLocation;
worldLocation.X = (int)newPosition.X;
worldLocation.Y = (int)newPosition.Y;

collisionRectangle = new Microsoft.Xna.Framework.Rectangle(WorldLocation.X + 39, WorldLocation.Y + 21, 50, 78);


Being as HandleFloatingPlatforms() adjusts the world location of the entity, it being placed before the character is even moved, its adjustments were just being overwritten a few lines down. After readjusting a few things, it works. The working code looks like this:

Vector2 moveAmount = velocity * elapsed;

slopeCollisionMode = false;

moveAmount = horizontalCollision(moveAmount, layer);
moveAmount = verticalCollision(moveAmount, layer);

Location newPosition = new Location((worldLocation.X + (int)moveAmount.X),(worldLocation.Y + (int)moveAmount.Y));

newPosition = new Location(
(int)MathHelper.Clamp(newPosition.X, 0, layer.Map.DisplayWidth - frameWidth),
(int)MathHelper.Clamp(newPosition.Y, -layer.Map.DisplayHeight * 2, layer.Map.DisplayHeight + frameHeight));

oldLocation = worldLocation;
worldLocation.X = (int)newPosition.X;
worldLocation.Y = (int)newPosition.Y;

HandleFloatingPlatforms(moveAmount);

collisionRectangle = new Microsoft.Xna.Framework.Rectangle(WorldLocation.X + 39, WorldLocation.Y + 21, 50, 78);

if (hasCollidedVertically)
{
selfSpeed.Y = 0;
}
if (hasCollidedHorizontally)
{
selfSpeed.X = 0;
}

• It all makes sense now :) – wolfdawn Oct 1 '12 at 0:09

Where do you get the frameHeight variable from, is it large enough to ensure the worldLocation.Y will be low enough to meet the condition collisionRectangle.Bottom <= platform.CollisionRectangle.Top the second time? You said that it stops for a second and then continues to fall so my educated guess is that you are not fixing it up enough.

Give this a shot:

worldLocation.Y = platform.CollisionRectangle.Y - frameHeight - 20;


See if it gets stuck on top, 'bouncing' in a jerky motion.

If that is the case then frameHeight is too small to correct the player back on the platform right after the player falls through.

It appears the issue was in the order of the code. The player fell through the platform, it was detected and the speed on y-axis was reset(hence he stopped for a second). Moving the player was handled after that and the player was moved through the platform to the originally designated new position.

• This does exactly what you say it does, it produces a jerky bouncing motion. frameHeight is the value of the entity's Texture2D.Height. – TheBroodian Sep 30 '12 at 23:48
• It is a little smaller than the value you need. My best guess is that is a few pixels short. I need to trace the values in the code to see. I was also wondering, are you setting back the fall speed to zero each time the player lands on the platform? – wolfdawn Sep 30 '12 at 23:58
• Yes, there's a method that checks to see if the player is 'standing' on anything. If something is found beneath his feet, then fall speed resets to 0. – TheBroodian Oct 1 '12 at 0:21