using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace KinematicCharacterController
{
///
/// Represents the entire state of a PhysicsMover that is pertinent for simulation.
/// Use this to save state or revert to past state
///
[System.Serializable]
public struct PhysicsMoverState
{
public Vector3 Position;
public Quaternion Rotation;
public Vector3 Velocity;
public Vector3 AngularVelocity;
}
///
/// Component that manages the movement of moving kinematic rigidbodies for
/// proper interaction with characters
///
[RequireComponent(typeof(Rigidbody))]
public class PhysicsMover : MonoBehaviour
{
///
/// The mover's Rigidbody
///
[ReadOnly]
public Rigidbody Rigidbody;
///
/// Determines if the platform moves with rigidbody.MovePosition (when true), or with rigidbody.position (when false)
///
public bool MoveWithPhysics = true;
///
/// Index of this motor in KinematicCharacterSystem arrays
///
[NonSerialized]
public IMoverController MoverController;
///
/// Remembers latest position in interpolation
///
[NonSerialized]
public Vector3 LatestInterpolationPosition;
///
/// Remembers latest rotation in interpolation
///
[NonSerialized]
public Quaternion LatestInterpolationRotation;
///
/// The latest movement made by interpolation
///
[NonSerialized]
public Vector3 PositionDeltaFromInterpolation;
///
/// The latest rotation made by interpolation
///
[NonSerialized]
public Quaternion RotationDeltaFromInterpolation;
///
/// Index of this motor in KinematicCharacterSystem arrays
///
public int IndexInCharacterSystem { get; set; }
///
/// Remembers initial position before all simulation are done
///
public Vector3 Velocity { get; protected set; }
///
/// Remembers initial position before all simulation are done
///
public Vector3 AngularVelocity { get; protected set; }
///
/// Remembers initial position before all simulation are done
///
public Vector3 InitialTickPosition { get; set; }
///
/// Remembers initial rotation before all simulation are done
///
public Quaternion InitialTickRotation { get; set; }
///
/// The mover's Transform
///
public Transform Transform { get; private set; }
///
/// The character's position before the movement calculations began
///
public Vector3 InitialSimulationPosition { get; private set; }
///
/// The character's rotation before the movement calculations began
///
public Quaternion InitialSimulationRotation { get; private set; }
private Vector3 _internalTransientPosition;
///
/// The mover's rotation (always up-to-date during the character update phase)
///
public Vector3 TransientPosition
{
get
{
return _internalTransientPosition;
}
private set
{
_internalTransientPosition = value;
}
}
private Quaternion _internalTransientRotation;
///
/// The mover's rotation (always up-to-date during the character update phase)
///
public Quaternion TransientRotation
{
get
{
return _internalTransientRotation;
}
private set
{
_internalTransientRotation = value;
}
}
private void Reset()
{
ValidateData();
}
private void OnValidate()
{
ValidateData();
}
///
/// Handle validating all required values
///
public void ValidateData()
{
Rigidbody = gameObject.GetComponent();
Rigidbody.centerOfMass = Vector3.zero;
Rigidbody.maxAngularVelocity = Mathf.Infinity;
Rigidbody.maxDepenetrationVelocity = Mathf.Infinity;
Rigidbody.isKinematic = true;
Rigidbody.interpolation = RigidbodyInterpolation.None;
}
private void OnEnable()
{
KinematicCharacterSystem.EnsureCreation();
KinematicCharacterSystem.RegisterPhysicsMover(this);
}
private void OnDisable()
{
KinematicCharacterSystem.UnregisterPhysicsMover(this);
}
private void Awake()
{
Transform = this.transform;
ValidateData();
TransientPosition = Rigidbody.position;
TransientRotation = Rigidbody.rotation;
InitialSimulationPosition = Rigidbody.position;
InitialSimulationRotation = Rigidbody.rotation;
LatestInterpolationPosition = Transform.position;
LatestInterpolationRotation = Transform.rotation;
}
///
/// Sets the mover's position directly
///
public void SetPosition(Vector3 position)
{
Transform.position = position;
Rigidbody.position = position;
InitialSimulationPosition = position;
TransientPosition = position;
}
///
/// Sets the mover's rotation directly
///
public void SetRotation(Quaternion rotation)
{
Transform.rotation = rotation;
Rigidbody.rotation = rotation;
InitialSimulationRotation = rotation;
TransientRotation = rotation;
}
///
/// Sets the mover's position and rotation directly
///
public void SetPositionAndRotation(Vector3 position, Quaternion rotation)
{
Transform.SetPositionAndRotation(position, rotation);
Rigidbody.position = position;
Rigidbody.rotation = rotation;
InitialSimulationPosition = position;
InitialSimulationRotation = rotation;
TransientPosition = position;
TransientRotation = rotation;
}
///
/// Returns all the state information of the mover that is pertinent for simulation
///
public PhysicsMoverState GetState()
{
PhysicsMoverState state = new PhysicsMoverState();
state.Position = TransientPosition;
state.Rotation = TransientRotation;
state.Velocity = Velocity;
state.AngularVelocity = AngularVelocity;
return state;
}
///
/// Applies a mover state instantly
///
public void ApplyState(PhysicsMoverState state)
{
SetPositionAndRotation(state.Position, state.Rotation);
Velocity = state.Velocity;
AngularVelocity = state.AngularVelocity;
}
///
/// Caches velocity values based on deltatime and target position/rotations
///
public void VelocityUpdate(float deltaTime)
{
InitialSimulationPosition = TransientPosition;
InitialSimulationRotation = TransientRotation;
MoverController.UpdateMovement(out _internalTransientPosition, out _internalTransientRotation, deltaTime);
if (deltaTime > 0f)
{
Velocity = (TransientPosition - InitialSimulationPosition) / deltaTime;
Quaternion rotationFromCurrentToGoal = TransientRotation * (Quaternion.Inverse(InitialSimulationRotation));
AngularVelocity = (Mathf.Deg2Rad * rotationFromCurrentToGoal.eulerAngles) / deltaTime;
}
}
}
}