# Floats vs. Ints for position and collision

So I’m writing a player class and using floats to store the positon and velocity (Vector2) as well as using it when drawing. When it comes to collision I get the player bounds using this code: public Rectangle Bounds => new Rectangle((int)_pos.X, (int)_pos.Y, 12, 23); to test it against solid blocks.

The issue comes when I apply gravity to the player and the player moves in <1 increments per frame eg. first frame 0, second frame 0.25, etc. This causes the player to jitter when above a block due to him falling down little by little until the collision code (which uses ints) pushes it back up.

One solution I came across is to use the Bounds I calculated earlier for drawing, instead of using the position directly. However there is another problem (because the problems never stop coming)… Now the jitter occurs behind the scenes causing the ground detection to not work. How can I make the float positioning and int collision system work in harmony??

The player class' file:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;

public class Player
{
public Rectangle Bounds
=> new Rectangle((int)_pos.X, (int)_pos.Y, 16, 16);

Vector2 _prevPos;
Vector2 _pos;
Vector2 _vel;

World _world;

const float GRAVITY = 500;
const float MOVE_SPEED = 100;
const float JUMP_FORCE = 275;
const float MAX_FALL_SPEED = 350;

public Player(Vector2 position)
{
_pos = position;
_world = Main.World;
}

public void Update(float dt)
{
// Gravity
_vel.Y += GRAVITY * dt;
_vel.Y = MathHelper.Clamp(_vel.Y, -MAX_FALL_SPEED, MAX_FALL_SPEED);

// Horizontal movement
if (Input.IsKeyHeld(Keys.A))
_vel.X = -MOVE_SPEED;
else if (Input.IsKeyHeld(Keys.D))
_vel.X = MOVE_SPEED;
else
_vel.X = 0f;

// Jumping
if (Input.IsKeyDown(Keys.Space))
_vel.Y = -JUMP_FORCE;

// Calculate position
_prevPos = _pos;
_pos += _vel * dt;

HandleCollisions();

System.Console.WriteLine("Velocity: {0}", _vel);
}

void HandleCollisions()
{
Rectangle bounds = Bounds;
Rectangle prevBounds = new Rectangle((int)_prevPos.X, (int)_prevPos.Y, bounds.Width, bounds.Height);

// Only check blocks around player
int left = bounds.Left / TileData.TILE_SIZE;
int right = bounds.Right / TileData.TILE_SIZE;
int top = bounds.Top / TileData.TILE_SIZE;
int bottom = bounds.Bottom / TileData.TILE_SIZE;

for (int x = left; x <= right; x++)
{
for (int y = top; y <= bottom; y++)
{
// Not a solid block
if (_world.GetBlock(x, y) == -1)
continue;

Rectangle blockBounds = new Rectangle(x * TileData.TILE_SIZE, y * TileData.TILE_SIZE, TileData.TILE_SIZE, TileData.TILE_SIZE);

// Resolve collision on x axis
if (bounds.Intersects(blockBounds))
{
// Previously to left of block
if (prevBounds.Right <= blockBounds.Left)
{
_pos.X = blockBounds.Left - bounds.Width;
_vel.X = 0f;
}
// Previoulsy to right of block
else if (prevBounds.Left >= blockBounds.Right)
{
_pos.X = blockBounds.Right;
_vel.X = 0f;
}
}

// Perform further collision using new bounds
bounds = Bounds;

// Resolve collision on y axis
if (bounds.Intersects(blockBounds))
{
// Previously above block
if (prevBounds.Bottom <= blockBounds.Top)
{
_pos.Y = blockBounds.Top - bounds.Height;
_vel.Y = 0f;

// _isGrounded = true; Doesn't work due to float and int mismatch
}
// Previoulsy below block
else if (prevBounds.Top >= blockBounds.Bottom)
{
_pos.Y = blockBounds.Bottom;
_vel.Y = 0f;
}
}
}
}
}

public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.FillRectangle(Bounds, Color.White);
}
}

• I've edited your question to put the code into it. While I understand you don't want to cluster the question, the code tags make it readable within the question and it will avoid the question becoming non-understandable if the link becomes invalid. Jun 28 at 8:23

You want to make it so that 'bottom' resolves into the next tile when there is a small increase in _pos.Y, the same goes for 'right' and _pos.X. This will also fix the edge case when you're exactly aligned within a tile ie. 'top' and 'bottom' will be within the same tile in that case.

So to calculate the left, right, top and bottom, do something like the following:

const int maxCells = 0x1000;            // Arbitrarily large. Beware float precision issues.
int pixels = maxCells * TileWidth;
int xLeft = (int)_pos.X / TileWidth;
int xRight = maxCells - (int)(pixels - _pos.X) / TileWidth;    // Aligns correctly within a tile in the edge case
int yTop = (int)_pos.Y / TileHeight;
int yBottom = maxCells - (int)(pixels - _pos.Y) / TileHeight;


Basically for 'bottom' and 'right' you're calculating the tile position from the other side and negating to give the desired result. The reason for subtracting from a constant is to keep everything in the positive range for the (int) cast.

With this you should be able to detect when 'bottom' enters the ground correctly.