c# - 统一的敌人波生成器
问题描述
我正在尝试为我正在创建的自上而下的游戏创建一个波浪生成器。我已经创建了 wave spawner 脚本,但是当我点击播放时,什么也没有发生。倒计时没有开始。理想情况下,它应该从 2 开始,一旦达到 0,第一波应该与一个敌人一起生成。一旦那个敌人被杀死,倒计时应该从 5 开始,一旦达到 0,就应该开始下一波有 2 个敌人的波,依此类推。在所有当前敌人被摧毁之前,新一波不应开始。
public enum SpawnState { SPAWNING, WAITING, COUNTING };
public SpawnState state = SpawnState.COUNTING;
public Transform enemy;
public float timeBetweenWaves = 5f;
public float countDown = 2f;
private int waveIndex = 0;
public float searchCountdown = 1f;
void Update()
{
if (state == SpawnState.WAITING)
{
if (!EnemyisAlive())
{
WaveCompleted();
}
else
{
return;
}
}
if (countDown <= 0f)
{
if (state != SpawnState.SPAWNING)
{
StartCoroutine(SpawnWave());
countDown = timeBetweenWaves;
}
else
{
countDown -= Time.deltaTime;
}
}
}
void WaveCompleted()
{
state = SpawnState.COUNTING;
countDown = timeBetweenWaves;
SpawnWave();
}
bool EnemyisAlive()
{
searchCountdown -= Time.deltaTime;
if (searchCountdown <= 0)
{
searchCountdown = 1f;
if (GameObject.FindGameObjectsWithTag("Enemy").Length == 0)
{
return false;
}
}
return true;
}
IEnumerator SpawnWave()
{
state = SpawnState.SPAWNING;
waveIndex++;
for (int i = 0; i < waveIndex; i++)
{
SpawnEnemy();
yield return new WaitForSeconds(0.5f);
}
state = SpawnState.WAITING;
yield break;
}
void SpawnEnemy()
{
Instantiate(enemy, transform.position, transform.rotation);
}
解决方案
我建议你使用协程来完成所有这些。这使一些事情变得更容易。例如,您可以简单地等到另一个 Ienumertaor 完成。然后我只需将生成的敌人添加到列表中,过滤null
条目并使用计数。使用Find
或在您的情况下,FindGameObjectsWithTag
每个框架的效率都非常低!
using System.Linq;
using System.Collections.Generic;
...
public Transform enemy;
public float timeBetweenWaves = 5f;
public float countDown = 2f;
//public float searchCountdown = 1f;
private List<Transform> enemies = new List<Transform>();
private int waveIndex = 0;
private void Start()
{
StartCoroutine(RunSpawner());
}
// this replaces your Update method
private IEnumerator RunSpawner()
{
// first time wait 2 seconds
yield return new WaitForSeconds(countDown);
// run this routine infinite
while(true)
{
state = SpawnState.SPAWNING;
// do the spawning and at the same time wait until it's finished
yield return SpawnWave();
state = SpawnState.WAITING;
// wait until all enemies died (are destroyed)
yield return new WaitWhile(EnemyisAlive);
state = SpawnState.COUNTING
// wait 5 seconds
yield return new WaitForSeconds(timeBetweenWaves);
}
}
private bool EnemyisAlive()
{
// uses Linq to filter out null (previously detroyed) entries
enemies = enemies.Where(e => e != null).ToList();
return enemies.Count > 0;
}
private IEnumerator SpawnWave()
{
waveIndex++;
for (int i = 0; i < waveIndex; i++)
{
SpawnEnemy();
yield return new WaitForSeconds(0.5f);
}
}
private void SpawnEnemy()
{
enemies.Add(Instantiate(enemy, transform.position, transform.rotation));
}
为了稍微提高效率,您还可以避免实例化和销毁,而是使用对象池- 仅在需要时启用和禁用对象并最终生成新对象。
推荐阅读
- algorithm - 如何获取不在给定 IP 地址范围内的所有 IP 地址
- javascript - css链接如何为前端浏览器生成哈希码
- c - C中的设计原则DRY?
- cloud - 为 GOOGLE_APPLICATION_CREDENTIALS 设置环境变量后要做什么
- java - 验证 Jackon JsonAnySetter 被称为 Junit
- node.js - Node-red:node-function - if 条件中缺少“null”值
- php - 使用 PHP 在数据库中插入信息
- java - java日期解析错误行为
- laravel-5 - 具有多个参数的路由上缺少必需的参数错误
- ios - Xamarin - IOS - CLLocationManager - 手机进入睡眠状态时计时器停止