implementation of drecon in unity 2022 lts
forked from:
https://github.com/joanllobera/marathon-envs
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
357 lines
13 KiB
357 lines
13 KiB
|
|
using UnityEngine;
|
|
|
|
|
|
public class AnimationController : MonoBehaviour, IAnimationController
|
|
{
|
|
public float MaxForwardVelocity = 1f; // Max run speed.
|
|
public float MinTurnVelocity = 400f; // Turn velocity when moving at maximum speed.
|
|
public float MaxTurnVelocity = 1400f; // Turn velocity when stationary.
|
|
public float JumpSpeed = 5f; //
|
|
public bool debugForceJump;
|
|
|
|
|
|
[SerializeField]
|
|
Animator _anim;
|
|
|
|
|
|
[SerializeField]
|
|
CharacterController _characterController;
|
|
|
|
|
|
[SerializeField]
|
|
InputController _inputController;
|
|
|
|
bool _isGrounded;
|
|
bool _previouslyGrounded;
|
|
const float kAirborneTurnSpeedProportion = 5.4f;
|
|
const float kGroundTurnSpeedProportion = 200f / 2;
|
|
const float kGroundedRayDistance = 1f;
|
|
const float kJumpAbortSpeed = 10f;
|
|
|
|
const float kInverseOneEighty = 1f / 180f;
|
|
const float kStickingGravityProportion = 0.3f;
|
|
|
|
float _forwardVelocity;
|
|
Vector3 _lastGroundForwardVelocity;
|
|
float _desiredForwardSpeed;
|
|
float _verticalVelocity = -1f;
|
|
|
|
Quaternion _targetDirection; // direction we want to move towards
|
|
float _angleDiff; // delta between targetRotation and current roataion
|
|
Quaternion _targetRotation;
|
|
bool _readyToJump;
|
|
bool _inCombo;
|
|
|
|
[SerializeField]
|
|
Material materialUnderFoot;
|
|
|
|
public LayerMask IgnoreLayers;
|
|
|
|
|
|
[Tooltip("for debugging, we disable this when setTpose in MarathonTestBedController is on")]
|
|
public bool doFixedUpdate = true;
|
|
|
|
protected bool IsMoveInput
|
|
{
|
|
get { return !Mathf.Approximately(_inputController.MovementVector.sqrMagnitude, 0f); }
|
|
}
|
|
|
|
public void OnEnable()
|
|
{
|
|
|
|
OnAgentInitialize();
|
|
}
|
|
|
|
|
|
//TODO: this is also called from RagdollAgent004. Dependency should be removed, somehow.
|
|
public void OnAgentInitialize()
|
|
{
|
|
if (!_anim)
|
|
_anim = GetComponent<Animator>();
|
|
|
|
if (!_characterController)
|
|
_characterController = GetComponent<CharacterController>();
|
|
|
|
|
|
if (!_inputController) //if it is used without a ragdoll agent (for example, for ROM extraction), we still need to initialize it
|
|
_inputController = GetComponent<InputController>();
|
|
|
|
|
|
_targetDirection = Quaternion.Euler(0, 90, 0);
|
|
|
|
|
|
|
|
//Moved to Training Environment Generator
|
|
/*
|
|
var ragDoll = _spawnableEnv.GetComponentInChildren<RagDollAgent>( true);//we include inactive childs
|
|
if (ragDoll)//in the ROM extraction case we do not have any ragdoll agent
|
|
{
|
|
_layerMask = 1 << ragDoll.gameObject.layer;
|
|
_layerMask |= 1 << this.gameObject.layer;
|
|
_layerMask = ~(_layerMask);
|
|
}
|
|
|
|
*/
|
|
}
|
|
public Vector3 GetDesiredVelocity()
|
|
{
|
|
Vector3 desiredVelocity = new Vector3(
|
|
_inputController.DesiredHorizontalVelocity.x,
|
|
0f,
|
|
_inputController.DesiredHorizontalVelocity.y);
|
|
return desiredVelocity;
|
|
}
|
|
|
|
void FixedUpdate()
|
|
{
|
|
OnFixedUpdate();
|
|
}
|
|
|
|
|
|
void OnFixedUpdate()
|
|
{
|
|
// RotateTarget(Time.fixedDeltaTime);
|
|
SetTargetFromMoveInput();
|
|
CalculateForwardMovement(Time.fixedDeltaTime);
|
|
CalculateVerticalMovement(Time.fixedDeltaTime);
|
|
|
|
if (this.IsMoveInput)
|
|
SetTargetRotation();
|
|
|
|
UpdateOrientation(Time.fixedDeltaTime);
|
|
|
|
// PlayAudio();
|
|
|
|
// TimeoutToIdle();
|
|
|
|
_previouslyGrounded = _isGrounded;
|
|
}
|
|
|
|
public void OnReset()
|
|
{
|
|
}
|
|
void OldOnReset()
|
|
{
|
|
_isGrounded = true;
|
|
_previouslyGrounded = true;
|
|
_inCombo = false;
|
|
_readyToJump = false;
|
|
_forwardVelocity = 0f;
|
|
_lastGroundForwardVelocity = Vector3.zero;
|
|
_desiredForwardSpeed = 0f;
|
|
_verticalVelocity = 0f;
|
|
_angleDiff = 0f;
|
|
|
|
if (!doFixedUpdate)
|
|
return;
|
|
|
|
_anim.SetBool("onGround", _isGrounded);
|
|
// _anim.SetFloat("verticalVelocity", _verticalVelocity);
|
|
_anim.SetFloat("angleDeltaRad", _angleDiff * Mathf.Deg2Rad);
|
|
_anim.SetFloat("forwardVelocity", _forwardVelocity);
|
|
_anim.SetBool("backflip", false);
|
|
_anim.Rebind();
|
|
_anim.SetBool("onGround", _isGrounded);
|
|
// _anim.SetFloat("verticalVelocity", _verticalVelocity);
|
|
_anim.SetFloat("angleDeltaRad", _angleDiff * Mathf.Deg2Rad);
|
|
_anim.SetFloat("forwardVelocity", _forwardVelocity);
|
|
_anim.SetBool("backflip", false);
|
|
|
|
|
|
OnFixedUpdate();
|
|
_anim.Update(0f);
|
|
}
|
|
|
|
|
|
// Called each physics step (so long as the Animator component is set to Animate Physics) after FixedUpdate to override root motion.
|
|
void OnAnimatorMove()
|
|
{
|
|
if (_anim == null)
|
|
return;
|
|
Vector3 movement;
|
|
float verticalVelocity = _verticalVelocity;
|
|
if (_isGrounded)
|
|
{
|
|
// find ground
|
|
RaycastHit hit;
|
|
var rayStart = transform.position + ((Vector3.up * kGroundedRayDistance) * 0.5f);
|
|
Ray ray = new Ray(rayStart, -Vector3.up);
|
|
if (Physics.Raycast(ray, out hit, kGroundedRayDistance, ~IgnoreLayers, QueryTriggerInteraction.Ignore))
|
|
{
|
|
// project velocity on plane
|
|
movement = _anim.deltaPosition;
|
|
movement.y = 0f;
|
|
movement = Vector3.ProjectOnPlane(_anim.deltaPosition, hit.normal);
|
|
|
|
// store material under foot
|
|
Renderer groundRenderer = hit.collider.GetComponentInChildren<Renderer>();
|
|
materialUnderFoot = groundRenderer ? groundRenderer.sharedMaterial : null;
|
|
}
|
|
else
|
|
{
|
|
// fail safe incase ray does not collide
|
|
movement = _anim.deltaPosition;
|
|
materialUnderFoot = null;
|
|
}
|
|
_lastGroundForwardVelocity = movement / Time.fixedDeltaTime;
|
|
}
|
|
else
|
|
{
|
|
movement = _lastGroundForwardVelocity * Time.fixedDeltaTime;
|
|
}
|
|
// Rotate the transform of the character controller by the animation's root rotation.
|
|
_characterController.transform.rotation *= _anim.deltaRotation;
|
|
// print ($"delta:{_anim.deltaPosition.magnitude} movement:{movement.magnitude} delta:{_anim.deltaPosition} movement:{movement}");
|
|
|
|
// Add to the movement with the calculated vertical speed.
|
|
movement += verticalVelocity * Vector3.up * Time.fixedDeltaTime;
|
|
|
|
// Move the character controller.
|
|
_characterController.Move(movement);
|
|
|
|
// After the movement store whether or not the character controller is grounded.
|
|
_isGrounded = _characterController.isGrounded;
|
|
|
|
// If Ellen is not on the ground then send the vertical speed to the animator.
|
|
// This is so the vertical speed is kept when landing so the correct landing animation is played.
|
|
|
|
if (!_isGrounded)
|
|
_anim.SetFloat("verticalVelocity", verticalVelocity);
|
|
|
|
// Send whether or not Ellen is on the ground to the animator.
|
|
_anim.SetBool("onGround", _isGrounded);
|
|
}
|
|
|
|
void RotateTarget(float deltaTime)
|
|
{
|
|
if (!Mathf.Approximately(_inputController.CameraRotation.x * _inputController.CameraRotation.x, 0f))
|
|
{
|
|
float roation = _targetDirection.eulerAngles.y;
|
|
float delta = _inputController.CameraRotation.x * kGroundTurnSpeedProportion * deltaTime;
|
|
roation += delta;
|
|
// print($"{_targetDirection.eulerAngles.y} delta:{delta}, {roation}");
|
|
_targetDirection = Quaternion.Euler(0f, roation, 0f);
|
|
}
|
|
}
|
|
void SetTargetFromMoveInput()
|
|
{
|
|
if (!_inputController) //if it is used without a ragdoll agent (for example, for ROM extraction), we still need to initialize it
|
|
OnAgentInitialize();
|
|
|
|
Vector2 moveInput = _inputController.MovementVector;
|
|
Vector3 localMovementDirection = new Vector3(moveInput.x, 0f, moveInput.y).normalized;
|
|
_targetDirection = Quaternion.Euler(localMovementDirection);
|
|
}
|
|
|
|
void SetTargetRotation()
|
|
{
|
|
// Create three variables, move input local to the player, flattened forward direction of the camera and a local target rotation.
|
|
Vector2 moveInput = _inputController.MovementVector;
|
|
Vector3 localMovementDirection = new Vector3(moveInput.x, 0f, moveInput.y).normalized;
|
|
|
|
Vector3 forward = _targetDirection * Vector3.forward;
|
|
forward.y = 0f;
|
|
forward.Normalize();
|
|
|
|
Quaternion targetRotation;
|
|
|
|
// // If the local movement direction is the opposite of forward then the target rotation should be towards the camera.
|
|
// if (Mathf.Approximately(Vector3.Dot(localMovementDirection, Vector3.forward), -1.0f))
|
|
// {
|
|
// targetRotation = Quaternion.LookRotation(-forward);
|
|
// }
|
|
// else
|
|
// {
|
|
// // Otherwise the rotation should be the offset of the input from the camera's forward.
|
|
// Quaternion cameraToInputOffset = Quaternion.FromToRotation(Vector3.forward, localMovementDirection);
|
|
// targetRotation = Quaternion.LookRotation(cameraToInputOffset * forward);
|
|
// }
|
|
// targetRotation = Quaternion.LookRotation(-forward);
|
|
Quaternion cameraToInputOffset = Quaternion.FromToRotation(Vector3.forward, localMovementDirection);
|
|
targetRotation = Quaternion.LookRotation(cameraToInputOffset * forward);
|
|
|
|
|
|
// The desired forward direction.
|
|
Vector3 resultingForward = targetRotation * Vector3.forward;
|
|
|
|
// Find the difference between the current rotation of the player and the desired rotation of the player in radians.
|
|
float angleCurrent = Mathf.Atan2(transform.forward.x, transform.forward.z) * Mathf.Rad2Deg;
|
|
float targetAngle = Mathf.Atan2(resultingForward.x, resultingForward.z) * Mathf.Rad2Deg;
|
|
|
|
_angleDiff = Mathf.DeltaAngle(angleCurrent, targetAngle);
|
|
_targetRotation = targetRotation;
|
|
}
|
|
void UpdateOrientation(float deltaTime)
|
|
{
|
|
_anim.SetFloat("angleDeltaRad", _angleDiff * Mathf.Deg2Rad);
|
|
|
|
Vector3 localInput = new Vector3(_inputController.MovementVector.x, 0f, _inputController.MovementVector.y);
|
|
float groundedTurnSpeed = Mathf.Lerp(MaxTurnVelocity, MinTurnVelocity, _forwardVelocity / _desiredForwardSpeed);
|
|
float actualTurnSpeed = _isGrounded ? groundedTurnSpeed : Vector3.Angle(transform.forward, localInput) * kInverseOneEighty * kAirborneTurnSpeedProportion * groundedTurnSpeed;
|
|
_targetRotation = Quaternion.RotateTowards(transform.rotation, _targetRotation, actualTurnSpeed * deltaTime);
|
|
bool hasNan = float.IsNaN(_targetRotation.x) || float.IsNaN(_targetRotation.y) || float.IsNaN(_targetRotation.z);
|
|
if (!hasNan)
|
|
transform.rotation = _targetRotation;
|
|
}
|
|
|
|
void CalculateForwardMovement(float deltaTime)
|
|
{
|
|
// Cache the move input and cap it's magnitude at 1.
|
|
Vector2 moveInput = _inputController.MovementVector;
|
|
if (moveInput.sqrMagnitude > 1f)
|
|
moveInput.Normalize();
|
|
|
|
// Calculate the speed intended by input.
|
|
_desiredForwardSpeed = moveInput.magnitude * MaxForwardVelocity;
|
|
|
|
// Note: acceleration is handle in InputController
|
|
_forwardVelocity = _desiredForwardSpeed;
|
|
|
|
// Set the animator parameter to control what animation is being played.
|
|
_anim.SetFloat("forwardVelocity", _forwardVelocity);
|
|
}
|
|
void CalculateVerticalMovement(float deltaTime)
|
|
{
|
|
// If jump is not currently held and is on the ground then ready to jump.
|
|
if (!_inputController.Jump && _isGrounded)
|
|
_readyToJump = true;
|
|
|
|
_anim.SetBool("backflip", _inputController.Backflip);
|
|
|
|
if (_isGrounded)
|
|
{
|
|
// When grounded we apply a slight negative vertical speed to make Ellen "stick" to the ground.
|
|
_verticalVelocity = Physics.gravity.y * kStickingGravityProportion;
|
|
|
|
// If jump is held, Ellen is ready to jump and not currently in the middle of a melee combo...
|
|
if (_inputController.Jump && _readyToJump && !_inCombo)
|
|
{
|
|
// ... then override the previously set vertical speed and make sure she cannot jump again.
|
|
_verticalVelocity = JumpSpeed;
|
|
_isGrounded = false;
|
|
_readyToJump = false;
|
|
_anim.SetBool("onGround", false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If Ellen is airborne, the jump button is not held and Ellen is currently moving upwards...
|
|
if (!_inputController.Jump && _verticalVelocity > 0.0f)
|
|
{
|
|
// ... decrease Ellen's vertical speed.
|
|
// This is what causes holding jump to jump higher that tapping jump.
|
|
_verticalVelocity -= kJumpAbortSpeed * deltaTime;
|
|
}
|
|
|
|
// If a jump is approximately peaking, make it absolute.
|
|
if (Mathf.Approximately(_verticalVelocity, 0f))
|
|
{
|
|
_verticalVelocity = 0f;
|
|
}
|
|
|
|
// If Ellen is airborne, apply gravity.
|
|
_verticalVelocity += Physics.gravity.y * deltaTime;
|
|
}
|
|
}
|
|
}
|