iamrece
Designer & Developer
>> contact@iamrece.com
>> view resume


Platform Slopes & Angle Collision Functions



Preface

  Within platformer game mechanics collision detection is needed in some form. There's the range detection using a radius in different dimensions, boundingBox rectangle collisions, and pixel-perfect collisions that test the alpha layer of each pixel. Figuring out these on your own or finding a good source of information to explain them is not that hard (check the sources below), but what if you want a ball to roll down a slope or simply have your character run up some angles? Well, this is what I had to figure out and I imagine more people would run into the same wall for a bit so I'd try to explain how I got it to work. I'm still making adjustments and this function is in need of some optimizing, but explaining it so far will give you a starting off point and also give myself a better idea of it's inner-workings.
  First off, if you are not comfortable with angles, slopes, sines, cosines, and tangents, etc. - you might want to grab the book Algebra and Triginometry with Analytical Geometry by Earl W. Swokowski and Jeffery A. Cole. The normal bounding-box collision test works well for sharp horizontal and vertical tests, but having a good understanding of angles will help push these tests further.




The Work

  So, I have a tree and I want my character to run across the branch with the angle of the branch I drew (instead of flattening out all of my branches). I have a list of points notifying the different slopes I want to test for. I'm using C# with XNA so i'm using List to hold each set of points together. The point on the character's boundingBox i'm testing against is the bottom mid-point:

Vector2 midPoint;
midPoint.X = (characterPosition.X + (characterWidth / 2));
midPoint.Y = (characterPosition.Y + characterHeight);


  First you'll want to do a general rectangle collisionTest to make sure the character is within range of these two points (Using the two points to form a box and adding some value to the bottom depending on how you're using gravity). We get the slope of Point-1 to Point-2 using the normal slope formula (and being careful of divideByZero errors):

// Split this equation up to check if denominator is zero.
slopeOfPlatform = ((P2.Y - P1.Y) / (P2.X - P1.X));


  And we get the slope from Point-1 to our character's mid-point:

// Split this equation up to check if denominator is zero.
slopeOfP_toChar = ((midPoint.Y - P1.Y) / (midPoint.X - P1.X));


  By this point if the character's slope is lower than slopeOfPlatform then the character has hit the angle. Easy enough, but now you need to snap the character to standing on the angled platform. You do this by finding the length of a and b (noted in the image below):



  We have the values of Point-1, Point-2, and our character's mid-point so that allows us find values we need:

d = Sqrt((P2.X - P1.X)2 + (P2.Y - P1.Y)2);
k = Sqrt((midPoint.X - P1.X)2 + (midPoint.Y - P1.Y)2);
j = Sqrt((P2.X - midPoint.X)2 + (P2.Y - midPoint.Y)2);
x1 = (P2.X - P1.X);


  And using the Law of Cosines and the Law of Sines:

angle u = cos-1((d2 + k2 + j2) / (2dk));
angle w = sin-1(x1 / d);
n = k sin(u);
x2 = d2 * sin(n);
y = d2 * cos(n);


  And those values allows us to find a and b:

a = (midPoint.X - P1.X) - x2;
b = y - (P1.Y - midPoint.Y);


  So then, you would want to move your character's position a units back (left) and b units up and your character should be standing on the angle properly. Further use of these vars would let you get the rotation needed so that the character would lay flat on this angle.



Notes

  When setting up the angled platforms using a list make sure set the correct points in the correct order (i.e. A-B, B-C, C-D) to not have gaps where they are unwanted. When debugging you can setup a for loop within your Draw method to iterate through the angled platform list and draw a node for each point. Also, if the values aren't adding up to what you have on paper, try breaking up the equations (i.e. Change ((x + y) - c) into 2 seperate equations being sent to different variables so when stepping through the function you can check your work).



Further

  Implementing the code would depend on how you have your game setup. In my case, I have a constant gravity variable pulling the character down (unless jumping or some other mechanic i'm using kicks in). If the character hits a platform due to gravity it will revert the gravity value then snap the character's feet to the platform's top. The snapping of the character into place is so my character won't be inside the platform nor floating above it - the character's feet will be right on the top of the platform.



Links