crouching with new beta assets

i understand what i need to do i think but need help implementing it

if (Input.GetButtonDown ("Crouch")){
capsule colliders height = 1 and its y axis = 0.50 and smotthing transition
make head joint follow down aswell 

how would i go about implementing this psuedocode into this script

using UnityEngine;
using System.Collections;

public class FirstPersonCharacter : MonoBehaviour
{
	[SerializeField] private float runSpeed = 8f;                                       // The speed at which we want the character to move
	[SerializeField] private float strafeSpeed = 4f;                                    // The speed at which we want the character to be able to strafe
	[SerializeField] private float jumpPower = 5f;                                      // The power behind the characters jump. increase for higher jumps
	#if !MOBILE_INPUT
	[SerializeField] private bool walkByDefault = true;									// controls how the walk/run modifier key behaves.
	[SerializeField] private float walkSpeed = 3f;                                      // The speed at which we want the character to move
	#endif
	[SerializeField] private AdvancedSettings advanced = new AdvancedSettings();        // The container for the advanced settings ( done this way so that the advanced setting are exposed under a foldout
	[SerializeField] private bool lockCursor = true;

	[System.Serializable]
	public class AdvancedSettings                                                       // The advanced settings
	{
		public float gravityMultiplier = 1f;                                            // Changes the way gravity effect the player ( realistic gravity can look bad for jumping in game )
		public PhysicMaterial zeroFrictionMaterial;                                     // Material used for zero friction simulation
		public PhysicMaterial highFrictionMaterial;                                     // Material used for high friction ( can stop character sliding down slopes )
		public float groundStickyEffect = 5f;											// power of 'stick to ground' effect - prevents bumping down slopes.
	}
	
	private CapsuleCollider capsule;                                                    // The capsule collider for the first person character
	private const float jumpRayLength = 0.7f;                                           // The length of the ray used for testing against the ground when jumping
	public bool grounded { get; private set; }
	private Vector2 input;
	private IComparer rayHitComparer;
	void Awake ()
	{
		// Set up a reference to the capsule collider.
		capsule = collider as CapsuleCollider;
		grounded = true;
		Screen.lockCursor = lockCursor;
		rayHitComparer = new RayHitComparer();
	}

	void OnDisable()
	{
		Screen.lockCursor = false;
	}
	
	void Update()
	{
		if (Input.GetMouseButtonUp(0))
		{
			Screen.lockCursor = lockCursor;
		}
	}
	
	
	public void FixedUpdate ()
	{
		float speed = runSpeed;

		// Read input
#if CROSS_PLATFORM_INPUT
		float h = CrossPlatformInput.GetAxis("Horizontal");
		float v = CrossPlatformInput.GetAxis("Vertical");
		bool jump = CrossPlatformInput.GetButton("Jump");
#else
		float h = Input.GetAxis("Horizontal");
		float v = Input.GetAxis("Vertical");
		bool jump = Input.GetButton("Jump");
#endif

#if !MOBILE_INPUT
		
		// On standalone builds, walk/run speed is modified by a key press.
		// We select appropriate speed based on whether we're walking by default, and whether the walk/run toggle button is pressed:
		bool walkOrRun =  Input.GetKey(KeyCode.LeftShift);
		speed = walkByDefault ? (walkOrRun ? runSpeed : walkSpeed) : (walkOrRun ? walkSpeed : runSpeed);
		
		// On mobile, it's controlled in analogue fashion by the v input value, and therefore needs no special handling.
		

#endif
		
		input = new Vector2( h, v );

		// normalize input if it exceeds 1 in combined length:
		if (input.sqrMagnitude > 1) input.Normalize();
		
		// Get a vector which is desired move as a world-relative direction, including speeds
		Vector3 desiredMove = transform.forward * input.y * speed + transform.right * input.x * strafeSpeed;

		// preserving current y velocity (for falling, gravity)
		float yv = rigidbody.velocity.y;

		// add jump power
		if (grounded && jump) {
			yv += jumpPower;
			grounded = false;
		}
		
		// Set the rigidbody's velocity according to the ground angle and desired move
		rigidbody.velocity = desiredMove + Vector3.up * yv;
		
		// Use low/high friction depending on whether we're moving or not
		if (desiredMove.magnitude > 0 || !grounded)
		{
			collider.material = advanced.zeroFrictionMaterial;
		} else {
			collider.material = advanced.highFrictionMaterial;
		}

		
		// Ground Check:
		
		// Create a ray that points down from the centre of the character.
		Ray ray = new Ray(transform.position, -transform.up);
		
		// Raycast slightly further than the capsule (as determined by jumpRayLength)
		RaycastHit[] hits = Physics.RaycastAll(ray, capsule.height * jumpRayLength );
		System.Array.Sort (hits, rayHitComparer);
		
		
		if (grounded || rigidbody.velocity.y < jumpPower * .5f)
		{
			// Default value if nothing is detected:
			grounded = false;
			// Check every collider hit by the ray
			for (int i = 0; i < hits.Length; i++)
			{
				// Check it's not a trigger
				if (!hits*.collider.isTrigger)*
  •  		{*
    
  •  			// The character is grounded, and we store the ground angle (calculated from the normal)*
    
  •  			grounded = true;*
    
  •  			// stick to surface - helps character stick to ground - specially when running down slopes*
    
  •  			//if (rigidbody.velocity.y <= 0) {*
    

rigidbody.position = Vector3.MoveTowards (rigidbody.position, hits_.point + Vector3.up * capsule.height*.5f, Time.deltaTime * advanced.groundStickyEffect);_
* //}*
* rigidbody.velocity = new Vector3(rigidbody.velocity.x, 0, rigidbody.velocity.z);*
* break;*
* }*
* }*
* }*

_ Debug.DrawRay(ray.origin, ray.direction * capsule.height * jumpRayLength, grounded ? Color.green : Color.red );_

* // add extra gravity*
_ rigidbody.AddForce(Physics.gravity * (advanced.gravityMultiplier - 1));_
* }*

* //used for comparing distances*
* class RayHitComparer: IComparer*
* {*
* public int Compare(object x, object y)*
* {*
* return ((RaycastHit)x).distance.CompareTo(((RaycastHit)y).distance);*
* } *
* }*

}

Let’s look at what we can learn from the much loved [Run and Crouch][1] script by the legend Aldo.

I have previously [examined the script here][2], the highlights are :

  • line 33 lerps the character controller height from its current height to h (h is either standing height or crouched height).
  • line 34 repositions the character so it doesn’t fall through the floor when scaling to a larger height, and doesn’t appear to be floating when scaling to a smaller height.

With that knowledge, you could bring Aldos code over to the beta FirstPersonCharacter by calling a function at the end of FixedUpdate, then adding the following code :

	// add extra gravity
    rigidbody.AddForce(Physics.gravity * (advanced.gravityMultiplier - 1));
//}
	// MODIFIED FOR CROUCHING
	DoCrouch();
}

