Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using System.Collections;
- public class CharMove : MonoBehaviour {
- float moveSpeedMultiplier = 1;
- float stationaryTurnSpeed = 180; //if the character is not moving, how fast he will turn
- float movingTurnSpeed = 360; //same as the above but for when the character is moving
- public bool onGround; //if true the character is on the ground
- Animator animator;
- Vector3 moveInput; //The move vector
- float turnAmount; //the calculated turn amount to pass to mecanim
- float forwardAmount; //the calculated forward amount to pass to mecanim
- Vector3 velocity; //the 3d velocity of the character
- float jumpPower = 10;
- IComparer rayHitComparer;
- public float autoTurnThreshold = 10;
- public float autoTurnSpeed = 20;
- bool aim;
- Vector3 currentLookPos;
- public Transform LeftHand;
- float lastAirTime;
- Collider collider;
- Rigidbody rigidBody;
- public PhysicMaterial highFriction;
- public PhysicMaterial lowFriction;
- Vector3 GroundNormal;
- bool inCover;
- // Use this for initialization
- void Start () {
- animator = GetComponentInChildren<Animator> ();
- SetUpAnimator();
- rigidBody = GetComponent<Rigidbody> ();
- collider = GetComponent<Collider> ();
- }
- void SetUpAnimator()
- {
- // this is a ref to the animator component on the root.
- animator = GetComponent<Animator>();
- // we use avatar from a child animator component if present
- // (this is to enable easy swapping of the character model as a child node)
- foreach (var childAnimator in GetComponentsInChildren<Animator>()) {
- if (childAnimator != animator) {
- animator.avatar = childAnimator.avatar;
- Destroy (childAnimator);
- break; //if you find the first animator, stop searching
- }
- }
- LeftHand = animator.GetBoneTransform (HumanBodyBones.LeftHand);
- }
- //Updates the movement of the character based on its current speed and the moveSpeedMultiplier
- public void OnAnimatorMove()
- {
- if(onGround && Time.deltaTime > 0) //If the character is on the ground and is not the first frame of play
- {
- Vector3 v = (animator.deltaPosition * moveSpeedMultiplier)/ Time.deltaTime; //calculate the speed that the character should have
- //Delta position (position difference) - The difference in the position between the current frame and the previous one
- //Speed = the position difference of the animator * speed multiplier / time
- v.y = rigidBody.velocity.y; //store the characters vertical velocity (in order to not to affect jump speed)
- if(!inCover)
- rigidBody.velocity = v; //update the character's speed
- else
- rigidBody.interpolation = RigidbodyInterpolation.None;
- }
- }
- public void Move(Vector3 move, bool aim, Vector3 lookPos, bool inCover)
- {
- //Vector3 move is the input in word space
- if (move.magnitude > 1) //Make sure that the movement is normalized
- move.Normalize ();
- this.moveInput = move; //store the move
- this.aim = aim;
- this.inCover = inCover;
- velocity = GetComponent<Rigidbody>().velocity; //store the current velocity
- ConvertMoveInput ();
- //New
- this.currentLookPos = lookPos;
- if(!aim)
- {
- TurnTowardsCameraForward ();
- ApplyExtraTurnRotation ();
- }
- //GroundCheck ();
- onGround = true;
- //part 4
- SetFriction ();
- // control and velocity handling is different when grounded and airborne:
- if (onGround) {
- HandleGroundedVelocities();
- } else {
- HandleAirborneVelocities();
- }
- UpdateAnimator ();
- }
- void ConvertMoveInput ()
- {
- // convert the world relative moveInput vector into a local-relative
- // turn amount and forward amount required to head in the desired
- // direction.
- //convert the move input (e.g. left -> (-1, 0, 0) from the world space to the characters local space
- Vector3 localMove = transform.InverseTransformDirection (moveInput);
- //calculate the turn amount trigonometrically
- turnAmount = Mathf.Atan2 (localMove.x, localMove.z);
- forwardAmount = localMove.z;
- }
- void ApplyExtraTurnRotation ()
- {
- // help the character turn faster (this is in addition to root rotation in the animation)
- //based on movingTurnSpeed and stationaryTurnSpeed and the forward amount of the character
- float turnSpeed = Mathf.Lerp (stationaryTurnSpeed, movingTurnSpeed, forwardAmount);
- transform.Rotate (0, turnAmount * turnSpeed * Time.deltaTime, 0);
- }
- void UpdateAnimator ()
- {
- //part 4
- if (!inCover)
- animator.applyRootMotion = onGround;
- else
- animator.applyRootMotion = false;
- if(!aim && !inCover)
- {
- animator.SetFloat ("Forward", forwardAmount, 0.1f, Time.deltaTime);
- animator.SetFloat ("Turn", turnAmount, 0.1f, Time.deltaTime);
- }
- animator.SetBool ("Aim", aim);
- //part 4
- animator.SetBool ("OnGround", onGround);
- }
- public float ra2y;
- //Checks if the character is on the ground or airborne
- void GroundCheck ()
- {
- Ray ray = new Ray (transform.position + Vector3.up * .5f, -Vector3.up);
- RaycastHit[] hits = Physics.RaycastAll (ray, .5f); //perform a raycast using that ray for a distance of 0.5
- rayHitComparer = new RayHitComparer();
- System.Array.Sort (hits, rayHitComparer); //sort the hits using our comparer (based on distance)
- if (velocity.y < jumpPower * .5f)
- { //if the character is not airborne due to a jump
- //we will talk about jumping in the next tutorials
- //assume that the character is on the air and falling
- // onGround = false;
- rigidBody.useGravity = true;
- foreach (var hit in hits) { //for each of the hits
- // check whether we hit a non-trigger collider (and not the character itself)
- if (!hit.collider.isTrigger) {
- // this counts as being on ground.
- // stick to surface - helps character stick to ground - specially when running down slopes
- //if the character is falling and is close to the ground, we assume that he goes down a slope
- if (velocity.y <= 0) {
- rigidBody.position = Vector3.MoveTowards (GetComponent<Rigidbody>().position, hit.point, Time.deltaTime * 5);
- //change the rigid body potition to the hit point
- }
- onGround = true; //set the on ground variable since we found our collider
- rigidBody.useGravity = false; //disable gravity since we use the above to stick the character to the ground
- break; //ignore the rest of the hits
- }
- }
- }
- //part 4
- // remember when we were last in air, for jump delay
- if (!onGround)
- {
- lastAirTime = Time.time;
- }
- }
- //part 4
- void SetFriction()
- {
- //if we are on the ground
- if (onGround) {
- // and we have movement
- if (moveInput.magnitude == 0) {
- // swap the material to a high friction one
- collider.material = highFriction;
- } else {
- // but when moving, we want no friction:
- collider.material = lowFriction;
- }
- } else {
- // while in air, we want no friction against surfaces (walls, ceilings, etc)
- collider.material = lowFriction;
- }
- }
- void HandleGroundedVelocities()
- {
- //if we are on the ground then we don't want any velocity on the Y
- velocity.y = 0;
- //and if we are not moving, manipulate all the velocities so that we don't slide on slopes
- if (moveInput.magnitude == 0) {
- velocity.x = 0;
- velocity.z = 0;
- }
- }
- void HandleAirborneVelocities ()
- {
- // we allow some movement in air but we only make it to have a small change in the trajectory
- Vector3 airMove = new Vector3 (moveInput.x * 6, velocity.y, moveInput.z * 6);
- velocity = Vector3.Lerp (velocity, airMove, Time.deltaTime * 2);
- //we want gravity
- rigidBody.useGravity = true;
- // apply extra gravity from multiplier:
- //we want more gravity, so we multiply it by 2 and
- Vector3 extraGravityForce = (Physics.gravity * 2);
- rigidBody.AddForce(extraGravityForce);
- }
- void TurnTowardsCameraForward ()
- {
- // automatically turn to face camera direction,
- // when not moving, and beyond the specified angle threshold
- if (Mathf.Abs (forwardAmount) < .01f) {
- //our look direction is the transformed direction from wolrd space to local space
- Vector3 lookDelta = transform.InverseTransformDirection (currentLookPos - transform.position);
- //Returns the angle in radians Radians-to-degrees conversion
- float lookAngle = Mathf.Atan2 (lookDelta.x, lookDelta.z) * Mathf.Rad2Deg;
- // are we beyond the threshold of where need to turn to face the camera?
- if (Mathf.Abs (lookAngle) > autoTurnThreshold) {
- turnAmount += lookAngle * autoTurnSpeed * .001f;
- }
- }
- }
- //Compares two raycasts based on their distance
- class RayHitComparer: IComparer
- {
- public int Compare(object x, object y)
- {
- return ((RaycastHit)x).distance.CompareTo(((RaycastHit)y).distance);
- //this returns < 0 if x < y
- // > 0 if x > y
- // 0 if x = y
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement