diff options
| author | realtradam <[email protected]> | 2022-12-10 04:09:08 -0500 |
|---|---|---|
| committer | realtradam <[email protected]> | 2022-12-10 04:09:08 -0500 |
| commit | 1b7c9c7fc27541bb9420b91b3cd68f3a726e435c (patch) | |
| tree | 461ccf5b4a933bfc5ba8c5d76f252034b4a39aec /Assets/Scripts | |
| parent | f4323d161a589b076b0ccd64e2a1cffcd09b0681 (diff) | |
| download | Magnet-Run-3D-1b7c9c7fc27541bb9420b91b3cd68f3a726e435c.tar.gz Magnet-Run-3D-1b7c9c7fc27541bb9420b91b3cd68f3a726e435c.zip | |
orbiting camera
Diffstat (limited to 'Assets/Scripts')
| -rw-r--r-- | Assets/Scripts/MovingSphere.cs | 28 | ||||
| -rw-r--r-- | Assets/Scripts/OrbitCamera.cs | 202 | ||||
| -rw-r--r-- | Assets/Scripts/OrbitCamera.cs.meta | 11 |
3 files changed, 236 insertions, 5 deletions
diff --git a/Assets/Scripts/MovingSphere.cs b/Assets/Scripts/MovingSphere.cs index dfbd378..77ac00f 100644 --- a/Assets/Scripts/MovingSphere.cs +++ b/Assets/Scripts/MovingSphere.cs @@ -4,6 +4,9 @@ using UnityEngine; public class MovingSphere : MonoBehaviour
{
+ [SerializeField]
+ Transform playerInputSpace = default;
+
Rigidbody body;
Renderer renderer;
@@ -46,6 +49,8 @@ public class MovingSphere : MonoBehaviour bool OnGround => groundContactCount > 0;
bool OnSteep => steepContactCount > 0;
+ Vector3 upAxis;
+
// 1.0 means walls
// 0.0 means floors
@@ -75,7 +80,19 @@ public class MovingSphere : MonoBehaviour desiredJump |= Input.GetButtonDown("Jump");
- inputVelocity = new Vector3(playerInput.x, 0f, playerInput.y) * maxSpeed;
+ if(playerInputSpace)
+ {
+ Vector3 forward = playerInputSpace.forward;
+ forward.y = 0f;
+ forward.Normalize();
+ Vector3 right = playerInputSpace.right;
+ right.y = 0f;
+ right.Normalize();
+ inputVelocity =
+ ((forward * playerInput.y) + (right * playerInput.x)) * maxSpeed;
+ }
+ else
+ inputVelocity = new Vector3(playerInput.x, 0f, playerInput.y) * maxSpeed;
Color purple = Color.red + Color.blue;
//renderer.material.SetColor(
@@ -88,6 +105,7 @@ public class MovingSphere : MonoBehaviour void FixedUpdate()
{
+ upAxis = -Physics.gravity.normalized;
UpdateState();
AdjustVelocity();
@@ -127,7 +145,7 @@ public class MovingSphere : MonoBehaviour contactNormal.Normalize();
}
else
- contactNormal = Vector3.up;
+ contactNormal = upAxis;
}
void Jump()
@@ -152,8 +170,8 @@ public class MovingSphere : MonoBehaviour stepsSinceLastJump = 0;
jumpPhase += 1;
- float jumpSpeed = Mathf.Sqrt(-2f * Physics.gravity.y * jumpHeight);
- jumpDirection = (jumpDirection + Vector3.up).normalized;
+ float jumpSpeed = Mathf.Sqrt(2f * Physics.gravity.magnitude * jumpHeight);
+ jumpDirection = (jumpDirection + upAxis).normalized;
float alignedSpeed = Vector3.Dot(velocity, jumpDirection);
if(alignedSpeed > 0f)
jumpSpeed = Mathf.Max(jumpSpeed - alignedSpeed, 0f);
@@ -169,7 +187,7 @@ public class MovingSphere : MonoBehaviour return false;
if(!Physics.Raycast(
body.position,
- Vector3.down,
+ -upAxis,
out RaycastHit hit,
raycastProbeDistance,
probeMask
diff --git a/Assets/Scripts/OrbitCamera.cs b/Assets/Scripts/OrbitCamera.cs new file mode 100644 index 0000000..81a6941 --- /dev/null +++ b/Assets/Scripts/OrbitCamera.cs @@ -0,0 +1,202 @@ +using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+[RequireComponent(typeof(Camera))]
+public class OrbitCamera : MonoBehaviour
+{
+ Camera regularCamera;
+
+
+ [SerializeField]
+ Transform focus = default;
+
+ [SerializeField, Range(1f, 20f)]
+ float distance = 5f;
+
+ [SerializeField, Min(0f)]
+ float focusLimitRadius = 1f;
+
+ [SerializeField, Range(0f, 1f)]
+ float focusCenteringSpeed = 0.5f;
+
+ [SerializeField, Range(1f, 360f)]
+ float rotationSpeed = 90f;
+
+ [SerializeField, Range(-89f, 89f)]
+ float minVerticalAngle = -30f;
+ [SerializeField, Range(-89f, 89f)]
+ float maxVerticalAngle = 60f;
+
+ [SerializeField, Min(0f)]
+ float alignDelay = 5f;
+
+ [SerializeField, Range(0f, 90f)]
+ float alignSmoothRange = 45;
+
+ float lastManualRotationTime;
+
+ Vector3 focusPoint;
+ Vector3 previousFocusPoint;
+
+ Vector3 orbitAngles = new Vector2(45f, 0f);
+
+ [SerializeField]
+ LayerMask obstructionMask = -1;
+
+ void Awake()
+ {
+ regularCamera = GetComponent<Camera>();
+ focusPoint = focus.position;
+ transform.localRotation = Quaternion.Euler(orbitAngles);
+ }
+
+ void LateUpdate()
+ {
+ UpdateFocusPoint();
+ Quaternion lookRotation;
+ if(ManualRotation() || AutomaticRotation())
+ {
+ ConstrainAngles();
+ lookRotation = Quaternion.Euler(orbitAngles);
+ }
+ else
+ lookRotation = transform.localRotation;
+
+ Vector3 lookDirection = lookRotation * Vector3.forward;
+ Vector3 lookPosition = focusPoint - lookDirection * distance;
+
+ Vector3 rectOffset = lookDirection * regularCamera.nearClipPlane;
+ Vector3 rectPosition = lookPosition + rectOffset;
+ Vector3 castFrom = focus.position;
+ Vector3 castLine = rectPosition - castFrom;
+ float castDistance = castLine.magnitude;
+ Vector3 castDirection = castLine / castDistance;
+
+ if(Physics.BoxCast(
+ castFrom,
+ CameraHalfExtends,
+ castDirection,
+ out RaycastHit hit,
+ lookRotation,
+ castDistance,
+ obstructionMask
+ )
+ )
+ {
+ rectPosition = castFrom + castDirection * hit.distance;
+ lookPosition = rectPosition - rectOffset;
+ }
+ transform.SetPositionAndRotation(lookPosition, lookRotation);
+ }
+
+ void UpdateFocusPoint()
+ {
+ previousFocusPoint = focusPoint;
+ Vector3 targetPoint = focus.position;
+ if(focusLimitRadius > 0f)
+ {
+ float t = 1f;
+ float distance = Vector3.Distance(targetPoint, focusPoint);
+ if(distance > 0.01f && focusCenteringSpeed > 0f)
+ t = Mathf.Pow(1f - focusCenteringSpeed, Time.unscaledDeltaTime);
+ if(distance > focusLimitRadius)
+ {
+ t = Mathf.Min(t, focusLimitRadius / distance);
+ }
+ focusPoint = Vector3.Lerp(
+ targetPoint,
+ focusPoint,
+ t
+ );
+ }
+ else
+ focusPoint = targetPoint;
+ }
+
+ bool ManualRotation()
+ {
+ Vector2 input = new Vector2(
+ Input.GetAxis("Vertical Camera"),
+ Input.GetAxis("Horizontal Camera")
+ );
+ const float e = 0.001f;
+ if(
+ input.x < -e ||
+ input.x > e ||
+ input.y < -e ||
+ input.y > e
+ )
+ {
+ orbitAngles += rotationSpeed * Time.unscaledDeltaTime * (Vector3)input;
+ lastManualRotationTime = Time.unscaledTime;
+ return true;
+ }
+ return false;
+ }
+
+ void ConstrainAngles()
+ {
+ orbitAngles.x = Mathf.Clamp(
+ orbitAngles.x,
+ minVerticalAngle,
+ maxVerticalAngle);
+
+ if(orbitAngles.y < 0f)
+ orbitAngles.y += 360f;
+ else if(orbitAngles.y >= 360f)
+ orbitAngles.y -= 360f;
+ }
+
+ bool AutomaticRotation()
+ {
+ if(Time.unscaledTime - lastManualRotationTime < alignDelay)
+ return false;
+
+ Vector2 movement = new Vector2(
+ focusPoint.x - previousFocusPoint.x,
+ focusPoint.z - previousFocusPoint.z
+ );
+ float movementDeltaSqr = movement.sqrMagnitude;
+ if(movementDeltaSqr < 0.0001f)
+ return false;
+
+ float headingAngle = GetAngle(movement / Mathf.Sqrt(movementDeltaSqr));
+ float deltaAbs = Mathf.Abs(Mathf.DeltaAngle(orbitAngles.y, headingAngle));
+ float rotationChange = rotationSpeed * Mathf.Min(Time.unscaledDeltaTime, movementDeltaSqr);
+ if(deltaAbs < alignSmoothRange)
+ rotationChange *= deltaAbs / alignSmoothRange;
+ else if(180f - deltaAbs < alignSmoothRange)
+ rotationChange *= (180f - deltaAbs) / alignSmoothRange;
+ orbitAngles.y = Mathf.MoveTowardsAngle(orbitAngles.y, headingAngle, rotationChange);
+
+ return true;
+ }
+
+ Vector3 CameraHalfExtends
+ {
+ get
+ {
+ Vector3 halfExtends;
+ halfExtends.y =
+ regularCamera.nearClipPlane *
+ Mathf.Tan(0.5f * Mathf.Deg2Rad * regularCamera.fieldOfView);
+ halfExtends.x = halfExtends.y * regularCamera.aspect;
+ halfExtends.z = 0f;
+ return halfExtends;
+ }
+ }
+
+ static float GetAngle (Vector2 direction)
+ {
+ float angle = Mathf.Acos(direction.y) * Mathf.Rad2Deg;
+ return direction.x < 0f ? 360f - angle : angle;
+ }
+
+ // Santizes inspector configuration
+ void OnValidate()
+ {
+ if(maxVerticalAngle < minVerticalAngle)
+ maxVerticalAngle = minVerticalAngle;
+ }
+}
diff --git a/Assets/Scripts/OrbitCamera.cs.meta b/Assets/Scripts/OrbitCamera.cs.meta new file mode 100644 index 0000000..d560811 --- /dev/null +++ b/Assets/Scripts/OrbitCamera.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36c86d11be8a51812b882ba4c4be645a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |
