2025-11-25 08:19:33 -05:00
|
|
|
|
using System;
|
|
|
|
|
|
using DG.Tweening;
|
2026-02-13 09:22:11 -05:00
|
|
|
|
using SLSUtilities.General;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.AI;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Cielonos.MainGame.Characters
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial class LandMovementSubcontroller : MovementSubcontrollerBase
|
|
|
|
|
|
{
|
|
|
|
|
|
protected AnimationSubcontrollerBase animationSc => owner.animationSc;
|
|
|
|
|
|
protected Animator animator => animationSc.animator;
|
2026-02-13 09:22:11 -05:00
|
|
|
|
|
2026-01-12 03:22:16 -05:00
|
|
|
|
protected virtual void OnAnimatorMove()
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2026-02-13 09:22:11 -05:00
|
|
|
|
movementModifier = Vector3.zero;
|
|
|
|
|
|
|
2025-11-25 08:19:33 -05:00
|
|
|
|
if (owner.animationSc.isDuringRootMotion)
|
|
|
|
|
|
{
|
|
|
|
|
|
UpdateRootMotionMovement();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
UpdateRegularMovement();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ApplyGravity();
|
|
|
|
|
|
UpdateFinalMovement();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void Update()
|
|
|
|
|
|
{
|
|
|
|
|
|
isOnGround = groundDetector.DetectGround();
|
2026-05-23 08:27:50 -04:00
|
|
|
|
|
|
|
|
|
|
if (owner.movementSc.dodgeIntervalTimer > 0f)
|
|
|
|
|
|
{
|
|
|
|
|
|
owner.movementSc.dodgeIntervalTimer -= DeltaTime;
|
|
|
|
|
|
}
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public partial class LandMovementSubcontroller
|
|
|
|
|
|
{
|
2026-02-13 09:22:11 -05:00
|
|
|
|
/// <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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public partial class LandMovementSubcontroller
|
|
|
|
|
|
{
|
|
|
|
|
|
void UpdateRootMotionMovement()
|
|
|
|
|
|
{
|
|
|
|
|
|
Quaternion originalDeltaRotation = animator.deltaRotation;
|
|
|
|
|
|
characterTransform.rotation *= originalDeltaRotation;
|
|
|
|
|
|
|
|
|
|
|
|
Vector3 originalDeltaPosition = animator.deltaPosition;
|
2026-01-12 03:22:16 -05:00
|
|
|
|
|
2025-11-25 08:19:33 -05:00
|
|
|
|
Vector3 localDeltaPosition = characterTransform.InverseTransformDirection(originalDeltaPosition);
|
2026-02-13 09:22:11 -05:00
|
|
|
|
Vector3 adjustedLocalDeltaPosition = new Vector3(
|
2026-05-23 08:27:50 -04:00
|
|
|
|
localDeltaPosition.x * rootMotionMultiplier.x,
|
2026-02-13 09:22:11 -05:00
|
|
|
|
localDeltaPosition.y,
|
2026-05-23 08:27:50 -04:00
|
|
|
|
localDeltaPosition.z * rootMotionMultiplier.z);
|
2025-11-25 08:19:33 -05:00
|
|
|
|
Vector3 adjustedDeltaPosition = characterTransform.TransformDirection(adjustedLocalDeltaPosition);
|
|
|
|
|
|
|
|
|
|
|
|
if (isDashing || isDodging)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 deltaPosition = adjustedLocalDeltaPosition;
|
|
|
|
|
|
deltaPosition.z *= isDashing ? dashMoveMultiplier : dodgeMoveMultiplier;
|
|
|
|
|
|
horizontalMovement = characterTransform.TransformDirection(deltaPosition);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
horizontalMovement = adjustedDeltaPosition;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-23 08:27:50 -04:00
|
|
|
|
verticalMovement = new Vector3(0, animator.deltaPosition.y * rootMotionMultiplier.y, 0);
|
2025-11-25 08:19:33 -05:00
|
|
|
|
|
|
|
|
|
|
if ( /*!player.statusModule.CanMove ||*/ animationSc.isDisablingMoveXZ)
|
|
|
|
|
|
{
|
|
|
|
|
|
horizontalMovement = Vector3.zero;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (animationSc.isDisablingMoveY)
|
|
|
|
|
|
{
|
2026-02-13 09:22:11 -05:00
|
|
|
|
verticalMovement = Vector3.zero;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void UpdateRegularMovement()
|
|
|
|
|
|
{
|
|
|
|
|
|
horizontalMovement = targetDirection.normalized * (moveSpeed * DeltaTime);
|
2026-02-13 09:22:11 -05:00
|
|
|
|
verticalMovement = Vector3.zero;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-23 08:27:50 -04:00
|
|
|
|
/// <summary>落地检测的最短延迟(秒),避免起飞瞬间误判在地面上。</summary>
|
|
|
|
|
|
private const float LAUNCH_GROUND_CHECK_DELAY = 0.1f;
|
|
|
|
|
|
|
2026-02-13 09:22:11 -05:00
|
|
|
|
protected virtual void ApplyGravity()
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2026-02-13 09:22:11 -05:00
|
|
|
|
if (!isApplyingGravity)
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2026-02-13 09:22:11 -05:00
|
|
|
|
currentGravity = Vector3.zero;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
gravitationalMovement = Vector3.zero;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-23 08:27:50 -04:00
|
|
|
|
// 击飞脉冲活跃时,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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 09:22:11 -05:00
|
|
|
|
if (groundDetector.isOnGround)
|
|
|
|
|
|
{
|
|
|
|
|
|
currentGravity = Vector3.zero;
|
|
|
|
|
|
gravitationalMovement = Vector3.zero;
|
|
|
|
|
|
movementModifier += Vector3.down * DeltaTime;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
currentGravity = normalGravity * Vector3.down * DeltaTime;
|
|
|
|
|
|
gravitationalMovement += currentGravity * DeltaTime;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void UpdateFinalMovement()
|
|
|
|
|
|
{
|
|
|
|
|
|
horizontalMovement.y = 0;
|
2026-02-13 09:22:11 -05:00
|
|
|
|
verticalMovement.x = 0;
|
|
|
|
|
|
verticalMovement.z = 0;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
|
2026-02-13 09:22:11 -05:00
|
|
|
|
initiativeMovementVelocity = horizontalMovement + (verticalMovement * verticalMoveMultiplier);
|
2025-11-25 08:19:33 -05:00
|
|
|
|
|
2026-02-13 09:22:11 -05:00
|
|
|
|
Vector3 jumpMove = new Vector3(0, jumpVelocity * DeltaTime, 0);
|
2026-03-20 12:07:44 -04:00
|
|
|
|
|
2026-05-23 08:27:50 -04:00
|
|
|
|
Vector3 forceMove = impulseSm.Update(DeltaTime);
|
2025-11-25 08:19:33 -05:00
|
|
|
|
|
2026-02-13 09:22:11 -05:00
|
|
|
|
finalMovementVelocity = initiativeMovementVelocity +
|
|
|
|
|
|
gravitationalMovement * verticalMoveMultiplier * gravityMultiplier +
|
2026-03-20 12:07:44 -04:00
|
|
|
|
forceMove +
|
|
|
|
|
|
jumpMove * verticalMoveMultiplier;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
{
|
2026-05-23 08:27:50 -04:00
|
|
|
|
if (!Application.isPlaying) return;
|
|
|
|
|
|
|
2025-11-25 08:19:33 -05:00
|
|
|
|
float groundedOffset = groundDetector?.groundedOffset ?? 0.05f;
|
|
|
|
|
|
float groundedRadius = groundDetector?.groundedLength ?? 0.1f;
|
2026-02-13 09:22:11 -05:00
|
|
|
|
|
|
|
|
|
|
float predictDistance = -character.movementSc.finalMovementVelocity.y;
|
|
|
|
|
|
float adjustedRadius = groundedRadius + Mathf.Max(0, predictDistance);
|
|
|
|
|
|
|
2025-11-25 08:19:33 -05:00
|
|
|
|
Gizmos.color = Color.red;
|
2026-02-13 09:22:11 -05:00
|
|
|
|
Gizmos.DrawWireSphere(transform.position - new Vector3(0, groundedOffset, 0), adjustedRadius);
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|