these buttons are required in project input settings
Forward
Back
Left
Right
Run
Jump
LookAround
ToggleCrouch
Mouse X
Mouse Y
attach to a capsule and set camera that is its child in the inspector
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(CapsuleCollider))]
[RequireComponent(typeof(Rigidbody))]
public class Rbctrl : MonoBehaviour
{
CapsuleCollider capsCollider;
float crouchHeight,standHeight;
Rigidbody rb;
public Transform cam;
public bool invertY;
public float acceleration=6,deceleration=6,maxForwardSpeed=22,maxBackSpeed=18,maxStrafeSpeed=18,runModifier=18,crouchModifier=.6f,
rotSpeed=4,minRotX=-90,maxRotX=90,minRotY=-90,maxRotY=90,
rigidbodyDrag=5, speedMultiplierX=1,speedMultiplierZ=1,
minJumpPower=9,maxJumpPower=9,
jumpMultiplierX=.01f,jumpMultiplierY=.6f,jumpMultiplierZ=.01f,
groundCheckDistance = .1f,
stickToGroundHelperDistance=.05f,
camBobX=.006f,camBobY=.008f,camBobZ=0,camReturnSpeed=.04f,
playStepSoundAmount=666;
public AudioClip[] stepSounds;
public AudioClip[] jumpSounds;
public AudioClip[] landSounds;
AudioSource stepSourceA,stepSourceB,jumpSource,landSource;
float currentAcceleration,currentDeceleration,currentMaxForwardSpeed,currentMaxBackSpeed,currentMaxStrafeSpeed,currentRunModifier,
currentSpeedZ,currentSpeedX,speedBoost,
rotationY,
jumpPower,jumpZ,jumpX,
addedJumpX,addedJumpZ,
stepSoundAmount,stepVolume,
camRotX,camRotY,previousCamRotX,
camX,camY,camZ,camBobSpeed,
n0,n1,combinedSpeeds,camSlerpAmount;
int randomStepSoundIndex,lastStepIndex,randomLandSoundIndex,randomJumpSoundIndex;
bool grounded,lookingAround,stepToggle,crouching,jumping;
Quaternion camStartRot;
Vector3 camTargetPosLocal,camStandTargetPos,camCrouchTargetPos;
void Start ()
{
capsCollider=GetComponent<CapsuleCollider>();
PhysicMaterial mat=new PhysicMaterial();
mat.dynamicFriction=0;
mat.staticFriction=1;
capsCollider.material=mat;
rb = GetComponent<Rigidbody>();
rb.constraints=RigidbodyConstraints.FreezeRotation;
rb.collisionDetectionMode=CollisionDetectionMode.ContinuousDynamic;
crouchHeight=capsCollider.bounds.size.y*.66f;
standHeight=capsCollider.bounds.size.y;
camStandTargetPos=cam.localPosition;
camCrouchTargetPos=new Vector3(camStandTargetPos.x,camStandTargetPos.y*.6f,camStandTargetPos.z);
camTargetPosLocal=camStandTargetPos;
camY=camTargetPosLocal.y;
camX=camTargetPosLocal.x;
camZ=camTargetPosLocal.z;
camBobSpeed=(camBobX+camBobY+camBobZ)*1.1f;
currentAcceleration= acceleration;
currentDeceleration=deceleration;
currentMaxForwardSpeed =maxForwardSpeed;
currentMaxStrafeSpeed =maxStrafeSpeed;
currentMaxBackSpeed= maxBackSpeed;
currentRunModifier= runModifier;
n0 = (maxStrafeSpeed+maxBackSpeed+maxForwardSpeed)/3;
n1=n0+runModifier;
stepSourceA=gameObject.AddComponent<AudioSource>();
stepSourceB=gameObject.AddComponent<AudioSource>();
jumpSource=gameObject.AddComponent<AudioSource>();
landSource=gameObject.AddComponent<AudioSource>();
}
void Update()
{
if(Input.GetButtonDown ("ToggleCrouch"))
{
crouching=!crouching;
if(crouching)
{
capsCollider.height=crouchHeight;
camTargetPosLocal=camCrouchTargetPos;
camX=camTargetPosLocal.x;
camY=camTargetPosLocal.y;
camZ=camTargetPosLocal.z;
currentAcceleration*=crouchModifier;
currentDeceleration*=crouchModifier;
currentMaxBackSpeed*=crouchModifier;
currentMaxForwardSpeed*=crouchModifier;
currentMaxStrafeSpeed*=crouchModifier;
currentRunModifier*=crouchModifier;
}
else
{
capsCollider.height=standHeight;
camTargetPosLocal=camStandTargetPos;
camX=camTargetPosLocal.x;
camY=camTargetPosLocal.y;
camZ=camTargetPosLocal.z;
currentAcceleration=acceleration;
currentDeceleration=deceleration;
currentMaxBackSpeed=maxBackSpeed;
currentMaxForwardSpeed=maxForwardSpeed;
currentMaxStrafeSpeed=maxStrafeSpeed;
currentRunModifier=runModifier;
}
}
if(!lookingAround)
{
if(invertY)
{
camRotX += Input.GetAxisRaw ("Mouse Y")*rotSpeed;
}
else
{
camRotX -= Input.GetAxisRaw ("Mouse Y")*rotSpeed;
}
camRotX = Mathf.Clamp (camRotX, minRotX,maxRotX);
cam.localRotation=Quaternion.Euler (camRotX,0,0);
if(Input.GetButtonDown ("LookAround"))
{
previousCamRotX=camRotX;
lookingAround=true;
cam.localPosition=camTargetPosLocal;
}
}
else
{
if(Input.GetButtonUp ("LookAround"))
{
camStartRot = cam.localRotation;
StartCoroutine ("ReturnCamRot");
}
camRotY+=Input.GetAxisRaw ("Mouse X")*rotSpeed;
camRotY = Mathf.Clamp (camRotY,minRotY,maxRotY);
if(invertY)
{
camRotX += Input.GetAxisRaw ("Mouse Y")*rotSpeed;
}
else
{
camRotX -= Input.GetAxisRaw ("Mouse Y")*rotSpeed;
}
camRotX = Mathf.Clamp (camRotX, minRotX,maxRotX);
cam.localRotation=Quaternion.Euler (camRotX,camRotY,0);
}
if(Input.GetButton ("Jump"))
{
jumpPower+=currentAcceleration;
if(Input.GetButton ("Forward"))
jumpZ+=currentAcceleration;
if(Input.GetButton ("Back"))
jumpZ-=currentAcceleration;
if(Input.GetButton ("Left"))
jumpX-=currentAcceleration;
if(Input.GetButton ("Right"))
jumpX+=currentAcceleration;
}
if(Input.GetButtonUp ("Forward"))
if(!Input.GetButton ("Back"))
StartCoroutine ("SlowDownZ");
if(Input.GetButtonUp ("Back"))
if(!Input.GetButton ("Forward"))
StartCoroutine ("SlowDownZ");
if(Input.GetButtonUp ("Left"))
if(!Input.GetButton ("Right"))
StartCoroutine ("SlowDownX");
if(Input.GetButtonUp ("Right"))
if(!Input.GetButton ("Left"))
StartCoroutine ("SlowDownX");
if(Input.GetButtonUp ("Jump"))
{
if(grounded)
{
jumpZ = Mathf.Clamp (jumpZ,-maxJumpPower,maxJumpPower);
jumpX = Mathf.Clamp (jumpX,-maxJumpPower,maxJumpPower);
addedJumpX = jumpX + currentSpeedX;
addedJumpZ = jumpZ + currentSpeedZ;
jumpPower = Mathf.Clamp (jumpPower,minJumpPower,maxJumpPower);
rb.AddRelativeForce (addedJumpX*jumpMultiplierX, jumpPower*jumpMultiplierY,addedJumpZ*jumpMultiplierZ,ForceMode.Impulse);
if(jumpSounds.Length>0)
{
randomJumpSoundIndex=Random.Range (0,jumpSounds.Length);
jumpSource.clip=jumpSounds[randomJumpSoundIndex];
jumpSource.volume=Random.Range (.5f,1f);
jumpSource.Play ();
}
stepSoundAmount=0;
StopCoroutine ("SlowDownX");
StopCoroutine ("SlowDownZ");
currentSpeedZ=0;
currentSpeedX=0;
jumping=true;
}
jumpPower = 0;
jumpX = 0;
jumpZ = 0;
}
if(grounded)
{
rotationY=Input.GetAxis ("Mouse X");
if(Input.GetButtonDown ("Forward") || Input.GetButtonDown ("Back"))
{
StopCoroutine ("SlowDownZ");
}
if(Input.GetButtonDown ("Left") || Input.GetButtonDown ("Right"))
{
StopCoroutine ("SlowDownX");
}
if(Input.GetButton ("Forward"))
{
currentSpeedZ+=currentAcceleration;
}
if(Input.GetButton ("Back"))
{
currentSpeedZ-=currentAcceleration;
}
if(Input.GetButton ("Left"))
{
currentSpeedX-=currentAcceleration;
}
if(Input.GetButton ("Right"))
{
currentSpeedX+=currentAcceleration;
}
if(Input.GetButton ("Run"))
{
speedBoost+=currentAcceleration;
}
else
{
speedBoost-=currentDeceleration;
}
speedBoost = Mathf.Clamp (speedBoost,0,runModifier);
currentSpeedZ = Mathf.Clamp (currentSpeedZ,-currentMaxBackSpeed-speedBoost,currentMaxForwardSpeed+speedBoost);
currentSpeedX = Mathf.Clamp (currentSpeedX,-currentMaxStrafeSpeed-speedBoost,currentMaxStrafeSpeed+speedBoost);
}
}
IEnumerator SlowDownZ()
{
while(true)
{
currentSpeedZ+=currentSpeedZ>0 ? -deceleration:deceleration;
if(Mathf.Abs (currentSpeedZ)<=deceleration)
{
currentSpeedZ=0;
yield break;
}
else
{
yield return null;
}
}
}
IEnumerator SlowDownX()
{
while(true)
{
currentSpeedX+=currentSpeedX>0 ? -deceleration:deceleration;
if(Mathf.Abs (currentSpeedX)<=deceleration)
{
currentSpeedX=0;
yield break;
}
else
{
yield return null;
}
}
}
IEnumerator ReturnCamRot()
{
while(true)
{
camSlerpAmount+=camReturnSpeed;
cam.localRotation = Quaternion.Slerp (camStartRot,Quaternion.Euler (previousCamRotX,0,0),camSlerpAmount);
if(camSlerpAmount>.99f)
{
camSlerpAmount = 0;
camRotY = 0;
camRotX=previousCamRotX;
cam.localRotation = Quaternion.Euler (camRotX,0,0);
cam.localPosition=camTargetPosLocal;
camY=camTargetPosLocal.y;
camX=camTargetPosLocal.x;
camZ=camTargetPosLocal.z;
lookingAround=false;
yield break;
}
yield return null;
}
}
Quaternion deltaRotation;
void FixedUpdate()
{
GroundCheck();
if(grounded)
{
rb.AddRelativeForce (currentSpeedX*speedMultiplierX,0,currentSpeedZ*speedMultiplierZ);
if(!lookingAround)
{
deltaRotation = Quaternion.Euler(new Vector3(0,rotationY*rotSpeed,0));
transform.rotation=transform.rotation*deltaRotation;
}
if(currentSpeedX==0&¤tSpeedZ==0)
{
cam.localPosition=Vector3.MoveTowards (cam.localPosition,camTargetPosLocal,camBobSpeed);
}
combinedSpeeds=Mathf.Abs (currentSpeedZ) + Mathf.Abs (currentSpeedX);
if(currentSpeedX != 0 && currentSpeedZ != 0)
{
stepSoundAmount+=combinedSpeeds*.5f*
Mathf.Clamp ( Mathf.Abs (transform.InverseTransformDirection (rb.velocity).z)+
Mathf.Abs (transform.InverseTransformDirection (rb.velocity).x),0,1) ;
}
else
{
stepSoundAmount+=combinedSpeeds*
Mathf.Clamp ( Mathf.Abs (transform.InverseTransformDirection (rb.velocity).z)+
Mathf.Abs (transform.InverseTransformDirection (rb.velocity).x),0,1) ;
}
if(!lookingAround)
{
if(stepSoundAmount>playStepSoundAmount*.5f)
{
camY-=camBobY;
camZ+=camBobZ;
camX += stepToggle ? -camBobX : camBobX;
cam.localPosition=Vector3.MoveTowards (cam.localPosition,new Vector3(camX,camY,camZ),camBobSpeed*
Mathf.Clamp ( Mathf.Abs (transform.InverseTransformDirection (rb.velocity).z)+
Mathf.Abs (transform.InverseTransformDirection (rb.velocity).x),0,1));
}
else if(stepSoundAmount>playStepSoundAmount*.2f)
{
cam.localPosition=Vector3.MoveTowards (cam.localPosition,camTargetPosLocal,camBobSpeed*1.45f);
}
}
if(stepSoundAmount>playStepSoundAmount)
{
stepToggle=!stepToggle;
camY=camTargetPosLocal.y;
camX=camTargetPosLocal.x;
camZ=camTargetPosLocal.z;
if(stepSounds.Length>0)
{
if(stepSounds.Length>1)
{
for(int i=0;i<Mathf.Infinity;i++)
{
randomStepSoundIndex=Random.Range (0,stepSounds.Length);
if(randomStepSoundIndex!=lastStepIndex)
break;
}
}
if(currentSpeedX != 0 && currentSpeedZ != 0)
{
stepVolume = ((float)Mathf.Abs (currentSpeedX)/n1+(float)Mathf.Abs (currentSpeedZ)/n1)*.5f;
}
else
{
stepVolume = ((float)Mathf.Abs (currentSpeedX)/n1+(float)Mathf.Abs (currentSpeedZ)/n1);
}
stepVolume=Mathf.Clamp (stepVolume,0,1);
if(stepToggle)
{
stepSourceA.clip=stepSounds[randomStepSoundIndex];
stepSourceA.volume=stepVolume;
stepSourceA.Play ();
}
else
{
stepSourceB.clip=stepSounds[randomStepSoundIndex];
stepSourceB.volume=stepVolume;
stepSourceB.Play ();
}
lastStepIndex=randomStepSoundIndex;
}
stepSoundAmount=0;
}
}
StickToGroundHelper ();
}
RaycastHit hitInfo;
bool previouslyGrounded;
void GroundCheck()
{
if (Physics.SphereCast(transform.position, capsCollider.radius-.01f, Vector3.down, out hitInfo,
((capsCollider.height/2f) - capsCollider.radius) + groundCheckDistance))
{
rb.drag=rigidbodyDrag;
grounded = true;
if(!previouslyGrounded&&jumping)
{
if(landSounds.Length>0)
{
if(!landSource.isPlaying)
{
randomLandSoundIndex=Random.Range (0,landSounds.Length);
landSource.clip=landSounds[randomLandSoundIndex];
landSource.volume=Random.Range (.5f,1f);
landSource.Play ();
}
}
jumping=false;
}
}
else
{
rb.drag=0;
grounded = false;
}
previouslyGrounded=grounded;
}
void StickToGroundHelper()
{
if (Physics.SphereCast(transform.position, capsCollider.radius-.01f, Vector3.down, out hitInfo,
((capsCollider.height/2f) - capsCollider.radius) +
stickToGroundHelperDistance))
{
if (Mathf.Abs(Vector3.Angle(hitInfo.normal, Vector3.up)) < 85f)
{
rb.velocity = Vector3.ProjectOnPlane(rb.velocity, hitInfo.normal);
}
}
}
}