From Physics
This commit is contained in:
155
Assets/Scripts/MovingSphere.cs
Normal file
155
Assets/Scripts/MovingSphere.cs
Normal file
@ -0,0 +1,155 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class MovingSphere : MonoBehaviour
|
||||
{
|
||||
[SerializeField, Range(0f, 100f)]
|
||||
private float maxSpeed = 10f;
|
||||
|
||||
[SerializeField, Range(0f, 100f)]
|
||||
private float maxAcceleration = 10f, maxAirAcceleration = 1f;
|
||||
|
||||
[SerializeField, Range(0f, 10f)]
|
||||
private float jumpHeight = 2f;
|
||||
|
||||
[SerializeField, Range(0, 5)]
|
||||
private int maxAirJumps = 0;
|
||||
|
||||
[SerializeField, Range(0f, 90f)]
|
||||
private float maxGroundAngle = 25f;
|
||||
|
||||
private Rigidbody body;
|
||||
|
||||
private Vector3 desiredVelocity = new Vector3(0f, 0f, 0f);
|
||||
private bool desiredJump = false;
|
||||
|
||||
private int groundContactCount;
|
||||
private bool onGround => groundContactCount > 0;
|
||||
private int jumpPhase;
|
||||
private Vector3 velocity;
|
||||
private Vector3 contactNormal;
|
||||
private float minGroundDotProduct;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
minGroundDotProduct = Mathf.Cos(maxGroundAngle * Mathf.Deg2Rad);
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
body = GetComponent<Rigidbody>();
|
||||
OnValidate();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
Vector2 playerInput;
|
||||
playerInput.x = Input.GetAxis("Horizontal");
|
||||
playerInput.y = Input.GetAxis("Vertical");
|
||||
playerInput = Vector2.ClampMagnitude(playerInput, 1f);
|
||||
desiredVelocity = new Vector3(playerInput.x, 0f, playerInput.y) * maxSpeed;
|
||||
|
||||
desiredJump |= Input.GetButtonDown("Jump");
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
UpdateState();
|
||||
|
||||
AdjustVelocity();
|
||||
|
||||
if (desiredJump)
|
||||
{
|
||||
desiredJump = false;
|
||||
Jump();
|
||||
}
|
||||
|
||||
body.velocity = velocity;
|
||||
|
||||
ClearState();
|
||||
}
|
||||
|
||||
private void UpdateState()
|
||||
{
|
||||
velocity = body.velocity;
|
||||
if (onGround)
|
||||
{
|
||||
jumpPhase = 0;
|
||||
if (groundContactCount > 1)
|
||||
{
|
||||
contactNormal.Normalize();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
contactNormal = Vector3.up;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCollisionEnter(Collision collision)
|
||||
{
|
||||
EvaluateCollision(collision);
|
||||
}
|
||||
|
||||
private void OnCollisionStay(Collision collision)
|
||||
{
|
||||
EvaluateCollision(collision);
|
||||
}
|
||||
|
||||
private void EvaluateCollision(Collision collision)
|
||||
{
|
||||
for (int i = 0; i < collision.contactCount; i++)
|
||||
{
|
||||
var normal = collision.GetContact(i).normal;
|
||||
if (normal.y >= minGroundDotProduct)
|
||||
{
|
||||
groundContactCount += 1;
|
||||
contactNormal += normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Jump()
|
||||
{
|
||||
if (onGround || jumpPhase < maxAirJumps)
|
||||
{
|
||||
jumpPhase++;
|
||||
float jumpSpeed = Mathf.Sqrt(-2f * Physics.gravity.y * jumpHeight);
|
||||
float alignedSpeed = Vector3.Dot(velocity, contactNormal);
|
||||
if (alignedSpeed > 0f)
|
||||
{
|
||||
jumpSpeed = Mathf.Max(jumpSpeed - alignedSpeed, 0f);
|
||||
}
|
||||
velocity += contactNormal * jumpSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
private void AdjustVelocity()
|
||||
{
|
||||
Vector3 xAxis = ProjectOnContactPlane(Vector3.right).normalized;
|
||||
Vector3 zAxis = ProjectOnContactPlane(Vector3.forward).normalized;
|
||||
|
||||
float currentX = Vector3.Dot(velocity, xAxis);
|
||||
float currentZ = Vector3.Dot(velocity, zAxis);
|
||||
|
||||
float acceleration = onGround ? maxAcceleration : maxAirAcceleration;
|
||||
float maxSpeedChange = acceleration * Time.deltaTime;
|
||||
|
||||
float newX =
|
||||
Mathf.MoveTowards(currentX, desiredVelocity.x, maxSpeedChange);
|
||||
float newZ =
|
||||
Mathf.MoveTowards(currentZ, desiredVelocity.z, maxSpeedChange);
|
||||
|
||||
velocity += xAxis * (newX - currentX) + zAxis * (newZ - currentZ);
|
||||
}
|
||||
|
||||
private Vector3 ProjectOnContactPlane(Vector3 vector)
|
||||
{
|
||||
return vector - contactNormal * Vector3.Dot(vector, contactNormal);
|
||||
}
|
||||
|
||||
void ClearState()
|
||||
{
|
||||
groundContactCount = 0;
|
||||
contactNormal = Vector3.zero;
|
||||
}
|
||||
}
|
11
Assets/Scripts/MovingSphere.cs.meta
Normal file
11
Assets/Scripts/MovingSphere.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50beb4685c906ba49b7db3438cc30dfc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user