using DG.Tweening; using Sirenix.OdinInspector; using SLSUtilities.General; using UnityEngine; using UnityEngine.Serialization; namespace Cielonos.MainGame.Characters { public partial class MovementSubcontrollerBase : SubcontrollerBase { 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) { 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); owner.transform.DORotateQuaternion(Quaternion.LookRotation(directionToTarget), duration).Play(); } } 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; /// 当前已使用的跳跃次数(含首次跳跃),落地时重置为 0。 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; /// 闪避/冲刺间隔剩余冷却时间(秒),> 0 时禁止新的闪避/冲刺 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, } } }