Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm creating an RPG using XNA/C# and am trying to add some complicated collision detection code. I have the playable character 'Wizard' and when it collides with something, a method gets called in his class with the sprite which he collided with as a parameter.

Now what I want the wizard to do is be able to 'slide' around the sprite when he collides with (In this case it's a tree), both sprites are 8px x 8px (they are scaled up by x 8 when drawn to the screen). So far what I've done is find the co ordinates of each corner of both sprites and the co ordinates of the mid points of each side of both sprites and storing them as Vector2's.

Vector2 spriteTopLeft = new Vector2(sprite.X, sprite.Y);
Vector2 spriteTopRight = new Vector2(sprite.X + sprite.Width, sprite.Y);
Vector2 spriteBottomLeft = new Vector2(sprite.X + sprite.Height, sprite.Y + sprite.Height);
Vector2 spriteBottomRight = new Vector2(sprite.X + sprite.Width, sprite.Y + sprite.Height);

Vector2 wizardTopLeft = new Vector2(X, Y);
Vector2 wizardTopRight = new Vector2(X + Width, Y);
Vector2 wizardBottomLeft = new Vector2(X, Y + Height);
Vector2 wizardBottomRight = new Vector2(X + Width, Y + Height);

Vector2 spriteTopMid = new Vector2(spriteTopLeft.X + (sprite.Width / 2), spriteTopLeft.Y);
Vector2 spriteRightMid = new Vector2(spriteTopRight.X, spriteTopRight.Y + (sprite.Height / 2));
Vector2 spriteBottomMid = new Vector2(spriteBottomLeft.X + (sprite.Width / 2), spriteBottomLeft.Y);
Vector2 spriteLeftMid = new Vector2(spriteTopLeft.X, spriteTopLeft.Y + (sprite.Height / 2));

Vector2 wizardTopMid = new Vector2(wizardTopLeft.X + (Width / 2), wizardTopLeft.Y);
Vector2 wizardRightMid = new Vector2(wizardTopRight.X, wizardTopRight.Y + (Height / 2));
Vector2 wizardBottomMid = new Vector2(wizardBottomLeft.X + (Width / 2), wizardBottomLeft.Y);
Vector2 wizardLeftMid = new Vector2(wizardTopLeft.X, wizardTopLeft.Y + (Height / 2));

Then I'm comparing different corners of both sprites to decide which sides are being collided together, so wherever the wizard is on the top of the tree, to the left, right or underneath it. Next by using the midpoints of the sides of the 2 sprites, I'm calculating which way the wizard should slide.

For example, if the wizard in on the top of the tree, but on the right hand side of the top half, then it should slide around the right side of the tree. I've tried to show what I mean with the following image:

enter image description here

To try to achieve this, I've implemented this code:

    float leverage = 1.5f;
Vector2 temp = new Vector2(0, 0);

if (wizardBottomRight.Y <= spriteTopRight.Y + leverage && wizardBottomLeft.Y <= spriteTopLeft.Y + leverage)
{
    //Top
    if (wizardBottomMid.X <= spriteTopMid.X)
    {
        //Left
        temp = new Vector2(-speed, 0);
    }
    else if (wizardBottomMid.X >= spriteTopMid.X)
    {
        //Top
        temp = new Vector2(speed, 0);
    }
}
else if (wizardTopRight.X <= spriteTopLeft.X + leverage && wizardBottomRight.X <= spriteTopLeft.X + leverage)
{
    //Left
    if (wizardRightMid.Y <= spriteLeftMid.Y)
    {
        //Top
        temp = new Vector2(0, -speed);
    }
    else if (wizardRightMid.Y >= spriteLeftMid.Y)
    {
        //Bottom
        temp = new Vector2(0, speed);
    }
}
else if (wizardTopRight.Y >= spriteBottomRight.Y - leverage && wizardTopLeft.Y >= spriteBottomLeft.Y - leverage)
{
    //Bottom
    if (wizardTopMid.X <= spriteBottomMid.X)
    {
        //Left
        temp = new Vector2(-speed, 0);
    }
    else if (wizardTopMid.X >= spriteBottomMid.X)
    {
        //Right
        temp = new Vector2(speed, 0);
    }
}
else if (wizardBottomRight.X >= spriteBottomLeft.X - leverage && wizardTopRight.X >= spriteTopLeft.X - leverage)
{
    //Right
    if (wizardLeftMid.Y <= spriteRightMid.Y)
    {
        //Top
        temp = new Vector2(0, -speed);
    }
    else if (wizardLeftMid.Y >= spriteRightMid.Y)
    {
        //Bottom
        temp = new Vector2(0, speed);
    }
}

position += temp;

(The variable 'speed' is a float with the value 0.6, 'sprite' is the tree that gets passed into the method which the Wizard collides with)

So far this detection works 75% of the time, need to work on tweaking the leverage amount. At the moment the wizard sort of moves to the right/left and kinda jumps almost around the tree when walking in from the top or bottom and doesn't work correctly at all when walking in from the left/right.

Is this a good way of doing this? Or is there a better method? Also how would I get this code working correctly so that the wizard smoothly walks around the tree?

Thanks in advance!

share|improve this question
    
have you tried using circle collision instead? Or just add a direction vector depending on the axis it's standing. ( top left -> add direction vector to left. Top right -> add direction vector to move right, right-top - > direction up. Right-bottom -> down etc. –  Sidar May 15 '13 at 21:43

2 Answers 2

Do your objects need to be represented by boxes in your collision system? If you used circles or spheres instead of a bounding box, you can quickly detect when objects are colliding and then apply your movement speed along the tangent vector at the intersection point of your colliding objects. Each tick, the wizard would collide, adjust, and slide along the new tangent until it's around the tree and able to continue in the original direction. This gives a very smooth effect like you'd see in your favorite JRPG and your code would also be much smaller (no if-checks for each side of the bounding boxes).

The downside is if your sprites don't fit well in circles, you would either get some overlap or separation depending on the radii you choose.

Here's one explanation, but Google will quickly point you to more http://strawberrycowbear.blogspot.com/2011/06/simple-sphere-based-collision-detection.html

share|improve this answer
    
All sprites are 8x8 pixels large, so using circles would generate a lot 'white space' around the sprites which would cause things to collide when they don't look like they should collide. Good idea though, something to think about. Cheers. –  Thomas Owers Apr 15 '13 at 22:05
1  
@ThomasOwers Your sprite does not need to be a circle. instead of box collision you simply apply circle collision. It's a more of a mathematical thing than anything visual. –  Sidar May 15 '13 at 21:45

I have not tried this, but it is along the lines of how this usually works in 3D physics Using 2D Vector math will yield more elegant and flexible solution. Essentially all you want to do is get rid of the velocity component which is in direct opposition to the obstacle.

E.g. Let w = wizard.Position, t = tree.Position, and assume bounding squares.

if (overlapping(w,t)) // we have a collision
{
    Vector2 d = t - w; // direction to obstacle
    float mx = d.X; float my = d.Y;
    Vector v;
    if (Math.Abs(mx) > Math.Abs(my)) // find direction of collision
        v = new Vector2(mx,0); 
    else
        v = new Vector2(0,my);
    v = d - v;
    wizard.Velocity = v;
}

This is pseudocode. Even if this does not work, the goal behind it should give you the general idea.

share|improve this answer
    
Don't think you quite understand my goal here, when I walk into the tree, I want the wizard to walk around it when I hold down the movement keys. But this method getting the direction of collision is pretty good! Thanks anyway. –  Thomas Owers Mar 22 '13 at 10:56
    
I see. Try A* search algoritm and generate a small path when a collision occurs. –  indeed005 Mar 23 '13 at 4:40
    
@indeed005 That's way overkill for what Thomas wants to achieve. Apparently it's rather a dynamic movement. –  Sidar May 15 '13 at 21:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.