497 lines
22 KiB
C#
497 lines
22 KiB
C#
![]() |
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Concurrent;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
using System.Threading;
|
||
|
using Animancer;
|
||
|
using BITKit;
|
||
|
using BITKit.Entities;
|
||
|
using BITKit.Pool;
|
||
|
using Cysharp.Threading.Tasks;
|
||
|
using Microsoft.Extensions.Logging;
|
||
|
using Net.Project.B.Health;
|
||
|
using Net.Project.B.Inventory;
|
||
|
using NodeCanvas.Framework;
|
||
|
using Project.B.Animation;
|
||
|
using Project.B.CharacterController;
|
||
|
using Unity.Mathematics;
|
||
|
using UnityEngine;
|
||
|
using Object = UnityEngine.Object;
|
||
|
|
||
|
namespace Project.B.Animation
|
||
|
{
|
||
|
public class PlayerAnimancerController:IDisposable
|
||
|
{
|
||
|
public int Layer;
|
||
|
public AnimancerComponent AnimancerComponent;
|
||
|
private readonly Transform _transform;
|
||
|
private readonly GameObject _gameObject;
|
||
|
private readonly IPlayerWeaponInventory _weaponInventory;
|
||
|
private readonly IPlayerCharacterController _playerCharacterController;
|
||
|
private readonly ICharacterController _characterController;
|
||
|
private readonly IHumanoidTransitionAnimationFactory _transitionAnimationFactory;
|
||
|
private readonly IPlayerAnimationFactory _playerAnimationFactory;
|
||
|
private readonly ITicker _ticker;
|
||
|
|
||
|
private readonly IWrapper<float2> _idleAnimation;
|
||
|
private readonly IWrapper<float2> _walkAnimation;
|
||
|
private readonly IWrapper<float2> _crouchedAnimation;
|
||
|
private readonly IWrapper<float2> _knockedAnimation;
|
||
|
private readonly IWrapper<float> _runAnimation;
|
||
|
private readonly IWrapper<float> _sprintAnimation;
|
||
|
private readonly IEntity _entity;
|
||
|
|
||
|
private readonly IWrapper<float2> _idleToWalkWrapper;
|
||
|
private readonly IWrapper<float2> _idleTurnAnimation;
|
||
|
private readonly IWrapper<float2> _walkToIdleAnimation;
|
||
|
|
||
|
private readonly IWrapper<float> _ladderAnimation;
|
||
|
|
||
|
private readonly IWrapper<float> _climbingAnimation;
|
||
|
|
||
|
private readonly IWrapper<float2> _parachuteAnimation;
|
||
|
|
||
|
private readonly IWrapper<float> _swimmingAnimation;
|
||
|
|
||
|
private readonly IHealthService _healthService;
|
||
|
private readonly ILogger<PlayerAnimancerController> _logger;
|
||
|
|
||
|
private CancellationTokenSource _transitionCts;
|
||
|
|
||
|
|
||
|
public PlayerAnimancerController(AnimancerComponent animancerComponent, ICharacterController characterController, IPlayerAnimationFactory playerAnimationFactory, ITicker ticker, IEntity entity, GameObject gameObject, IPlayerWeaponInventory weaponInventory, IHealthService healthService, ILogger<PlayerAnimancerController> logger, IHumanoidTransitionAnimationFactory transitionAnimationFactory, IPlayerCharacterController playerCharacterController, Transform transform)
|
||
|
{
|
||
|
AnimancerComponent = animancerComponent;
|
||
|
_characterController = characterController;
|
||
|
_playerAnimationFactory = playerAnimationFactory;
|
||
|
_ticker = ticker;
|
||
|
_entity = entity;
|
||
|
_gameObject = gameObject;
|
||
|
_weaponInventory = weaponInventory;
|
||
|
_healthService = healthService;
|
||
|
_logger = logger;
|
||
|
_transitionAnimationFactory = transitionAnimationFactory;
|
||
|
_playerCharacterController = playerCharacterController;
|
||
|
_transform = transform;
|
||
|
|
||
|
|
||
|
|
||
|
_idleAnimation = playerAnimationFactory.CreateIdleAnimation();
|
||
|
_walkAnimation = playerAnimationFactory.CreateWalkAnimation();
|
||
|
_crouchedAnimation = playerAnimationFactory.CreateCrouchedAnimation();
|
||
|
_knockedAnimation = playerAnimationFactory.CreateKnockedAnimation();
|
||
|
_runAnimation = playerAnimationFactory.CreateRunAnimation();
|
||
|
_sprintAnimation = playerAnimationFactory.CreateSprintAnimation();
|
||
|
|
||
|
_ladderAnimation = _playerAnimationFactory.CreateLadderAnimation();
|
||
|
|
||
|
_climbingAnimation = _playerAnimationFactory.CreateClimbingAnimation();
|
||
|
|
||
|
_idleToWalkWrapper = transitionAnimationFactory.CreateIdleToWalk();
|
||
|
_idleTurnAnimation = transitionAnimationFactory.CreateIdleTurn();
|
||
|
_walkToIdleAnimation = transitionAnimationFactory.CreateWalkToIdle();
|
||
|
|
||
|
_parachuteAnimation = playerAnimationFactory.CreateParachuteAnimation();
|
||
|
|
||
|
_swimmingAnimation = playerAnimationFactory.CreateSwimmingAnimation();
|
||
|
|
||
|
_characterController.OnStateChanged += OnStateChanged;
|
||
|
ticker.Add(OnTick);
|
||
|
|
||
|
_healthService.OnHealthChanged += OnHealthChanged;
|
||
|
|
||
|
_playerCharacterController.AllowTpsCamera.AddListener(OnTPS);
|
||
|
|
||
|
// _logger.LogInformation("已创建Animancer控制器");
|
||
|
|
||
|
}
|
||
|
|
||
|
private void OnTPS(bool obj)
|
||
|
{
|
||
|
OnStateChanged(_characterController.CurrentState,_characterController.CurrentState);
|
||
|
}
|
||
|
|
||
|
private void OnHealthChanged(int arg1, int arg2, int arg3, object arg4)
|
||
|
{
|
||
|
if(arg1!=_entity.Id)return;
|
||
|
if (arg3 >= 0)
|
||
|
{
|
||
|
OnStateChanged(null, _characterController.CurrentState);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
private ICharacterState _currentState;
|
||
|
|
||
|
private void OnTick(float delta)
|
||
|
{
|
||
|
var velocity = _characterController.SelfVelocity;
|
||
|
|
||
|
if (_playerCharacterController.AllowTpsCamera.Allow)
|
||
|
{
|
||
|
velocity = (Quaternion)_characterController.ViewRotation * _playerCharacterController.MoveInput;
|
||
|
velocity = _transform.InverseTransformDirection(velocity);
|
||
|
}
|
||
|
|
||
|
AnimancerComponent.Layers[Layer].Speed = _characterController.CurrentState switch
|
||
|
{
|
||
|
(ICharacterStateWalk or ICharacterStateRun or ICharacterSprint) when _characterController.IsGrounded is false=>0.32f,
|
||
|
_ => 1
|
||
|
};
|
||
|
|
||
|
switch (_characterController.CurrentState)
|
||
|
{
|
||
|
case ICharacterStateWalk:
|
||
|
_walkAnimation.Value =math.lerp(_walkAnimation.Value,new Vector2(velocity.x, velocity.z),16*Time.deltaTime);
|
||
|
break;
|
||
|
case ICharacterStateCrouched:
|
||
|
_crouchedAnimation.Value =math.lerp(_crouchedAnimation.Value,new Vector2(velocity.x, velocity.z),16*Time.deltaTime);
|
||
|
break;
|
||
|
case ICharacterStateRun:
|
||
|
{
|
||
|
if (_characterController.CurrentState is ICharacterStateData data)
|
||
|
{
|
||
|
_runAnimation.Value = _playerCharacterController.AllowTpsCamera.Allow ? 1 : _characterController.SelfVelocity.z / data.BaseSpeed;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case ICharacterSprint:
|
||
|
{
|
||
|
if (_characterController.CurrentState is ICharacterStateData data)
|
||
|
{
|
||
|
_sprintAnimation.Value =_playerCharacterController.AllowTpsCamera.Allow ? 1 : _characterController.SelfVelocity.z / data.BaseSpeed;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case ICharacterLadder:
|
||
|
{
|
||
|
_ladderAnimation.Value = Mathf.Lerp( _ladderAnimation.Value , _playerCharacterController.MoveInput.z,2*delta);
|
||
|
}
|
||
|
break;
|
||
|
case ICharacterKnocked:
|
||
|
_knockedAnimation.Value = new Vector2(velocity.x, velocity.z);
|
||
|
break;
|
||
|
case ICharacterStateClimb:
|
||
|
{
|
||
|
_climbingAnimation.Value = Mathf.Lerp(_climbingAnimation.Value,
|
||
|
_playerCharacterController.MoveInput.x, 2 * delta);
|
||
|
}
|
||
|
break;
|
||
|
case ICharacterParachute:
|
||
|
{
|
||
|
var v = _playerCharacterController.CharacterController.SelfVelocity;
|
||
|
_parachuteAnimation.Value = math.lerp(_parachuteAnimation.Value,new(v.x,v.y)
|
||
|
, 2 * delta);
|
||
|
}
|
||
|
break;
|
||
|
case ICharacterSwimming:
|
||
|
{
|
||
|
var v = _playerCharacterController.CharacterController.SelfVelocity;
|
||
|
_swimmingAnimation.Value =math.clamp(math.lerp(_swimmingAnimation.Value,MathV.GetLength(v), 2 * delta),0,1) ;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
if (_playerCharacterController.AllowTpsCamera.Allow )
|
||
|
{
|
||
|
switch (_characterController.CurrentState)
|
||
|
{
|
||
|
case ICharacterStateWalk:
|
||
|
case ICharacterStateRun:
|
||
|
case ICharacterSprint:
|
||
|
{
|
||
|
if(((Vector3)velocity).GetLength()<0.1f)break;
|
||
|
|
||
|
var targetRotation =Quaternion.LookRotation(
|
||
|
Vector3.ProjectOnPlane((Quaternion)_characterController.ViewRotation * _playerCharacterController.MoveInput, Vector3.up));
|
||
|
|
||
|
var currentRotation = _characterController.Rotation;
|
||
|
|
||
|
_characterController.Rotation = Quaternion.Lerp(currentRotation, targetRotation, _transitionCts is {IsCancellationRequested:true} ? 2 * delta : delta);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private async void OnStateChanged(ICharacterState arg1, ICharacterState arg2)
|
||
|
{
|
||
|
_playerCharacterController.ForceRootMotion.SetElements(this,_playerCharacterController.AllowTpsCamera.Allow && arg2 switch
|
||
|
{
|
||
|
ICharacterStateWalk=>true,
|
||
|
ICharacterStateRun=>true,
|
||
|
ICharacterStateIdle=>true,
|
||
|
ICharacterSprint=>true,
|
||
|
_=>false,
|
||
|
} && _playerCharacterController.CharacterController.IsGrounded);
|
||
|
|
||
|
if(Equals(_currentState,arg2))return;
|
||
|
|
||
|
_transitionCts?.Cancel();
|
||
|
_transitionCts = new CancellationTokenSource();
|
||
|
|
||
|
if (arg2 is null)
|
||
|
{
|
||
|
AnimancerComponent.Layers[Layer].Stop();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
_playerCharacterController.ForceRootMotion.SetElements(15616,
|
||
|
arg2 switch
|
||
|
{
|
||
|
ICharacterLadder=>true,
|
||
|
ICharacterStateClimb=>true,
|
||
|
_=>false,
|
||
|
});
|
||
|
|
||
|
var velocity = _characterController.SelfVelocity;
|
||
|
|
||
|
_currentState = arg2;
|
||
|
|
||
|
var fadeDuration = (arg1, arg2)
|
||
|
switch
|
||
|
{
|
||
|
(ICharacterStateStepUp,_)=>0.32f,
|
||
|
(ICharacterStateClimb,_)=>0.32f,
|
||
|
(ICharacterSliding,not ICharacterSliding)=>0.32f,
|
||
|
_ => 0.1f
|
||
|
};
|
||
|
|
||
|
if (_playerCharacterController.AllowTpsCamera.Allow)
|
||
|
{
|
||
|
switch (arg1,arg2)
|
||
|
{
|
||
|
|
||
|
case (ICharacterStateIdle,ICharacterStateWalk):
|
||
|
|
||
|
var dir = (Quaternion)_characterController.ViewRotation * _playerCharacterController.MoveInput;
|
||
|
|
||
|
var direction = (Vector3)_characterController.Position + dir;
|
||
|
direction = Vector3.ProjectOnPlane(_transform.InverseTransformPoint(direction), Vector3.up)
|
||
|
;
|
||
|
|
||
|
_idleToWalkWrapper.Value = new(direction.x, direction.z);
|
||
|
|
||
|
try
|
||
|
{
|
||
|
using var wait = _playerCharacterController.ForceRootMotion.GetHandle();
|
||
|
|
||
|
var walkState = AnimancerComponent.Layers[Layer].Play(_idleToWalkWrapper.Obj as AnimancerState, 0.2f);
|
||
|
// walkState.Time = 0.2f;
|
||
|
await walkState.WithCancellation(_transitionCts.Token);
|
||
|
}
|
||
|
catch (OperationCanceledException)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case (ICharacterStateRun or ICharacterSprint, ICharacterStateIdle):
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
await AnimancerComponent.Layers[Layer].Play(_transitionAnimationFactory.CreateRunToIdle() as AnimationClip);
|
||
|
}
|
||
|
catch (OperationCanceledException)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case (ICharacterStateWalk, ICharacterStateIdle):
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
_walkToIdleAnimation.Value = new(0, 1);
|
||
|
await AnimancerComponent.Layers[Layer].Play(_walkToIdleAnimation.Obj as AnimancerState, 0.2f).WithCancellation(_transitionCts.Token);
|
||
|
}
|
||
|
catch (OperationCanceledException)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (arg1,arg2)
|
||
|
{
|
||
|
case (ICharacterKnocked, _):
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
using var wait = _playerCharacterController.ForceRootMotion.GetHandle();
|
||
|
using var disable = _playerCharacterController.DisableStateTransition.GetHandle();
|
||
|
|
||
|
var walkState = AnimancerComponent.Layers[Layer]
|
||
|
.Play(_playerAnimationFactory.CreateRevivedAnimation() as AnimationClip, 0.2f);
|
||
|
// walkState.Time = 0.2f;
|
||
|
await walkState.WithCancellation(_transitionCts.Token);
|
||
|
}
|
||
|
catch (OperationCanceledException)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case (ICharacterStateClimb, ICharacterStateStepUp):
|
||
|
{
|
||
|
using var waiter = _playerCharacterController.ForceRootMotion.GetHandle();
|
||
|
try
|
||
|
{
|
||
|
await AnimancerComponent.Layers[Layer]
|
||
|
.Play(_playerAnimationFactory.CreateClimbUpAnimation() as AnimationClip).WithCancellation(_transitionCts.Token);
|
||
|
_characterController.TransitionState<ICharacterStateIdle>();
|
||
|
}
|
||
|
catch (OperationCanceledException)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
case (_, ICharacterLadder):
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
await AnimancerComponent.Layers[Layer]
|
||
|
.Play(_playerAnimationFactory.CreateLadderEnterAnimation() as AnimationClip, 0.2f)
|
||
|
.WithCancellation(_transitionCts.Token);
|
||
|
await AnimancerComponent.Layers[Layer].Play(_ladderAnimation.Obj as AnimancerState).WithCancellation(_transitionCts.Token);
|
||
|
}
|
||
|
catch (OperationCanceledException)
|
||
|
{
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
case (ICharacterLadder ladder,ICharacterStateIdle):
|
||
|
{
|
||
|
using var c = _playerCharacterController.DisableCollision.GetHandle();
|
||
|
using var wait = _playerCharacterController.ForceRootMotion.GetHandle();
|
||
|
using var disable = _playerCharacterController.DisableStateTransition.GetHandle();
|
||
|
try
|
||
|
{
|
||
|
await AnimancerComponent.Layers[Layer]
|
||
|
.Play(_playerAnimationFactory.CreateLadderExitAnimation() as AnimationClip).WithCancellation(_transitionCts.Token);
|
||
|
|
||
|
}
|
||
|
catch (OperationCanceledException)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(_transitionCts.IsCancellationRequested)return;
|
||
|
|
||
|
switch (arg2)
|
||
|
{
|
||
|
case ICharacterStateIdle:
|
||
|
AnimancerComponent.Layers[Layer].Play(_idleAnimation.Obj as MixerState<Vector2>,fadeDuration).Time = 0;
|
||
|
if (_playerCharacterController.AllowTpsCamera.Allow)
|
||
|
{
|
||
|
_idleAnimation.Value = default;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_idleAnimation.Value = MathV.GetLength(velocity)>3 ? new Vector2(velocity.x, velocity.z) : default(float2);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
case ICharacterStateWalk:
|
||
|
AnimancerComponent.Layers[Layer].Play(_walkAnimation.Obj as MixerState<Vector2>,fadeDuration).Time = 0;
|
||
|
break;
|
||
|
case ICharacterStateCrouched:
|
||
|
AnimancerComponent.Layers[Layer].Play(_crouchedAnimation.Obj as MixerState<Vector2>,fadeDuration).Time = 0;
|
||
|
break;
|
||
|
case ICharacterStateRun:
|
||
|
AnimancerComponent.Layers[Layer].Play(_runAnimation.Obj as MixerState<float>,fadeDuration).Time = 0;
|
||
|
if (_playerCharacterController.AllowTpsCamera.Allow)
|
||
|
{
|
||
|
_runAnimation.Value = 1;
|
||
|
}
|
||
|
break;
|
||
|
case ICharacterSprint:
|
||
|
AnimancerComponent.Layers[Layer].Play(_sprintAnimation.Obj as MixerState<float>,fadeDuration).Time = 0;
|
||
|
if (_playerCharacterController.AllowTpsCamera.Allow)
|
||
|
{
|
||
|
_sprintAnimation.Value = 1;
|
||
|
}
|
||
|
break;
|
||
|
case ICharacterStateStepUp:
|
||
|
AnimancerComponent.Layers[Layer].Play(_playerAnimationFactory.CreateStepUpAnimation() as AnimationClip,fadeDuration).Time=0;
|
||
|
break;
|
||
|
case ICharacterSliding:
|
||
|
AnimancerComponent.Layers[Layer].Play(
|
||
|
_playerAnimationFactory.CreateSlidingAnimation() as AnimationClip,fadeDuration);
|
||
|
break;
|
||
|
case ICharacterStateClimb:
|
||
|
try
|
||
|
{
|
||
|
await AnimancerComponent.Layers[Layer].Play(_playerAnimationFactory.CreateClimbAnimation() as AnimationClip,fadeDuration).WithCancellation(_transitionCts.Token);
|
||
|
|
||
|
AnimancerComponent.Layers[Layer].Play(_climbingAnimation.Obj as AnimancerState);
|
||
|
}
|
||
|
catch (OperationCanceledException)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case ICharacterKnocked:
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
await AnimancerComponent.Layers[Layer].Play(
|
||
|
_playerAnimationFactory.CreateKnockingAnimation() as AnimationClip, fadeDuration)
|
||
|
.WithCancellation(_transitionCts.Token);
|
||
|
|
||
|
AnimancerComponent.Layers[Layer].Play(_knockedAnimation.Obj as MixerState<Vector2>,
|
||
|
fadeDuration);
|
||
|
}
|
||
|
catch (OperationCanceledException)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case ICharacterSeating:
|
||
|
AnimancerComponent.Layers[Layer].Play(_playerAnimationFactory.CreateSeatAnimation() as AnimationClip,fadeDuration);
|
||
|
|
||
|
break;
|
||
|
case ICharacterParachute:
|
||
|
try
|
||
|
{
|
||
|
await AnimancerComponent.Layers[Layer].Play(_playerAnimationFactory.CreateOpenParachuteAnimation() as AnimationClip,fadeDuration).WithCancellation(_transitionCts.Token);
|
||
|
|
||
|
AnimancerComponent.Layers[Layer].Play(_parachuteAnimation.Obj as AnimancerState, fadeDuration);
|
||
|
}
|
||
|
catch (OperationCanceledException)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case ICharacterFreeFall:
|
||
|
AnimancerComponent.Layers[Layer].Play(_playerAnimationFactory.CreateFreeFallAnimation() as AnimationClip,fadeDuration);
|
||
|
break;
|
||
|
case ICharacterSwimming:
|
||
|
AnimancerComponent.Layers[Layer].Play(_swimmingAnimation.Obj as AnimancerState,fadeDuration);
|
||
|
break;
|
||
|
case ICharacterStateVault:
|
||
|
AnimancerComponent.Layers[Layer].Play(_playerAnimationFactory.CreateVaultAnimation() as AnimationClip,fadeDuration).Time=0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
_transitionCts.Cancel();
|
||
|
}
|
||
|
|
||
|
public void Dispose()
|
||
|
{
|
||
|
_transitionCts?.Cancel();
|
||
|
|
||
|
_playerCharacterController.AllowTpsCamera.RemoveListener(OnTPS);
|
||
|
_characterController.OnStateChanged -= OnStateChanged;
|
||
|
_healthService.OnHealthChanged -= OnHealthChanged;
|
||
|
_ticker.Remove(OnTick);
|
||
|
}
|
||
|
}
|
||
|
}
|