Pastebin
API
tools
faq
paste
Login
Sign up
Please fix the following errors:
New Paste
Syntax Highlighting
// comment the line below if missing Lines.cs (found at http://pastebin.com/8m69iTut ) #define SHOW_AXIS_MATH using UnityEngine; using System.Collections; // TODO camera zoom with mouse wheel AxisCamera // TODO gravity source /// <summary> /// used for calculating and organizing 3D axis math /// </summary> public class Axis { public Vector3 forward, up, position; private Vector3 right; public void SetIdentity() { up = Vector3.up; forward = Vector3.forward; right = Vector3.right; position = Vector3.zero; } public bool Equals(Transform t) { return up == t.up && forward == t.forward && position == t.position; } public Axis(Axis other) { up = other.up; right = other.right; forward = other.forward; position = other.position; } public Axis() { } public Vector3 GetRight() { return right; //return Vector3.Cross(up, forward).normalized; } #if SHOW_AXIS_MATH public LineRenderer DrawSimple(ref GameObject lineObj, Color c, float size) { const float epsilon = 0.001f; Vector3 u = up * size, f = forward * size; Vector3[] points = { position + u, position + u * epsilon, position + f * epsilon, position + f * (1 - epsilon), position + f, Vector3.zero }; points[points.Length - 1] = Vector3.Lerp(points[3], points[0], 0.125f); LineRenderer lr = Lines.Make(ref lineObj, c, points, points.Length, .1f, .1f); return lr; } private Vector3[] thumbtack_points_base = null; public LineRenderer DrawThumbtack(ref GameObject lineObj, Color c, float size, float lineWidth) { const float epsilon = 0.001f; if(thumbtack_points_base == null) { Vector3 pstn = Vector3.zero; Vector3 fwrd = Vector3.forward * size; Vector3 rght = Vector3.right * size; Vector3 up__ = Vector3.up; float startAngle = (360.0f / 4) - (360.0f / 32); Vector3 v = Quaternion.AngleAxis(startAngle, up__) * fwrd; Lines.MakeArc(ref thumbtack_points_base, 32, up__, v, 360, pstn); Vector3 tip = pstn + fwrd * Mathf.Sqrt(2); thumbtack_points_base[0] = thumbtack_points_base[thumbtack_points_base.Length - 1]; int m = (32 * 5 / 8) + 1; thumbtack_points_base[m++] = thumbtack_points_base[m] + (tip - thumbtack_points_base[m]) * (1 - epsilon); thumbtack_points_base[m++] = tip; int n = (32 * 7 / 8) + 1; while(n < 32) { thumbtack_points_base[m++] = thumbtack_points_base[n++]; } Vector3 side = pstn + rght; thumbtack_points_base[m++] = thumbtack_points_base[m] + (side - thumbtack_points_base[m]) * (1 - epsilon); thumbtack_points_base[m++] = pstn + rght; thumbtack_points_base[m++] = pstn + rght * epsilon; thumbtack_points_base[m++] = pstn; thumbtack_points_base[m++] = pstn + up__ * size * (1 - epsilon); thumbtack_points_base[m++] = pstn + up__ * size; } LineRenderer lr = Lines.Make(ref lineObj, c, thumbtack_points_base, thumbtack_points_base.Length, lineWidth, lineWidth); lr.useWorldSpace = false; return lr; } #endif public void SetFrom(Transform t) { position = t.position; up = t.up; forward = t.forward; right = t.right; } public void SetFrom(Axis t) { position = t.position; up = t.up; forward = t.forward; right = t.right; } public void WriteInto(Transform t) { t.position = position; t.rotation = Quaternion.LookRotation(forward, up); } public void Turn(float t) { Quaternion turn = Quaternion.AngleAxis(t, up); forward = turn * forward; right = turn * right; } public void Pitch(float p) { Quaternion turn = Quaternion.AngleAxis(p, right); forward = turn * forward; up = turn * up; } public Quaternion GetUpright(Vector3 nextUp) { Vector3 r = Vector3.Cross(forward, nextUp); Vector3 fwd = Vector3.Cross(nextUp, r); return Quaternion.LookRotation(fwd, nextUp); } public Quaternion DeltaTo(Quaternion rotation) { Quaternion q = Quaternion.LookRotation(this.forward, this.up); return rotation * Quaternion.Inverse(q); } public Quaternion UprightDelta(Vector3 nextUp) { return DeltaTo(GetUpright(nextUp)); } public void Rotate(Quaternion rotation) { forward = rotation * forward; up = rotation * up; right = rotation * right; } public void SetRotation(Quaternion rotation) { forward = rotation * Vector3.forward; up = rotation * Vector3.up; right = rotation * Vector3.right; } public void SetUpright(Vector3 up) { SetRotation(GetUpright(up)); } } [System.Serializable] public struct TupleMinMax { public float min, max; public TupleMinMax(float min, float max) { this.min = min; this.max = max; } public float Difference(float value) { if(value > max) { return max - value; } if(value < min) { return min - value; } return 0; } public float Lerp(float t) { return (max - min) * t + min; } public float PercentageOf(float value) { return (value - min) / (max - min); } } public class AxisAgent : MonoBehaviour { /// <summary>how the body is oriented, which decides how key input creates movement impulses</summary> private Axis body = new Axis(); /// <summary>how the face is oriented, which decides where the agent's head transform is looking (if there is one)</summary> private Axis face = new Axis(); /// <summary>cached rigidbody of this agent</summary> private Rigidbody rb; [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."), ContextMenuItem("Setup Standard Axis Agent", "SetStandardAgent")] public Transform head; public Camera playerCamera; #if SHOW_AXIS_MATH GameObject line_body, line_head, line_stand, line_gravity, line_velocity, line_move; #endif void SetStandardAgent() { if(head == null) { head = gameObject.transform.FindChild("head"); if(head == null) { head = new GameObject("head").transform; head.position = transform.position + transform.up * 0.875f; head.transform.SetParent(transform); head.localRotation = Quaternion.identity; } } if(playerCamera == null) { Transform t = head.FindChild("camera"); playerCamera = (t != null) ? t.GetComponent<Camera>() : null; if(playerCamera == null) { playerCamera = new GameObject("camera").AddComponent<Camera>(); playerCamera.transform.SetParent(head); playerCamera.transform.localPosition = new Vector3(0, 5, -10); playerCamera.transform.localRotation = Quaternion.Euler(25, 0, 0); } } Collider col = GetComponent<Collider>(); if(col == null) { CapsuleCollider cap = gameObject.AddComponent<CapsuleCollider>(); cap.height = 2; cap.radius = 0.5f; } rb = GetComponent<Rigidbody>(); if(rb == null) { rb = gameObject.AddComponent<Rigidbody>(); } } [System.Serializable] public struct Gravity { [SerializeField, Tooltip("How strong the gravity force is")] private float force; [SerializeField, Tooltip("The direction of the gravity force")] private Vector3 direction; private Vector3 calculatedForce; public Gravity(float force, Vector3 dir) { this.force = force; this.direction = dir; this.calculatedForce = force*dir; } public Vector3 GetDirection() { return direction; } public void SetDirection(Vector3 dir) { direction = dir; Refresh(); } public float GetForce() { return force; } public void SetForce(float force) { force = this.force; Refresh(); } public Vector3 Force() { return calculatedForce; } public void Negate() { calculatedForce = Vector3.zero; } public void Refresh() { calculatedForce = force * direction; } public Vector3 FixedUpdate(Rigidbody rb) { Vector3 v; rb.AddForce(v = Force()); return v; } } public Gravity gravity = new Gravity(20, Vector3.down); [System.Serializable] /// <summary>a system opposing gravity that allows an agent to hover very slightly over the ground, and move without friction</summary> public class Stand { [SerializeField, Tooltip("How far from the center (in the gravity direction) the standing volume goes")] private float distance = 1; [SerializeField, Tooltip("The radius of the standing volume")] private float radius = .375f; [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.")] public Transform marker; /// <summary>the actual spot being stood on</summary> private Vector3 groundContact; /// <summary>how the ground is sloped in 3D space</summary> private Vector3 surfaceNormal = Vector3.up; /// <summary>a 1D value describing how the ground is sloped. used to limit standing force</summary> private float surfaceAngle; /// <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> private float standRadiusEpsilon = 1 / 128.0f; /// <summary>used as fast adjustment to position using the physics system (without directly setting transform.position)</summary></summary> private Vector3 oneTimeForce; /// true if an adjustment to position needs to be made</summary> private bool usingOneTimeForce = false; /// <summary>true if standing volume is on the ground</summary> private bool isOnGround = true; [SerializeField, Tooltip("If true, will automatically match motion of transform being stood on")] private bool becomeParentedToPlatform = true; /// <summary>the actual transform being stood on</summary> Transform stoodOn = null; /// <summary>the velocity of the transform being stood on</summary> private Vector3 stoodOnVelocity; /// <summary>axis (position and rotation) of the transform being stood on</summary> Axis parentTransform = new Axis(); /// <summary>the physics calculation done last frame to keep up with the stood-on transform</summary> Vector3 lastPlatformMove; public bool IsOnGround() { return isOnGround; } public void SetOnGround(bool onGround) { isOnGround = onGround; } public float GetSurfaceAngle() { return surfaceAngle; } public Vector3 GetSurfaceNormal() { return surfaceNormal; } public Vector3 GetGroundContact() { return groundContact; } /// <param name="a"></param> /// <returns>force to apply to a Rigidbody, using AddForce</returns> public Vector3 Force(AxisAgent a, ref Gravity g) { Vector3 force = Vector3.zero; if(usingOneTimeForce) { usingOneTimeForce = false; force -= oneTimeForce; } // if non-rigid-body parent has moved if(becomeParentedToPlatform && stoodOn != null && !parentTransform.Equals(stoodOn)) { a.rb.AddForce(-lastPlatformMove); stoodOnVelocity = stoodOn.position - parentTransform.position; lastPlatformMove = stoodOnVelocity / Time.deltaTime; parentTransform.SetFrom(stoodOn); a.rb.AddForce(lastPlatformMove); a.transform.position = a.transform.position + stoodOnVelocity; } Vector3 standingDirection = -g.GetDirection(); Ray ray = new Ray(a.transform.position, -standingDirection); RaycastHit hitInfo = new RaycastHit(); a.GetComponent<Collider>().enabled = false; if(!a.jumping.IsJumping() && Physics.SphereCast(ray, radius, out hitInfo, distance) && hitInfo.distance <= distance) { groundContact = hitInfo.point; surfaceNormal = hitInfo.normal; surfaceAngle = Vector3.Angle(standingDirection, surfaceNormal); if(Vector3.Dot(a.body.forward, surfaceNormal) > 0) { surfaceAngle *= -1; } Vector3 centerOfFoot = a.transform.position - standingDirection * distance; if(marker != null) { marker.position = centerOfFoot; } float dist = Vector3.Distance(groundContact, centerOfFoot); float groundOverlap = radius - dist; if(groundOverlap > 0) { // instead of setting the position, set the force needed to clip out, then remove that force next frame. usingOneTimeForce = true; oneTimeForce = (surfaceNormal * (groundOverlap - standRadiusEpsilon)) / (Time.deltaTime*Time.deltaTime); force += oneTimeForce; } float downForce = Vector2.Dot(-standingDirection, a.rb.velocity); if(!isOnGround && downForce > 0) { force += standingDirection * downForce / Time.deltaTime; } // reset double-jump variable if on the ground a.jumping.ResetJumpCount(); isOnGround = true; g.Negate(); if(becomeParentedToPlatform) { if(stoodOn != hitInfo.collider.transform) { stoodOn = hitInfo.collider.transform; parentTransform.SetFrom(stoodOn); } } } else { isOnGround = false; g.Refresh(); if(becomeParentedToPlatform) { //if(stoodOn != null) print("no parent"); stoodOn = null; parentTransform.SetIdentity(); } } a.GetComponent<Collider>().enabled = true; return force; } public Vector3 FixedUpdate(Rigidbody rb, AxisAgent a, ref Gravity gravity) { Vector3 standForce = Force(a, ref gravity); rb.AddForce(standForce); return standForce; } } public Stand stand; [System.Serializable] public class Jump { public TupleMinMax height = new TupleMinMax(1, 5); public float fullJumpPressDuration = 0.5f; public int maxJumps = 2; public bool jumpStartResetsVerticalMotion = true; /// how long the user has been holding jump float timeJumpHeld; /// how the jump is currently doing float currentJumpVelocity; float targetHeight; float heightReached; #if SHOW_AXIS_MATH Vector3 jumpStart; float heightReachedTotal; #endif bool jumpPeaked = false; /// whether or not the user is currently jumping bool jumpImpulseActive = false; int jumpsSoFar = 0; public enum JumpDirection { opposingGravity, opposingGroundSurface } GameObject jumpShow; public bool IsRequestingJump(AxisAgent a) { return !jumpImpulseActive && (a.input.jump || a.input.jumpHeld); } public bool IsJumping() { return currentJumpVelocity > 0; } public void ResetJumpCount() { jumpsSoFar = 0; } public Vector3 Force(AxisAgent a, ref Gravity g, ref Movement movement) { Vector3 force = Vector3.zero; Vector3 jumpDirection = -g.GetDirection();//onlyJumpAgainstGravity ? -g.GetDirection() : a.stand.GetSurfaceNormal();// // if the user wants to jump, and is allowed to jump again if(IsRequestingJump(a) && (jumpsSoFar < maxJumps)) { #if SHOW_AXIS_MATH if(jumpsSoFar == 0) { jumpStart = a.transform.position; heightReachedTotal = 0; } #endif heightReached = 0; timeJumpHeld = 0; jumpsSoFar++; targetHeight = height.min; float velocityRequiredToJump = Mathf.Sqrt(targetHeight * 2 * g.GetForce()); // cancel out current jump/fall forces if(jumpStartResetsVerticalMotion) { float motionInVerticalDirection = Vector3.Dot(jumpDirection, a.rb.velocity); force -= (motionInVerticalDirection * jumpDirection) / Time.deltaTime; } // apply proper jump force currentJumpVelocity = velocityRequiredToJump; jumpPeaked = false; force += (jumpDirection * currentJumpVelocity) / Time.deltaTime; jumpImpulseActive = true; a.stand.SetOnGround(false); } else // if a jump is happening if(currentJumpVelocity > 0) { // handle jump height: the longer you hold jump, the higher you jump if(a.input.jumpHeld) { timeJumpHeld += Time.deltaTime; if(timeJumpHeld >= fullJumpPressDuration) { targetHeight = height.max; timeJumpHeld = fullJumpPressDuration; } else { targetHeight = height.Lerp(timeJumpHeld / fullJumpPressDuration); } if(heightReached < targetHeight) { float requiredJumpVelocity = Mathf.Sqrt((targetHeight - heightReached) * 2 * g.GetForce()); float forceNeeded = requiredJumpVelocity - currentJumpVelocity; force += (jumpDirection * forceNeeded) / Time.deltaTime; currentJumpVelocity = requiredJumpVelocity; } } else { jumpImpulseActive = false; } } if(currentJumpVelocity > 0) { float moved = currentJumpVelocity * Time.deltaTime; heightReached += moved; #if SHOW_AXIS_MATH heightReachedTotal += moved; Lines.Make(ref jumpShow, Color.black, jumpStart, a.transform.position, .5f, 0f); #endif currentJumpVelocity -= g.GetForce() * Time.deltaTime; } else if(!jumpPeaked && !a.stand.IsOnGround()) { jumpPeaked = true; jumpImpulseActive = false; } return force; } public Vector3 FixedUpdate(Rigidbody rb, AxisAgent a, ref Gravity gravity, ref Movement movement) { Vector3 f = Force(a, ref gravity, ref movement); rb.AddForce(f); return f; } } public Jump jumping; [System.Serializable] public class Input { public enum Source { none, mouseAndKeyboard } [Tooltip("Where to get input from")] public Source source = Source.mouseAndKeyboard; /// [Header("Controller Variables, set automatically by reading controller input")] /// variable:+/-, forward:forward/backward, strafe:right/left, turn:right/left, pitch:down/up [HideInInspector] public float forward, strafe, turn, pitch; /// [Tooltip("button inputs")] [HideInInspector] public bool jump, jumpHeld, fire1, fire1Held, fire2, fire2Held, gravityToggle, fullStop, invertPitch, runHeld; public void ReleaseAllInput() { forward = strafe = turn = pitch = 0; //mouseWheel = 0; jump = jumpHeld = fire1 = fire1Held = fire2 = fire2Held = runHeld = false; } [System.Serializable] public class Sensitivity { [Tooltip("x mouse sensitivity")] public float horizontal = 10F; [Tooltip("y mouse sensitivity")] public float vertical = 5F; } public Sensitivity sensitivity; public void LoadInputFromController() { switch(source) { case Source.none: break; case Source.mouseAndKeyboard: forward = UnityEngine.Input.GetAxis("Vertical"); strafe = UnityEngine.Input.GetAxis("Horizontal"); turn = UnityEngine.Input.GetAxis("Mouse X") * sensitivity.horizontal; pitch = -UnityEngine.Input.GetAxis("Mouse Y") * sensitivity.vertical; jump = UnityEngine.Input.GetButtonDown("Jump"); jumpHeld = UnityEngine.Input.GetButton("Jump"); fire1 = UnityEngine.Input.GetButtonDown("Fire1"); fire1Held = UnityEngine.Input.GetButton("Fire1"); fire2 = UnityEngine.Input.GetButtonDown("Fire2"); fire2Held = UnityEngine.Input.GetButton("Fire2"); runHeld = UnityEngine.Input.GetKey(KeyCode.LeftShift) ||UnityEngine.Input.GetKey(KeyCode.RightShift); break; default: throw new System.Exception("unsupported controller " + source); } if(invertPitch) pitch *= -1; } } public Input input; [System.Serializable] public class Movement { ///<summary>current movement force</summary> private Vector3 force; ///<summary>velocity vector if viewed directly from above</summary> private Vector3 groundVelocity; ///<summary>groundVelocity.magnitude</summary> private Vector3 groundDir; ///<summary>the direction according to the input</summary> private Vector3 inputDir; ///<summary>how much rise/fall is going on</summary> private float verticalVelocity; ///<summary>velocity absent rise/fall</summary> private float groundSpeed; ///<summary>max speed based on input, taking directional speed limits into account</summary> private float maxInputSpeed; ///<summary>how much faster the agent is going than the current speed limit</summary> private float overSpeed; public Vector3 defaultUpDirection = Vector3.up; Axis movementAxis; ///<summary>how far the 3rd person camera can move back based on obstacles in the way</summary> float distanceLimitedTo; ///<summary>where the 3rd person camera is</summary> float actualDistance; #if SHOW_AXIS_MATH GameObject line_movementAxis; #endif public Vector3 CalculatedSurfaceUpDirection(AxisAgent a) { return a.stand.IsOnGround() ? a.stand.GetSurfaceNormal() : defaultUpDirection; } public Vector3 Force(AxisAgent a, Settings s) { if(movementAxis == null) movementAxis = new Axis(); movementAxis.SetFrom(a.body); Vector3 upDirection = (Mathf.Abs(a.stand.GetSurfaceAngle()) < s.maxIncline) ? CalculatedSurfaceUpDirection(a) : defaultUpDirection;// if(a.body.up != upDirection) { movementAxis.SetUpright(upDirection); } #if SHOW_AXIS_MATH movementAxis.DrawThumbtack(ref line_movementAxis, Color.blue, 2, .0625f); movementAxis.WriteInto(line_movementAxis.transform); #endif force = Vector3.zero; verticalVelocity = Vector3.Dot(defaultUpDirection, a.rb.velocity); groundVelocity = a.rb.velocity - (defaultUpDirection * verticalVelocity); groundSpeed = groundVelocity.magnitude; groundDir = groundVelocity / groundSpeed; inputDir = Vector3.zero; // input impulse if(a.input.forward != 0 || a.input.strafe != 0) { maxInputSpeed = s.GetSpeedBasedOnInput(a.input, a.stand.GetSurfaceAngle()); inputDir = movementAxis.forward * a.input.forward + movementAxis.GetRight() * a.input.strafe; inputDir.Normalize(); float accelSpeedInCurrentDirection = Vector3.Dot(inputDir, groundVelocity); force = inputDir * ((accelSpeedInCurrentDirection > 0) ? s.acceleration : s.deceleration); if(groundSpeed > maxInputSpeed) { overSpeed = Vector3.Dot(groundDir, force); overSpeed += groundSpeed - maxInputSpeed; force += groundDir * -overSpeed; force = force.normalized * s.acceleration; } } else { // stop logic if(s.stopWhenNoInputGiven && groundSpeed != 0) { // figure out how much force is needed to stop float stopNeededToBringToZero = groundSpeed / Time.deltaTime; // if that is too much force, go with the max possible. if(stopNeededToBringToZero > s.deceleration) { force += -groundDir * s.deceleration; } else { force += -groundDir * stopNeededToBringToZero; } } } return force; } [System.Serializable] public class Settings { [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")] public string name = "standard"; [Tooltip("Maximum speed when pressing forward/backward")] public float speedForward = 15, speedBackward = 5; [Tooltip("Maximum speed when pressing strafe right/left")] public float speedRight = 10, speedLeft = 10; [Tooltip("Maximum acceleration when going forward/backward or strafing right/left")] public float acceleration = 20; [Tooltip("Maximum acceleration when bringing velocity toward zero")] public float deceleration = 30; [Tooltip("If true, movement calculations will cause a stop if inputs are released")] public bool stopWhenNoInputGiven = true; [Tooltip("the agent will not be able to move around on surfaces with an incline greater than this")] public float maxIncline = 50; [Tooltip("Percentage of speed possible as the current surface angle approaches the max incline")] public AnimationCurve inclineSpeedLoss = AnimationCurve.Linear(0,0,1,1); /// TODO implement these for hover, climb, and parkour movement types [Tooltip("Acts against gravity force")] public float antiGravityForce = 0; [Tooltip("Causes gravity to match player up direction, the stronger force the more un-aligned with gravity it will work")] public float gravityRealignForce = 0; public float GetInclineSpeedAdjustment(float surfaceAngle) { return (surfaceAngle > 0) ? (1-inclineSpeedLoss.Evaluate(surfaceAngle / maxIncline)) :1; } [System.Serializable] public class HeadTurning { public TupleMinMax pitchLimit = new TupleMinMax(-140, 110); float currentVerticalAngle; // TODO allow the head transform to turn independently of the body, and make the body match if the turnLimit is reached or movement starts // public TupleMinMax turnLimit = new TupleMinMax(-50, 50); // public bool turnBodyBeyondMaximum = true; // public bool pitchBodyBeyondMaximum = false; public void Update(AxisAgent a) { if(a.input.pitch != 0) { a.face.SetFrom(a.head); a.face.Pitch(a.input.pitch); currentVerticalAngle = Vector3.Angle(a.body.up, a.face.up); if(Vector3.Dot(a.face.forward, a.body.up) > 0) { currentVerticalAngle *= -1; } float difference = pitchLimit.Difference(currentVerticalAngle); if(difference != 0) { a.face.Pitch(difference); currentVerticalAngle += difference; } a.face.WriteInto(a.head); thirdPersonCamera.CameraAngleUpdate(a.playerCamera, pitchLimit.PercentageOf(currentVerticalAngle)); } float wheel = UnityEngine.Input.GetAxis("Mouse ScrollWheel"); if(wheel != 0) { thirdPersonCamera.Move(a.playerCamera.transform, wheel); } } [System.Serializable] public class ThirdPersonCameraController { [Tooltip("How far the user wants the camera to be")] public float thirdPersonDistance = 10; [Tooltip("How quickly to move the camera to it's spot (lower is faster)"), Range(1, 128)] public float collisionSpeed = 8; public AnimationCurve viewAngle3rdPerson = DefaultCameraLookCurve(); public static AnimationCurve DefaultCameraLookCurve() { AnimationCurve curve = new AnimationCurve(); curve.AddKey(0, 0); curve.AddKey(.5f, .25f); curve.AddKey(.75f, .25f); curve.AddKey(1, 1); return curve; } public void Move(Transform camera, float change) { change *= 5; thirdPersonDistance -= change; if(thirdPersonDistance < change) { camera.position = camera.parent.position; thirdPersonDistance = 0; } } public void CameraAngleUpdate(Camera camera, float vertical) { vertical = viewAngle3rdPerson.Evaluate(vertical); float fieldOfView = camera.fieldOfView; float viewAngle = fieldOfView * vertical; camera.transform.localRotation = Quaternion.Euler(viewAngle - 30, 0, 0); } } public ThirdPersonCameraController thirdPersonCamera = new ThirdPersonCameraController(); } public HeadTurning headTurning = new HeadTurning(); [System.Serializable] public class RotationControl { [Tooltip("Be precise when turning with the mouse (no lag, or continued turning)")] public bool stopControlledAngularVelocity = true; [Tooltip("stop the spinning!")] public bool stopUncontrolledAngularVelocity = true; [Tooltip("set the player standing correctly if angle is perterbed")] public bool automaticallySetRightsideUp = true; [Tooltip("Force used to stop uncontrolled angular rotation")] public Vector3 angularVelocityCounterForce = new Vector3(15, 90, 15); [Tooltip("Force used to set player upright")] public float rightsideUpForce = 20; } public RotationControl rotationControl = new RotationControl(); public Settings(float forward, float backward, float strafeRight, float strafeLeft, float accel, float decel) { this.speedForward = forward; this.speedBackward = backward; this.speedRight = strafeRight; this.speedLeft = strafeLeft; this.acceleration = accel; this.deceleration = decel; } public float GetSpeedBasedOnInput(Input i, float angle) { float result; if(i.forward == 0) { if(i.strafe == 0) result = 0; else if(i.strafe < 0) result = speedLeft; else result = speedRight; } else if(i.strafe == 0) { if(i.forward > 0) result = speedForward; else result = speedBackward; } else { float sum, f, s; if(i.forward > 0) { f = i.forward; if(i.strafe > 0) { s = i.strafe; sum = f + s; f /= sum; s /= sum; result = (f * speedForward) + (s * speedRight); } else { s = -i.strafe; sum = f + s; f /= sum; s /= sum; result = (f * speedForward) + (s * speedLeft); } } else { f = -i.forward; if(i.strafe > 0) { s = i.strafe; sum = f + s; f /= sum; s /= sum; result = (f * speedBackward) + (s * speedRight); } else { s = -i.strafe; sum = f + s; f /= sum; s /= sum; result = (f * speedBackward) + (s * speedLeft); } } } return result * GetInclineSpeedAdjustment(angle); } } public Settings currentSettings = new Settings(15, 5, 10, 10, 20, 60); private Vector3 angularJerk, standUpJerk; #if SHOW_AXIS_MATH /// visuals to help debug rotation forces GameObject rot_axis, rot_fwd, rot_up, rot_target; #endif public void FixedUpdateRotation(AxisAgent a, Input inputSource, Transform transform, Axis body, Rigidbody rb) { bool balancingRotation = false; // if the agent is controlling angular jerks, to emulate precise rotation, and there was an angular jerk last frame if(currentSettings.rotationControl.stopControlledAngularVelocity && angularJerk != Vector3.zero) { // find out how much that angular jerk has depreciated Vector3 adjusted = angularJerk - (angularJerk * rb.angularDrag * Time.deltaTime); // remove the jerk from the current angular rotation rb.AddTorque(-adjusted, ForceMode.Acceleration); // mark that there is no more angular jerk (it has been undone) angularJerk = Vector3.zero; // mark thata balancing rotation occured, which will prevent further balancing rotations balancingRotation = true; } if(currentSettings.rotationControl.automaticallySetRightsideUp && body.up != defaultUpDirection) { Quaternion uprightRotation = body.GetUpright(defaultUpDirection); Quaternion rotationToRightSelf = body.DeltaTo(uprightRotation);//body.UprightDelta(-gravity.GetDirection()); Vector3 euler = rotationToRightSelf.eulerAngles; bool change = false; if(euler.x > 180) { euler.x -= 360; change = true; } if(euler.y > 180) { euler.y -= 360; change = true; } if(euler.z > 180) { euler.z -= 360; change = true; } const float epsilon = 1 / 128f; if(Mathf.Abs(euler.x) < epsilon) euler.x = 0; if(Mathf.Abs(euler.y) < epsilon) euler.y = 0; if(Mathf.Abs(euler.z) < epsilon) euler.z = 0; if(change) { //print(Time.time+":["+euler.x + " " + euler.y + " " + euler.z+"]"); rotationToRightSelf = Quaternion.Euler(euler); } if(euler != Vector3.zero) { Vector3 rotAxis = Vector3.zero; float rotAngle; rotationToRightSelf.ToAngleAxis(out rotAngle, out rotAxis); #if SHOW_AXIS_MATH Lines.Make(ref rot_axis, Color.magenta, transform.position + rotAxis, transform.position - rotAxis, .1f, .1f); Lines.MakeArc(ref rot_fwd, Color.magenta, transform.position, rotAxis, transform.forward, rotAngle, 8, .1f, 0); Lines.MakeArc(ref rot_up, Color.magenta, transform.position, rotAxis, transform.up, rotAngle, 8, .1f, 0); Axis next = new Axis(body); next.Rotate(rotationToRightSelf); next.DrawSimple(ref rot_target, Color.black, 1); #endif float f = currentSettings.rotationControl.rightsideUpForce; euler.x = Mathf.Clamp(euler.x, -f, f); euler.y = Mathf.Clamp(euler.y, -f, f); euler.z = Mathf.Clamp(euler.z, -f, f); //print(Time.time + ": " + euler.x + " " + euler.y + " " + euler.z); if(standUpJerk != euler) { // divide by 2 because... it makes it work better. TODO more controlled right-side-up angular forces! rb.AddTorque(-standUpJerk/2, ForceMode.Acceleration); standUpJerk = euler; rb.AddTorque(euler, ForceMode.Acceleration); } } } // if the player wants to turn (horizontal motion) if(inputSource.turn != 0) { // turn horizontally angularJerk.y += inputSource.turn / Time.deltaTime; rb.AddTorque(angularJerk, ForceMode.Acceleration); } else { // if no turn is going on, and no balancing rotation is going on, and this agent should be stopping uncontrolled rotations if(currentSettings.rotationControl.stopUncontrolledAngularVelocity && !balancingRotation) { // if there is rotation Vector3 angle = rb.angularVelocity; if(angle != Vector3.zero) { // calculate a counter-force to stop rotation Vector3 counterForce = currentSettings.rotationControl.angularVelocityCounterForce;// Vector3.zero; counterForce.x = Mathf.Clamp(angle.x, -counterForce.x, counterForce.x); counterForce.y = Mathf.Clamp(angle.y, -counterForce.y, counterForce.y); counterForce.z = Mathf.Clamp(angle.z, -counterForce.z, counterForce.z); rb.AddTorque(-counterForce / Time.deltaTime, ForceMode.Acceleration); } } } } public Vector3 Force(AxisAgent a) { return Force(a, currentSettings); } public Vector3 FixedUpdate(Rigidbody rb, AxisAgent a) { Vector3 f = Force(a); rb.AddForce(f); return f; } public void MoveCameraBack(Transform camera) { float thirdPersonDistance = currentSettings.headTurning.thirdPersonCamera.thirdPersonDistance; if(thirdPersonDistance == 0) return; RaycastHit rh = new RaycastHit(); Vector3 dir = -camera.parent.forward; float nextPosition = actualDistance; if(!Physics.Raycast(camera.parent.position, dir, out rh, thirdPersonDistance)) { distanceLimitedTo = thirdPersonDistance; } else { distanceLimitedTo = rh.distance; } if(actualDistance != distanceLimitedTo) { float delta = (distanceLimitedTo - actualDistance) / currentSettings.headTurning.thirdPersonCamera.collisionSpeed; nextPosition = (Mathf.Abs(delta) > 1 / 128.0f) ? (actualDistance + delta) : distanceLimitedTo; } if(nextPosition != actualDistance) { actualDistance = nextPosition; camera.localPosition = -Vector3.forward * actualDistance; } } public void Update(AxisAgent a) { currentSettings.headTurning.Update(a); MoveCameraBack(a.playerCamera.transform); } } [Tooltip("Variables that set how this agent moves, and keep track of orientation")] public Movement movement; public void SetMovementSettings(Movement.Settings moveSettings) { movement.currentSettings = moveSettings; } /////////////////////////////////////////////////////////////////////////////////////////////// /// uses Rigidbody.AddForce() to modify the rigidbody's behavior. void FixedUpdate () { // update axis body.SetFrom(transform); face.SetFrom(head); // update components. keep track of forces locally so visuals can be updated Vector3 moveForce = movement.FixedUpdate(rb, this); Vector3 gravityForce = gravity.FixedUpdate(rb); Vector3 jumpingForce = jumping.FixedUpdate(rb, this, ref gravity, ref movement); Vector3 standForce = stand.FixedUpdate(rb, this, ref gravity); // TODO RotationMovement movement.FixedUpdateRotation(this, input, transform, body, rb); #if SHOW_AXIS_MATH DrawAxisOnTransform(ref line_body, Color.cyan, body, transform, .75f); DrawAxisOnTransform(ref line_head, Color.yellow, face, head, .5f); Vector3 p = transform.position; Vector3 s = stand.GetGroundContact(); Vector3 v = transform.position + rb.velocity; Lines.Make(ref line_gravity, Color.magenta, p, p + gravityForce, .2f, 0); Lines.Make(ref line_stand, Color.green, s, s + standForce, .4f, 0); Lines.Make(ref line_velocity, Color.blue, p, v, .1f, .1f); Lines.Make(ref line_move, Color.red, v, v + moveForce, .1f, .1f); #endif } #if SHOW_AXIS_MATH void DrawAxisOnTransform(ref GameObject line_, Color c, Axis a, Transform t, float size) { a.DrawThumbtack(ref line_, c, size, .1f); line_.transform.SetParent(t); line_.transform.localPosition = Vector3.zero; line_.transform.localRotation = Quaternion.identity; } #endif struct MoveSettingsManager { Movement.Settings defaultMoveSetting; [Tooltip("walk, run, crawl, swim, climb, parkour, jump, fall, fly, hover")] public Movement.Settings[] movementSettings; // TODO run button, crawl button, fly minimum speed float, swim boolean toggle // walk is standard movement, just slow. motion axis aligns with ground, if in the air, it aligns with player-up // if crawl and run pressed while standing) // crawl crouches the player, and is very slow movement (with a smaller height profile) // crawl button. jump stands player up // run is standard movement, but fast. // automatically parkour if on non-ground surface // climb aligns gravity to be against a surface, allowing scaling of walls (and ceiling too if gravity alignment force is strong enough) // if crawl and run pressed while against non-walkable surface. jump ends climb, and goes into jump (fall) // 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) // if running at surface that is too steep to be ground. release run to drop into standard movement. crawl to climb. // fall activates when the player is jumping or falling (non air-movement, but still in the air) // jump again for double jump. if no more double jumps possible, go into hover. // 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. // 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 // 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 // crawl to drop into fall, falling to minimum speed drops into fall // 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 // climb works. leave swim zone to end swim. jump to go into hover // (water areas have a move-speed modifier and direction of flow) } void Start() { rb = GetComponent<Rigidbody>(); rb.useGravity = false; rb.angularDrag = 0; rb.maxAngularVelocity = 360; } void Update() { input.LoadInputFromController(); movement.Update(this); } }
Optional Paste Settings
Category:
None
Cryptocurrency
Cybersecurity
Fixit
Food
Gaming
Haiku
Help
History
Housing
Jokes
Legal
Money
Movies
Music
Pets
Photo
Science
Software
Source Code
Spirit
Sports
Travel
TV
Writing
Tags:
Syntax Highlighting:
None
Bash
C
C#
C++
CSS
HTML
JSON
Java
JavaScript
Lua
Markdown (PRO members only)
Objective C
PHP
Perl
Python
Ruby
Swift
4CS
6502 ACME Cross Assembler
6502 Kick Assembler
6502 TASM/64TASS
ABAP
AIMMS
ALGOL 68
APT Sources
ARM
ASM (NASM)
ASP
ActionScript
ActionScript 3
Ada
Apache Log
AppleScript
Arduino
Asymptote
AutoIt
Autohotkey
Avisynth
Awk
BASCOM AVR
BNF
BOO
Bash
Basic4GL
Batch
BibTeX
Blitz Basic
Blitz3D
BlitzMax
BrainFuck
C
C (WinAPI)
C Intermediate Language
C for Macs
C#
C++
C++ (WinAPI)
C++ (with Qt extensions)
C: Loadrunner
CAD DCL
CAD Lisp
CFDG
CMake
COBOL
CSS
Ceylon
ChaiScript
Chapel
Clojure
Clone C
Clone C++
CoffeeScript
ColdFusion
Cuesheet
D
DCL
DCPU-16
DCS
DIV
DOT
Dart
Delphi
Delphi Prism (Oxygene)
Diff
E
ECMAScript
EPC
Easytrieve
Eiffel
Email
Erlang
Euphoria
F#
FO Language
Falcon
Filemaker
Formula One
Fortran
FreeBasic
FreeSWITCH
GAMBAS
GDB
GDScript
Game Maker
Genero
Genie
GetText
Go
Godot GLSL
Groovy
GwBasic
HQ9 Plus
HTML
HTML 5
Haskell
Haxe
HicEst
IDL
INI file
INTERCAL
IO
ISPF Panel Definition
Icon
Inno Script
J
JCL
JSON
Java
Java 5
JavaScript
Julia
KSP (Kontakt Script)
KiXtart
Kotlin
LDIF
LLVM
LOL Code
LScript
Latex
Liberty BASIC
Linden Scripting
Lisp
Loco Basic
Logtalk
Lotus Formulas
Lotus Script
Lua
M68000 Assembler
MIX Assembler
MK-61/52
MPASM
MXML
MagikSF
Make
MapBasic
Markdown (PRO members only)
MatLab
Mercury
MetaPost
Modula 2
Modula 3
Motorola 68000 HiSoft Dev
MySQL
Nagios
NetRexx
Nginx
Nim
NullSoft Installer
OCaml
OCaml Brief
Oberon 2
Objeck Programming Langua
Objective C
Octave
Open Object Rexx
OpenBSD PACKET FILTER
OpenGL Shading
Openoffice BASIC
Oracle 11
Oracle 8
Oz
PARI/GP
PCRE
PHP
PHP Brief
PL/I
PL/SQL
POV-Ray
ParaSail
Pascal
Pawn
Per
Perl
Perl 6
Phix
Pic 16
Pike
Pixel Bender
PostScript
PostgreSQL
PowerBuilder
PowerShell
ProFTPd
Progress
Prolog
Properties
ProvideX
Puppet
PureBasic
PyCon
Python
Python for S60
QBasic
QML
R
RBScript
REBOL
REG
RPM Spec
Racket
Rails
Rexx
Robots
Roff Manpage
Ruby
Ruby Gnuplot
Rust
SAS
SCL
SPARK
SPARQL
SQF
SQL
SSH Config
Scala
Scheme
Scilab
SdlBasic
Smalltalk
Smarty
StandardML
StoneScript
SuperCollider
Swift
SystemVerilog
T-SQL
TCL
TeXgraph
Tera Term
TypeScript
TypoScript
UPC
Unicon
UnrealScript
Urbi
VB.NET
VBScript
VHDL
VIM
Vala
Vedit
VeriLog
Visual Pro Log
VisualBasic
VisualFoxPro
WHOIS
WhiteSpace
Winbatch
XBasic
XML
XPP
Xojo
Xorg Config
YAML
YARA
Z80 Assembler
ZXBasic
autoconf
jQuery
mIRC
newLISP
q/kdb+
thinBasic
Paste Expiration:
Never
Burn after read
10 Minutes
1 Hour
1 Day
1 Week
2 Weeks
1 Month
6 Months
1 Year
Paste Exposure:
Public
Unlisted
Private
Folder:
(members only)
Password
NEW
Enabled
Disabled
Burn after read
NEW
Paste Name / Title:
Create New Paste
Hello
Guest
Sign Up
or
Login
Sign in with Facebook
Sign in with Twitter
Sign in with Google
You are currently not logged in, this means you can not edit or delete anything you paste.
Sign Up
or
Login
Public Pastes
Untitled
6 hours ago | 1.88 KB
Untitled
6 hours ago | 0.67 KB
Untitled
6 hours ago | 3.33 KB
Untitled
6 hours ago | 1.00 KB
Untitled
6 hours ago | 0.33 KB
Untitled
6 hours ago | 1.55 KB
my software
10 hours ago | 0.03 KB
disable countdown timer in cart for drop pric...
PHP | 14 hours ago | 0.23 KB
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
Not a member of Pastebin yet?
Sign Up
, it unlocks many cool features!