using UnityEngine; namespace BaseGames.Enemies { /// /// 敌人移动组件(架构 07_EnemyModule §3)。 /// 实现:水平移动、面向目标、击退。 /// ⚠️ 使用 Rigidbody2D.velocity(Unity 2022 LTS)。 /// [RequireComponent(typeof(Rigidbody2D))] public class EnemyMovement : MonoBehaviour { [SerializeField] private EnemyStatsSO _config; [SerializeField] private SpriteRenderer _spriteRenderer; private Rigidbody2D _rb; private int _facingDir = 1; public bool IsGrounded { get; private set; } private void Awake() { Debug.Assert(_config != null, "[EnemyMovement] _config 未赋值,请在 Prefab Inspector 中指定 EnemyStatsSO。", this); _rb = GetComponent(); } /// 按 SO 配置速度水平移动。dir: +1 右 / -1 左 / 0 停止。 public void MoveHorizontal(float dir) { float speed = _config.WalkSpeed; _rb.velocity = new Vector2(dir * speed, _rb.velocity.y); UpdateFacing(dir); } /// 显式指定速度(BD 追击任务调用)。 public void MoveWithSpeed(float dir, float speed) { _rb.velocity = new Vector2(dir * speed, _rb.velocity.y); UpdateFacing(dir); } public void FaceTarget(Vector2 targetPos) { float dir = targetPos.x < transform.position.x ? -1f : 1f; UpdateFacing(dir); } public void ApplyKnockback(Vector2 dir, float force) { _rb.velocity = dir.normalized * force; } public void StopHorizontal() { _rb.velocity = new Vector2(0f, _rb.velocity.y); } /// /// 向目标位置抖跃(抛物线累加填充)。 /// 计算初速使尔子到达目标,用 Impulse 施加力。 /// public void JumpToTarget(Vector2 target) { if (_rb == null) return; Vector2 delta = target - (Vector2)transform.position; float gravMag = Mathf.Abs(Physics2D.gravity.y * _rb.gravityScale); float timeAloft = Mathf.Max(0.1f, delta.x != 0f ? Mathf.Abs(delta.x) / _config.RunSpeed : 0.5f); float vy = (delta.y - 0.5f * (-gravMag) * timeAloft * timeAloft) / timeAloft; float vx = delta.x / timeAloft; _rb.velocity = new Vector2(vx, vy); UpdateFacing(vx); } private void UpdateFacing(float dir) { if (Mathf.Approximately(dir, 0f)) return; int newDir = dir > 0f ? 1 : -1; if (newDir == _facingDir) return; _facingDir = newDir; if (_spriteRenderer != null) { _spriteRenderer.flipX = newDir < 0; } else { // SpriteRenderer 未绑定时通过 localScale 翻转朝向 Vector3 s = transform.localScale; transform.localScale = new Vector3(Mathf.Abs(s.x) * newDir, s.y, s.z); } } private void OnDrawGizmos() { #if UNITY_EDITOR // ── 1. 敌人物理轮廓(珊瑚红,区别于玩家绿色)──────────────── Gizmos.color = new Color(1f, 0.45f, 0.35f, 0.65f); foreach (var col in GetComponents()) { if (col.isTrigger) continue; BaseGames.Combat.HitBox.DrawCollider2DWire(col); } // ── 2. 朝向箭头(橙色)────────────────────────────────────── Vector3 center = transform.position; DrawArrow2D(center, center + new Vector3(_facingDir * 0.5f, 0f, 0f), new Color(1f, 0.6f, 0.1f, 0.9f)); #endif } private void OnDrawGizmosSelected() { #if UNITY_EDITOR // 运行时:青色箭头显示速度向量(选中时) if (!Application.isPlaying || _rb == null) return; Vector2 vel = _rb.velocity; if (vel.sqrMagnitude < 0.01f) return; DrawArrow2D(transform.position, transform.position + (Vector3)(vel * 0.12f), new Color(0.2f, 0.9f, 1f, 0.9f), 0.1f); #endif } // 在 Gizmos 空间绘制带箭头的 2D 有向线段 private static void DrawArrow2D(Vector3 from, Vector3 to, Color color, float headLen = 0.15f) { Vector3 dir = to - from; if (dir.sqrMagnitude < 0.0001f) return; dir = dir.normalized; Gizmos.color = color; Gizmos.DrawLine(from, to); float cos = 0.8192f, sin = 0.5736f; // cos/sin 35° float bx = -dir.x, by = -dir.y; Vector3 wing1 = new Vector3(bx * cos - by * sin, bx * sin + by * cos, 0f) * headLen; Vector3 wing2 = new Vector3(bx * cos + by * sin, -bx * sin + by * cos, 0f) * headLen; Gizmos.DrawLine(to, to + wing1); Gizmos.DrawLine(to, to + wing2); } } }