G2A Many GEOs
SHARE
TWEET

AxisAgent.cs

mvaganov May 27th, 2015 269 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // comment the line below if missing Lines.cs (found at http://pastebin.com/8m69iTut )
  2. #define SHOW_AXIS_MATH
  3. using UnityEngine;
  4. using System.Collections;
  5.  
  6. // TODO camera zoom with mouse wheel AxisCamera
  7. // TODO gravity source
  8.  
  9. /// <summary>
  10. /// used for calculating and organizing 3D axis math
  11. /// </summary>
  12. public class Axis {
  13.         public Vector3 forward, up, position;
  14.         private Vector3 right;
  15.  
  16.         public void SetIdentity() {
  17.                 up = Vector3.up;
  18.                 forward = Vector3.forward;
  19.                 right = Vector3.right;
  20.                 position = Vector3.zero;
  21.         }
  22.  
  23.         public bool Equals(Transform t) {
  24.                 return up == t.up && forward == t.forward && position == t.position;
  25.         }
  26.  
  27.         public Axis(Axis other) {
  28.                 up = other.up;
  29.                 right = other.right;
  30.                 forward = other.forward;
  31.                 position = other.position;
  32.         }
  33.         public Axis() { }
  34.  
  35.         public Vector3 GetRight() {
  36.                 return right;
  37.                 //return Vector3.Cross(up, forward).normalized;
  38.         }
  39. #if SHOW_AXIS_MATH
  40.         public LineRenderer DrawSimple(ref GameObject lineObj, Color c, float size) {
  41.                 const float epsilon = 0.001f;
  42.                 Vector3 u = up * size, f = forward * size;
  43.                 Vector3[] points = {
  44.                         position + u,
  45.                         position + u * epsilon,
  46.                         position + f * epsilon,
  47.                         position + f * (1 - epsilon),
  48.                         position + f,
  49.                         Vector3.zero };
  50.                 points[points.Length - 1] = Vector3.Lerp(points[3], points[0], 0.125f);
  51.                 LineRenderer lr = Lines.Make(ref lineObj, c, points, points.Length, .1f, .1f);
  52.                 return lr;
  53.         }
  54.         private Vector3[] thumbtack_points_base = null;
  55.         public LineRenderer DrawThumbtack(ref GameObject lineObj, Color c, float size, float lineWidth) {
  56.                 const float epsilon = 0.001f;
  57.                 if(thumbtack_points_base == null) {
  58.                         Vector3 pstn = Vector3.zero;
  59.                         Vector3 fwrd = Vector3.forward * size;
  60.                         Vector3 rght = Vector3.right * size;
  61.                         Vector3 up__ = Vector3.up;
  62.                         float startAngle = (360.0f / 4) - (360.0f / 32);
  63.                         Vector3 v = Quaternion.AngleAxis(startAngle, up__) * fwrd;
  64.                         Lines.MakeArc(ref thumbtack_points_base, 32, up__, v, 360, pstn);
  65.                         Vector3 tip = pstn + fwrd * Mathf.Sqrt(2);
  66.                         thumbtack_points_base[0] = thumbtack_points_base[thumbtack_points_base.Length - 1];
  67.                         int m = (32 * 5 / 8) + 1;
  68.                         thumbtack_points_base[m++] = thumbtack_points_base[m] + (tip - thumbtack_points_base[m]) * (1 - epsilon);
  69.                         thumbtack_points_base[m++] = tip;
  70.                         int n = (32 * 7 / 8) + 1;
  71.                         while(n < 32) {
  72.                                 thumbtack_points_base[m++] = thumbtack_points_base[n++];
  73.                         }
  74.                         Vector3 side = pstn + rght;
  75.                         thumbtack_points_base[m++] = thumbtack_points_base[m] + (side - thumbtack_points_base[m]) * (1 - epsilon);
  76.                         thumbtack_points_base[m++] = pstn + rght;
  77.                         thumbtack_points_base[m++] = pstn + rght * epsilon;
  78.                         thumbtack_points_base[m++] = pstn;
  79.                         thumbtack_points_base[m++] = pstn + up__ * size * (1 - epsilon);
  80.                         thumbtack_points_base[m++] = pstn + up__ * size;
  81.                 }
  82.                 LineRenderer lr = Lines.Make(ref lineObj, c, thumbtack_points_base, thumbtack_points_base.Length, lineWidth, lineWidth);
  83.                 lr.useWorldSpace = false;
  84.                 return lr;
  85.         }
  86. #endif
  87.         public void SetFrom(Transform t) {
  88.                 position = t.position;
  89.                 up = t.up;
  90.                 forward = t.forward;
  91.                 right = t.right;
  92.         }
  93.  
  94.         public void SetFrom(Axis t) {
  95.                 position = t.position;
  96.                 up = t.up;
  97.                 forward = t.forward;
  98.                 right = t.right;
  99.         }
  100.  
  101.         public void WriteInto(Transform t) {
  102.                 t.position = position;
  103.                 t.rotation = Quaternion.LookRotation(forward, up);
  104.         }
  105.  
  106.         public void Turn(float t) {
  107.                 Quaternion turn = Quaternion.AngleAxis(t, up);
  108.                 forward = turn * forward;
  109.                 right = turn * right;
  110.         }
  111.  
  112.         public void Pitch(float p) {
  113.                 Quaternion turn = Quaternion.AngleAxis(p, right);
  114.                 forward = turn * forward;
  115.                 up = turn * up;
  116.         }
  117.  
  118.         public Quaternion GetUpright(Vector3 nextUp) {
  119.                 Vector3 r = Vector3.Cross(forward, nextUp);
  120.                 Vector3 fwd = Vector3.Cross(nextUp, r);
  121.                 return Quaternion.LookRotation(fwd, nextUp);
  122.         }
  123.  
  124.         public Quaternion DeltaTo(Quaternion rotation) {
  125.                 Quaternion q = Quaternion.LookRotation(this.forward, this.up);
  126.                 return rotation * Quaternion.Inverse(q);
  127.         }
  128.  
  129.         public Quaternion UprightDelta(Vector3 nextUp) {
  130.                 return DeltaTo(GetUpright(nextUp));
  131.         }
  132.  
  133.         public void Rotate(Quaternion rotation) {
  134.                 forward = rotation * forward;
  135.                 up = rotation * up;
  136.                 right = rotation * right;
  137.         }
  138.  
  139.         public void SetRotation(Quaternion rotation) {
  140.                 forward = rotation * Vector3.forward;
  141.                 up = rotation * Vector3.up;
  142.                 right = rotation * Vector3.right;
  143.         }
  144.  
  145.         public void SetUpright(Vector3 up) {
  146.                 SetRotation(GetUpright(up));
  147.         }
  148. }
  149.  
  150. [System.Serializable]
  151. public struct TupleMinMax {
  152.         public float min, max;
  153.         public TupleMinMax(float min, float max) { this.min = min; this.max = max; }
  154.         public float Difference(float value) {
  155.                 if(value > max) { return max - value; }
  156.                 if(value < min) { return min - value; }
  157.                 return 0;
  158.         }
  159.         public float Lerp(float t) { return (max - min) * t + min; }
  160.         public float PercentageOf(float value) { return (value - min) / (max - min); }
  161. }
  162.  
  163. public class AxisAgent : MonoBehaviour {
  164.         /// <summary>how the body is oriented, which decides how key input creates movement impulses</summary>
  165.         private Axis body = new Axis();
  166.         /// <summary>how the face is oriented, which decides where the agent's head transform is looking (if there is one)</summary>
  167.         private Axis face = new Axis();
  168.         /// <summary>cached rigidbody of this agent</summary>
  169.         private Rigidbody rb;
  170.  
  171.         [Tooltip("What is moved with mouse-look, and determines the direction being aimed at.\n\nRight-click to setup a controllable agent from an otherwise Empty object."),
  172.         ContextMenuItem("Setup Standard Axis Agent", "SetStandardAgent")]
  173.         public Transform head;
  174.         public Camera playerCamera;
  175. #if SHOW_AXIS_MATH
  176.         GameObject line_body, line_head, line_stand, line_gravity, line_velocity, line_move;
  177. #endif
  178.  
  179.         void SetStandardAgent() {
  180.                 if(head == null) {
  181.                         head = gameObject.transform.FindChild("head");
  182.                         if(head == null) {
  183.                                 head = new GameObject("head").transform;
  184.                                 head.position = transform.position + transform.up * 0.875f;
  185.                                 head.transform.SetParent(transform);
  186.                                 head.localRotation = Quaternion.identity;
  187.                         }
  188.                 }
  189.                 if(playerCamera == null) {
  190.                         Transform t = head.FindChild("camera");
  191.                         playerCamera = (t != null) ? t.GetComponent<Camera>() : null;
  192.                         if(playerCamera == null) {
  193.                                 playerCamera = new GameObject("camera").AddComponent<Camera>();
  194.                                 playerCamera.transform.SetParent(head);
  195.                                 playerCamera.transform.localPosition = new Vector3(0, 5, -10);
  196.                                 playerCamera.transform.localRotation = Quaternion.Euler(25, 0, 0);
  197.                         }
  198.                 }
  199.                 Collider col = GetComponent<Collider>();
  200.                 if(col == null) {
  201.                         CapsuleCollider cap = gameObject.AddComponent<CapsuleCollider>();
  202.                         cap.height = 2;
  203.                         cap.radius = 0.5f;
  204.                 }
  205.                 rb = GetComponent<Rigidbody>();
  206.                 if(rb == null) {
  207.                         rb = gameObject.AddComponent<Rigidbody>();
  208.                 }
  209.         }
  210.  
  211.         [System.Serializable]
  212.         public struct Gravity {
  213.                 [SerializeField, Tooltip("How strong the gravity force is")]
  214.                 private float force;
  215.                 [SerializeField, Tooltip("The direction of the gravity force")]
  216.                 private Vector3 direction;
  217.                 private Vector3 calculatedForce;
  218.  
  219.                 public Gravity(float force, Vector3 dir) {
  220.                         this.force = force; this.direction = dir; this.calculatedForce = force*dir; }
  221.                 public Vector3 GetDirection() { return direction; }
  222.                 public void SetDirection(Vector3 dir) { direction = dir; Refresh(); }
  223.                 public float GetForce() { return force; }
  224.                 public void SetForce(float force) { force = this.force; Refresh(); }
  225.                 public Vector3 Force() { return calculatedForce; }
  226.                 public void Negate() { calculatedForce = Vector3.zero; }
  227.                 public void Refresh() { calculatedForce = force * direction; }
  228.  
  229.                 public Vector3 FixedUpdate(Rigidbody rb) { Vector3 v; rb.AddForce(v = Force()); return v; }
  230.         }
  231.         public Gravity gravity = new Gravity(20, Vector3.down);
  232.  
  233.         [System.Serializable]
  234.         /// <summary>a system opposing gravity that allows an agent to hover very slightly over the ground, and move without friction</summary>
  235.         public class Stand {
  236.                 [SerializeField, Tooltip("How far from the center (in the gravity direction) the standing volume goes")]
  237.                 private float distance = 1;
  238.                 [SerializeField, Tooltip("The radius of the standing volume")]
  239.                 private float radius = .375f;
  240.                 [Tooltip("If non-null, this transform's position will be set to the location where the standing is centered.\n\nSet to a sphere with the radius above to visualize the standing volume.")]
  241.                 public Transform marker;
  242.  
  243.                 /// <summary>the actual spot being stood on</summary>
  244.                 private Vector3 groundContact;
  245.                 /// <summary>how the ground is sloped in 3D space</summary>
  246.                 private Vector3 surfaceNormal = Vector3.up;
  247.                 /// <summary>a 1D value describing how the ground is sloped. used to limit standing force</summary>
  248.                 private float surfaceAngle;
  249.                 /// <summary>used to keep the standing volume from pushing fully out of the ground. keeping the standing volume slightly overlapping helps verify that the agent is still standing.</summary>
  250.                 private float standRadiusEpsilon = 1 / 128.0f;
  251.                 /// <summary>used as fast adjustment to position using the physics system (without directly setting transform.position)</summary></summary>
  252.                 private Vector3 oneTimeForce;
  253.                 /// true if an adjustment to position needs to be made</summary>
  254.                 private bool usingOneTimeForce = false;
  255.                 /// <summary>true if standing volume is on the ground</summary>
  256.                 private bool isOnGround = true;
  257.                 [SerializeField, Tooltip("If true, will automatically match motion of transform being stood on")]
  258.                 private bool becomeParentedToPlatform = true;
  259.                 /// <summary>the actual transform being stood on</summary>
  260.                 Transform stoodOn = null;
  261.                 /// <summary>the velocity of the transform being stood on</summary>
  262.                 private Vector3 stoodOnVelocity;
  263.                 /// <summary>axis (position and rotation) of the transform being stood on</summary>
  264.                 Axis parentTransform = new Axis();
  265.                 /// <summary>the physics calculation done last frame to keep up with the stood-on transform</summary>
  266.                 Vector3 lastPlatformMove;
  267.  
  268.                 public bool IsOnGround() { return isOnGround; }
  269.                 public void SetOnGround(bool onGround) { isOnGround = onGround; }
  270.                 public float GetSurfaceAngle() { return surfaceAngle; }
  271.                 public Vector3 GetSurfaceNormal() { return surfaceNormal; }
  272.                 public Vector3 GetGroundContact() { return groundContact; }
  273.  
  274.                 /// <param name="a"></param>
  275.                 /// <returns>force to apply to a Rigidbody, using AddForce</returns>
  276.                 public Vector3 Force(AxisAgent a, ref Gravity g) {
  277.                         Vector3 force = Vector3.zero;
  278.                         if(usingOneTimeForce) {
  279.                                 usingOneTimeForce = false;
  280.                                 force -= oneTimeForce;
  281.                         }
  282.                         // if non-rigid-body parent has moved  
  283.                         if(becomeParentedToPlatform && stoodOn != null && !parentTransform.Equals(stoodOn)) {
  284.                                 a.rb.AddForce(-lastPlatformMove);
  285.                                 stoodOnVelocity = stoodOn.position - parentTransform.position;
  286.                                 lastPlatformMove = stoodOnVelocity / Time.deltaTime;
  287.                                 parentTransform.SetFrom(stoodOn);
  288.                                 a.rb.AddForce(lastPlatformMove);
  289.                                 a.transform.position = a.transform.position + stoodOnVelocity;
  290.                         }
  291.                         Vector3 standingDirection = -g.GetDirection();
  292.                         Ray ray = new Ray(a.transform.position, -standingDirection);
  293.                         RaycastHit hitInfo = new RaycastHit();
  294.                         a.GetComponent<Collider>().enabled = false;
  295.                         if(!a.jumping.IsJumping() && Physics.SphereCast(ray, radius, out hitInfo, distance) && hitInfo.distance <= distance) {
  296.                                 groundContact = hitInfo.point;
  297.                                 surfaceNormal = hitInfo.normal;
  298.                                 surfaceAngle = Vector3.Angle(standingDirection, surfaceNormal);
  299.                                 if(Vector3.Dot(a.body.forward, surfaceNormal) > 0) {
  300.                                         surfaceAngle *= -1;
  301.                                 }
  302.                                 Vector3 centerOfFoot = a.transform.position - standingDirection * distance;
  303.                                 if(marker != null) {
  304.                                         marker.position = centerOfFoot;
  305.                                 }
  306.                                 float dist = Vector3.Distance(groundContact, centerOfFoot);
  307.                                 float groundOverlap = radius - dist;
  308.                                 if(groundOverlap > 0) {
  309.                                         // instead of setting the position, set the force needed to clip out, then remove that force next frame.
  310.                                         usingOneTimeForce = true;
  311.                                         oneTimeForce = (surfaceNormal * (groundOverlap - standRadiusEpsilon)) / (Time.deltaTime*Time.deltaTime);
  312.                                         force += oneTimeForce;
  313.                                 }
  314.                                 float downForce = Vector2.Dot(-standingDirection, a.rb.velocity);
  315.                                 if(!isOnGround && downForce > 0) {
  316.                                         force += standingDirection * downForce / Time.deltaTime;
  317.                                 }
  318.                                 // reset double-jump variable if on the ground
  319.                                 a.jumping.ResetJumpCount();
  320.                                 isOnGround = true;
  321.                                 g.Negate();
  322.                                 if(becomeParentedToPlatform) {
  323.                                         if(stoodOn != hitInfo.collider.transform) {
  324.                                                 stoodOn = hitInfo.collider.transform;
  325.                                                 parentTransform.SetFrom(stoodOn);
  326.                                         }
  327.                                 }
  328.                         } else {
  329.                                 isOnGround = false;
  330.                                 g.Refresh();
  331.                                 if(becomeParentedToPlatform) {
  332.                                         //if(stoodOn != null) print("no parent");
  333.                                         stoodOn = null;
  334.                                         parentTransform.SetIdentity();
  335.                                 }
  336.                         }
  337.                         a.GetComponent<Collider>().enabled = true;
  338.                         return force;
  339.                 }
  340.                 public Vector3 FixedUpdate(Rigidbody rb, AxisAgent a, ref Gravity gravity) {
  341.                         Vector3 standForce = Force(a, ref gravity);
  342.                         rb.AddForce(standForce);
  343.                         return standForce;
  344.                 }
  345.         }
  346.         public Stand stand;
  347.  
  348.         [System.Serializable]
  349.         public class Jump {
  350.                 public TupleMinMax height = new TupleMinMax(1, 5);
  351.                 public float fullJumpPressDuration = 0.5f;
  352.                 public int maxJumps = 2;
  353.                 public bool jumpStartResetsVerticalMotion = true;
  354.  
  355.                 /// how long the user has been holding jump
  356.                 float timeJumpHeld;
  357.                 /// how the jump is currently doing
  358.                 float currentJumpVelocity;
  359.                 float targetHeight;
  360.                 float heightReached;
  361. #if SHOW_AXIS_MATH
  362.                 Vector3 jumpStart;
  363.                 float heightReachedTotal;
  364. #endif
  365.                 bool jumpPeaked = false;
  366.                 /// whether or not the user is currently jumping
  367.                 bool jumpImpulseActive = false;
  368.                 int jumpsSoFar = 0;
  369.  
  370.                 public enum JumpDirection { opposingGravity, opposingGroundSurface }
  371.                 GameObject jumpShow;
  372.                 public bool IsRequestingJump(AxisAgent a) { return !jumpImpulseActive && (a.input.jump || a.input.jumpHeld); }
  373.                 public bool IsJumping() { return currentJumpVelocity > 0; }
  374.                 public void ResetJumpCount() { jumpsSoFar = 0; }
  375.  
  376.                 public Vector3 Force(AxisAgent a, ref Gravity g, ref Movement movement) {
  377.                         Vector3 force = Vector3.zero;
  378.                         Vector3 jumpDirection = -g.GetDirection();//onlyJumpAgainstGravity ? -g.GetDirection() : a.stand.GetSurfaceNormal();//
  379.                         // if the user wants to jump, and is allowed to jump again
  380.                         if(IsRequestingJump(a) && (jumpsSoFar < maxJumps)) {
  381. #if SHOW_AXIS_MATH
  382.                                 if(jumpsSoFar == 0) {
  383.                                         jumpStart = a.transform.position;
  384.                                         heightReachedTotal = 0;
  385.                                 }
  386. #endif
  387.                                 heightReached = 0;
  388.                                 timeJumpHeld = 0;
  389.                                 jumpsSoFar++;
  390.                                 targetHeight = height.min;
  391.                                 float velocityRequiredToJump = Mathf.Sqrt(targetHeight * 2 * g.GetForce());
  392.                                 // cancel out current jump/fall forces
  393.                                 if(jumpStartResetsVerticalMotion) {
  394.                                         float motionInVerticalDirection = Vector3.Dot(jumpDirection, a.rb.velocity);
  395.                                         force -= (motionInVerticalDirection * jumpDirection) / Time.deltaTime;
  396.                                 }
  397.                                 // apply proper jump force
  398.                                 currentJumpVelocity = velocityRequiredToJump;
  399.                                 jumpPeaked = false;
  400.                                 force += (jumpDirection * currentJumpVelocity) / Time.deltaTime;
  401.                                 jumpImpulseActive = true;
  402.                                 a.stand.SetOnGround(false);
  403.                         } else
  404.                         // if a jump is happening      
  405.                         if(currentJumpVelocity > 0) {
  406.                                 // handle jump height: the longer you hold jump, the higher you jump
  407.                                 if(a.input.jumpHeld) {
  408.                                         timeJumpHeld += Time.deltaTime;
  409.                                         if(timeJumpHeld >= fullJumpPressDuration) {
  410.                                                 targetHeight = height.max;
  411.                                                 timeJumpHeld = fullJumpPressDuration;
  412.                                         } else {
  413.                                                 targetHeight = height.Lerp(timeJumpHeld / fullJumpPressDuration);
  414.                                         }
  415.                                         if(heightReached < targetHeight) {
  416.                                                 float requiredJumpVelocity = Mathf.Sqrt((targetHeight - heightReached) * 2 * g.GetForce());
  417.                                                 float forceNeeded = requiredJumpVelocity - currentJumpVelocity;
  418.                                                 force += (jumpDirection * forceNeeded) / Time.deltaTime;
  419.                                                 currentJumpVelocity = requiredJumpVelocity;
  420.                                         }
  421.                                 } else {
  422.                                         jumpImpulseActive = false;
  423.                                 }
  424.                         }
  425.                         if(currentJumpVelocity > 0) {
  426.                                 float moved = currentJumpVelocity * Time.deltaTime;
  427.                                 heightReached += moved;
  428. #if SHOW_AXIS_MATH
  429.                                 heightReachedTotal += moved;
  430.                                 Lines.Make(ref jumpShow, Color.black, jumpStart, a.transform.position, .5f, 0f);
  431. #endif
  432.                                 currentJumpVelocity -= g.GetForce() * Time.deltaTime;
  433.                         } else if(!jumpPeaked && !a.stand.IsOnGround()) {
  434.                                 jumpPeaked = true;
  435.                                 jumpImpulseActive = false;
  436.                         }
  437.                         return force;
  438.                 }
  439.  
  440.                 public Vector3 FixedUpdate(Rigidbody rb, AxisAgent a, ref Gravity gravity, ref Movement movement) {
  441.                         Vector3 f = Force(a, ref gravity, ref movement);
  442.                         rb.AddForce(f);
  443.                         return f;
  444.                 }
  445.         }
  446.         public Jump jumping;
  447.  
  448.         [System.Serializable]
  449.         public class Input {
  450.                 public enum Source { none, mouseAndKeyboard }
  451.                 [Tooltip("Where to get input from")]
  452.                 public Source source = Source.mouseAndKeyboard;
  453.                 /// [Header("Controller Variables, set automatically by reading controller input")]
  454.                 /// variable:+/-, forward:forward/backward, strafe:right/left, turn:right/left, pitch:down/up
  455.                 [HideInInspector] public float forward, strafe, turn, pitch;
  456.                 /// [Tooltip("button inputs")]
  457.                 [HideInInspector] public bool jump, jumpHeld, fire1, fire1Held, fire2, fire2Held, gravityToggle, fullStop, invertPitch, runHeld;
  458.  
  459.                 public void ReleaseAllInput() {
  460.                         forward = strafe = turn = pitch = 0; //mouseWheel = 0;
  461.                         jump = jumpHeld = fire1 = fire1Held = fire2 = fire2Held = runHeld = false;
  462.                 }
  463.                 [System.Serializable]
  464.                 public class Sensitivity {
  465.                         [Tooltip("x mouse sensitivity")]
  466.                         public float horizontal = 10F;
  467.                         [Tooltip("y mouse sensitivity")]
  468.                         public float vertical = 5F;
  469.                 }
  470.                 public Sensitivity sensitivity;
  471.  
  472.                 public void LoadInputFromController() {
  473.                         switch(source) {
  474.                         case Source.none: break;
  475.                         case Source.mouseAndKeyboard:
  476.                                 forward = UnityEngine.Input.GetAxis("Vertical");
  477.                                 strafe = UnityEngine.Input.GetAxis("Horizontal");
  478.                                 turn = UnityEngine.Input.GetAxis("Mouse X") * sensitivity.horizontal;
  479.                                 pitch = -UnityEngine.Input.GetAxis("Mouse Y") * sensitivity.vertical;
  480.                                 jump = UnityEngine.Input.GetButtonDown("Jump");
  481.                                 jumpHeld = UnityEngine.Input.GetButton("Jump");
  482.                                 fire1 = UnityEngine.Input.GetButtonDown("Fire1");
  483.                                 fire1Held = UnityEngine.Input.GetButton("Fire1");
  484.                                 fire2 = UnityEngine.Input.GetButtonDown("Fire2");
  485.                                 fire2Held = UnityEngine.Input.GetButton("Fire2");
  486.                                 runHeld = UnityEngine.Input.GetKey(KeyCode.LeftShift)
  487.                                                 ||UnityEngine.Input.GetKey(KeyCode.RightShift);
  488.                                 break;
  489.                         default:
  490.                                 throw new System.Exception("unsupported controller " + source);
  491.                         }
  492.                         if(invertPitch) pitch *= -1;
  493.                 }
  494.         }
  495.         public Input input;
  496.  
  497.         [System.Serializable]
  498.         public class Movement {
  499.                 ///<summary>current movement force</summary>
  500.                 private Vector3 force;
  501.                 ///<summary>velocity vector if viewed directly from above</summary>
  502.                 private Vector3 groundVelocity;
  503.                 ///<summary>groundVelocity.magnitude</summary>
  504.                 private Vector3 groundDir;
  505.                 ///<summary>the direction according to the input</summary>
  506.                 private Vector3 inputDir;
  507.                 ///<summary>how much rise/fall is going on</summary>
  508.                 private float verticalVelocity;
  509.                 ///<summary>velocity absent rise/fall</summary>
  510.                 private float groundSpeed;
  511.                 ///<summary>max speed based on input, taking directional speed limits into account</summary>
  512.                 private float maxInputSpeed;
  513.                 ///<summary>how much faster the agent is going than the current speed limit</summary>
  514.                 private float overSpeed;
  515.  
  516.                 public Vector3 defaultUpDirection = Vector3.up;
  517.  
  518.                 Axis movementAxis;
  519.  
  520.                 ///<summary>how far the 3rd person camera can move back based on obstacles in the way</summary>
  521.                 float distanceLimitedTo;
  522.                 ///<summary>where the 3rd person camera is</summary>
  523.                 float actualDistance;
  524.  
  525. #if SHOW_AXIS_MATH
  526.                 GameObject line_movementAxis;
  527. #endif
  528.                 public Vector3 CalculatedSurfaceUpDirection(AxisAgent a) {
  529.                         return a.stand.IsOnGround() ? a.stand.GetSurfaceNormal() : defaultUpDirection;
  530.                 }
  531.  
  532.                 public Vector3 Force(AxisAgent a, Settings s) {
  533.                         if(movementAxis == null) movementAxis = new Axis();
  534.                         movementAxis.SetFrom(a.body);
  535.                         Vector3 upDirection = (Mathf.Abs(a.stand.GetSurfaceAngle()) < s.maxIncline) ? CalculatedSurfaceUpDirection(a) : defaultUpDirection;//
  536.                         if(a.body.up != upDirection) {
  537.                                 movementAxis.SetUpright(upDirection);
  538.                         }
  539. #if SHOW_AXIS_MATH
  540.                         movementAxis.DrawThumbtack(ref line_movementAxis, Color.blue, 2, .0625f);
  541.                         movementAxis.WriteInto(line_movementAxis.transform);
  542. #endif
  543.                         force = Vector3.zero;
  544.                         verticalVelocity = Vector3.Dot(defaultUpDirection, a.rb.velocity);
  545.                         groundVelocity = a.rb.velocity - (defaultUpDirection * verticalVelocity);
  546.                         groundSpeed = groundVelocity.magnitude;
  547.                         groundDir = groundVelocity / groundSpeed;
  548.                         inputDir = Vector3.zero;
  549.                         // input impulse
  550.                         if(a.input.forward != 0 || a.input.strafe != 0) {
  551.  
  552.                                 maxInputSpeed = s.GetSpeedBasedOnInput(a.input, a.stand.GetSurfaceAngle());
  553.                                 inputDir = movementAxis.forward * a.input.forward + movementAxis.GetRight() * a.input.strafe;
  554.                                 inputDir.Normalize();
  555.                                 float accelSpeedInCurrentDirection = Vector3.Dot(inputDir, groundVelocity);
  556.                                 force = inputDir * ((accelSpeedInCurrentDirection > 0) ? s.acceleration : s.deceleration);
  557.                                 if(groundSpeed > maxInputSpeed) {
  558.                                         overSpeed = Vector3.Dot(groundDir, force);
  559.                                         overSpeed += groundSpeed - maxInputSpeed;
  560.                                         force += groundDir * -overSpeed;
  561.                                         force = force.normalized * s.acceleration;
  562.                                 }
  563.                         } else {
  564.                                 // stop logic
  565.                                 if(s.stopWhenNoInputGiven && groundSpeed != 0) {
  566.                                         // figure out how much force is needed to stop
  567.                                         float stopNeededToBringToZero = groundSpeed / Time.deltaTime;
  568.                                         // if that is too much force, go with the max possible.
  569.                                         if(stopNeededToBringToZero > s.deceleration) {
  570.                                                 force += -groundDir * s.deceleration;
  571.                                         } else {
  572.                                                 force += -groundDir * stopNeededToBringToZero;
  573.                                         }
  574.                                 }
  575.                         }
  576.                         return force;
  577.                 }
  578.  
  579.                 [System.Serializable]
  580.                 public class Settings {
  581.                         [Tooltip("What to use this movement profile. For example, there could be different movement settings for: walk, run, crawl, swim, climb, parkour, jump, fall, fly, hover")]
  582.                         public string name = "standard";
  583.                         [Tooltip("Maximum speed when pressing forward/backward")]
  584.                         public float speedForward = 15, speedBackward = 5;
  585.                         [Tooltip("Maximum speed when pressing strafe right/left")]
  586.                         public float speedRight = 10, speedLeft = 10;
  587.                         [Tooltip("Maximum acceleration when going forward/backward or strafing right/left")]
  588.                         public float acceleration = 20;
  589.                         [Tooltip("Maximum acceleration when bringing velocity toward zero")]
  590.                         public float deceleration = 30;
  591.                         [Tooltip("If true, movement calculations will cause a stop if inputs are released")]
  592.                         public bool stopWhenNoInputGiven = true;
  593.                         [Tooltip("the agent will not be able to move around on surfaces with an incline greater than this")]
  594.                         public float maxIncline = 50;
  595.                         [Tooltip("Percentage of speed possible as the current surface angle approaches the max incline")]
  596.                         public AnimationCurve inclineSpeedLoss = AnimationCurve.Linear(0,0,1,1);
  597.  
  598.                         /// TODO implement these for hover, climb, and parkour movement types
  599.                         [Tooltip("Acts against gravity force")]
  600.                         public float antiGravityForce = 0;
  601.                         [Tooltip("Causes gravity to match player up direction, the stronger force the more un-aligned with gravity it will work")]
  602.                         public float gravityRealignForce = 0;
  603.  
  604.                         public float GetInclineSpeedAdjustment(float surfaceAngle) {
  605.                                 return (surfaceAngle > 0) ? (1-inclineSpeedLoss.Evaluate(surfaceAngle / maxIncline)) :1;
  606.                         }
  607.  
  608.                         [System.Serializable]
  609.                         public class HeadTurning {
  610.                                 public TupleMinMax pitchLimit = new TupleMinMax(-140, 110);
  611.                                 float currentVerticalAngle;
  612.                                 // TODO allow the head transform to turn independently of the body, and make the body match if the turnLimit is reached or movement starts
  613. //                              public TupleMinMax turnLimit = new TupleMinMax(-50, 50);
  614. //                              public bool turnBodyBeyondMaximum = true;
  615. //                              public bool pitchBodyBeyondMaximum = false;
  616.  
  617.                                 public void Update(AxisAgent a) {
  618.                                         if(a.input.pitch != 0) {
  619.                                                 a.face.SetFrom(a.head);
  620.                                                 a.face.Pitch(a.input.pitch);
  621.                                                 currentVerticalAngle = Vector3.Angle(a.body.up, a.face.up);
  622.                                                 if(Vector3.Dot(a.face.forward, a.body.up) > 0) {
  623.                                                         currentVerticalAngle *= -1;
  624.                                                 }
  625.                                                 float difference = pitchLimit.Difference(currentVerticalAngle);
  626.                                                 if(difference != 0) {
  627.                                                         a.face.Pitch(difference);
  628.                                                         currentVerticalAngle += difference;
  629.                                                 }
  630.                                                 a.face.WriteInto(a.head);
  631.                                                 thirdPersonCamera.CameraAngleUpdate(a.playerCamera, pitchLimit.PercentageOf(currentVerticalAngle));
  632.                                         }
  633.                                         float wheel = UnityEngine.Input.GetAxis("Mouse ScrollWheel");
  634.                                         if(wheel != 0) {
  635.                                                 thirdPersonCamera.Move(a.playerCamera.transform, wheel);
  636.                                         }
  637.                                 }
  638.  
  639.                                 [System.Serializable]
  640.                                 public class ThirdPersonCameraController {
  641.                                         [Tooltip("How far the user wants the camera to be")]
  642.                                         public float thirdPersonDistance = 10;
  643.                                         [Tooltip("How quickly to move the camera to it's spot (lower is faster)"), Range(1, 128)]
  644.                                         public float collisionSpeed = 8;
  645.                                         public AnimationCurve viewAngle3rdPerson = DefaultCameraLookCurve();
  646.  
  647.                                         public static AnimationCurve DefaultCameraLookCurve() {
  648.                                                 AnimationCurve curve = new AnimationCurve();
  649.                                                 curve.AddKey(0, 0);
  650.                                                 curve.AddKey(.5f, .25f);
  651.                                                 curve.AddKey(.75f, .25f);
  652.                                                 curve.AddKey(1, 1);
  653.                                                 return curve;
  654.                                         }
  655.  
  656.                                         public void Move(Transform camera, float change) {
  657.                                                 change *= 5;
  658.                                                 thirdPersonDistance -= change;
  659.                                                 if(thirdPersonDistance < change) {
  660.                                                         camera.position = camera.parent.position;
  661.                                                         thirdPersonDistance = 0;
  662.                                                 }
  663.                                         }
  664.  
  665.                                         public void CameraAngleUpdate(Camera camera, float vertical) {
  666.                                                 vertical = viewAngle3rdPerson.Evaluate(vertical);
  667.                                                 float fieldOfView = camera.fieldOfView;
  668.                                                 float viewAngle = fieldOfView * vertical;
  669.                                                 camera.transform.localRotation = Quaternion.Euler(viewAngle - 30, 0, 0);
  670.                                         }
  671.                                 }
  672.                                 public ThirdPersonCameraController thirdPersonCamera = new ThirdPersonCameraController();
  673.                         }
  674.                         public HeadTurning headTurning = new HeadTurning();
  675.  
  676.                         [System.Serializable]
  677.                         public class RotationControl {
  678.                                 [Tooltip("Be precise when turning with the mouse (no lag, or continued turning)")]
  679.                                 public bool stopControlledAngularVelocity = true;
  680.                                 [Tooltip("stop the spinning!")]
  681.                                 public bool stopUncontrolledAngularVelocity = true;
  682.                                 [Tooltip("set the player standing correctly if angle is perterbed")]
  683.                                 public bool automaticallySetRightsideUp = true;
  684.                                 [Tooltip("Force used to stop uncontrolled angular rotation")]
  685.                                 public Vector3 angularVelocityCounterForce = new Vector3(15, 90, 15);
  686.                                 [Tooltip("Force used to set player upright")]
  687.                                 public float rightsideUpForce = 20;
  688.                         }
  689.                         public RotationControl rotationControl = new RotationControl();
  690.  
  691.                         public Settings(float forward, float backward, float strafeRight, float strafeLeft, float accel, float decel) {
  692.                                 this.speedForward = forward;
  693.                                 this.speedBackward = backward;
  694.                                 this.speedRight = strafeRight;
  695.                                 this.speedLeft = strafeLeft;
  696.                                 this.acceleration = accel;
  697.                                 this.deceleration = decel;
  698.                         }
  699.  
  700.                         public float GetSpeedBasedOnInput(Input i, float angle) {
  701.                                 float result;
  702.                                 if(i.forward == 0) {
  703.                                         if(i.strafe == 0) result = 0;
  704.                                         else if(i.strafe < 0) result = speedLeft;
  705.                                         else result = speedRight;
  706.                                 } else if(i.strafe == 0) {
  707.                                         if(i.forward > 0) result = speedForward;
  708.                                         else result = speedBackward;
  709.                                 } else {
  710.                                         float sum, f, s;
  711.                                         if(i.forward > 0) {
  712.                                                 f = i.forward;
  713.                                                 if(i.strafe > 0) { s = i.strafe; sum = f + s; f /= sum; s /= sum; result = (f * speedForward) + (s * speedRight); }
  714.                                                 else             { s = -i.strafe; sum = f + s; f /= sum; s /= sum; result = (f * speedForward) + (s * speedLeft); }
  715.                                         } else {
  716.                                                 f = -i.forward;
  717.                                                 if(i.strafe > 0) { s = i.strafe; sum = f + s; f /= sum; s /= sum; result = (f * speedBackward) + (s * speedRight); }
  718.                                                 else             { s = -i.strafe; sum = f + s; f /= sum; s /= sum; result = (f * speedBackward) + (s * speedLeft); }
  719.                                         }
  720.                                 }
  721.                                 return result * GetInclineSpeedAdjustment(angle);
  722.                         }
  723.                 }
  724.  
  725.                 public Settings currentSettings = new Settings(15, 5, 10, 10, 20, 60);
  726.  
  727.                 private Vector3 angularJerk, standUpJerk;
  728.  
  729. #if SHOW_AXIS_MATH
  730.                 /// visuals to help debug rotation forces
  731.                 GameObject rot_axis, rot_fwd, rot_up, rot_target;
  732. #endif
  733.                 public void FixedUpdateRotation(AxisAgent a, Input inputSource, Transform transform, Axis body, Rigidbody rb) {
  734.                         bool balancingRotation = false;
  735.                         // if the agent is controlling angular jerks, to emulate precise rotation, and there was an angular jerk last frame
  736.                         if(currentSettings.rotationControl.stopControlledAngularVelocity && angularJerk != Vector3.zero) {
  737.                                 // find out how much that angular jerk has depreciated
  738.                                 Vector3 adjusted = angularJerk - (angularJerk * rb.angularDrag * Time.deltaTime);
  739.                                 // remove the jerk from the current angular rotation
  740.                                 rb.AddTorque(-adjusted, ForceMode.Acceleration);
  741.                                 // mark that there is no more angular jerk (it has been undone)
  742.                                 angularJerk = Vector3.zero;
  743.                                 // mark thata balancing rotation occured, which will prevent further balancing rotations
  744.                                 balancingRotation = true;
  745.                         }
  746.                         if(currentSettings.rotationControl.automaticallySetRightsideUp && body.up != defaultUpDirection) {
  747.                                 Quaternion uprightRotation = body.GetUpright(defaultUpDirection);
  748.                                 Quaternion rotationToRightSelf = body.DeltaTo(uprightRotation);//body.UprightDelta(-gravity.GetDirection());
  749.                                 Vector3 euler = rotationToRightSelf.eulerAngles;
  750.                                 bool change = false;
  751.                                 if(euler.x > 180) { euler.x -= 360; change = true; }
  752.                                 if(euler.y > 180) { euler.y -= 360; change = true; }
  753.                                 if(euler.z > 180) { euler.z -= 360; change = true; }
  754.                                 const float epsilon = 1 / 128f;
  755.                                 if(Mathf.Abs(euler.x) < epsilon) euler.x = 0;
  756.                                 if(Mathf.Abs(euler.y) < epsilon) euler.y = 0;
  757.                                 if(Mathf.Abs(euler.z) < epsilon) euler.z = 0;
  758.                                 if(change) {
  759.                                         //print(Time.time+":["+euler.x + " " + euler.y + " " + euler.z+"]");
  760.                                         rotationToRightSelf = Quaternion.Euler(euler);
  761.                                 }
  762.                                 if(euler != Vector3.zero) {
  763.                                         Vector3 rotAxis = Vector3.zero;
  764.                                         float rotAngle;
  765.                                         rotationToRightSelf.ToAngleAxis(out rotAngle, out rotAxis);
  766. #if SHOW_AXIS_MATH
  767.                                         Lines.Make(ref rot_axis, Color.magenta, transform.position + rotAxis, transform.position - rotAxis, .1f, .1f);
  768.                                         Lines.MakeArc(ref rot_fwd, Color.magenta, transform.position, rotAxis, transform.forward, rotAngle, 8, .1f, 0);
  769.                                         Lines.MakeArc(ref rot_up, Color.magenta, transform.position, rotAxis, transform.up, rotAngle, 8, .1f, 0);
  770.                                         Axis next = new Axis(body);
  771.                                         next.Rotate(rotationToRightSelf);
  772.                                         next.DrawSimple(ref rot_target, Color.black, 1);
  773. #endif
  774.                                         float f = currentSettings.rotationControl.rightsideUpForce;
  775.                                         euler.x = Mathf.Clamp(euler.x, -f, f);
  776.                                         euler.y = Mathf.Clamp(euler.y, -f, f);
  777.                                         euler.z = Mathf.Clamp(euler.z, -f, f);
  778.                                         //print(Time.time + ": " + euler.x + " " + euler.y + " " + euler.z);
  779.                                         if(standUpJerk != euler) {
  780.                                                 // divide by 2 because... it makes it work better. TODO more controlled right-side-up angular forces!
  781.                                                 rb.AddTorque(-standUpJerk/2, ForceMode.Acceleration);
  782.                                                 standUpJerk = euler;
  783.                                                 rb.AddTorque(euler, ForceMode.Acceleration);
  784.                                         }
  785.                                 }
  786.                         }
  787.                         // if the player wants to turn (horizontal motion)
  788.                         if(inputSource.turn != 0) {
  789.                                 // turn horizontally
  790.                                 angularJerk.y += inputSource.turn / Time.deltaTime;
  791.                                 rb.AddTorque(angularJerk, ForceMode.Acceleration);
  792.                         } else {
  793.                                 // if no turn is going on, and no balancing rotation is going on, and this agent should be stopping uncontrolled rotations
  794.                                 if(currentSettings.rotationControl.stopUncontrolledAngularVelocity && !balancingRotation) {
  795.                                         // if there is rotation
  796.                                         Vector3 angle = rb.angularVelocity;
  797.                                         if(angle != Vector3.zero) {
  798.                                                 // calculate a counter-force to stop rotation
  799.                                                 Vector3 counterForce = currentSettings.rotationControl.angularVelocityCounterForce;// Vector3.zero;
  800.                                                 counterForce.x = Mathf.Clamp(angle.x, -counterForce.x, counterForce.x);
  801.                                                 counterForce.y = Mathf.Clamp(angle.y, -counterForce.y, counterForce.y);
  802.                                                 counterForce.z = Mathf.Clamp(angle.z, -counterForce.z, counterForce.z);
  803.                                                 rb.AddTorque(-counterForce / Time.deltaTime, ForceMode.Acceleration);
  804.                                         }
  805.                                 }
  806.                         }
  807.                 }
  808.  
  809.                 public Vector3 Force(AxisAgent a) {
  810.                         return Force(a, currentSettings);
  811.                 }
  812.  
  813.                 public Vector3 FixedUpdate(Rigidbody rb, AxisAgent a) {
  814.                         Vector3 f = Force(a);
  815.                         rb.AddForce(f);
  816.                         return f;
  817.                 }
  818.  
  819.                 public void MoveCameraBack(Transform camera) {
  820.                         float thirdPersonDistance = currentSettings.headTurning.thirdPersonCamera.thirdPersonDistance;
  821.                         if(thirdPersonDistance == 0) return;
  822.                         RaycastHit rh = new RaycastHit();
  823.                         Vector3 dir = -camera.parent.forward;
  824.                         float nextPosition = actualDistance;
  825.                         if(!Physics.Raycast(camera.parent.position, dir, out rh, thirdPersonDistance)) {
  826.                                 distanceLimitedTo = thirdPersonDistance;
  827.                         } else {
  828.                                 distanceLimitedTo = rh.distance;
  829.                         }
  830.                         if(actualDistance != distanceLimitedTo) {
  831.                                 float delta = (distanceLimitedTo - actualDistance) / currentSettings.headTurning.thirdPersonCamera.collisionSpeed;
  832.                                 nextPosition = (Mathf.Abs(delta) > 1 / 128.0f) ? (actualDistance + delta) : distanceLimitedTo;
  833.                         }
  834.                         if(nextPosition != actualDistance) {
  835.                                 actualDistance = nextPosition;
  836.                                 camera.localPosition = -Vector3.forward * actualDistance;
  837.                         }
  838.                 }
  839.  
  840.                 public void Update(AxisAgent a) {
  841.                         currentSettings.headTurning.Update(a);
  842.                         MoveCameraBack(a.playerCamera.transform);
  843.                 }
  844.         }
  845.  
  846.         [Tooltip("Variables that set how this agent moves, and keep track of orientation")]
  847.         public Movement movement;
  848.  
  849.         public void SetMovementSettings(Movement.Settings moveSettings) {
  850.                 movement.currentSettings = moveSettings;
  851.         }
  852.  
  853.         ///////////////////////////////////////////////////////////////////////////////////////////////
  854.        
  855.         /// uses Rigidbody.AddForce() to modify the rigidbody's behavior.
  856.         void FixedUpdate () {
  857.                 // update axis
  858.                 body.SetFrom(transform);
  859.                 face.SetFrom(head);
  860.                 // update components. keep track of forces locally so visuals can be updated
  861.                 Vector3 moveForce = movement.FixedUpdate(rb, this);
  862.                 Vector3 gravityForce = gravity.FixedUpdate(rb);
  863.                 Vector3 jumpingForce = jumping.FixedUpdate(rb, this, ref gravity, ref movement);
  864.                 Vector3 standForce = stand.FixedUpdate(rb, this, ref gravity);
  865.                 // TODO RotationMovement
  866.                 movement.FixedUpdateRotation(this, input, transform, body, rb);
  867. #if SHOW_AXIS_MATH
  868.                 DrawAxisOnTransform(ref line_body, Color.cyan, body, transform, .75f);
  869.                 DrawAxisOnTransform(ref line_head, Color.yellow, face, head, .5f);
  870.                 Vector3 p = transform.position;
  871.                 Vector3 s = stand.GetGroundContact();
  872.                 Vector3 v = transform.position + rb.velocity;
  873.                 Lines.Make(ref line_gravity, Color.magenta, p, p + gravityForce, .2f, 0);
  874.                 Lines.Make(ref line_stand, Color.green, s, s + standForce, .4f, 0);
  875.                 Lines.Make(ref line_velocity, Color.blue, p, v, .1f, .1f);
  876.                 Lines.Make(ref line_move, Color.red, v, v + moveForce, .1f, .1f);
  877. #endif
  878.         }
  879.  
  880. #if SHOW_AXIS_MATH
  881.         void DrawAxisOnTransform(ref GameObject line_, Color c, Axis a, Transform t, float size) {
  882.                 a.DrawThumbtack(ref line_, c, size, .1f);
  883.                 line_.transform.SetParent(t);
  884.                 line_.transform.localPosition = Vector3.zero;
  885.                 line_.transform.localRotation = Quaternion.identity;
  886.         }
  887. #endif
  888.  
  889.         struct MoveSettingsManager {
  890.                 Movement.Settings defaultMoveSetting;
  891.                 [Tooltip("walk, run, crawl, swim, climb, parkour, jump, fall, fly, hover")]
  892.                 public Movement.Settings[] movementSettings;
  893.                 // TODO run button, crawl button, fly minimum speed float, swim boolean toggle
  894.                 // walk is standard movement, just slow. motion axis aligns with ground, if in the air, it aligns with player-up
  895.                 //     if crawl and run pressed while standing)
  896.                 // crawl crouches the player, and is very slow movement (with a smaller height profile)
  897.                 //     crawl button. jump stands player up
  898.                 // run is standard movement, but fast.
  899.                 //     automatically parkour if on non-ground surface
  900.                 // climb aligns gravity to be against a surface, allowing scaling of walls (and ceiling too if gravity alignment force is strong enough)
  901.                 //     if crawl and run pressed while against non-walkable surface. jump ends climb, and goes into jump (fall)
  902.                 // parkour causes player-up to shift when running on surfaces, and aligns gravity if able, allowing wall running (and ceiling running if gravity alignment force is strong enough)
  903.                 //     if running at surface that is too steep to be ground. release run to drop into standard movement. crawl to climb.
  904.                 // fall activates when the player is jumping or falling (non air-movement, but still in the air)
  905.                 //     jump again for double jump. if no more double jumps possible, go into hover.
  906.                 // hover is an air-travel, feels like no-clip movement in a FPS game. jump is up, crawl is down. uses antigravity force to balance out gravity. re-orient to up after movement and turning stops.
  907.                 //     activate if pressing jump during fall at the end of last double-jump. run to drop into fall, or switch into fly if speed is sufficient
  908.                 // fly is a fast air-travel, like a flight-sim, where left and right roll, forward and back pitch. player-up is not bound to gravity. must be in motion. free look. slowing down drops player into hover
  909.                 //     crawl to drop into fall, falling to minimum speed drops into fall
  910.                 // swim is triggered when entering a swim zone (water). dramatically reduces gravity, and makes the motion axis align with the look axis, allowing motion in any direction
  911.                 //     climb works. leave swim zone to end swim. jump to go into hover
  912.                 //     (water areas have a move-speed modifier and direction of flow)
  913.         }
  914.  
  915.         void Start() {
  916.                 rb = GetComponent<Rigidbody>();
  917.                 rb.useGravity = false;
  918.                 rb.angularDrag = 0;
  919.                 rb.maxAngularVelocity = 360;
  920.         }
  921.  
  922.         void Update() {
  923.                 input.LoadInputFromController();
  924.                 movement.Update(this);
  925.         }
  926. }
RAW Paste Data
Ledger Nano X - The secure hardware wallet
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top