private float height;
private Transform tr;

void Start()
{
	tr = transform;
	height = capsule.height;
}

void DoCrouch()
{
	float h = height;

	if ( Input.GetKey(KeyCode.C) || Input.GetKey(KeyCode.LeftControl) ) // press C or LeftCTRL to crouch
	{
		h = 0.5f * height;
		//speed = crchSpeed; // slow down when crouching
	}

	float lastHeight = capsule.height; // crouch/stand up smoothly 

	capsule.height = Mathf.Lerp( capsule.height, h, 5.0f * Time.deltaTime );
	tr.position += new Vector3( 0, ( capsule.height - lastHeight ) * 0.5f, 0 ); // fix vertical position
}

So that takes care of the character height, but what about the character speed? Well the whole script needs a lot of modification to factor that in.

  • some new global variables need to be declared for crouch speed and crouch strafe speed
  • a new temporary variable needs to be created for assigning the strafe speed to the Vector3 desiredMove if crouched
  • all the other calculations in the above example function need to be moved to inside FixedUpdate so the speed values can be modified, before calculating the Vector3 desiredMove that is applied to the rigidbody.velocity

I have modified the script to only use crouch in StandAlone builds, so all the above points are mostly added to the Compilation Dependent part of the script (where sprint for StandAlone is calculated). I added the temporary strafe variable after the temporary speed variable, and changed line 95 to factor in the temporary strafe variable (now at line 134).

