游戏世界事件系统
GameWorldEvent 是神岛引擎提供的服务端游戏世界事件系统,用于处理游戏世界中的各种事件,如玩家加入、离开、碰撞等。
基础用法
玩家事件监听
typescript
@apclass("PlayerManager")
class PlayerManager extends Component<GameEntity> {
start() {
// 监听玩家加入事件
GameWorldEvent.on(world.onPlayerJoin, this.handlePlayerJoin, this);
// 监听玩家离开事件
GameWorldEvent.on(world.onPlayerLeave, this.handlePlayerLeave, this);
}
private handlePlayerJoin({ entity }: GamePlayerEntityEvent) {
console.log(`玩家 ${entity.player.name} 加入游戏`);
this.node.emit("playerJoined", entity);
}
private handlePlayerLeave({ entity }: GamePlayerEntityEvent) {
console.log(`玩家 ${entity.player.name} 离开游戏`);
this.node.emit("playerLeft", entity);
}
onDestroy() {
// 清理事件监听
GameWorldEvent.off(world.onPlayerJoin, this.handlePlayerJoin, this);
GameWorldEvent.off(world.onPlayerLeave, this.handlePlayerLeave, this);
}
}
高级用法
玩家输入系统
typescript
@apclass("InputSystem")
class InputSystem extends Component<GameEntity> {
start() {
// 监听按键按下事件
GameWorldEvent.on(world.onPress, this.handleKeyPress, this);
// 监听按键释放事件
GameWorldEvent.on(world.onRelease, this.handleKeyRelease, this);
// 监听鼠标点击事件
GameWorldEvent.on(world.onClick, this.handleClick, this);
}
private handleKeyPress({ button, entity }: GameInputEvent) {
switch (button) {
case GameButtonType.WALK:
this.moveForward(entity);
break;
case GameButtonType.JUMP:
this.jump(entity);
break;
}
}
private handleKeyRelease({ button, entity }: GameInputEvent) {
// 处理按键释放逻辑
}
private handleClick({ button, position }: GameClickEvent) {
console.log(`点击位置: ${position.x}, ${position.y}, ${position.z}`);
}
private moveForward(entity: GameEntity) {
// 移动逻辑
}
private jump(entity: GameEntity) {
// 跳跃逻辑
}
onDestroy() {
GameWorldEvent.off(world.onPress, this.handleKeyPress, this);
GameWorldEvent.off(world.onRelease, this.handleKeyRelease, this);
GameWorldEvent.off(world.onClick, this.handleClick, this);
}
}
聊天系统
typescript
@apclass("ChatSystem")
class ChatSystem extends Component<GameEntity> {
start() {
// 监听聊天消息
GameWorldEvent.on(world.onChat, this.handleChat, this);
}
private handleChat({ entity, message }: GameChatEvent) {
// 处理普通聊天消息
if (!message.startsWith("/")) {
console.log(`${entity.player.name}: ${message}`);
return;
}
// 处理命令
this.handleCommand(entity, message.slice(1));
}
private handleCommand(entity: GameEntity, command: string) {
const [cmd, ...args] = command.split(" ");
switch (cmd) {
case "help":
this.showHelp(entity);
break;
case "tp":
this.teleport(entity, args);
break;
}
}
private showHelp(entity: GameEntity) {
entity.player.directMessage("可用命令:/help, /tp");
}
private teleport(entity: GameEntity, args: string[]) {
// 传送逻辑
}
onDestroy() {
GameWorldEvent.off(world.onChat, this.handleChat, this);
}
}
实战示例:游戏管理系统
typescript
@apclass("GameManager")
class GameManager extends Component<GameEntity> {
private players: Map<string, GameEntity> = new Map();
private gameState: "waiting" | "playing" | "ended" = "waiting";
start() {
// 监听玩家相关事件
GameWorldEvent.on(world.onPlayerJoin, this.handlePlayerJoin, this);
GameWorldEvent.on(world.onPlayerLeave, this.handlePlayerLeave, this);
GameWorldEvent.on(world.onChat, this.handleChat, this);
// 监听游戏循环事件
GameWorldEvent.on(world.onTick, this.gameLoop, this);
}
private handlePlayerJoin({ entity }: GamePlayerEntityEvent) {
this.players.set(entity.player.userId, entity);
// 检查是否可以开始游戏
if (this.players.size >= 2 && this.gameState === "waiting") {
this.startGame();
}
}
private handlePlayerLeave({ entity }: GamePlayerEntityEvent) {
this.players.delete(entity.player.userId);
// 检查是否需要结束游戏
if (this.players.size < 2 && this.gameState === "playing") {
this.endGame();
}
}
private handleChat({ entity, message }: GameChatEvent) {
if (message === "!ready" && this.gameState === "waiting") {
entity.player.directMessage("你已准备就绪!");
}
}
private gameLoop() {
if (this.gameState !== "playing") return;
// 更新游戏状态
this.updateGameState();
}
private startGame() {
this.gameState = "playing";
this.broadcastMessage("游戏开始!");
}
private endGame() {
this.gameState = "ended";
this.broadcastMessage("游戏结束!");
}
private broadcastMessage(message: string) {
this.players.forEach((player) => {
player.player.directMessage(message);
});
}
private updateGameState() {
// 游戏逻辑更新
}
onDestroy() {
// 清理所有事件监听
GameWorldEvent.off(world.onPlayerJoin, this.handlePlayerJoin, this);
GameWorldEvent.off(world.onPlayerLeave, this.handlePlayerLeave, this);
GameWorldEvent.off(world.onChat, this.handleChat, this);
GameWorldEvent.off(world.onTick, this.gameLoop, this);
}
}
注意事项
事件清理
- 必须在组件销毁时清理所有事件监听
- 使用同一个回调函数引用进行注册和清理
性能优化
- 避免在事件回调中执行耗时操作
- 合理使用事件节流和防抖
- 及时清理不需要的事件监听
事件处理顺序
- 注意事件的触发顺序
- 避免在事件处理中修改会触发其他事件的状态
常见问题
Q: 为什么事件没有触发?
A: 检查以下几点:
- 事件监听是否正确注册
- 事件名称是否正确
- 回调函数的 this 绑定是否正确
Q: 如何避免事件监听器内存泄漏?
A:
- 在 onDestroy 中清理所有事件
- 保持对事件回调函数的引用
- 使用 bind 或箭头函数确保回调函数引用一致
Q: 事件系统和组件通信如何选择?
A:
- 使用事件系统:处理游戏世界级别的事件
- 使用组件通信:处理组件间的局部通信