using System; using DragonLi.Frame; using UnityEngine; public class SwordProjectile : MonoBehaviour { public enum State { Idle, FlyingOut, Grounded, Returning } [Header("飞行参数")] public float flySpeed = 15f; [Tooltip("落地后停留时间")] public float stayDuration = 2f; [Tooltip("玩家被击中半径,不使用物理碰撞")] private float hitRadius = 3f; [Tooltip("落地方向距离的高度偏移(可让剑从空中稍微高出)")] public float heightOffset = 0f; [Header("伤害")] public float damageAmount = 15f; private State currentState = State.Idle; private Vector3 startPosition; // BOSS 背部原始位置 private Vector3 targetPosition; // 本次飞行的地面目标位置 private float groundY; // 地面高度 (scene 中地面 Y 坐标) private float stayTimer = 0f; private bool hasHitPlayerThisPhase = false; private Transform playerTransform; // 返回完成时的回调事件(由 BossController 订阅,用于结束投掷动画) public event Action OnReturnComplete; /// /// 由 BossController 实例化后调用,用来设置飞行目标并开始飞行 /// /// 玩家 Transform /// BOSS 背部挂点 Transform /// 飞行速度 /// 地面 Y 坐标 /// 落地停留时间 /// 击中玩家距离阈值 /// 伤害值 public void Initialize(Transform player, Transform bossBackPoint, float flySpd, float groundYPos, float stayTime, float radius, float dmg) { playerTransform = player; flySpeed = flySpd; groundY = groundYPos; stayDuration = stayTime; hitRadius = radius; damageAmount = dmg; currentState = State.FlyingOut; hasHitPlayerThisPhase = false; stayTimer = 0f; // 记录起始位置(Boss 背部挂点) startPosition = bossBackPoint.position; // 目标落点:在玩家当前位置正上方,附加 heightOffset Vector3 playerPos = playerTransform != null ? playerTransform.position : Vector3.zero; targetPosition = new Vector3(playerPos.x, groundY, playerPos.z); // 让剑从稍微高于背部位置处起飞(视觉效果可调整) transform.position = startPosition + Vector3.up * heightOffset; } private void Update() { switch (currentState) { case State.FlyingOut: FlyOut(); break; case State.Grounded: HandleGrounded(); break; case State.Returning: FlyBack(); break; } } /// /// 飞出阶段:朝 targetPosition 飞行 /// private void FlyOut() { Vector3 dir = (targetPosition - transform.position).normalized; transform.position += dir * flySpeed * Time.deltaTime; // 飞行途中持续检测与玩家距离,若小于 hitRadius 且本阶段未曾击中,则造成一次伤害 if (!hasHitPlayerThisPhase && playerTransform != null) { float sqrDist = (transform.position - playerTransform.position).sqrMagnitude; if (sqrDist <= hitRadius * hitRadius) { HitPlayer(); hasHitPlayerThisPhase = true; } } // 到达或跌落到 groundY 时,进入 Grounded 阶段 if (transform.position.y <= groundY) { // 瞬间把 Y 设为 groundY Vector3 pos = transform.position; pos.y = groundY; transform.position = pos; currentState = State.Grounded; hasHitPlayerThisPhase = false; // 重置,本阶段可再击中一次 stayTimer = 0f; } transform.LookAt(playerTransform.position); } /// /// 落地停留阶段 /// private void HandleGrounded() { stayTimer += Time.deltaTime; // 停留阶段再次检测“玩家距离”,若小于阈值且尚未击中本阶段,则造成伤害 if (!hasHitPlayerThisPhase && playerTransform != null) { float sqrDist = (transform.position - playerTransform.position).sqrMagnitude; if (sqrDist <= hitRadius * hitRadius) { HitPlayer(); hasHitPlayerThisPhase = true; } } // 停留时长到,进入返回阶段 if (stayTimer >= stayDuration) { currentState = State.Returning; hasHitPlayerThisPhase = false; } } /// /// 返回阶段:朝 startPosition 上方飞行 (保留 heightOffset), /// 到达后触发 OnReturnComplete,销毁自身 /// private void FlyBack() { // 目标为背部挂点上方相同高度 Vector3 returnTarget = startPosition + Vector3.up * heightOffset; Vector3 dir = (returnTarget - transform.position).normalized; transform.position += dir * flySpeed * Time.deltaTime; if (!hasHitPlayerThisPhase && playerTransform != null) { float sqrDist = (transform.position - playerTransform.position).sqrMagnitude; if (sqrDist <= hitRadius * hitRadius) { HitPlayer(); hasHitPlayerThisPhase = true; } } // 检测是否到达“返回目标”足够近 if ((transform.position - returnTarget).sqrMagnitude <= 0.01f) { OnReturnComplete?.Invoke(); Destroy(gameObject); } } private void HitPlayer() { var ph = playerTransform.GetComponent(); if (ph != null) ph.ApplyDamage(damageAmount,null,transform); } }