Files
Cielonos/Assets/Scripts/MainGame/Characters/Base/Subcontrollers/LandMovementSubcontroller.cs
SoulliesOfficial 649b7a5ddc 更新
2026-05-23 08:27:50 -04:00

209 lines
7.4 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 DG.Tweening;
using SLSUtilities.General;
using UnityEngine;
using UnityEngine.AI;
namespace Cielonos.MainGame.Characters
{
public partial class LandMovementSubcontroller : MovementSubcontrollerBase
{
protected AnimationSubcontrollerBase animationSc => owner.animationSc;
protected Animator animator => animationSc.animator;
protected virtual void OnAnimatorMove()
{
movementModifier = Vector3.zero;
if (owner.animationSc.isDuringRootMotion)
{
UpdateRootMotionMovement();
}
else
{
UpdateRegularMovement();
}
ApplyGravity();
UpdateFinalMovement();
}
protected virtual void Update()
{
isOnGround = groundDetector.DetectGround();
if (owner.movementSc.dodgeIntervalTimer > 0f)
{
owner.movementSc.dodgeIntervalTimer -= DeltaTime;
}
}
}
public partial class LandMovementSubcontroller
{
/// <summary>
/// 如果角色当前在空中,强制其落地。
/// </summary>
public void ForceLanding()
{
if(isOnGround) return;
if (groundDetector.GetGroundPosition(out Vector3 landingPosition))
{
jumpVelocity = 0;
gravitationalMovement = Vector3.zero;
if (owner.collisionSc.useCharacterController)
{
owner.collisionSc.characterController.enabled = false;
owner.transform.position = landingPosition + new Vector3(0, groundDetector.groundedOffset + 0.1f, 0);
owner.collisionSc.characterController.enabled = true;
}
else
{
owner.collisionSc.mainRigidbody.position = landingPosition + new Vector3(0, groundDetector.groundedOffset + 0.1f, 0);
}
}
}
}
public partial class LandMovementSubcontroller
{
void UpdateRootMotionMovement()
{
Quaternion originalDeltaRotation = animator.deltaRotation;
characterTransform.rotation *= originalDeltaRotation;
Vector3 originalDeltaPosition = animator.deltaPosition;
Vector3 localDeltaPosition = characterTransform.InverseTransformDirection(originalDeltaPosition);
Vector3 adjustedLocalDeltaPosition = new Vector3(
localDeltaPosition.x * rootMotionMultiplier.x,
localDeltaPosition.y,
localDeltaPosition.z * rootMotionMultiplier.z);
Vector3 adjustedDeltaPosition = characterTransform.TransformDirection(adjustedLocalDeltaPosition);
if (isDashing || isDodging)
{
Vector3 deltaPosition = adjustedLocalDeltaPosition;
deltaPosition.z *= isDashing ? dashMoveMultiplier : dodgeMoveMultiplier;
horizontalMovement = characterTransform.TransformDirection(deltaPosition);
}
else
{
horizontalMovement = adjustedDeltaPosition;
}
verticalMovement = new Vector3(0, animator.deltaPosition.y * rootMotionMultiplier.y, 0);
if ( /*!player.statusModule.CanMove ||*/ animationSc.isDisablingMoveXZ)
{
horizontalMovement = Vector3.zero;
}
if (animationSc.isDisablingMoveY)
{
verticalMovement = Vector3.zero;
}
}
private void UpdateRegularMovement()
{
horizontalMovement = targetDirection.normalized * (moveSpeed * DeltaTime);
verticalMovement = Vector3.zero;
}
/// <summary>落地检测的最短延迟(秒),避免起飞瞬间误判在地面上。</summary>
private const float LAUNCH_GROUND_CHECK_DELAY = 0.1f;
protected virtual void ApplyGravity()
{
if (!isApplyingGravity)
{
currentGravity = Vector3.zero;
gravitationalMovement = Vector3.zero;
return;
}
// 击飞脉冲活跃时Y 轴位移由 ImpulseSubmodule 接管
if (impulseSm.launchImpulse.IsActive)
{
// 抛物线落地检测:度过起飞延迟且已在下落阶段且触地 → 结束击飞
if (impulseSm.launchImpulse.IsParabolic
&& impulseSm.launchImpulse.ElapsedTime > LAUNCH_GROUND_CHECK_DELAY
&& impulseSm.launchImpulse.SampleSignedSpeed() <= 0f
&& groundDetector.isOnGround)
{
impulseSm.ClearLaunch();
// 不 return — 落地后立即走正常的 isOnGround 重力分支
}
else
{
currentGravity = Vector3.zero;
gravitationalMovement = Vector3.zero;
return;
}
}
if (groundDetector.isOnGround)
{
currentGravity = Vector3.zero;
gravitationalMovement = Vector3.zero;
movementModifier += Vector3.down * DeltaTime;
return;
}
currentGravity = normalGravity * Vector3.down * DeltaTime;
gravitationalMovement += currentGravity * DeltaTime;
}
protected virtual void UpdateFinalMovement()
{
horizontalMovement.y = 0;
verticalMovement.x = 0;
verticalMovement.z = 0;
initiativeMovementVelocity = horizontalMovement + (verticalMovement * verticalMoveMultiplier);
Vector3 jumpMove = new Vector3(0, jumpVelocity * DeltaTime, 0);
Vector3 forceMove = impulseSm.Update(DeltaTime);
finalMovementVelocity = initiativeMovementVelocity +
gravitationalMovement * verticalMoveMultiplier * gravityMultiplier +
forceMove +
jumpMove * verticalMoveMultiplier;
}
protected virtual void InitiativeMove()
{
if (owner.collisionSc.useCharacterController)
{
owner.collisionSc.characterController.Move(finalMovementVelocity + movementModifier);
}
else
{
Vector3 startPosition = owner.collisionSc.mainRigidbody.position;
owner.collisionSc.mainRigidbody.MovePosition(startPosition + finalMovementVelocity + movementModifier);
}
}
}
public partial class LandMovementSubcontroller
{
private void OnDrawGizmos()
{
if (!Application.isPlaying) return;
float groundedOffset = groundDetector?.groundedOffset ?? 0.05f;
float groundedRadius = groundDetector?.groundedLength ?? 0.1f;
float predictDistance = -character.movementSc.finalMovementVelocity.y;
float adjustedRadius = groundedRadius + Mathf.Max(0, predictDistance);
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position - new Vector3(0, groundedOffset, 0), adjustedRadius);
}
}
}