daily pastebin goal
38%
SHARE
TWEET

MovingEntity_CameraInput.cs

mvaganov Jun 14th, 2017 (edited) 50 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4.  
  5. /// <summary>A custom Unity3D character controller, useful for player characters
  6. /// Latest version at: https://pastebin.com/pC0Ddjsi
  7. /// The complementary MovingEntity script is at: https://pastebin.com/xFUD4tk2 </summary>
  8. /// <description>MIT License - TL;DR - This code is free, don't bother me about it!</description>
  9. public class MovingEntity_CameraInput : MonoBehaviour {
  10.     [Tooltip("if left null, will search for a MobileEntity script on this object.")]
  11.     public MovingEntityBase controlling;
  12.     public BaseInputController inputController;
  13.  
  14.     void Start() {
  15.         MovingEntityBase toControl = controlling;
  16.         controlling = null;
  17.         if (toControl == null) { toControl = GetComponent<MovingEntityBase> (); }
  18.         Control(toControl);
  19.     }
  20.     public void Control(MovingEntityBase me) {
  21.         // un-control previous
  22.         if (controlling != null) {
  23.             controlling.transform.tag = "Untagged";
  24.             inputController.Release (controlling);
  25.         }
  26.         // take control of current
  27.         controlling = me;
  28.         if(controlling.transform.tag == "Untagged" || controlling.transform.tag.Length == 0) {
  29.             controlling.transform.tag = "Player";
  30.         }
  31.         if (controlling is MovingEntity) {
  32.             if (!(inputController is GroundedInputController)) {
  33.                 if (inputController != null) {
  34.                     inputController = new GroundedInputController (inputController);
  35.                 } else {
  36.                     inputController = new GroundedInputController ();
  37.                 }
  38.             }
  39.         } else {
  40.             if (inputController == null) inputController = new BaseInputController ();
  41.         }
  42.         inputController.Start(controlling);
  43.     }
  44.     void Update() {
  45.         controlling.MoveDirection = inputController.Update(controlling);
  46.     }
  47.     // let the controlled entity call LateUpdate after any positional adjustments
  48.     void LateUpdate() {
  49.         inputController.LateUpdate(controlling);
  50.     }
  51. }
  52.  
  53. [System.Serializable]
  54. public class BaseInputController {
  55.     /// <summary>the transform controlling where the camera should go. Might be different than myCamera if a VR headset is plugged in.</summary>
  56.     [HideInInspector]
  57.     public Transform camHandle;
  58.     /// <summary>how the 3D camera should move with the player.</summary>
  59.     [Tooltip("how the 3D camera should move with the player\n"+
  60.         "* Fixed Camera: other code should control the camera\n"+
  61.         "* Lock To Player: follow player with current offset\n"+
  62.         "* Rotate 3rd Person: 3rd person, scrollwheel zoom\n"+
  63.         "* Lock-and-Rotate-with-RMB: like the Unity editor Scene view")]
  64.     public ControlStyle mouseLookMode = ControlStyle.freeRotate;
  65.     public enum ControlStyle { staticCamera, noRotate, freeRotate, rotateWithRMB }
  66.     /// <summary>how far away the camera should be from the player</summary>
  67.     protected Vector3 cameraOffset;
  68.     public float horizontalSensitivity = 5, verticalSensitivity = 5;
  69.     [System.Serializable]
  70.     public class ControlAxisNames {
  71.         public string forward = "Vertical", right = "Horizontal",
  72.         turnHorizontal = "Mouse X", turnVertical = "Mouse Y",
  73.         jump = "Jump", zoomInAndOut = "Mouse ScrollWheel";
  74.     }
  75.     [Tooltip("Axis used for controls\n(see: Edit->Project Settings->Input")]
  76.     public ControlAxisNames controls = new ControlAxisNames();
  77.     [Tooltip("if true, automatically slow velocity to zero if there is no user-input")]
  78.     public bool AutoSlowdown = true;
  79.     [Tooltip("If true, a raycast is sent to make sure the camera doesn't clip through solid objects.")]
  80.     public bool cameraWontClip = true;
  81.     [Tooltip("how far the camera should be from the PlayerControl transform")]
  82.     public float cameraDistance = 5;
  83.     [Tooltip("how far the eye-focus (where the camera rests) should be above the PlayerControl transform")]
  84.     public float eyeHeight = 0.125f;
  85.     [HideInInspector]
  86.     public float currentPitch { get; protected set; }
  87.     /// <summary>keeps the camera from looking too far (only effective with gravity)</summary>
  88.     [Tooltip("keeps the camera from looking too far (only effective with gravity)")]
  89.     public float maxCameraPitch = 90, minCameraPitch = -90;
  90.     [Tooltip("Camera for the PlayerControl to use. Will automagically find one if not set.")]
  91.     public Camera myCamera;
  92.     /// <summary>'up' direction for the player, used to orient the camera when there is gravity</summary>
  93.     [HideInInspector]
  94.     public Vector3 cameraUp = Vector3.up;
  95.     /// <summary>the vertical tilt of the camera</summary>
  96.     public Vector3 CameraCenter(Transform t) { return (eyeHeight == 0)? t.position : t.position + t.up * eyeHeight; }
  97.  
  98.     public void Copy(BaseInputController c) {
  99.         myCamera = c.myCamera;
  100.         camHandle = c.camHandle;
  101.         mouseLookMode = c.mouseLookMode;
  102.         cameraDistance = c.cameraDistance;
  103.         horizontalSensitivity = c.horizontalSensitivity;
  104.         verticalSensitivity = c.verticalSensitivity;
  105.         cameraWontClip = c.cameraWontClip;
  106.     }
  107.     public virtual void UpdateCameraAngles(float dx, float dy) {
  108.         // simplistic gravity-less rotation
  109.         camHandle.Rotate(Vector3.up, dx);
  110.         camHandle.Rotate(Vector3.right, -dy);
  111.     }
  112.     protected void EnsureCamera(MovingEntityBase p) {
  113.         if (!myCamera) { // make sure there is a camera to control!
  114.             myCamera = Camera.main;
  115.             if (myCamera == null) {
  116.                 myCamera = (new GameObject ("<main camera>")).AddComponent<Camera> ();
  117.                 myCamera.tag = "MainCamera";
  118.             }
  119.         } else {
  120.             cameraOffset = camHandle.position - p.transform.position;
  121.             cameraDistance = cameraOffset.magnitude;
  122.         }
  123.         if(UnityEngine.VR.VRDevice.isPresent) {
  124.             camHandle = (new GameObject("<camera handle>")).transform;
  125.             myCamera.transform.position = Vector3.zero;
  126.             myCamera.transform.SetParent(camHandle);
  127.         } else {
  128.             camHandle = myCamera.transform;
  129.         }
  130.         UpdateCamera (p, true);
  131.     }
  132.     public virtual void Start(MovingEntityBase p) {
  133.         EnsureCamera (p);
  134.         p.AutomaticallyTurnToFaceLookDirection = false;
  135.     }
  136.     public virtual void Release(MovingEntityBase me) { }
  137.     public bool ChangeCameraDistanceBasedOnScrollWheel() {
  138.         float scroll = Input.GetAxis(controls.zoomInAndOut);
  139.         if(scroll != 0) {
  140.             cameraDistance -= scroll * 10;
  141.             cameraDistance = Mathf.Max(0, cameraDistance);
  142.             if(cameraDistance > 0 && cameraOffset != Vector3.zero) {
  143.                 cameraOffset = cameraOffset.normalized * cameraDistance;
  144.             }
  145.             return true;
  146.         }
  147.         return false;
  148.     }
  149.     public virtual void LateUpdate(MovingEntityBase me) {
  150.         bool mustUpdateCamera = ChangeCameraDistanceBasedOnScrollWheel();
  151.         UpdateCamera (me, mustUpdateCamera);
  152.     }
  153.     public virtual void UpdateCamera(MovingEntityBase me, bool mustUpdate) {
  154.         if(mouseLookMode == ControlStyle.staticCamera && !mustUpdate) { return; }
  155.         bool updatingWithMouseInput = (mouseLookMode == ControlStyle.freeRotate) ||
  156.             (mouseLookMode == ControlStyle.rotateWithRMB && Input.GetMouseButton(1));
  157.         // camera rotation
  158.         if (updatingWithMouseInput) {
  159.             // get the rotations that the user input is indicating
  160.             UpdateCameraAngles (Input.GetAxis (controls.turnHorizontal) * horizontalSensitivity, Input.GetAxis (controls.turnVertical) * verticalSensitivity);
  161.         } else if (mustUpdate) {
  162.             UpdateCameraAngles (0, 0);
  163.         }
  164.         me.LookDirection = camHandle.forward;
  165.         Vector3 eyeFocus = CameraCenter(me.transform);
  166.         // move the camera to be looking at the player's eyes/head, ideally with no geometry in the way
  167.         RaycastHit rh;
  168.         float calculatedDistForCamera = cameraDistance;
  169.         if(cameraWontClip && Physics.SphereCast(eyeFocus, myCamera.nearClipPlane, -camHandle.forward, out rh, cameraDistance)) {
  170.             calculatedDistForCamera = rh.distance;
  171.         }
  172.         if(calculatedDistForCamera != 0) { cameraOffset = -myCamera.transform.forward * calculatedDistForCamera; }
  173.         Vector3 nextLocation = eyeFocus + ((cameraDistance > 0) ? cameraOffset : Vector3.zero);
  174.         camHandle.position = nextLocation;
  175.     }
  176.     public virtual Vector3 Update(MovingEntityBase me) {
  177.         float inputF = Input.GetAxis (controls.forward), inputR = Input.GetAxis (controls.right);
  178.         Vector3 MoveDirection = default(Vector3);
  179.         if (inputF != 0 || inputR != 0) {
  180.             Transform t = myCamera.transform;
  181.             MoveDirection = (inputR * t.right) + (inputF * t.forward);
  182.             MoveDirection.Normalize ();
  183.         } else if (AutoSlowdown) {
  184.             me.IsBrakeOn = true;
  185.         }
  186.         if (!me.AutomaticallyTurnToFaceLookDirection) {
  187.             me.TurnToFace (myCamera.transform.forward, myCamera.transform.up);
  188.         }
  189.         return MoveDirection;
  190.     }
  191.     public virtual void GetMoveVectors(Vector3 upVector, out Vector3 forward, out Vector3 right) {
  192.         Transform importantT = myCamera.transform;
  193.         right = importantT.right; forward = importantT.forward;
  194.     }
  195. }
  196.  
  197. public class GroundedInputController : BaseInputController {
  198.     MovingEntity pc;
  199.     public GroundedInputController() { }
  200.     public GroundedInputController(BaseInputController cameraControl) { base.Copy(cameraControl); }
  201.     public override void LateUpdate(MovingEntityBase me) {
  202.         if (!pc.AutomaticallyFollowPositionOnPlatform && pc.gravityApplication != MovingEntity.GravityState.none) {
  203.             pc.FollowPositionOnPlatform ();
  204.         }
  205.         bool mustUpdateCamera = OrientUp () | ChangeCameraDistanceBasedOnScrollWheel();
  206.         UpdateCamera (me, mustUpdateCamera);
  207.     }
  208.     public override void UpdateCameraAngles(float dx, float dy) {
  209.         if(pc.gravityApplication != MovingEntity.GravityState.none) {
  210.             currentPitch -= dy; // rotate accordingly, minus because of standard 'inverted' Y axis rotation
  211.             camHandle.Rotate(Vector3.right, -currentPitch);// un-rotate zero-out camera's "up", re-applied soon
  212.             if(cameraUp == Vector3.zero) return;
  213.             Vector3 rightSide = (cameraUp != camHandle.forward)?Vector3.Cross(camHandle.forward, cameraUp):camHandle.right;
  214.             Vector3 unrotatedMoveForward = Vector3.Cross(cameraUp, rightSide);
  215.             camHandle.rotation = Quaternion.LookRotation(unrotatedMoveForward, cameraUp); // force zero rotation
  216.             camHandle.Rotate(Vector3.up, dx); // re-apply rotation
  217.             while(currentPitch > 180) { currentPitch -= 360; } // normalize the angles to be between -180 and 180
  218.             while(currentPitch < -180) { currentPitch += 360; }
  219.             currentPitch = Mathf.Clamp(currentPitch, minCameraPitch, maxCameraPitch);
  220.             camHandle.Rotate(Vector3.right, currentPitch);
  221.         } else {
  222.             base.UpdateCameraAngles(dx,dy); // simplistic gravity-less rotation
  223.             cameraUp = camHandle.up;
  224.             currentPitch = 0;
  225.         }
  226.     }
  227.     public override void Start(MovingEntityBase me) {
  228.         pc = me as MovingEntity;
  229.         base.Start (me);
  230.         // calculate current pitch based on camera
  231.         Vector3 currentRight = Vector3.Cross(cameraUp, camHandle.forward);
  232.         Vector3 currentMoveForward = Vector3.Cross(currentRight, cameraUp);
  233.         Quaternion playerIdentity = Quaternion.LookRotation(currentMoveForward, cameraUp);
  234.         currentPitch = Quaternion.Angle(playerIdentity, camHandle.rotation);
  235.         pc.AutomaticallyFollowPositionOnPlatform = false;
  236.         pc.AutomaticallyTurnToFaceLookDirection = false;
  237.     }
  238.     public override void Release(MovingEntityBase me) {
  239.         if (pc == null) { Debug.LogError (pc+" strange state... camera/input controller should always have a target"); }
  240.         if (me != pc) { Debug.LogError (pc+" never released!"); }
  241.         pc.AutomaticallyFollowPositionOnPlatform = true;
  242.         pc.AutomaticallyTurnToFaceLookDirection = true;
  243.         pc = null;
  244.     }
  245.     public override Vector3 Update(MovingEntityBase me) {
  246.         float input_forward = Input.GetAxis(controls.forward);
  247.         float input_right = Input.GetAxis(controls.right);
  248.         Vector3 MoveDirection = Vector3.zero;
  249.         if (input_forward != 0 || input_right != 0) {
  250.             Vector3 currentRight, currentMoveForward;
  251.             if (pc.gravityApplication == MovingEntity.GravityState.useGravity) {
  252.                 GetMoveVectors (pc.GroundNormal /*isStableOnGround?GroundNormal:GetUpOrientation()*/, out currentMoveForward, out currentRight);
  253.             } else {
  254.                 currentMoveForward = camHandle.forward; currentRight = camHandle.right;
  255.             }
  256.             MoveDirection = (currentRight * input_right) + (currentMoveForward * input_forward);
  257.             MoveDirection.Normalize ();
  258.         } else if (AutoSlowdown) {
  259.             me.IsBrakeOn = true;
  260.         }
  261.         pc.jump.SecondsToPressJump = Input.GetButton (controls.jump)?1:0;
  262.         if(!pc.AutomaticallyTurnToFaceLookDirection) {
  263.             if (pc.gravityApplication != MovingEntity.GravityState.none) { pc.UpdateFacing (); }
  264.             else { pc.TurnToFace (myCamera.transform.forward, myCamera.transform.up); }
  265.         }
  266.         return MoveDirection;
  267.     }
  268.     public override void GetMoveVectors(Vector3 upVector, out Vector3 forward, out Vector3 right) {
  269.         Transform importantT = myCamera.transform;
  270.         if(pc.gravityApplication != MovingEntity.GravityState.none) {
  271.             Vector3 generalDir = importantT.forward;
  272.             if(importantT.forward == upVector) { generalDir = -importantT.up; } else if(importantT.forward == -upVector) { generalDir = importantT.up; }
  273.             MovingEntity.CalculatePlanarMoveVectors(generalDir, upVector, out forward, out right);
  274.             if(currentPitch > 90) { right *= -1; forward *= -1; } // if we're upside-down, flip to keep it consistent
  275.         } else {
  276.             right = importantT.right; forward = importantT.forward;
  277.         }
  278.     }
  279.     public void GetMoveVectors(out Vector3 forward, out Vector3 right) { GetMoveVectors(pc.GroundNormal, out forward, out right); }
  280.     private bool OrientUp() {
  281.         if (pc.gravityApplication != MovingEntity.GravityState.none && cameraUp != -pc.gravity.dir) {
  282.             Vector3 delta = -pc.gravity.dir - cameraUp;
  283.             float upDifference = delta.magnitude;
  284.             float movespeed = Time.deltaTime * pc.MoveSpeed / 2;
  285.             if (upDifference < movespeed) {
  286.                 cameraUp = -pc.gravity.dir;
  287.             } else {
  288.                 cameraUp += delta * movespeed;
  289.             }
  290.             return true;
  291.         }
  292.         return false;
  293.     }
  294. }
RAW Paste Data
Top