前言
WebSocket 是一种支持双向通信的网络协议,多用于实时通信场景,例如在线聊天、多人游戏等。Express.js 作为一种流行的 Node.js Web 框架,也提供了 WebSocket 相关的功能。本文将介绍如何使用 Express.js 构建基于 WebSocket 的游戏,并包含示例代码。
WebSocket 介绍
WebSocket 是一种基于 TCP 的协议,它允许客户端和服务器之间进行双向通信。与 HTTP 不同的是,WebSocket 不需要发送请求头和响应头,因此可以更快地建立连接。WebSocket 还支持长连接,可以在一定程度上解决 HTTP 短暂连接的问题。
在 JavaScript 中,可以使用标准的 WebSocket API 进行操作。WebSocket 与 HTTP 建立在同一个端口上,因此不受浏览器的外域限制。例如,可以通过 JavaScript 代码从一个域名的网页连接到另一个域名的 WebSocket 服务。
Express.js 与 WebSocket
Express.js 提供了一种 ws 中间件,用于向 Express 应用程序添加 WebSocket 支持。该中间件基于 ws 库实现,提供了 WebSocket 相关的功能,如协议解析、编码和事件处理等。
使用 ws 中间件,我们可以通过以下代码向 Express 应用程序添加 WebSocket 支持:
// www.javascriptcn.com code example
const express = require('express');
const app = express();
const server = app.listen(3000, () => {
console.log('Server started');
});
const WebSocket = require('ws');
const wss = new WebSocket.Server({
server: server,
path: '/ws'
});
wss.on('connection', (ws) => {
console.log('WebSocket connected');
ws.on('message', (msg) => {
console.log('Received message: ' + msg);
ws.send('Echo: ' + msg);
});
ws.on('close', () => {
console.log('WebSocket disconnected');
});
});上述代码中,我们创建了一个 Express 应用程序,并将其绑定到端口 3000。然后通过 ws 中间件创建了一个 WebSocket 服务,并将其绑定到 Express 应用程序的路由 /ws 上。在 connection 事件中,我们处理了客户端连接、收到信息和断开连接等事件。
构建基于 WebSocket 的游戏
使用 Express.js 和 WebSocket,我们可以轻松构建一个基于 WebSocket 的游戏。下面我们将演示一个简单的游戏,名为“猜数字”。
游戏规则
游戏中,服务器会随机生成一个 1 到 100 的整数,玩家需要通过猜测这个数字来获取分数。每次猜测都会扣除一定的分数,但如果猜对了,就可以得到更多的分数。游戏时间为 30 秒,时间结束后将公布最高得分榜。
实现思路
我们需要在服务器端生成随机数,同时处理玩家的猜测,并将游戏状态实时推送给客户端。另外,我们还需要在客户端实现游戏界面和用户操作。
在服务器端,我们可以使用 Express.js 和 ws 中间件实现 WebSocket 服务,处理玩家猜测的逻辑。在客户端,我们可以使用 JavaScript 和 HTML 实现游戏界面和用户操作。通过 WebSocket 进行通信,实时更新游戏状态。
示例代码
下面是服务器端的代码:
// www.javascriptcn.com code example
const express = require('express');
const app = express();
const server = app.listen(3000, () => {
console.log('Server started');
});
const WebSocket = require('ws');
const wss = new WebSocket.Server({
server: server,
path: '/ws'
});
let number = Math.ceil(Math.random() * 100);
let score = 0;
let timeLeft = 30;
let isRunning = false;
function startGame() {
isRunning = true;
setInterval(() => {
timeLeft--;
if (timeLeft <= 0) {
isRunning = false;
timeLeft = 0;
wss.clients.forEach(ws => {
ws.send(JSON.stringify({
type: 'gameover'
}));
});
} else {
wss.clients.forEach(ws => {
ws.send(JSON.stringify({
type: 'time',
payload: {
timeLeft: timeLeft
}
}));
});
}
}, 1000);
}
wss.on('connection', (ws) => {
console.log('WebSocket connected');
ws.on('message', (msg) => {
console.log('Received message: ' + msg);
const data = JSON.parse(msg);
if (data.type === 'guess') {
const guess = parseInt(data.payload, 10);
if (!Number.isNaN(guess)) {
if (!isRunning) {
ws.send(JSON.stringify({
type: 'notrunning'
}));
} else if (guess === number) {
score += 10;
number = Math.ceil(Math.random() * 100);
wss.clients.forEach(ws => {
ws.send(JSON.stringify({
type: 'number',
payload: {
number: number
}
}));
ws.send(JSON.stringify({
type: 'score',
payload: {
score: score
}
}));
});
} else {
score--;
wss.clients.forEach(ws => {
ws.send(JSON.stringify({
type: 'score',
payload: {
score: score
}
}));
});
}
}
} else if (data.type === 'start') {
score = 0;
timeLeft = 30;
isRunning = true;
number = Math.ceil(Math.random() * 100);
wss.clients.forEach(ws => {
ws.send(JSON.stringify({
type: 'number',
payload: {
number: number
}
}));
ws.send(JSON.stringify({
type: 'score',
payload: {
score: score
}
}));
ws.send(JSON.stringify({
type: 'time',
payload: {
timeLeft: timeLeft
}
}));
});
startGame();
}
});
ws.on('close', () => {
console.log('WebSocket disconnected');
});
});上述代码中,我们生成了一个随机数 number,表示游戏目标数字。同时,我们在 WebSocket 服务的 connection 事件中处理了客户端连接和收到消息等事件。在收到消息时,我们将消息解析为 JSON 将类型解析出来,根据业务逻辑进行处理。例如,当收到 guess 类型的消息时,我们将解析出猜测的数字,根据猜测结果进行分数更新。
下面是客户端的代码:
// www.javascriptcn.com code example
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>猜数字游戏</title>
</head>
<body>
<h1>猜数字游戏</h1>
<button id="start-btn">开始游戏</button>
<hr>
<div id="guess-div" style="display:none">
<h2>猜测</h2>
<p>剩余时间:<span id="time-span">30</span>s</p>
<p>得分:<span id="score-span">0</span></p>
<p>目标数字:<span id="number-span">?</span></p>
<input type="number" id="guess-input">
<button id="guess-btn">猜</button>
</div>
<hr>
<div id="result-div" style="display:none">
<h2>游戏结果</h2>
<p>得分:<span id="result-score-span">0</span></p>
<p>排名:</p>
<ol id="result-ol"></ol>
<button id="restart-btn">重新开始</button>
</div>
<script>
const ws = new WebSocket('ws://localhost:3000/ws');
const startBtn = document.getElementById('start-btn');
const guessDiv = document.getElementById('guess-div');
const resultDiv = document.getElementById('result-div');
const guessInput = document.getElementById('guess-input');
const guessBtn = document.getElementById('guess-btn');
const timeSpan = document.getElementById('time-span');
const scoreSpan = document.getElementById('score-span');
const numberSpan = document.getElementById('number-span');
const resultScoreSpan = document.getElementById('result-score-span');
const restartBtn = document.getElementById('restart-btn');
const resultOl = document.getElementById('result-ol');
ws.onopen = () => {
console.log('WebSocket connected');
};
ws.onmessage = (evt) => {
console.log('Received message: ' + evt.data);
const data = JSON.parse(evt.data);
if (data.type === 'notrunning') {
alert('游戏已结束');
} else if (data.type === 'number') {
const number = data.payload.number;
numberSpan.innerText = number;
} else if (data.type === 'score') {
const score = data.payload.score;
scoreSpan.innerText = score;
} else if (data.type === 'time') {
const timeLeft = data.payload.timeLeft;
timeSpan.innerText = timeLeft;
} else if (data.type === 'gameover') {
guessDiv.style.display = 'none';
resultDiv.style.display = 'block';
resultScoreSpan.innerText = scoreSpan.innerText;
}
};
startBtn.onclick = () => {
ws.send(JSON.stringify({
type: 'start'
}));
startBtn.style.display = 'none';
guessDiv.style.display = 'block';
};
guessBtn.onclick = () => {
const guess = parseInt(guessInput.value, 10);
if (!Number.isNaN(guess)) {
ws.send(JSON.stringify({
type: 'guess',
payload: guess
}));
guessInput.value = '';
}
};
restartBtn.onclick = () => {
location.reload();
}
</script>
</body>
</html>在客户端代码中,我们使用 WebSocket 类创建了 WebSocket 连接,并处理了 open 和 message 等事件。在收到消息时,我们解析 JSON 数据,并根据类型更新游戏界面。
以上就是一个简单的基于 WebSocket 的游戏实现。通过本例子的实践,您将学会使用 Express.js 和 ws 中间件构建基于 WebSocket 的应用程序,以及如何在客户端使用 WebSocket 进行双向通信,实现实时游戏互动。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d7db84a941bf7134e0e8fb