Because the headbob script uses the rigidbody velocity, the footstep sounds also change speed if crouched. However I have noticed some weird snapping of the camera when finishing the transition to crouch or stand. (but hey, nobody’s perfect!)

Now here’s the modified script. Please try to understand all the changes made, and maybe (hopefully) somebody can improve on this.


Edit : using a version of the script downloaded on June 26th 2014

FirstPersonCharacter.cs

using UnityEngine;

public class FirstPersonCharacter : MonoBehaviour
{
	[SerializeField] private float runSpeed = 8f;                                       // The speed at which we want the character to move
	[SerializeField] private float strafeSpeed = 4f;                                    // The speed at which we want the character to be able to strafe
    [SerializeField] private float jumpPower = 5f;                                      // The power behind the characters jump. increase for higher jumps
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8)
    [SerializeField] private bool walkByDefault = true;									// controls how the walk/run modifier key behaves.
	[SerializeField] private float walkSpeed = 3f;                                      // The speed at which we want the character to move
	[SerializeField] private float crouchSpeed = 1.7f;                                  // The speed at which we want the character to move when crouched
	[SerializeField] private float crouchStrafeSpeed = 1.8f;                            // The speed at which we want the character to be able to strafe when crouched
#endif
    [SerializeField] private AdvancedSettings advanced = new AdvancedSettings();        // The container for the advanced settings ( done this way so that the advanced setting are exposed under a foldout

    [System.Serializable]
    public class AdvancedSettings                                                       // The advanced settings
    {
        public float gravityMultiplier = 1f;                                            // Changes the way gravity effect the player ( realistic gravity can look bad for jumping in game )
        public PhysicMaterial zeroFrictionMaterial;                                     // Material used for zero friction simulation
        public PhysicMaterial highFrictionMaterial;                                     // Material used for high friction ( can stop character sliding down slopes )
    }

    private CapsuleCollider capsule;                                                    // The capsule collider for the first person character
    private const float jumpRayLength = 0.7f;                                           // The length of the ray used for testing against the ground when jumping
	public bool grounded { get; private set; }
	private Vector2 input;
	
	private float height;
	private Transform tr;


    void Awake ()
	{
        // Set up a reference to the capsule collider.
	    capsule = collider as CapsuleCollider;
		grounded = true;
	}
	
	
	void Start()
	{
		tr = transform;
		height = capsule.height;
	}

	
	public void FixedUpdate ()
	{
        // Read input
		float h = CrossPlatformInput.GetAxis("Horizontal");
		float v = CrossPlatformInput.GetAxis("Vertical");
		bool jump = CrossPlatformInput.GetButton("Jump");

		input = new Vector2( h, v );

		float speed = runSpeed;
		float sideSpeed = strafeSpeed; // modified for crouch strafe

		#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8)
		// On standalone builds, walk/run speed is modified by a key press.
		// We select appropriate speed based on whether we're walking by default, and whether the walk/run toggle button is pressed:
		bool walkOrRun =  Input.GetKey(KeyCode.LeftShift);
		speed = walkByDefault ? (walkOrRun ? runSpeed : walkSpeed) : (walkOrRun ? walkSpeed : runSpeed);


		// MODIFIED FOR CROUCHING (ONLY FOR STANDALONE BUILDS)
		
		float hgt = height;
		
		// press C or LeftCTRL to crouch
		bool crouch = Input.GetKey(KeyCode.C) || Input.GetKey(KeyCode.LeftControl) ? true : false; // using Input as CrossPlatformInput only checks for buttons (set in the Input Settings)
		
		// if crouched, modify capsule collider height and speed
		if ( crouch )
		{
			hgt = 0.5f * height;
			
			// slow down when crouching
			speed = crouchSpeed; 
			sideSpeed = crouchStrafeSpeed;
		}
		
		float lastHeight = capsule.height; // crouch/stand up smoothly 
		
		capsule.height = Mathf.Lerp( capsule.height, hgt, 5.0f * Time.deltaTime );
		tr.position += new Vector3( 0, ( capsule.height - lastHeight ) * 0.5f, 0 ); // fix vertical position

        #endif
		
		// On mobile, it's controlled in analogue fashion by the v input value, and therefore needs no special handling.


        
        // Ground Check:

		// Create a ray that points down from the centre of the character.
		Ray ray = new Ray(transform.position, -transform.up);
		
		// Raycast slightly further than the capsule (as determined by jumpRayLength)
		RaycastHit[] hits = Physics.RaycastAll(ray, capsule.height * jumpRayLength );

	       
        float nearest = Mathf.Infinity;
	
		if (grounded || rigidbody.velocity.y < 0.1f)
		{
			// Default value if nothing is detected:
			grounded = false;
            
            // Check every collider hit by the ray
			for (int i = 0; i < hits.Length; i++)
			{
				// Check it's not a trigger
				if (!hits_.collider.isTrigger && hits*.distance < nearest)*_

* {*
* // The character is grounded, and we store the ground angle (calculated from the normal)*
* grounded = true;*
_ nearest = hits*.distance;
//Debug.DrawRay(transform.position, groundAngle * transform.forward, Color.green);
}
}
}*_

_ Debug.DrawRay(ray.origin, ray.direction * capsule.height * jumpRayLength, grounded ? Color.green : Color.red );_

// normalize input if it exceeds 1 in combined length:
* if (input.sqrMagnitude > 1) input.Normalize();*

* // Get a vector which is desired move as a world-relative direction, including speeds*
_ //Vector3 desiredMove = transform.forward * input.y * speed + transform.right * input.x * strafeSpeed;
Vector3 desiredMove = transform.forward * input.y * speed + transform.right * input.x * sideSpeed; // modified for crouch strafe (new variable sideSpeed used)_

* // preserving current y velocity (for falling, gravity)*
* float yv = rigidbody.velocity.y;*

* // add jump power*
* if (grounded && jump) {*
* yv += jumpPower;*
* grounded = false;*
* }*

* // Set the rigidbody’s velocity according to the ground angle and desired move*
_ rigidbody.velocity = desiredMove + Vector3.up * yv;_

// Use low/high friction depending on whether we’re moving or not
if (desiredMove.magnitude > 0 || !grounded)
* {*
collider.material = advanced.zeroFrictionMaterial;
* } else {*
* collider.material = advanced.highFrictionMaterial;*
* }*

* // add extra gravity*
rigidbody.AddForce(Physics.gravity * (advanced.gravityMultiplier - 1));
* }*

}
------------------------------------------------------------------------------------
Here is a list of all the changes that have been made to the script.
line 10 : add the variables
[SerializeField] private float crouchSpeed = 1.7f; // The speed at which we want the character to move when crouched
[SerializeField] private float crouchStrafeSpeed = 1.8f; // The speed at which we want the character to be able to strafe when crouched
line 26 (now line 28) : add the variables
private float height;
private Transform tr;
line 35 (now line 41) : add the function
void Start()
{
* tr = transform;*
* height = capsule.height;*
}
line 45 (now line 58) : add the variable
float sideSpeed = strafeSpeed; // modified for crouch strafe
line 51 (now line 65) : add the code
// MODIFIED FOR CROUCHING (ONLY FOR STANDALONE BUILDS)

float hgt = height;

// press C or LeftCTRL to crouch
bool crouch = Input.GetKey(KeyCode.C) || Input.GetKey(KeyCode.LeftControl) ? true : false; // using Input as CrossPlatformInput only checks for buttons (set in the Input Settings)

// if crouched, modify capsule collider height and speed
if ( crouch )
{
_ hgt = 0.5f * height;_

* // slow down when crouching*
* speed = crouchSpeed;*
* sideSpeed = crouchStrafeSpeed;*
}

float lastHeight = capsule.height; // crouch/stand up smoothly

capsule.height = Mathf.Lerp( capsule.height, hgt, 5.0f * Time.deltaTime );
tr.position += new Vector3( 0, ( capsule.height - lastHeight ) * 0.5f, 0 ); // fix vertical position
line 95 (now line 133) : edit the code
Vector3 desiredMove = transform.forward * input.y * speed + transform.right * input.x * sideSpeed; // modified for crouch strafe (new variable sideSpeed used)
*[1]: http://answers.unity3d.com/questions/164638/how-to-make-the-fps-character-controller-run-and-c.html*_
*[2]: http://answers.unity3d.com/questions/711952/crouching-script.html*_