4 个版本
0.2.2 | 2023 年 12 月 3 日 |
---|---|
0.2.1 | 2023 年 10 月 31 日 |
0.2.0 | 2023 年 10 月 30 日 |
0.1.0 | 2023 年 10 月 29 日 |
在 WebSocket 中排名第 76
每月下载 46 次
19KB
262 行
ezbrowsergameserver
你有没有想过创建并自己托管一个简单的、通常是基于文本的多人在线浏览器游戏?
我也是!这是一个小型库,希望能使这个过程尽可能简单 :)
入门指南
在你做任何事情之前,要知道 ezbrowsergameserver
不是一个为你的网站提供的服务器 - 它只提供 WebSocket,这将用于更新并同步所有玩家。
如果你已安装了 python3,你可以使用脚本 examples/server.sh
作为快速的无配置 Web 服务器,运行在 0.0.00:8080
上。
在这个示例中,你将使用 0.0.0.0:8080/00_min.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Min - ezbrowsergameserver</title>
<meta name="color-scheme" content="light dark">
<script>
var con = undefined;
function createLobby() {
joinLobby("new");
}
function joinLobby(id) {
let ip;
// if possible, use the same host that is hosting this html file.
// assume localhost if not possible (i.e. opened the file directly)
if (window.location.hostname) {
ip = window.location.hostname;
} else {
ip = "0.0.0.0";
}
// connect to the websocket
con = new WebSocket("ws://" + ip + ":8081");
// handle incoming messages
con.onmessage = (e) => {
let msg = e.data;
// allow the server to update the clients html
bodyDiv.innerHTML = msg;
};
// when the websocket finishes connecting...
con.onopen = () => {
// join a lobby
con.send(id);
};
}
</script>
</head>
<body>
<div id="bodyDiv">
<p>Lobby ID: <input id="lobbyId"></p>
<button onclick=createLobby()>Create new lobby</button>
<button onclick=joinLobbyPressed()>Join lobby by ID</button>
<script>
function joinLobbyPressed() {
joinLobby(lobbyId.value);
}
</script>
</div>
</body>
</html>
这允许你通过在文本输入中输入其 ID 来创建一个新的游戏室或加入一个现有的游戏室。使用 WebSocket 连接到你的游戏服务器 - 你即将使用此库创建的服务器。
但在我们开始制作你的第一个 ezbrowsergame 之前,你需要一个游戏室。
游戏室是游戏开始前人们聚集的地方。在游戏室中,人们可以更改游戏模式、游戏设置或你在游戏室中实现的其他任何内容。游戏室也是全局状态的地方,因为游戏结束后它仍然存在。游戏室可以通过其 ID 访问,格式为十六进制字符串({id:X}
)。
此示例将在玩家加入/离开游戏室时每次启动“游戏”。“游戏”将持续一秒钟并显示游戏室中的新玩家数量。
以下是示例中所需的导入项
use std::time::Instant;
use ezbrowsergameserver::prelude::*;
首先,为您的全局状态创建一个结构体
struct GlobalState {
player_count_changed: bool,
}
然后,为您的游戏创建一个
struct PlayerCountGame(Option<Instant>);
现在,为您的 GlobalState
结构体实现 LobbyState
#[async_trait]
impl LobbyState for GlobalState {
type PlayerState = ();
fn new() -> Self {
Self {
player_count_changed: false,
}
}
fn new_player() -> Self::PlayerState {
()
}
async fn player_joined(_id: usize, lobby: &mut Lobby<Self>, _player: PlayerIndex) {
lobby.state.player_count_changed = true;
}
async fn player_leaving(_id: usize, lobby: &mut Lobby<Self>, _player: PlayerIndex) {
lobby.state.player_count_changed = true;
}
async fn lobby_update(id: usize, lobby: &mut Lobby<Self>) -> Option<Box<dyn GameState<Self>>> {
if lobby.reset {
lobby.reset = false;
// show lobby screen to all clients
for (i, player) in lobby.players_mut().enumerate() {
player
.send(format!(
"<h1>You are player #{}</h1><p>Lobby ID: {id:X}</p>",
i + 1
))
.await;
}
}
for player in lobby.players_mut() {
if let Some(_) = player.get_msg().await {
// if we don't try to get_msg, we don't detect player disconnects
}
}
if lobby.state.player_count_changed {
lobby.state.player_count_changed = false;
// start the "game"
return Some(Box::new(PlayerCountGame(None)));
}
None
}
}
然后,为您的 PlayerCountGame
实现代码 GameState
#[async_trait]
impl GameState<GlobalState> for PlayerCountGame {
async fn update(&mut self, lobby: &mut Lobby<GlobalState>) -> bool {
// game starts, update all clients
if self.0.is_none() {
self.0 = Some(Instant::now());
let c = lobby.players().len();
for player in lobby.players_mut() {
player.send(format!("<h1>There are {c} players</h1>")).await;
}
}
// game ends after 1 seconds
self.0.is_some_and(|start| start.elapsed().as_secs() >= 1)
}
async fn player_leaving(&mut self, lobby: &mut Lobby<GlobalState>, _player: PlayerIndex) {
lobby.state.player_count_changed = true;
}
}
最后,添加您的 main
函数
#[tokio::main]
async fn main() {
host::<GlobalState>("0.0.0.0:8081").await;
}
这就完成了 - 我们已经创建了一个“游戏”。
如果您想尝试一下,请转到 examples/
目录,运行 ./server.sh
,然后运行 cargo run --example 00_min
,然后在浏览器中打开 0.0.0.0:8080/00_min.html
并创建一个新的大厅。
快速入门
cargo new my_project
cd my_project/
cargo add ezbrowsergameserver
cargo add tokio --features macros
echo 'use ezbrowsergameserver::prelude::*;
#[tokio::main]
async fn main() {
host::<ToDo>("0.0.0.0:8081").await;
}' > src/main.rs
请随意通过将示例文件复制到 src/main.rs
并更改不同的内容来实验示例文件 :)
依赖项
~3.5–5.5MB
~95K SLoC