Slope Sliding Enhancement

I’m currently adding the ability of the player to slide on steep surfaces. I have read several topics about that and I understand the concept. I managed to make something, that works pretty well, but I need some help on how to enhance it a little more.

function SlideOnSlope () {
var hit : RaycastHit;
if(grounded) {
sliding = false;
	if (Physics.Raycast(transform.position, -Vector3.up, hit, 7)) {
            if (Vector3.Angle(hit.normal, Vector3.up) > 30)
                sliding = true;
	}
			else {
            Physics.Raycast(contactPoint + Vector3.up, -Vector3.up, hit);
            if (Vector3.Angle(hit.normal, Vector3.up) > 30)
                sliding = true;
			} 
		
		}

		
		if(sliding){
			var groundNormal = hit.normal;
            slideDirection += Vector3(groundNormal.x/4, -groundNormal.y/4, groundNormal.z/4);
            
		}
		else 
		{
		slideDirection = Vector3(0,0,0);
		}

}

This is the sliding function, it raycasts downwards to see if the surface beneath the player is steep enough to start sliding and if so, than add some values to the slideDirection, after that I got this in the Update function:

controller.Move(moveDirection * Time.deltaTime);
controller.Move(slideDirection * Time.deltaTime);

Two controller.move functions (not sure if this is OK, but it works fine).

So now my first issue is this:

else 
{
slideDirection = Vector3(0,0,0);
}

No matter how huge is the sliding speed, if the slope is no longer enough to slide on, the slide will suddenly stop. I did this, because if I don’t set slideDirection to 0, than my player will continue sliding on and on.

So what should I do to invert this action:

 slideDirection += Vector3(groundNormal.x/4, -groundNormal.y/4, groundNormal.z/4);

Here the player keeps gains the speed smoothly as he slides down.

My second issue is for modifying the moveDirection. Now if the angle of the slope beneath the player is 30 or bigger he will start sliding down, but I can walk on a 29 degrees slope and speed wouldn’t even change, than suddenly if I step on a 30 degrees slope, my player will start immediately sliding.
So how would I go for modifying the speed acording to the slope I’m walking on ?

Thanks in advance!

Instead of two Moves (expensive), use just one -

.Move( (moveDirection + slideDirection ) * Time.deltaTime );

To slow down instead of insta-stopping, don’t set slideDirection to .zero, set it to something like -

slideDirection -= (slideDirection) * Time.deltaTime;

Decreasing it to zero over some amount of time.
Hopefully. :slight_smile:

And to make everything else redundant, when you find the slope of the surface, you can multiply the user’s desired moveDirection by a ratio that is zero at (unacceptable slope) and 1.0 at zero slope -

var slope : float = Vector3.Angle( moveDirection, normalVector );
... // do stuff with slope unaltered
if ( slope >= 90 ) { // player facing away from normal, i.e. uphill
 slope -= 90.0;
 if ( slope > maxSlope ) slope = maxSlope;
 moveDirection *= (maxSlope-slope) / maxSlope;
} else { // player facing downhill
 // speed up if not sliding?
}

I haven’t tested that but it looks like it’ll be close. Plus I need that for my own game so why not share. :slight_smile:

Actually I’m gonna jam that in my game now and make sure it’s not completely insane.

Edit - hahadur. Maths. Should work better now.

It’ll need some finessing to make it work nicely, but that ought to get you going in the right direction.

Hey, thanks! That was really helpful. I couldn’t get your code to work, but I think something like thiswould work:

controller.Move((moveDirection + slideDirection + Vector3(hit.normal.x, hit.normal.y, hit.normal.z)) * Time.deltaTime )

I still can’t get this to work, but I have the feeling that it could be made to work. What do you think?

Well, that’ll just get you kind of bouncing off of all the surfaces you touch. :smile:

You need to hinder movement speed somehow while you’re on surfaces that hinder movement. What exactly is the problem you’re having with mine? Mine works very well on my machine just like that. It should be easy enough to alter to fit your character.

Actually in my code instead of *='ing moveDirection, I have another float var called “hinderMovement” that I use.

