做不出来
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
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 Vector3 pendingPhysicsMovement;
|
||||
|
||||
protected virtual void InitiativeMove()
|
||||
{
|
||||
if (owner.collisionSc.useCharacterController && owner.collisionSc.characterController.enabled)
|
||||
{
|
||||
owner.collisionSc.characterController.Move(finalMovementVelocity + movementModifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingPhysicsMovement += finalMovementVelocity + movementModifier;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void FixedUpdate()
|
||||
{
|
||||
if (pendingPhysicsMovement != Vector3.zero && !owner.collisionSc.useCharacterController)
|
||||
{
|
||||
if (owner.collisionSc.mainRigidbody != null)
|
||||
{
|
||||
Vector3 startPosition = owner.collisionSc.mainRigidbody.position;
|
||||
owner.collisionSc.mainRigidbody.MovePosition(startPosition + pendingPhysicsMovement);
|
||||
}
|
||||
pendingPhysicsMovement = Vector3.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94eb66b650b2e0d4d8ab1a79bdef1871
|
||||
@@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using DG.Tweening;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSUtilities.General;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.Serialization;
|
||||
using Cielonos.MainGame.Effects;
|
||||
|
||||
namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
public partial class MovementSubcontrollerBase : SubcontrollerBase<CharacterBase>
|
||||
{
|
||||
protected CharacterBase character => owner;
|
||||
protected float DeltaTime => owner.selfTimeSm.DeltaTime;
|
||||
|
||||
[Tooltip("角色旋转方式,ByMovement为ARPG式默认移动旋转,ByAiming为八向移动")]
|
||||
public CharacterRotationType rotationType;
|
||||
|
||||
public ImpulseSubmodule impulseSm;
|
||||
|
||||
[HideInEditorMode]
|
||||
public Transform characterTransform;
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
impulseSm ??= new ImpulseSubmodule(this);
|
||||
|
||||
canMove = new CompoundBool(true);
|
||||
canRotate = new CompoundBool(true);
|
||||
canDash = true;
|
||||
canDodge = true;
|
||||
canJump = true;
|
||||
maxJumpCount = 1;
|
||||
currentJumpCount = 0;
|
||||
isApplyingGravity = true;
|
||||
|
||||
characterTransform = character.transform;
|
||||
|
||||
if (owner is Player)
|
||||
{
|
||||
var groundMasks = LayerMask.GetMask("Default", "Enemy", "Wall", "Ground", "FadableEnvironment", "UnfadableEnvironment");
|
||||
groundDetector ??= new GroundDetector(owner, 0.1f, 0.1f, 0.05f, groundMasks);
|
||||
}
|
||||
else
|
||||
{
|
||||
groundDetector ??= new GroundDetector(owner, 0.1f, 0.1f, 0.05f,
|
||||
LayerMask.GetMask("Default", "Wall", "Ground", "FadableEnvironment", "UnfadableEnvironment"));
|
||||
}
|
||||
}
|
||||
|
||||
public void SmartTurnToTarget(CharacterBase target, float maxTurnAngle = 360f, bool isInstant = false)
|
||||
{
|
||||
Vector3 directionToTarget = (target.CenterPoint.position - owner.CenterPoint.position).Flatten();
|
||||
if (directionToTarget.sqrMagnitude < 0.001f) return;
|
||||
|
||||
float angleToTarget = Vector3.SignedAngle(owner.transform.forward, directionToTarget, Vector3.up);
|
||||
float absAngle = Mathf.Abs(angleToTarget);
|
||||
|
||||
// 超过最大角度不转身
|
||||
if (absAngle > maxTurnAngle) return;
|
||||
|
||||
// 小角度瞬间转身
|
||||
if (absAngle <= 45f)
|
||||
{
|
||||
owner.transform.rotation = Quaternion.LookRotation(directionToTarget);
|
||||
}
|
||||
// 大角度平滑转身
|
||||
else
|
||||
{
|
||||
float duration = Mathf.Lerp(0.1f, 0.2f, (absAngle - 45f) / 135f);
|
||||
if(!isInstant) owner.transform.DORotateQuaternion(Quaternion.LookRotation(directionToTarget), duration).Play();
|
||||
else owner.transform.rotation = Quaternion.LookRotation(directionToTarget);
|
||||
}
|
||||
}
|
||||
|
||||
public void TurnToTargetByAngle(CharacterBase target, float angularSpeed)
|
||||
{
|
||||
Vector3 directionToTarget = (target.transform.position - characterTransform.position).Flatten();
|
||||
if (directionToTarget == Vector3.zero) return;
|
||||
|
||||
float targetAngle = Mathf.Atan2(directionToTarget.x, directionToTarget.z) * Mathf.Rad2Deg;
|
||||
float currentAngle = characterTransform.eulerAngles.y;
|
||||
float newAngle = Mathf.MoveTowardsAngle(currentAngle, targetAngle, angularSpeed * DeltaTime);
|
||||
characterTransform.rotation = Quaternion.Euler(0, newAngle, 0);
|
||||
}
|
||||
|
||||
public void TurnToDirection(Vector3 direction, float duration = 0f)
|
||||
{
|
||||
Vector3 targetDirection = direction.Flatten();
|
||||
if (targetDirection == Vector3.zero) return;
|
||||
|
||||
Quaternion targetRotation = Quaternion.LookRotation(targetDirection);
|
||||
characterTransform.DORotateQuaternion(targetRotation, duration).Play();
|
||||
}
|
||||
}
|
||||
|
||||
public partial class MovementSubcontrollerBase
|
||||
{
|
||||
[TitleGroup("Ground")]
|
||||
[Tooltip("留空以使用默认配置")]
|
||||
public GroundDetector groundDetector;
|
||||
public bool isOnGround;
|
||||
|
||||
[TitleGroup("XZ Movement")]
|
||||
public CompoundBool canMove;
|
||||
public bool is8WayMovement;
|
||||
public float moveSpeed;
|
||||
public float moveAcceleration;
|
||||
public float moveDeceleration;
|
||||
public bool isSprinting;
|
||||
public float sprintSpeedMultiplier = 1.5f;
|
||||
public float runningTime;
|
||||
|
||||
[TitleGroup("Y Movement & Jump")]
|
||||
public bool canJump;
|
||||
public int maxJumpCount;
|
||||
/// <summary> 当前已使用的跳跃次数(含首次跳跃),落地时重置为 0。 </summary>
|
||||
public int currentJumpCount;
|
||||
public float jumpForce = 15f;
|
||||
public float normalGravity = 40f;
|
||||
public float jumpGravity = 60f;
|
||||
public bool isStartJumping;
|
||||
public bool isJumping;
|
||||
public bool isExtraJumping;
|
||||
public float jumpVelocity;
|
||||
public float jumpTime;
|
||||
public float jumpHeldTime;
|
||||
public bool isJumpLanding;
|
||||
|
||||
[TitleGroup("Rush Stop")]
|
||||
public bool isRushStopping;
|
||||
public bool rushStopped;
|
||||
|
||||
[TitleGroup("Rotation")]
|
||||
public CompoundBool canRotate;
|
||||
public float targetRotation;
|
||||
public Vector3 targetDirection;
|
||||
public float rotationVelocity;
|
||||
public float rotationSmoothTime;
|
||||
|
||||
|
||||
[TitleGroup("Gravity")]
|
||||
public bool isApplyingGravity;
|
||||
public Vector3 currentGravity;
|
||||
public float gravityMultiplier = 1;
|
||||
|
||||
[TitleGroup("Dash")]
|
||||
public bool canDash;
|
||||
public bool isDashing;
|
||||
public bool afterDash;
|
||||
public float dashMoveMultiplier = 3;
|
||||
public float overrideDashMoveMultiplier = -1;
|
||||
|
||||
[TitleGroup("Dodge")]
|
||||
public bool canDodge;
|
||||
public bool isDodging;
|
||||
public bool afterDodge;
|
||||
public float dodgeMoveMultiplier = 1;
|
||||
public float overrideDodgeMoveMultiplier = -1;
|
||||
/// <summary> 闪避/冲刺间隔剩余冷却时间(秒),> 0 时禁止新的闪避/冲刺 </summary>
|
||||
public float dodgeIntervalTimer;
|
||||
|
||||
[TitleGroup("Root Motion")]
|
||||
public Vector3 rootMotionMultiplier = Vector3.one;
|
||||
//public float rootMotionMoveXMultiplier = 1;
|
||||
//public float rootMotionMoveYMultiplier = 1;
|
||||
//public float rootMotionMoveZMultiplier = 1;
|
||||
|
||||
[TitleGroup("Final Movement Calculation")]
|
||||
public Vector3 horizontalMovement;
|
||||
public Vector3 verticalMovement;
|
||||
public float verticalMoveMultiplier = 1;
|
||||
public Vector3 jumpMovement;
|
||||
public Vector3 gravitationalMovement;
|
||||
public Vector3 initiativeMovementVelocity;
|
||||
public Vector3 movementModifier;
|
||||
public Vector3 finalMovementVelocity;
|
||||
}
|
||||
|
||||
public partial class MovementSubcontrollerBase
|
||||
{
|
||||
public enum CharacterRotationType
|
||||
{
|
||||
ByAiming,
|
||||
ByMovement,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7f199b82947e4e45b501f645f39d49e
|
||||
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using Cielonos.MainGame.Effects;
|
||||
using SLSUtilities.General;
|
||||
|
||||
namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
public partial class MovementSubcontrollerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据目标敌人的碰撞体边缘,计算不产生重叠/挤压的安全折跃落脚点。
|
||||
/// </summary>
|
||||
/// <param name="target">折跃目标</param>
|
||||
/// <param name="stopDistance">目标表面前的停止缓冲距离(默认为 1.0f)</param>
|
||||
/// <returns>安全世界坐标</returns>
|
||||
public Vector3 GetSafePositionNearTarget(CharacterBase target, float stopDistance = 1.0f)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
return owner.transform.position;
|
||||
}
|
||||
|
||||
Vector3 selfPos = owner.transform.position;
|
||||
Vector3 targetPos = target.transform.position;
|
||||
|
||||
// 计算平面方向向量
|
||||
Vector3 dir = (targetPos - selfPos).Flatten();
|
||||
if (dir.sqrMagnitude < 0.001f)
|
||||
{
|
||||
dir = owner.transform.forward;
|
||||
}
|
||||
else
|
||||
{
|
||||
dir.Normalize();
|
||||
}
|
||||
|
||||
// 获取双方的碰撞半径(如果有 CharacterController)
|
||||
float selfRadius = 0.5f;
|
||||
float targetRadius = 0.5f;
|
||||
|
||||
if (owner.collisionSc != null && owner.collisionSc.characterController != null)
|
||||
{
|
||||
selfRadius = owner.collisionSc.characterController.radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
var cc = owner.GetComponent<CharacterController>();
|
||||
if (cc != null) selfRadius = cc.radius;
|
||||
}
|
||||
|
||||
if (target.collisionSc != null && target.collisionSc.characterController != null)
|
||||
{
|
||||
targetRadius = target.collisionSc.characterController.radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
var cc = target.GetComponent<CharacterController>();
|
||||
if (cc != null) targetRadius = cc.radius;
|
||||
}
|
||||
|
||||
// 安全距离 = 双方半径之和 + 额外的缓冲停止距离
|
||||
float safeDistance = selfRadius + targetRadius + stopDistance;
|
||||
|
||||
// 目标点位于:目标中心 沿着 玩家至目标的方向 往回拉 safeDistance 距离
|
||||
Vector3 finalDest = targetPos - dir * safeDistance;
|
||||
|
||||
// 保持 Y 轴与目标地面或自身对齐(避免陷地或腾空)
|
||||
finalDest.y = targetPos.y;
|
||||
|
||||
return finalDest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 瞬移/闪现至目标位置(支持高速移动过程)
|
||||
/// </summary>
|
||||
/// <param name="destination">目标位置</param>
|
||||
/// <param name="duration">移动时间(秒)。若为 0 则为即时瞬移</param>
|
||||
/// <param name="onComplete">瞬移完成后(或即时瞬移时)的回调函数,可用于生成 VFX/音效</param>
|
||||
public void Teleport(Vector3 destination, float duration, Action onComplete = null)
|
||||
{
|
||||
// 1. 进行 NavMesh 采样验证(寻找最近的可行进点)
|
||||
Vector3 validDestination = destination;
|
||||
if (NavMesh.SamplePosition(destination, out NavMeshHit hit, 5.0f, NavMesh.AllAreas))
|
||||
{
|
||||
validDestination = hit.position;
|
||||
}
|
||||
|
||||
// 2. 如果是即时瞬移(duration <= 0)
|
||||
if (duration <= 0f)
|
||||
{
|
||||
PerformMove(validDestination);
|
||||
onComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 带有延迟/移动过程的瞬移
|
||||
// 记录起始点
|
||||
Vector3 startPos = owner.transform.position;
|
||||
|
||||
// 赋予无敌状态(防受击)
|
||||
owner.statusSm.AddStatus(StatusType.Invincible, duration);
|
||||
|
||||
// 锁定移动和旋转输入(使用高优先级 99 隔离普通移动控制)
|
||||
canMove.Modify(false, 99);
|
||||
canRotate.Modify(false, 99);
|
||||
|
||||
// 开启残影生成(位移开始时生成单个残影)
|
||||
var afterImageGen = owner.GetComponent<AfterImageGenerator>();
|
||||
if (afterImageGen != null)
|
||||
{
|
||||
afterImageGen.CreateAfterImageSnapshot();
|
||||
}
|
||||
|
||||
// 获取并临时关闭物理/寻路组件,避免移动中碰撞卡顿或位置拉回
|
||||
var agent = owner.GetComponent<NavMeshAgent>();
|
||||
bool wasAgentActive = agent != null && agent.isActiveAndEnabled;
|
||||
if (wasAgentActive)
|
||||
{
|
||||
agent.enabled = false;
|
||||
}
|
||||
|
||||
var cc = owner.collisionSc != null ? owner.collisionSc.characterController : null;
|
||||
bool wasCcActive = cc != null && cc.enabled;
|
||||
if (wasCcActive)
|
||||
{
|
||||
cc.enabled = false;
|
||||
}
|
||||
|
||||
var rb = owner.collisionSc != null ? owner.collisionSc.mainRigidbody : null;
|
||||
bool wasRbKinematic = rb != null && rb.isKinematic;
|
||||
if (rb != null)
|
||||
{
|
||||
rb.isKinematic = true;
|
||||
}
|
||||
|
||||
// 使用本地计时器,更新过程中的插值位移
|
||||
float elapsed = 0f;
|
||||
owner.selfTimeSm.AddLocalTimer(duration,
|
||||
onComplete: () =>
|
||||
{
|
||||
// 确保移动完毕并最终强制对齐
|
||||
owner.transform.position = validDestination;
|
||||
|
||||
// 恢复组件状态
|
||||
if (rb != null)
|
||||
{
|
||||
rb.isKinematic = wasRbKinematic;
|
||||
}
|
||||
if (cc != null && wasCcActive)
|
||||
{
|
||||
cc.enabled = true;
|
||||
}
|
||||
if (agent != null && wasAgentActive)
|
||||
{
|
||||
agent.enabled = true;
|
||||
agent.Warp(validDestination);
|
||||
}
|
||||
|
||||
// 解锁移动和旋转输入
|
||||
canMove.Modify(true, 99);
|
||||
canRotate.Modify(true, 99);
|
||||
|
||||
// 触发完成回调
|
||||
onComplete?.Invoke();
|
||||
},
|
||||
onUpdate: () =>
|
||||
{
|
||||
elapsed += DeltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / duration);
|
||||
Vector3 currentPos = Vector3.Lerp(startPos, validDestination, t);
|
||||
|
||||
// 平滑设置物理和变换位置
|
||||
if (rb != null)
|
||||
{
|
||||
rb.position = currentPos;
|
||||
}
|
||||
owner.transform.position = currentPos;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 底层物理突变移动处理
|
||||
/// </summary>
|
||||
private void PerformMove(Vector3 targetPos)
|
||||
{
|
||||
var agent = owner.GetComponent<NavMeshAgent>();
|
||||
if (agent != null && agent.isActiveAndEnabled)
|
||||
{
|
||||
agent.Warp(targetPos);
|
||||
}
|
||||
else if (owner.collisionSc != null)
|
||||
{
|
||||
if (owner.collisionSc.useCharacterController && owner.collisionSc.characterController != null)
|
||||
{
|
||||
owner.collisionSc.characterController.enabled = false;
|
||||
owner.transform.position = targetPos;
|
||||
owner.collisionSc.characterController.enabled = true;
|
||||
}
|
||||
else if (owner.collisionSc.mainRigidbody != null)
|
||||
{
|
||||
owner.collisionSc.mainRigidbody.position = targetPos;
|
||||
owner.transform.position = targetPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
owner.transform.position = targetPos;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
owner.transform.position = targetPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d9130106184f0142a4fdf38d6a574e6
|
||||
Reference in New Issue
Block a user