快速上手多人游戏服务器开发。后续会基于 Google Agones
,更新相关 K8S
运维、大规模快速扩展专用游戏服务器的文章。拥抱☁️原生🤗 Cloud-Native!
系列
ColyseusJS 轻量级多人游戏服务器开发框架 - 中文手册(上)
Web-Socket Server
Server
Server
负责提供 WebSocket server 来实现服务器和客户端之间的通信。
constructor (options)
options.server
要绑定 WebSocket Server 的 HTTP server。你也可以在你的服务器上使用 express
。
// Colyseus + Express
import { Server } from "colyseus";
import { createServer } from "http";
import express from "express";
const port = Number(process.env.port) || 3000;
const app = express();
app.use(express.json());
const gameServer = new Server({
server: createServer(app)
});
gameServer.listen(port);
// Colyseus (barebones)
import { Server } from "colyseus";
const port = process.env.port || 3000;
const gameServer = new Server();
gameServer.listen(port);
options.pingInterval
服务器 "ping"
客户端的毫秒数。默认值: 3000
如果客户端在 pingMaxRetries
重试后不能响应,则将强制断开连接。
options.pingMaxRetries
没有响应的最大允许 ping
数。默认值: 2
。
options.verifyClient
这个方法发生在 WebSocket
握手之前。如果 verifyClient
没有设置,那么握手会被自动接受。
-
info
(Object)origin
(String) 客户端指定的Origin header
中的值。req
(http.IncomingMessage) 客户端HTTP GET
请求。secure
(Boolean)true
,如果req.connection.authorized
或req.connection.encrypted
被设置。
-
next
(Function) 用户必须在检查info
字段后调用该回调。此回调中的参数为:result
(Boolean) 是否接受握手。code
(Number) 当result
为false
时,该字段决定发送给客户端的 HTTP 错误状态码。name
(String) 当result
为false
时,该字段决定 HTTP 原因短语。
import { Server } from "colyseus";
const gameServer = new Server({
// ...
verifyClient: function (info, next) {
// validate 'info'
//
// - next(false) will reject the websocket handshake
// - next(true) will accept the websocket handshake
}
});
options.presence
当通过多个进程/机器扩展 Colyseus
时,您需要提供一个状态服务器。
import { Server, RedisPresence } from "colyseus";
const gameServer = new Server({
// ...
presence: new RedisPresence()
});
当前可用的状态服务器是:
RedisPresence
(在单个服务器和多个服务器上扩展)
options.gracefullyShutdown
自动注册 shutdown routine
。默认为 true
。如果禁用,则应在关闭进程中手动调用 gracefullyShutdown()
方法。
define (name: string, handler: Room, options?: any)
定义一个新的 room handler
。
Parameters:
name: string
-room
的公共名称。当从客户端加入room
时,您将使用这个名称。handler: Room
- 引用Room
handler 类。options?: any
-room
初始化的自定义选项。
// Define "chat" room
gameServer.define("chat", ChatRoom);
// Define "battle" room
gameServer.define("battle", BattleRoom);
// Define "battle" room with custom options
gameServer.define("battle_woods", BattleRoom, { map: "woods" });
"多次定义同一个 room handler":
- 您可以使用不同的
options
多次定义同一个room handler
。当调用Room#onCreate()
时,options
将包含您在Server#define()
中指定的合并值 + 创建房间时提供的选项。
Matchmaking 过滤器: filterBy(options)
参数
options: string[]
- 选项名称的列表
当一个房间由 create()
或 joinOrCreate()
方法创建时,只有 filterBy()
方法定义的 options
将被存储在内部,并用于在 join()
或 joinOrCreate()
调用中过滤出相关 rooms
。
示例: 允许不同的“游戏模式”。
gameServer
.define("battle", BattleRoom)
.filterBy(['mode']);
无论何时创建房间,mode
选项都将在内部存储。
client.joinOrCreate("battle", { mode: "duo" }).then(room => {/* ... */});
您可以在 onCreate()
和/或 onJoin()
中处理提供的选项,以在 room
实现中实现请求的功能。
class BattleRoom extends Room {
onCreate(options) {
if (options.mode === "duo") {
// do something!
}
}
onJoin(client, options) {
if (options.mode === "duo") {
// put this player into a team!
}
}
}
示例: 通过内置的 maxClients
进行过滤
maxClients
是一个用于 matchmaking
的内部变量,也可以用于过滤。
gameServer
.define("battle", BattleRoom)
.filterBy(['maxClients']);
然后客户端可以要求加入一个能够容纳一定数量玩家的房间。
client.joinOrCreate("battle", { maxClients: 10 }).then(room => {/* ... */});
client.joinOrCreate("battle", { maxClients: 20 }).then(room => {/* ... */});
Matchmaking 优先级: sortBy(options)
您还可以根据创建时加入房间的信息为加入房间赋予不同的优先级。
options
参数是一个键值对象,在左侧包含字段名称,在右侧包含排序方向。排序方向可以是以下值之一:-1
, "desc"
,"descending"
,1
,"asc"
或 "ascending"
。
示例: 按内置的 clients
排序
clients
是为 matchmaking
而存储的内部变量,其中包含当前已连接客户端的数量。在以下示例中,连接最多客户端的房间将具有优先权。使用 -1
,"desc"
或 "descending"
降序排列:
gameServer
.define("battle", BattleRoom)
.sortBy({ clients: -1 });
要按最少数量的玩家进行排序,您可以做相反的事情。将 1
,"asc"
或 "ascending"
用于升序:
gameServer
.define("battle", BattleRoom)
.sortBy({ clients: 1 });
启用大厅的实时 room 列表
为了允许 LobbyRoom
接收来自特定房间类型的更新,您应该在启用实时列表的情况下对其进行定义:
gameServer
.define("battle", BattleRoom)
.enableRealtimeListing();
监听 room 实例事件
define
方法将返回已注册的 handler
实例,您可以从 room
实例范围之外监听 match-making
事件。如:
"create"
- 当room
被创建时"dispose"
- 当room
被销毁时"join"
- 当客户端加入一个room
时"leave"
- 当客户端离开一个room
时"lock"
- 当room
已经被锁定时"unlock"
- 当room
已经被解锁时
Usage:
gameServer
.define("chat", ChatRoom)
.on("create", (room) => console.log("room created:", room.roomId))
.on("dispose", (room) => console.log("room disposed:", room.roomId))
.on("join", (room, client) => console.log(client.id, "joined", room.roomId))
.on("leave", (room, client) => console.log(client.id, "left", room.roomId));
不鼓励通过这些事件来操纵房间的 state
。而是在您的 room handler
中使用 abstract methods
simulateLatency (milliseconds: number)
这是一种便捷的方法,适用于您希望本地测试"laggy(滞后)"
客户端的行为而不必将服务器部署到远程云的情况。
// Make sure to never call the `simulateLatency()` method in production.
if (process.env.NODE_ENV !== "production") {
// simulate 200ms latency between server and client.
gameServer.simulateLatency(200);
}
attach (options: any)
你通常不需要调用它。只有在你有非常明确的理由时才使用它。
连接或创建 WebSocket server。
options.server
:用于绑定 WebSocket 服务器的 HTTP 服务器。options.ws
:现有的可重用 WebSocket 服务器。
Express
import express from "ex