function OnControllerColliderHit(...) {
...
if ( slope > maxWalkSlope ) slope = maxWalkSlope;
hinderMovement = (maxWalkSlope-slope) / maxWalkSlope;
...
}
 
function Update() {
totalMovement = Vector3.zero;
...
totalMovement += moveDirection * moveSpeed * hinderMovement;
controller.Move( totalMovement );
...
}

Well it was just behaving really strange.

This is all in the Update function:

	transform.Rotate(0, Input.GetAxis ("Mouse X") * 5, 0); 
		moveDirection = new Vector3(moveSideways*1, 0, moveForward*1);
		moveDirection = transform.TransformDirection(moveDirection);

	moveDirection.y -= gravity + Time.deltaTime;
	hinderDirection = moveDirection;
	var slope : float = Vector3.Angle(hinderDirection, hit.normal); 
	
	if (slope >= 90 ) {
 slope -= 90.0; 
 if ( slope > 60 ) slope = 60; 
 moveDirection *= (60-slope) / 60; 
} else {
} 
	var controller : CharacterController = GetComponent(CharacterController);
	grounded = (controller.Move( (moveDirection + slideDirection) * Time.deltaTime )  CollisionFlags.Below) !=0;

Honestly I don’t understand how your code works. That slope variable would be equal to 180 or something if I’m standing on a flat ground, that means that the if statement will be always executed and…I just don’t get it, it’s hard for me to read code, written by other people though, I’m just a little bit dumb :smile:

Naw, that’s pretty common, having a hard time reading other peoples’ code. Especially when they don’t comment very well. >_<

I didn’t realize your moveDirection also included speed; in my program, they’re independent ( and gravity is handled separately, so moveDirection is only horizontal movement)

As long as you’re moving, your move direction (flattened) will be close to the ground level

transform.Rotate(0, Input.GetAxis ("Mouse X") * 5, 0);
moveDirection = new Vector3(moveSideways*1, 0, moveForward*1);
moveDirection = transform.TransformDirection(moveDirection);

moveDirection.y -= gravity + Time.deltaTime;

// Default to unhindered movement
hinderMovementMultiplier = 1.0;

// We need the angle between our flattened direction and the slope's normal
var planarMovement = moveDirection;
planarMovement.y = 0;

// I'm assuming hit is stored information from a collision function :)
var slope : float = Vector3.Angle( planarMovement, hit.normal);
  
// If the angle between our movement and the slope normal is > 90; i.e., we're moving uphill 
if (slope >= 90 ) {

 // Alter slope to be the angle between Slope Forward( direction in which the slope ascends ) and Flat ( direction in which the slope ascends but with y-component zeroed )

 // It really helps me to draw pictures of this kind of stuff
 // But my ascii art is kinda suck
 slope -= 90.0;

 // Cap the multiplier to 1.0 so we don't move backwards instead of not moving
 if ( slope > 60 ) slope = 60;
 hinderMovementMultiplier = (60-slope) / 60;


} else {

 // do nothing for now; we're headed downhill
}

// Get controller
var controller : CharacterController = GetComponent(CharacterController);

// Split this up so it's fun to look at O_O
var totalMovement : Vector3 = moveDirection * hinderMovementMultiplier;
totalMovement += slideDirection;
totalMovement *= Time.deltaTime;

// Move
grounded = (controller.Move( totalMovement )  CollisionFlags.Below) !=0;

So I made a beautiful picture with my skills of an artist


Two uphill movement pictures and a downhill one that I didn’t bother mathing with.

If you’re walking on flat ground, the angle difference between your (flattened) movement direction and the ground slope is 90 degrees. As you move downhill, it shrinks (until 0, at which point you’re very much falling). As you move uphill, it increases. So if you discover that the angle between your forward and the slope normal is >90, you know you’re moving uphill. You can then create a ratio (hinderMovementMultiplier) that represents how uphilledly you are moving, and slow you appropriately.

phew. :slight_smile:

Thanks a million! That was really really helpful and I understood it. The image helped me to visualize it.

Excellent.

Glad to be of service. :slight_smile: