首页 > web前端 > js教程 > 攻击射程最远的敌人(塔防)

攻击射程最远的敌人(塔防)

Linda Hamilton
发布: 2024-12-12 12:59:11
原创
509 人浏览过

在上一篇文章中,我演示了如何使用最大堆有效跟踪最远的敌人。在本文中,我们将了解如何将其集成到游戏机制中。

事件驱动方法

现有的实现使用事件驱动的架构。在本文中,我们将重点关注敌人事件。这些事件将触发衍生行动。

每个敌人都会经历各种事件。以下是敌人可能经历的生命周期的示例:

Attacking the Furthest Enemy in Range (Tower Defence)

对于这篇文章,我对两个事件感兴趣:

  • 敌人移动:当敌人位置改变时触发。
  • 敌人移除*:当敌人从游戏中移除(例如被击败)时触发。

(*我计划在未来调整事件名称,因为敌人可能会因为不同的原因而被移除。)

计划

我创建了一个事件模型图来可视化不同事件如何交互。这有助于理解事物如何连接。

Attacking the Furthest Enemy in Range (Tower Defence)

对于每个事件,我都有一个触发它的命令。 (因此,事件是命令的结果。)在某些情况下,由于事件的结果,我们需要更新数据(绿色便签描述了这一点)。三者的组合是一个垂直切片

我的注意力将集中在绿色便签“塔范围内的敌人”上。

执行

我们的目标是每当敌人在塔的范围内时就更新可用的敌人,如果不在则将其移除。

我们将与塔类合作。在这个类中,我们有一个变量来存储敌人。

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中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板