事件
事件是脚本间通信的有效方式,可以响应发生的事情,而不必每帧检查。
许多 PlayCanvas 对象,例如脚本实例,都继承引擎的 EventHandler,内置事件处理能力。它们提供:
on():注册事件监听器。once():注册仅执行一次的监听器,首次调用后自动取消。off():取消事件监听器。fire():发送事件。hasEvent():查询对象是否监听指定事件。
使用事件
通过 fire() 触发事件。下面的 player 脚本每帧触发 move,并传入 x 和 y:
- ESM
- 经典脚本
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);
}
}
var Player = pc.createScript('player');
Player.prototype.update = function (dt) {
const x = 1;
const y = 1;
this.fire('move', x, y);
};
通过 on() 和 off() 监听和取消监听。下面的 display 脚本监听 player 上的 move,并输出 x、y 值。
- ESM
- 经典脚本
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);
});
}
}
}
var Display = pc.createScript('display');
// Set up an entity reference for the player entity
Display.attributes.add('playerEntity', { type: 'entity' });
Display.prototype.initialize = function () {
// Method to call when player moves
const onPlayerMove = (x, y) => {
console.log(x, y);
};
// Listen for the player move event
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:
- ESM
- 经典脚本
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);
});
}
}
var Player = pc.createScript('player');
Player.prototype.update = function (dt) {
const x = 1;
const y = 1;
this.app.fire('player:move', x, y);
};
监听 player:move:
var Display = pc.createScript('display');
Display.prototype.initialize = function () {
// 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', function() {
this.app.off('player:move', onPlayerMove);
});
};
这种方式减少了初始化配置,让代码更清晰。