Sign in to follow this  
tharuin

Efficient pixelperfect collision with collision mask

Recommended Posts

tharuin    100
Heyho everybody!

I'm currently trying to make the collision working for a sidescrolling ( platformer ) game. It uses a collision mask ( like this one: [url="http://dl.dropbox.com/u/2395375/collisionmask1.png"]http://dl.dropbox.co...lisionmask1.png[/url] BIG IMAGE!!! ).
My current code for this is this one:
[code]
override public void OnUpdate(GameTime gameTime)
{
//Input check
if (state != State.Jumping)
{
state = Player.State.Standing;
if (Keyboard.GetState().IsKeyDown(Keys.A))
{
Velocity = new Vector2(WalkSpeed*-1, Velocity.Y);
direction = Player.Direction.Left;
state = Player.State.Walking;
}
else if (Keyboard.GetState().IsKeyDown(Keys.D))
{
Velocity = new Vector2(WalkSpeed, Velocity.Y);
direction = Player.Direction.Right;
state = Player.State.Walking;
}
else
Velocity = new Vector2(0, Velocity.Y);

if (Keyboard.GetState().IsKeyDown(Keys.Space))
{
state = Player.State.Jumping;
Velocity = new Vector2(Velocity.X, JumpPower*-1);
}
}

//Position update
lastPosition = Position;
Velocity += Acceleration * (float)gameTime.ElapsedGameTime.TotalSeconds;
Position += Velocity;

switch (state)
{
case State.Walking: SetAnimation("Walk"); break;
case State.Jumping: SetAnimation("Jump"); break;
case State.Standing:
default:SetAnimation("Stand"); break;
}

//Collision check
int check = Level.GetCollisionMaskIndex(this);

//Check if player is already standing ( should mean that he collided the frame before )
if (state != State.Standing)
{
if (CheckCollision(check) != new Vector2(1.337f, 1.337f))
{
state = State.Standing;
Position = new Vector2(Position.X, Position.Y - (Size.Y / 2) - Vector2.Subtract(GetCenter(), CheckCollision(check)).Y + 5);
MoveToContact(check);
Velocity = new Vector2(Velocity.X, 0);
}
}
else
{
Position = new Vector2(Position.X, lastPosition.Y);
}

base.OnUpdate(gameTime);
}

private void MoveToContact(int Index)
{
Vector2 beforeCollision = Position;
int direction = 0;

if (CheckCollision(Index) != new Vector2(1.337f, 1.337f))
direction = -1;
else
direction = 1;

while (CheckCollision(Index) != new Vector2(1.337f, 1.337f))
{
beforeCollision = Position;
Position += new Vector2(0, direction);
}

Position = beforeCollision;
}

private Vector2 CheckCollision(int Index)
{
Rectangle rectangleA, rectangleB;
rectangleA = new Rectangle((int)Position.X, (int)Position.Y, (int)Size.X, (int)Size.Y);
rectangleB = new Rectangle((int)Level.CollisionMasks[Index].Position.X, (int)Level.CollisionMasks[Index].Position.Y, Level.CollisionMasks[Index].Texture.Width, Level.CollisionMasks[Index].Texture.Height);
Color[] dataA, dataB;
dataA = colorData;
dataB = Level.CollisionMasks[Index].colorInfo;

// Find the bounds of the rectangle intersection
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);

// Check every point within the intersection bounds
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
// Get the color of both pixels at this point
Color colorA = dataA[(x - rectangleA.Left) +
(y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) +
(y - rectangleB.Top) * rectangleB.Width];

// If both pixels are not completely transparent,
if (colorA.A != 0 && colorB.A != 0)
{
// then an intersection has been found
return new Vector2(x, y);
}
}
}

// No intersection found
return new Vector2(1.337f, 1.337f);
}
[/code]

This code has some bugs and behaviors that I actually don't want.
First of all its not very efficient. Its reducing the FPS when passing bigger slopes and when I'm changing to another window and go back the character just falls through the ground sometimes.
Also its possible to walk over any slope, I don't want it to move against a wall and appear on the top of the wall. My next point is the fact that it is currently only checking for vertical collision. I want it to check for all collision, so jumping against a platform over you makes you stopping and falling back.
I was google'ing and searching for the last days and didn't found any nice resource or examples for this. Are there any common ways to solve this?
( This is meant to be pixelperfect and big collision mask based, not rectangle and tiled collision masks )

I hope you can give me some hints or links.

Thank you!

Share this post


Link to post
Share on other sites
tharuin    100
Does nobody have an idea or a hint for me? :P
I already changed the collision to test pixel ( mask ) to player ( rectangle ), but this didn't change the basic behaviour.

Share this post


Link to post
Share on other sites
danong    125
hi,

i bet you re a novice game programmer,
so i hope my post helps u =)


first of all,
the idea of checking collision with pixels (with image) is not what a good game programmer should attempt to,
the reason is because the flipping of buffer (displaying image) would sometimes cause problems when u minimize ur windows or simply jump out of ur window,
the problems of your character falling down when u minimize ur window is probably becauase of this.

because the windows need to be repainted when you minimzie and resume your windows,
the moment you resume your window,
the graphic is not painted,
and hence no pixels are there,
that's the reason why your character is falling down.

so the best attempt is to,
construct a 2D array for your pixels and collision detection,
which is not for display purpose but for calculation purpose.

remember, image is for display,
the actual calculation should be done seperately.


Regards,
Daniel.

Share this post


Link to post
Share on other sites

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