在上一篇文章中,我演示了如何使用最大堆有效跟踪最远的敌人。在本文中,我们将了解如何将其集成到游戏机制中。
现有的实现使用事件驱动的架构。在本文中,我们将重点关注敌人事件。这些事件将触发衍生行动。
每个敌人都会经历各种事件。以下是敌人可能经历的生命周期的示例:
对于这篇文章,我对两个事件感兴趣:
(*我计划在未来调整事件名称,因为敌人可能会因为不同的原因而被移除。)
我创建了一个事件模型图来可视化不同事件如何交互。这有助于理解事物如何连接。
对于每个事件,我都有一个触发它的命令。 (因此,事件是命令的结果。)在某些情况下,由于事件的结果,我们需要更新数据(绿色便签描述了这一点)。三者的组合是一个垂直切片。
我的注意力将集中在绿色便签“塔范围内的敌人”上。
我们的目标是每当敌人在塔的范围内时就更新可用的敌人,如果不在则将其移除。
我们将与塔类合作。在这个类中,我们有一个变量来存储敌人。
export class Tower implements ITower { public enemies = new MaxHeap() constructor(id: number, coords: Coordinate) { this.id = id this.coords = coords // listeners will go here... }
将事件监听器放置在 Tower 类中可以集中逻辑,减少维护塔和敌人之间映射的需要。虽然这给类增加了一些复杂性,但它确保了更好的封装并简化了调试,这是目前更容易采取的方向。
首先,我们将编写一个测试来验证范围内的敌人是否已添加到塔的敌人堆中:
it('should add an enemy to the tower when enemy is within range', () => { const tower = new Tower(1, { col: 0, row: 1 }); const enemy = new TinyEnemy(); enemy.currentPosition = { col: 0, row: 1 }; triggerEnemyMovedEvent(enemy); expect(tower.enemies.length()).toBe(1); });
下面是相应的实现:
window.addEventListener("enemyMoved", event => { const enemy: Enemy = event.detail.enemy; if (enemyWithinRange(this, enemy)) { this.enemies.insertOrUpdate(enemy.id, enemy.distanceTraveled); } });
每当敌人移动被触发时,我们都会检查是否应该将敌人添加到堆中。我已经有enemyWithinRange函数,只需添加insertOrUpdate调用即可。
接下来,我们确保不会添加塔范围之外的敌人:
export class Tower implements ITower { public enemies = new MaxHeap() constructor(id: number, coords: Coordinate) { this.id = id this.coords = coords // listeners will go here... }
我们之前使用enemyWithinRange进行的检查已经涵盖了这种情况,因此不需要额外的代码。
现在我们测试离开范围的敌人是否会从塔的可见范围中移除:
it('should add an enemy to the tower when enemy is within range', () => { const tower = new Tower(1, { col: 0, row: 1 }); const enemy = new TinyEnemy(); enemy.currentPosition = { col: 0, row: 1 }; triggerEnemyMovedEvent(enemy); expect(tower.enemies.length()).toBe(1); });
window.addEventListener("enemyMoved", event => { const enemy: Enemy = event.detail.enemy; if (enemyWithinRange(this, enemy)) { this.enemies.insertOrUpdate(enemy.id, enemy.distanceTraveled); } });
如果敌人曾经在范围内,那么我们可以将其移除。
最后,我们确保从游戏中移除的敌人也会从塔堆中移除:
it('should not add an enemy to the tower if enemy is out of range', () => { const tower = new Tower(1, { col: 0, row: 1 }); const enemy = new TinyEnemy(); enemy.currentPosition = { col: 0, row: 99 }; triggerEnemyMovedEvent(enemy); expect(tower.enemies.length()).toBe(0); });
it('should remove an enemy from the tower when it moves out of range', () => { const tower = new Tower(1, { col: 0, row: 1 }); const enemy = new TinyEnemy(); enemy.currentPosition = { col: 0, row: 1 }; // enemy within range triggerEnemyMovedEvent(enemy); expect(tower.enemies.length()).toBe(1); // enemy outside of the range enemy.currentPosition = { col: 0, row: 99 }; triggerEnemyMovedEvent(enemy); expect(tower.enemies.length()).toBe(0); });
每当触发事件时,如果敌人在范围内,我们就可以将其移除。
通过将事件驱动方法与最大堆相结合,我们实现了塔楼动态优先处理敌人的有效方法。该实施与游戏的事件系统无缝连接,确保实时更新和响应能力。
此外,在测试时,使用事件驱动方法无需将内部代码与测试联系起来。因此使测试不那么脆弱。我们可以以任何我们想要的方式重构行为背后的代码,只要事件/侦听器设置正确,测试仍然应该通过。
此实施现在可以为以下目标铺平道路:
请随意将这种方法应用于您自己的塔防游戏。
以上是攻击射程最远的敌人(塔防)的详细内容。更多信息请关注PHP中文网其他相关文章!