近年来,在线游戏的流行度越来越高,而 WebSocket 技术则成为了实现实时双向通讯的一个重要方案。Deno 作为一个新兴的 JavaScript/TypeScript 运行时环境,也提供了相应的 WebSocket API,让我们可以更加方便地开发基于 WebSocket 的在线游戏。
本文将介绍如何在 Deno 中使用 WebSocket 实现一个简单的在线游戏,同时也会介绍一些 WebSocket 的基本概念及相关的 JavaScript/TypeScript 技术。希望本文能够给想要学习 WebSocket 技术的前端开发者带来帮助。
WebSocket 基础
WebSocket 是一种在单个 TCP 连接上进行全双工通信的网络通讯协议。和 HTTP 或 HTTPS 协议相比,WebSocket 可以更快地建立连接,并且可以在连接创建后保持长时间的双向通讯,让数据传输更加稳定可靠。
在 Web 应用中,我们可以通过 JavaScript/TypeScript 内置的 WebSocket 类来创建 WebSocket 连接,同时也需要实现相应的 WebSocket 服务器来接收和处理客户端的连接请求。
接下来,我们将通过一个简单的代码示例来介绍如何使用 WebSocket 进行基本的通讯。以下代码演示了如何在客户端上建立 WebSocket 连接,并向 WebSocket 服务器发送一条信息:
// javascriptcn.com 代码示例 const socket = new WebSocket('ws://localhost:8080'); socket.addEventListener('open', () => { console.log('connected to WebSocket server'); socket.send('hello, WebSocket'); }); socket.addEventListener('message', (event) => { console.log(`received message from server: ${event.data}`); });
在上面的代码中,我们首先使用 WebSocket 类创建了一个 WebSocket 连接,连接到本地的 8080 端口。当连接成功建立后,会触发 open
事件,在该事件的处理函数中我们向服务器发送了一条消息。在服务器接收到该消息后,会在处理函数中将消息发送回客户端,该消息会触发 message
事件,我们可以在事件的处理函数中获取消息内容并进行处理。
WebSocket 实现在线游戏
现在,我们已经知道如何使用 WebSocket 建立连接,并完成基本的通讯。接下来,我们将利用这个能力来实现一个在线游戏,让多个玩家可以在同一个游戏场景中实时交互。
在这个游戏中,玩家可以随意移动自己的游戏角色,同时也可以看到其他玩家的角色在游戏中的实时位置。玩家之间的移动信息和位置信息都会通过 WebSocket 传递,让游戏场景实现实时同步。
以下是 demo 的代码示例:
// javascriptcn.com 代码示例 // server.ts import { serve } from 'https://deno.land/std/http/server.ts'; import { acceptWebSocket, acceptable, WebSocket, } from 'https://deno.land/std/ws/mod.ts'; const players: Record<string, { x: number; y: number }> = {}; async function handleWebSocket(ws: WebSocket) { console.log('WebSocket connected.'); const playerID = Math.random().toString().slice(2); players[playerID] = { x: 0, y: 0 }; // send player ID to client ws.send(JSON.stringify({ type: 'ID', data: playerID })); // send all players' positions to this client const others = Object.entries(players) .filter(([id]) => id !== playerID) .map(([id, { x, y }]) => ({ id, x, y })); ws.send(JSON.stringify({ type: 'OTHERS', data: others })); for await (const event of ws) { if (typeof event === 'string') { console.log('received message:', event); try { const { type, data } = JSON.parse(event); switch (type) { case 'MOVE': const { x, y } = data; players[playerID] = { x, y }; sendMessageToOthers({ type: 'MOVE', data: { id: playerID, x, y }, }); break; } } catch (e) { console.error(e); } } else if (isWebSocketCloseEvent(event)) { console.log('WebSocket closed.'); delete players[playerID]; sendMessageToOthers({ type: 'LEAVE', data: playerID, }); } } } function sendMessageToOthers(message: { type: string; data: any }) { for (const ws of sockets) { if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify(message)); } } } const server = serve({ port: 8080 }); const sockets: WebSocket[] = []; async function main() { console.log('WebSocket server started'); for await (const req of server) { if (req.method !== 'GET' || !acceptable(req)) { req.respond({ status: 404 }); continue; } const ws = await acceptWebSocket({ conn: req.conn, bufReader: req.r, bufWriter: req.w }); sockets.push(ws); handleWebSocket(ws); } } main();
// javascriptcn.com 代码示例 <!-- client.html --> <!DOCTYPE html> <html> <head> <title>Simple Game</title> </head> <body> <h1>Simple Game</h1> <canvas id="canvas" width="400" height="400"></canvas> <script type="module"> import { WebSocket } from 'https://deno.land/std/ws/mod.ts'; const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const ws = new WebSocket('ws://localhost:8080'); let playerID = null; const others = new Map(); ws.addEventListener('open', () => { console.log('connected to WebSocket server'); }); ws.addEventListener('message', (event) => { console.log(`received message from server: ${event.data}`); try { const { type, data } = JSON.parse(event.data); switch (type) { case 'ID': playerID = data; break; case 'OTHERS': for (const { id, x, y } of data) { others.set(id, { x, y }); } break; case 'MOVE': const { id, x, y } = data; others.set(id, { x, y }); break; case 'LEAVE': others.delete(data); break; } } catch (e) { console.error(e); } }); function render() { ctx.clearRect(0, 0, canvas.width, canvas.height); // draw self if (playerID) { const { x, y } = others.get(playerID) || { x: 0, y: 0 }; ctx.fillStyle = 'blue'; ctx.fillRect(x - 10, y - 10, 20, 20); } // draw others for (const [id, { x, y }] of others) { if (id === playerID) continue; ctx.fillStyle = 'gray'; ctx.fillRect(x - 10, y - 10, 20, 20); } requestAnimationFrame(render); } render(); canvas.addEventListener('mousemove', (event) => { if (!playerID) return; const { x, y } = canvas.getBoundingClientRect(); const message = { type: 'MOVE', data: { x: event.clientX - x, y: event.clientY - y, }, }; ws.send(JSON.stringify(message)); }); </script> </body> </html>
在上面的代码示例中,我们使用 Deno 内置的 WebSocket 实现了一个简单的在线游戏。该游戏通过 WebSocket 技术实现了玩家之间的实时通讯,可以让多个玩家在同一个游戏场景中实时交互。
在服务器端的代码中,我们首先创建了一个 players
对象,用于保存所有玩家的位置信息。当玩家连接到服务器时,我们为该玩家分配一个随机的 playerID
,并将其位置信息保存到 players
对象中。接着,我们向该玩家发送了 playerID
,以及其他玩家的位置信息。这些信息可以在客户端的代码中使用。
随着玩家在游戏中的移动,客户端代码会通过 mousemove
事件创建消息并发送到服务器,服务器会将玩家的位置信息更新到 players
对象中,并向其他玩家发送 MOVE
类型的消息,以此实现玩家位置的同步。
除了玩家的位置信息外,还有 LEAVE
类型的消息,也会在玩家断开连接时发送给其他玩家,以通知其他玩家该玩家已离开游戏场景。
在游戏场景的渲染中,我们首先通过 Canvas 画布绘制了自己的角色,接着绘制了其他玩家的角色。这些信息来自客户端代码中维护的 others
Map,其中以 playerID
为键,对应位置信息为值。
总结
本文介绍了如何使用 WebSocket 在 Deno 中实现在线游戏,其中介绍了 WebSocket 技术的基础知识和相关的 JavaScript/TypeScript 技术。希望本文能够给前端开发者带来学习和指导帮助,并在未来的项目中融入这项技术。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/654723ce7d4982a6eb18239a