Move Object Along Ground Using Raycast

Hi, all!

I have a character in a sidescroller/platformer. So the Z axis is not a problem here. When I press A or D, the character moves horizontally. This is great, until I come upon a ramp or a curve. He just walks into it and stops.

I want to be able to move my character along the slope of the point immediately in front of him without just setting his transform.up to the hit.normal. This would not look very realistic in most cases.

So I decided I would draw a ray immediately in front of him, get the normal of the current face, and take the negative reciprocal of the slope of the normal in order to get the slope of the line tangent to the face.

Then I take a deltaX value and set the Y equivalent to the deltaX*m + transform.position.y

This does not work at all.

After doing some debugging, I decided to draw a Debug.Rays of the normal and of the calculated tangent. The normal is yellow and comes from the player’s feet and the tangent is red, stretching from the player’s feet (As an Origin) to the point along the line one unit away. On a flat surface, it works great. However, on a curved surface it doesn’t work. What’s up? I will offer some sample code and a few pictures.

Thanks! - YA

This is when he is on a flat surface. The red is the calculated tangent, the normal is yellow, and the ray test is cyan (It is a bit in front of the player so I know what is coming up before the player is over it)

alt text

This is when the player steps onto a gently-sloping ramp

alt text

Totally off…

Here is the code running the Debug and the rays.

	ray = new Ray( new Vector2( p.x + c.x + s.x * Mathf.Sign(deltaX), p.y + c.y + s.y/(3)), new Vector2( 0, -1 ) );
	Debug.DrawRay( ray.origin, ray.direction, Color.cyan );
	if( Physics.Raycast( ray, hit, s.y, collisionMask )) {
			var	slopeVec : Vector3 = hit.normal;
			var normSlope : float = ( slopeVec.y - transform.position.y) / (slopeVec.x - transform.position.x );
			slope = Mathf.Pow( (slopeVec.y/slopeVec.x), -1 )*-1; //Tangent line is negative reciprocal of normal
//			Debug.Log( slope  + "˚");
			Debug.DrawRay( transform.position, hit.normal, Color.yellow, 0.0, false);
			Debug.DrawLine( Vector3( transform.position.x,  transform.position.y, 0 ), Vector3( transform.position.x+1, (transform.position.x+1)*slope + transform.position.y, 0 ), Color.red, 0.0, false );
			if( Mathf.Abs( slope ) > (0.05) ) onRamp = true;
			else onRamp = false;
	}

If all you need is a movement vector, then all you need to do is calculate a vector from your current position to the position of the raycast. How you calculate that will depend on the pivot point of the character. If the pivot point is at the feet of the character (which has been recommend in a couple of writeup I’ve read on game development), then the movement vector will be:

var moveDirection = (hit.point - transform.position).normalized;

If your pivot is further up, say 0.5 units up, from the feet then the calculation is a bit more complicated:

var moveDirection = ((hit.point + hit.normal * 0.5) - transform.position;

As an alternate, you can raycast directly down from the character and use the cross product to find the direction.

var moveDirection = Vector3.Cross(hit.normal, transform.right);

I may have the parameters backwards in the Vector3.Cross().