Files
Cielonos/Assets/Scripts/MainGame/Characters/Player/PlayerLandMovementSubcontroller.cs
SoulliesOfficial 39b43680a9 爆更
2026-07-18 03:16:20 -04:00

314 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using Cielonos.MainGame.Effects.Feedback;
using DG.Tweening;
using SLSUtilities.General;
using SLSUtilities.FunctionalAnimation;
using UniRx;
using Unity.Cinemachine;
using UnityEngine;
namespace Cielonos.MainGame.Characters
{
[RequireComponent(typeof(Player))]
public partial class PlayerLandMovementSubcontroller : LandMovementSubcontroller
{
public Player player => owner as Player;
private PlayerAnimationSubcontroller animationSc => base.animationSc as PlayerAnimationSubcontroller;
private static readonly int RushStopTriggerHash = Animator.StringToHash("RushStop");
private const float RushStopTriggerSpeed = 5f;
private bool wasMovingLastFrame;
protected override void OnAnimatorMove()
{
if (DeltaTime == 0)
{
return;
}
Rotate();
Move();
Jump();
base.OnAnimatorMove();
InitiativeMove();
}
protected override void Update()
{
base.Update();
bool cannotDodge = owner.movementSc.isDashing || owner.movementSc.isDodging || owner.movementSc.dodgeIntervalTimer > 0f;
(owner as Player)!.bodyPartsSc.AuxiliaryDrone.SetDroneEmissionColor(cannotDodge ? Color.red : Color.cyan);
}
public void TurnToInputDirection(Vector3 direction, float duration = 0f)
{
Vector3 dashRotation = Vector3.zero;
float angle = Vector3.SignedAngle(Vector3.forward, direction, Vector3.up);
if (owner is Player player)
{
dashRotation.y = player.viewSc.playerCamera.transform.eulerAngles.y + angle;
}
else
{
dashRotation = new Vector3(0, angle, 0);
}
if (duration > 0)
{
characterTransform.DORotateQuaternion(Quaternion.Euler(dashRotation), duration).Play();
}
else
{
characterTransform.rotation = Quaternion.Euler(dashRotation);
}
}
}
public partial class PlayerLandMovementSubcontroller
{
void Rotate()
{
if (animationSc.isDuringRootMotion) return;
Vector3 inputDirection = new Vector3(player.inputSc.Move.x, 0.0f, player.inputSc.Move.y).normalized;
if (player.inputSc.IsMoving)
{
targetRotation = Mathf.Atan2(inputDirection.x, inputDirection.z) * Mathf.Rad2Deg +
player.viewSc.playerCamera.transform.eulerAngles.y;
if (rotationType == CharacterRotationType.ByMovement && canRotate.Value)
{
float rotation = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetRotation, ref rotationVelocity, rotationSmoothTime);
player.transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
}
}
targetDirection = Quaternion.Euler(0.0f, targetRotation, 0.0f) * Vector3.forward;
}
void Move()
{
if (!canMove.Value)
{
wasMovingLastFrame = player.inputSc.IsMoving;
moveSpeed = 0;
return;
}
float targetSpeed = player.attributeSm.Get(CharacterAttribute.MovementSpeed, 10f) * (isSprinting ? sprintSpeedMultiplier : 1f);
float movementAnimationSpeedMultiplier = !player.inputSc.IsWalking && targetSpeed > 10f ? targetSpeed / 10f : 1;
float inputMagnitude = player.inputSc.Move.magnitude;
moveAcceleration = player.attributeSm.Get(CharacterAttribute.MovementAcceleration, 6);
moveDeceleration = player.attributeSm.Get(CharacterAttribute.MovementDeceleration, 8);
bool isMoving = player.inputSc.IsMoving;
//TryPlayRushStop(isMoving);
if (isMoving)
{
bool success = animationSc.fullBodyFuncAnimSm.Stop(DisruptionType.Movement, 0.25f);
if (!success && animationSc.isDuringRootMotion)
{
if (!isDashing)
{
moveSpeed = Mathf.Lerp(moveSpeed, 0, DeltaTime * moveDeceleration);
}
wasMovingLastFrame = isMoving;
return;
}
}
else
{
isSprinting = false;
}
animator.SetFloat("MoveSpeedMultiplier", movementAnimationSpeedMultiplier);
if (!isJumpLanding && isMoving)
{
float finalTargetSpeed = !player.inputSc.IsWalking ? targetSpeed * inputMagnitude : 2f;
finalTargetSpeed = Mathf.Max(finalTargetSpeed, 1);
moveSpeed = Mathf.Lerp(moveSpeed, finalTargetSpeed, DeltaTime * moveAcceleration);
}
else if (!isDashing)
{
moveSpeed = Mathf.Lerp(moveSpeed, 0, DeltaTime * moveDeceleration);
}
/*if (MotionController.characterRotationType == PlayerMotionController.CharacterRotationType.ByAiming)
{
float mx = Mathf.Lerp(mx, Player.inputController.InputMoveValue.x, DeltaTime * movementSpeedAccelerationRate);
float my = Mathf.Lerp(my, Player.inputController.InputMoveValue.y, DeltaTime * movementSpeedAccelerationRate);
animator.SetFloat("MovementSpeedX", mx * movementSpeed);
animator.SetFloat("MovementSpeedZ", my * movementSpeed);
}
else*/
{
animator.SetFloat("MoveSpeedZ", moveSpeed);
}
if (moveSpeed > 5f * DeltaTime && isMoving)
{
runningTime += DeltaTime;
}
else
{
runningTime = 0;
}
wasMovingLastFrame = isMoving;
}
/// <summary>
/// 仅在奔跑状态下检测“释放方向输入”的瞬间,并触发一次性急停动作。
/// 没有配置急停动画时,不设置 Trigger继续使用普通减速流程。
/// </summary>
private void TryPlayRushStop(bool isMoving)
{
if (!wasMovingLastFrame ||
isMoving ||
!isSprinting ||
moveSpeed < RushStopTriggerSpeed ||
isDashing ||
isDodging ||
isStartJumping ||
isJumping ||
isJumpLanding ||
animationSc.isDuringRootMotion ||
animationSc.currentAnimationGroup?.rushStop == null)
{
return;
}
animator.SetTrigger(RushStopTriggerHash);
}
private void Jump()
{
if (player.inputSc.JumpPressed && animationSc.fullBodyFuncAnimSm.Stop(DisruptionType.NormalAction))
{
// 从属性系统实时读取最大跳跃次数,确保装备/buff变化后立即生效
maxJumpCount = Mathf.Max(1, Mathf.RoundToInt(player.attributeSm.Get(CharacterAttribute.MaxJumpCount, 1f)));
if (!isJumping)
{
FirstJump();
}
else if (currentJumpCount < maxJumpCount)
{
ExtraJump(-1, true);
}
}
if (isJumping)
{
jumpTime += DeltaTime;
if (jumpVelocity > 0)
{
jumpVelocity -= jumpGravity * DeltaTime;
}
else
{
jumpVelocity = 0f;
gravitationalMovement += new Vector3(0, -jumpGravity * gravityMultiplier * DeltaTime, 0) * DeltaTime;
}
if (jumpTime > 0.1f)
{
if (jumpTime > 1f && groundDetector.DetectGround(4f, 1f))
{
jumpVelocity = 0f;
animationSc.grounderFBBIK.weight = 1;
isJumping = false;
currentJumpCount = 0;
movementModifier = Vector3.zero;
animator.SetBool("IsLandingOnGround", true);
animator.SetTrigger("LandFromHighAltitude");
isJumpLanding = true;
Observable.Timer(TimeSpan.FromSeconds(0.4f)).Subscribe(_ => { isJumpLanding = false; });
return;
}
if (groundDetector.isOnGround || groundDetector.DetectGround())
{
jumpVelocity = 0f;
animationSc.grounderFBBIK.weight = 1;
animator.SetBool("IsLandingOnGround", true);
isJumping = false;
currentJumpCount = 0;
movementModifier = Vector3.zero;
}
}
}
}
public void FirstJump()
{
if (isStartJumping || isJumping || !groundDetector.isOnGround)
{
return;
}
animator.SetTrigger("Jump");
(animationSc as PlayerAnimationSubcontroller).grounderFBBIK.weight = 0;
isStartJumping = true;
player.eventSm.onFirstJump.Invoke();
player.selfTimeSm.AddLocalTimer(0.16f, () =>
{
jumpVelocity = jumpForce;
isStartJumping = false;
isJumping = true;
currentJumpCount = 1;
jumpTime = 0;
jumpHeldTime = 0;
gravitationalMovement = Vector3.zero;
animator.SetBool("IsLandingOnGround", false);
});
}
public void ExtraJump(float overrideForce = -1, bool hasAnimation = false, bool isAdditive = true)
{
if (!isAdditive)
{
jumpVelocity = overrideForce > 0 ? overrideForce : jumpForce;
}
else
{
jumpVelocity += overrideForce > 0 ? overrideForce : jumpForce;
}
currentJumpCount++;
isJumping = true;
gravitationalMovement = Vector3.zero;
}
protected override void UpdateFinalMovement()
{
base.UpdateFinalMovement();
if (!isDashing && !isDodging)
{
PostProcessingManager.Instance.speedLinesSm.remap.IsPausing = false;
float horizontalSpeed = horizontalMovement.magnitude / DeltaTime;
float remapFactor = Mathf.InverseLerp(10f, 15f, horizontalSpeed);
PostProcessingManager.Instance.speedLinesSm.SetRemap(1 - remapFactor);
//player.viewSc.cameraFovSm.UpdateFovBySpeed(horizontalSpeed, DeltaTime);
}
else
{
PostProcessingManager.Instance.speedLinesSm.remap.IsPausing = true;
}
}
}
}