跳到主要内容

事件

事件是脚本间通信的有效方式,可以响应发生的事情,而不必每帧检查。

许多 PlayCanvas 对象,例如脚本实例,都继承引擎的 EventHandler,内置事件处理能力。它们提供:

  • on():注册事件监听器。
  • once():注册仅执行一次的监听器,首次调用后自动取消。
  • off():取消事件监听器。
  • fire():发送事件。
  • hasEvent():查询对象是否监听指定事件。

使用事件​

通过 fire() 触发事件。下面的 player 脚本每帧触发 move,并传入 x 和 y:

import { Script } from 'playcanvas';

export class Player extends Script {
static scriptName = 'player';

update(dt) {
const x = 1;
const y = 1;
this.fire('move', x, y);
}
}

通过 on() 和 off() 监听和取消监听。下面的 display 脚本监听 player 上的 move,并输出 x、y 值。

import { Script } from 'playcanvas';

export class Display extends Script {
static scriptName = 'display';

/**
* @attribute
* @type {Entity}
*/
playerEntity;

initialize() {
// Method to call when player moves
const onPlayerMove = (x, y) => {
console.log(x, y);
};

// Listen for the player move event
if (this.playerEntity && this.playerEntity.script && this.playerEntity.script.player) {
this.playerEntity.script.player.on('move', onPlayerMove);

// Remove player move event listeners when script destroyed
this.playerEntity.script.player.once('destroy', () => {
this.playerEntity.script.player.off('move', onPlayerMove);
});
}
}
}

应用事件​

我们将一种方便而强大的跨实体通信方式称为“应用事件”。上面的例子需要先获得发出事件的实体引用,再监听其事件;这种方式有时适用,但一般情况下,将主应用 this.app 作为事件中心更合适。这样无需一直保存实体引用,也能使用事件通信。

所有事件都在 this.app 上触发和监听。按约定,事件名称使用命名空间表明作用范围并避免冲突。例如,在应用上触发 player:move,而不是在玩家对象上触发 move。

下面通过应用事件重写同一个例子。

触发 player:move:

import { Script } from 'playcanvas';

export class Player extends Script {
static scriptName = 'player';

update(dt) {
const x = 1;
const y = 1;
this.app.fire('player:move', x, y);
}
}

export class Display extends Script {
static scriptName = 'display';

initialize() {
// Method to call when player moves
const onPlayerMove = (x, y) => {
console.log(x, y);
};

// Listen for the player:move event
this.app.on('player:move', onPlayerMove);

// Remove player:move event listeners when script destroyed
this.on('destroy', () => {
this.app.off('player:move', onPlayerMove);
});
}
}

这种方式减少了初始化配置,让代码更清晰。