using SLSUtilities.General; using UnityEngine; using UnityEngine.AI; namespace Cielonos.MainGame.Characters { public partial class AutomataLandMovementSubcontroller : LandMovementSubcontroller { public NavMeshAgent navMeshAgent => (owner as Automata)!.behaviorSc.navMeshAgent; public LerpFloat moveSpeedX; public LerpFloat moveSpeedZ; public override void Initialize() { base.Initialize(); navMeshAgent.isStopped = true; moveSpeedX = new LerpFloat(0f, 5f); moveSpeedZ = new LerpFloat(0f, 5f); } private Vector3 lastDirection; protected override void Update() { base.Update(); // 更新 isOnGround HandleNavMeshState(); } protected override void OnAnimatorMove() { if (owner.selfTimeSm.DeltaTime == 0 || owner.statusSm.isDead) { return; } if (navMeshAgent != null && navMeshAgent.enabled) { if (!is8WayMovement) { if (!navMeshAgent.isStopped) { float distanceVelocity = navMeshAgent.velocity.magnitude; float angularVelocity = Vector3.Angle(lastDirection, transform.forward) / owner.selfTimeSm.DeltaTime; moveSpeedZ.targetValue = distanceVelocity + (angularVelocity * 0.02f); } else { moveSpeedZ.targetValue = 0f; } moveSpeedZ.Update(0.2f, 1); animator.SetFloat("MoveSpeedZ", moveSpeedZ.currentValue); } else { if (!navMeshAgent.isStopped) { Vector3 distanceVelocity = navMeshAgent.velocity; float xValue = Vector3.Dot(distanceVelocity, transform.right); float zValue = Vector3.Dot(distanceVelocity, transform.forward); moveSpeedX.targetValue = xValue; moveSpeedZ.targetValue = zValue; } else { moveSpeedX.targetValue = 0f; moveSpeedZ.targetValue = 0f; } moveSpeedX.Update(0.2f, 1); moveSpeedZ.Update(0.2f, 1); animator.SetFloat("MoveSpeedX", moveSpeedX.currentValue); animator.SetFloat("MoveSpeedZ", moveSpeedZ.currentValue); } } base.OnAnimatorMove(); InitiativeMove(); lastDirection = transform.forward; } private void HandleNavMeshState() { if (navMeshAgent == null) return; if (stagnantFirstHalf && !isOnGround && finalMovementVelocity.y <0) { stagnantFirstHalf = false; stagnantLastHalf = true; } if (stagnantLastHalf && isOnGround) { additionalForceSm.additionalForceY.currentValue = 0; if (!navMeshAgent.enabled) { navMeshAgent.enabled = true; navMeshAgent.Warp(transform.position); } stagnantFirstHalf = false; stagnantLastHalf = false; } } protected override void ApplyGravity() { base.ApplyGravity(); } protected override void InitiativeMove() { if (navMeshAgent.enabled) { navMeshAgent.Move(finalMovementVelocity); navMeshAgent.baseOffset += finalMovementVelocity.y; navMeshAgent.baseOffset = Mathf.Max(navMeshAgent.baseOffset, 0f); } else { if (owner.collisionSc.useCharacterController) { owner.collisionSc.characterController.Move(finalMovementVelocity); } else { Vector3 startPosition = owner.collisionSc.mainRigidbody.position; owner.collisionSc.mainRigidbody.MovePosition(startPosition + finalMovementVelocity); } } } protected override void UpdateFinalMovement() { base.UpdateFinalMovement(); } } public partial class AutomataLandMovementSubcontroller { public bool stagnantFirstHalf; public bool stagnantLastHalf; /// /// 处理受击位移 /// /// 力的矢量 /// 是否为“击飞”(无视抗性,重置重力) /// 滞空时间(秒) public void ApplyHitImpact(Vector3 force, bool isLaunch, float stasisDuration = 0f) { // 1. 瞬间切断导航 if (isLaunch && navMeshAgent.enabled) navMeshAgent.enabled = false; // 2. 施加力 // 如果是击飞(Launch),则 ignoreResistance 为 true (不扣除初速度) if (!stagnantFirstHalf && !stagnantLastHalf) { stagnantFirstHalf = true; } additionalForceSm.AddForce(force, isLaunch); // 3. 处理滞空逻辑 (鬼泣式) if (stasisDuration > 0) { jumpVelocity = 0; gravitationalMovement = Vector3.zero; } } } }