在 Colyseus 中实现实时排行榜和玩家分数同步
在 Colyseus 中实现实时排行榜和玩家分数同步,可以通过以下步骤完成。Colyseus 是一个基于 Node.js 的多人游戏框架,支持状态同步和消息通信,非常适合实时应用场景。
1. 设计房间 (Room) 的状态
在 Colyseus 中,房间状态(RoomState
)是共享的数据,服务器会将它同步到所有客户端。为实现排行榜和分数同步,可以设计如下的状态结构:
import { Schema, type, MapSchema } from "@colyseus/schema";
class Player extends Schema {
@type("string") id!: string;
@type("string") name!: string;
@type("number") score!: number;
}
export class RoomState extends Schema {
@type({ map: Player }) players = new MapSchema<Player>();
}
Player
类存储每个玩家的信息,包括 ID、名称和分数。RoomState
的players
属性是一个MapSchema
,用于存储所有玩家。
2. 创建房间类
实现房间逻辑来管理玩家连接、分数更新和排行榜计算。
import { Room, Client } from "colyseus";
import { RoomState, Player } from "./RoomState";
export class LeaderboardRoom extends Room<RoomState> {
onCreate() {
this.setState(new RoomState());
// 监听消息,用于更新玩家分数
this.onMessage("updateScore", (client, data) => {
const player = this.state.players.get(client.sessionId);
if (player) {
player.score += data.score; // 更新分数
this.sortLeaderboard(); // 排序排行榜
}
});
}
onJoin(client: Client, options: any) {
const player = new Player();
player.id = client.sessionId;
player.name = options.name || `Player ${client.sessionId}`;
player.score = 0;
this.state.players.set(client.sessionId, player);
}
onLeave(client: Client) {
this.state.players.delete(client.sessionId);
}
// 排序排行榜
sortLeaderboard() {
const sortedPlayers = Array.from(this.state.players.values()).sort(
(a, b) => b.score - a.score
);
sortedPlayers.forEach((player, index) => {
console.log(`#${index + 1} ${player.name}: ${player.score}`);
});
}
}
onJoin
: 玩家加入时添加到状态中。onLeave
: 玩家离开时从状态中移除。onMessage
: 监听玩家发送的分数更新消息。sortLeaderboard
: 按照分数降序排列玩家,用于在服务器端输出排行榜。
3. 客户端实现
客户端需要连接到 Colyseus 服务器,发送分数更新消息,并显示实时排行榜。
初始化客户端连接
import { Client } from "colyseus.js";
const client = new Client("ws://localhost:2567");
const room = await client.joinOrCreate("leaderboard_room", { name: "Player1" });
room.state.players.onAdd = (player, key) => {
console.log(`Player ${player.name} joined with score ${player.score}`);
};
room.state.players.onRemove = (player, key) => {
console.log(`Player ${player.name} left`);
};
room.state.players.onChange = (player, key) => {
console.log(`Player ${player.name} has a new score: ${player.score}`);
};
更新分数
function updateScore(points: number) {
room.send("updateScore", { score: points });
}
4. 实现排行榜显示
可以在客户端中实时监听玩家状态的变化,动态渲染排行榜。
示例:React 实现实时排行榜
import React, { useEffect, useState } from "react";
const Leaderboard = ({ room }) => {
const [players, setPlayers] = useState([]);
useEffect(() => {
const updatePlayers = () => {
const sortedPlayers = Array.from(room.state.players.values()).sort(
(a, b) => b.score - a.score
);
setPlayers(sortedPlayers);
};
room.state.players.onAdd = updatePlayers;
room.state.players.onChange = updatePlayers;
room.state.players.onRemove = updatePlayers;
return () => {
room.state.players.onAdd = null;
room.state.players.onChange = null;
room.state.players.onRemove = null;
};
}, [room]);
return (
<div>
<h1>Leaderboard</h1>
<ul>
{players.map((player, index) => (
<li key={player.id}>
#{index + 1} {player.name}: {player.score}
</li>
))}
</ul>
</div>
);
};
5. 优化和扩展
- 定时广播排行榜: 若玩家数量多,可以设置定时广播更新,而不是实时同步。
- 防作弊机制: 验证分数更新请求,避免客户端恶意操作。
- 分页排行榜: 若玩家较多,可实现分页加载排行榜。
- 持久化: 将玩家分数和排行榜存储到数据库中(如 MongoDB 或 Redis)。
6. 测试和调试
- 使用 WebSocket 客户端工具(如
wscat
)测试房间功能。 - 检查 Colyseus 客户端和服务器之间的消息通信。
通过上述步骤,您可以在 Colyseus 中实现一个功能强大且高效的实时排行榜和分数同步系统。