如何让敌人以波次攻击炮塔?Unity脚本问题与需求实现
问题修复与功能实现方案
编辑器参数中文翻译
- 敌人预制体(enemyPrefab):已指定敌人预制体
- 生成半径(spawnRadius):50
- 移动速度(moveSpeed):10
- 攻击触发概率(attackChance):0.1
- 攻击高度阈值(attackHeightThreshold):10
- 攻击波动周期(attackWaveDuration):1
- 攻击波动幅度(attackWaveAmplitude):5
原脚本问题分析
- 攻击协程频繁触发:每帧都执行
Random.value < targetAttackChance判断,10%的概率导致敌人几乎时刻处于攻击晃动状态,完全打断移动逻辑。 - 移动与攻击逻辑冲突:攻击协程直接覆盖敌人
position,完全忽略移动指令,敌人无法向炮塔靠近。 - 无绕圈飞行逻辑:仅实现直线移动,未满足绕炮塔圆周飞行的需求。
- 无波次生成机制:当前为单个随机生成,无法实现群体波次攻击。
修复后完整脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class TurretEnemyManager : MonoBehaviour { public GameObject enemyPrefab; public float spawnRadius = 50f; public float moveSpeed = 10f; public float attackChance = 0.01f; // 降低概率避免频繁触发攻击 public float attackHeightThreshold = 10f; public float attackWaveDuration = 1f; public float attackWaveAmplitude = 5f; public float circleOrbitSpeed = 2f; // 绕圈角速度 public float minCircleRadius = 15f; // 最小绕圈半径(靠近炮塔的距离) public float waveSpawnInterval = 8f; // 波次生成间隔 public int waveEnemyCount = 5; // 每波敌人数量 private List<EnemyController> enemies = new List<EnemyController>(); void Start() { StartCoroutine(SpawnSingleEnemies()); StartCoroutine(SpawnEnemyWaves()); } // 单个随机生成敌人 IEnumerator SpawnSingleEnemies() { while (true) { SpawnEnemy(); yield return new WaitForSeconds(Random.Range(2f, 5f)); } } // 群体波次生成敌人 IEnumerator SpawnEnemyWaves() { while (true) { yield return new WaitForSeconds(waveSpawnInterval); for (int i = 0; i < waveEnemyCount; i++) { SpawnEnemy(); yield return new WaitForSeconds(0.3f); // 波次内敌人间隔生成 } } } // 生成单个敌人并初始化状态 void SpawnEnemy() { Vector2 randomCircle = Random.insideUnitCircle.normalized * spawnRadius; Vector3 spawnPos = new Vector3(randomCircle.x, Random.Range(2f, 5f), randomCircle.y); GameObject enemyObj = Instantiate(enemyPrefab, spawnPos, Quaternion.identity); EnemyController enemy = enemyObj.AddComponent<EnemyController>(); enemy.Init(this, transform.position, moveSpeed, circleOrbitSpeed, minCircleRadius); enemies.Add(enemy); } void Update() { // 清理已销毁的敌人 enemies.RemoveAll(enemy => enemy == null); foreach (EnemyController enemy in enemies) { if (!enemy.IsAttacking && Random.value < attackChance) { StartCoroutine(EnemyAttack(enemy)); } } } // 敌人攻击逻辑:上下晃动+向炮塔靠近的复合运动 IEnumerator EnemyAttack(EnemyController enemy) { enemy.IsAttacking = true; float timeElapsed = 0f; Vector3 startPos = enemy.transform.position; Vector3 directionToTurret = (transform.position - startPos).normalized; while (timeElapsed < attackWaveDuration) { timeElapsed += Time.deltaTime; float waveOffset = Mathf.Sin(timeElapsed * Mathf.PI * 2f / attackWaveDuration) * attackWaveAmplitude; Vector3 newPos = startPos + directionToTurret * moveSpeed * timeElapsed + Vector3.up * waveOffset; enemy.transform.position = newPos; yield return null; } enemy.IsAttacking = false; } } // 敌人状态控制器:独立处理移动、绕圈逻辑 public class EnemyController : MonoBehaviour { private TurretEnemyManager manager; private Vector3 turretPos; private float moveSpeed; private float orbitSpeed; private float minOrbitRadius; private bool isOrbiting = false; private float currentOrbitAngle; public bool IsAttacking { get; set; } public void Init(TurretEnemyManager manager, Vector3 turretPos, float moveSpeed, float orbitSpeed, float minOrbitRadius) { this.manager = manager; this.turretPos = turretPos; this.moveSpeed = moveSpeed; this.orbitSpeed = orbitSpeed; this.minOrbitRadius = minOrbitRadius; IsAttacking = false; } void Update() { if (IsAttacking) return; float distanceToTurret = Vector3.Distance(transform.position, turretPos); if (distanceToTurret > minOrbitRadius && !isOrbiting) { // 向炮塔直线移动 Vector3 direction = (turretPos - transform.position).normalized; transform.Translate(direction * moveSpeed * Time.deltaTime, Space.World); } else if (!isOrbiting) { // 到达最小半径,切换为绕圈模式 isOrbiting = true; Vector3 directionToTurret = (turretPos - transform.position).normalized; currentOrbitAngle = Mathf.Atan2(directionToTurret.z, directionToTurret.x) * Mathf.Rad2Deg; } if (isOrbiting) { // 绕炮塔圆周运动 currentOrbitAngle += orbitSpeed * Time.deltaTime; float rad = currentOrbitAngle * Mathf.Deg2Rad; Vector3 orbitPos = turretPos + new Vector3(Mathf.Cos(rad), transform.position.y, Mathf.Sin(rad)) * minOrbitRadius; transform.position = orbitPos; // 始终看向炮塔 transform.LookAt(turretPos); } } }
关键修改说明
- 拆分逻辑模块:新增
EnemyController脚本单独处理敌人的移动、绕圈状态,避免主脚本逻辑混乱。 - 修复攻击触发逻辑:仅在敌人未处于攻击状态时判断是否触发攻击,同时降低
attackChance避免频繁打断移动。 - 实现绕圈飞行:当敌人到达设定的最小绕圈半径时,自动切换为绕炮塔圆周运动模式。
- 添加波次生成功能:新增
SpawnEnemyWaves协程,按固定间隔生成批量敌人,实现群体波次攻击。 - 优化攻击运动:攻击时不再原地晃动,改为结合向炮塔移动+上下晃动的复合运动,更符合攻击行为逻辑。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

