Detecting Ground Angle

Jan 24, 2011 at 9:07 PM

I'm having a slight issue detecting the ground angle of my player.  I am using the popular square/circle/motor joint character and am using an OnCollision event to check the angle.  to find the contact angle, I am using the contact.Manifold.LocalNormal.  This is basically jsut an update of Elsch's method I found here.  At first, it really looked to be working perfectly, but when I changed the angle of the slope, it broke. 

Here is my pertinent character code:

    	private bool OnWheelCollision(Fixture f1, Fixture f2, Contact contact)
            float angle = Vector2.Dot(contact.Manifold.LocalNormal, -Vector2.UnitY);
            if (Math.Abs(angle) >= .1)
                _activity = Activity.None;

            if (Math.Abs(angle) < .1f)
                _onWall = true;

            return true;
Here is a picture of the two scenarios.
The scenarion on the left produces a contact normal of (0, -1) and angle of 1.0, while the scenario on the right produces a contact normal of (-1, 0) and angle of 0.0.  It seems like the normal should be a unit vector in a wide variety of directions, but I can't seem to get it to work. 
Any thoughts?  Am I implementing this wrong?  Is there a better way?
Thanks in advance for the reply!
Jan 25, 2011 at 1:34 AM

My method was copy pasted from a tilebased engine using only square tiles. Vector2.Dot calculates the angle between the contact normal and the y-axis and i just check if it is near zero or one e.g. whether the angle is 0° or 90°. This only works for horizontal floors and vertical walls.

You need to check if the angle is within a range from -45° to 45° for example. First of all you have to decide at which angle you want to classify a slope as wall or ground.

Jan 25, 2011 at 2:48 AM

Well, from what I've been reading, it is better to use dot product to get an approximation of angle because it saves processor time over hefty trig functions.  In my code I am using .1 ("angle") as the cutoff because I want to be able to jump from all slope angles except for the steepest ones.  The problem seems to be with the contact.Manifold.LocalNormal.  It doesn't give me an angle that I would expect.  It is giving me either -Vector2.UnitY or -Vector2.UnitX as the LocalNormal.  On a 45 degree slope I would expect a normal similar to Vector2.Normalize(1, 1), so that when I calculate the dot product against the -Vector2.UnitY, I would get an "angle" close to .5.

I'm wondering how to calculate that angle correctly. 

Thanks for your help!

Jan 25, 2011 at 4:27 AM

May have figured it out...  I used contact.GetWorldManifold instead and it seems to be outputing more reasonable results.  Can anyone verify that this is the proper method?  Thanks!

Jan 25, 2011 at 8:18 AM

You're right. I just had a look at my own code and i use contact.GetWorldManifold myself ;)