Coding Sample: Slope-Based Penguin Sliding
/*
* ENGINE: UNITY3D
* LANGUAGE: C#
* Character Controller -- Sliding Code Snippet
* Code used in Penguin Playground Student Project.
* All content © 2014 DigiPen (USA) Corporation, all rights reserved.
* AUTHOR:
* Nathaniel Marshall
*/
/*
* This function manages and calculates the forces acting upon the Player,
* through both Player Input and Gravity/Sloped Ground interactions.
* When Sliding, the Player moves Automatically forward.
*
* PARAMETERS:
* Vector3 inputAxis -- a Vector3 based on the Keyboard/Gamepad Input of the Player.
* Vector3 camForward -- the Forward vector of the main camera, used in rotating inputAxis.
* Vector3 camRight -- the Right-hand vector of the main camera, used in rotating inputAxis.
* Vector3 heroVelocity -- the current Velocity of the player, PLUS modifications made by previous Functions
*
*
* RETURN VALUE:
* Vector3 forceOutput -- the force to be applied to the Player's Physics
*
*/
private Vector3 Move_Sliding(Vector3 inputAxis, Vector3 camForward, Vector3 camRight, Vector3 heroVelocity)
{
/*
* SCRIPT VARIABLES DEFINED OUTSIDE FUNCTION:
* float slide_Modifier_Hill -- ratio that the Hills affect Player Movement
* float speed_Slide_MAX -- the Maximum speed of the Player when Sliding.
* float slide_Modifier_Acceleration -- a multiplier added to the input to
increase Player Velocity when sliding.
*
*GLOBAL FUNCTIONS USED
*HelperFuncs.DrawRay(Vector3 startPosition, Vector3 endPositionReletive,
Color debugLineColor, float debugLineTimer)
*if the DebugMode bool is true, HelperFuncs.DrawRay() automatically draws a Debug.Ray()
*with endPositionReletive being Reletive to the startPosition.
*/
/*******************LOCAL VARIABLES******************/
//defining a blank Vector3 to be added/subtracted to as we calculate
//***forceOutput is what is ultimately returned.***
Vector3 forceOutput = Vector3.zero;
//defining a Target Maximum Speed that is to change depending on Input.
float Target_MaxSpeed = speed_Slide_MAX;
//the Input relative to the camera.
Vector3 slideDir;
//defining a Quat to rotate the Input based on the Player's Normal to the ground.
Quaternion groundInfluence = Quaternion.FromToRotation(Vector3.up, myNormal);
//calculating the difference between the Player's normal and straight up
//to be used in determining how Steep a Slope is.
Vector3 slopeDifference = myNormal - Vector3.up;
//used to calculate the slope of the Input after being rotated perpendicular to ground.
float slideAngle;
//calculate the slope of our velocity as an Angle.
float velocityAngle = Mathf.Atan2(rigidbody.velocity.z, rigidbody.velocity.x);
/****************************************************/
//calling a check to calculate if any special Forces are being applied
//based on the Terrain.
//Is TRUE if such forces exist
if (ground.ReturnForcedDirection() != Vector3.zero)
{
//if no/little forward input has been made, modify the input
//so that there is. This makes the player Slide Forward
//and bypasses the next If() check below.
if (inputAxis.z <= .5f)
{
inputAxis.z = .5f;
}
}
//Rotating the inputAxis so we move relative to the Camera.
slideDir = (inputAxis.x * camRight + inputAxis.z * camForward);
//**NOTE: SPECIAL FORCES OVERRIDES FOLLOWING IF CHECK**//
//if no Input is made...
if(inputAxis.magnitude <= .25f)
{
//..set the direction we're sliding in based on velocity
slideDir = heroVelocity.normalized;
//and lower the Maximum Speed Cap. This makes the player go slower if they're
//not pressing a direction
Target_MaxSpeed = 20;
}
//draw a Debug ray based on Position and the Input Direction before Slope is accounted for.
HelperFuncs.DrawRay(transform.position + new Vector3(0, 2, 0), slideDir, Color.green, 0.001f);
//rotate the slideDirection to account for the Slope of the Ground.
slideDir = groundInfluence * slideDir;
//draw a Debug ray from the Player's position straight up 3 units
HelperFuncs.DrawRay(transform.position, new Vector3(0,3,0), Color.black);
//from the top of the previous ray, draw another Debug ray displaying the influence
//of the Slope of the Ground.
HelperFuncs.DrawRay(transform.position + new Vector3(0, 3, 0), slideDir*3, Color.magenta);
//calculate the slope of our slideDirection (rotated Input) as an Angle.
slideAngle = Mathf.Atan2(slideDir.z, slideDir.x);
//calculate the slope of our velocity as an Angle.
velocityAngle = Mathf.Atan2(rigidbody.velocity.z, rigidbody.velocity.x);
//recalculating slideDirection as a Lerp step between current velocity direction
//and slideDirection (rotatedInput) based on the acceleration of Sliding.
slideDir = Vector3.Lerp(rigidbody.velocity.normalized, slideDir, slide_Modifier_Acceleration);
//draw a Debug ray from Player's position to the Player's Normal.
HelperFuncs.DrawRay(transform.position, myNormal * 5, Color.grey, 0.01f);
//check if we're below the MaximumSpeed
if(rigidbody.velocity.magnitude <= Target_MaxSpeed)
{
forceOutput = slideDir * slide_Modifier_Acceleration;
}
//else, check if the player is going in the exact opposite of the Slope of the ground.
//I.E., going straight up a very steep slope.
else if (Mathf.Abs(slideAngle - velocityAngle) > Mathf.PI/180)
{
//setting forceOutput to the opposite direction
//this prevents players from going up Steep Slopes
forceOutput = (slideDir - transform.forward) * slide_Modifier_Acceleration;
}
//Anything over .1f is considered and defined as a hill that affects Player Movement.
if (slopeDifference.magnitude > .1f)
{
//draw a Debug ray based on an offsetted Position and the slopeDifference
//this creates a triangle between the Vector3.Up and myNormal debugDraws.
//set behind the If check to avoid it being unnecessarily drawn when there is no Slope.
HelperFuncs.DrawRay(transform.position + new Vector3(0, 5, 0), slopeDifference * 5, Color.cyan, 0.001f);
//if originally had no Input, use the slopeDifference and slide_Modifier_Hillifier as acceleration
//as the Input to use.
if (inputAxis.magnitude == 0)
{
forceOutput = slopeDifference * slide_Modifier_Hill;
}
//Modify the forceOutput to take account of the slope.
//NOTE: This includes if no Input was made, doubling the effect of the hill.
forceOutput += slopeDifference * slide_Modifier_Hill;
}
//draw a Debug ray to show the final forceOutput of this function.
HelperFuncs.DrawRay(transform.position, forceOutput * 2, Color.red, 0.01f);
//forceOutput is incorporated into the Physics at the end of the move_DirectedUpdate()
//after other forces are applied to it (Gravity, etc.)
return forceOutput;
}