在当今社交化和联网化的时代,实时在线多人游戏的重要性随着互联网的发展而愈加显著。作为前端开发者,我们有必要掌握 Socket.io 和 PIXI.js 这两个库,来开发实时在线游戏。本文将重点介绍如何基于 Socket.io 和 PIXI.js 开发实时在线多人游戏,包括建立服务器、连接客户端、实现游戏机制、实现多人游戏等方面。
简介
Socket.io 是一个为实时应用提供跨平台、事件驱动的 JavaScript 库,它在客户端和服务器之间创建了持久性的连接,并提供了简单的 API 用于发送和接收数据。而 PIXI.js 是一个使用 JavaScript 编写的 2D 游戏渲染引擎,它能够高效地渲染出各种动态的 2D 图形,使我们能够用 JavaScript 创建极具交互性的游戏。
这两个库可以完美地搭配在一起,我们可以使用 Socket.io 来实现实时在线的通信,并使用 PIXI.js 来渲染出游戏画面。
建立服务器
首先,我们需要建立一个服务器以供客户端连接。可以使用 Node.js 和 Express 框架来搭建服务器。以下是一个简单的服务器框架:
// javascriptcn.com 代码示例 const express = require('express') const app = express() const server = require('http').createServer(app) const io = require('socket.io')(server) app.use(express.static(__dirname + '/public')) io.on('connection', (socket) => { console.log('a user connected') socket.emit('connection', 'Welcome to the game') }) server.listen(3000, () => { console.log('listening on *:3000') })
以上代码创建了一个 Express 服务器,并使用 socket.io
模块创建了一个 WebSocket 服务器,并注册了 connection
事件监听器,当有客户端连接到服务器时,便会自动触发该事件。在 connection
事件监听器中,我们向客户端发送了一个欢迎消息。
连接客户端
接下来,我们需要编写客户端的代码来连接服务器。可以使用 Socket.io 客户端库来实现客户端与服务器的通信。以下是客户端的代码:
// javascriptcn.com 代码示例 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Online Game</title> </head> <body> <canvas id="canvas"></canvas> <script src="/socket.io/socket.io.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.3.3/pixi.min.js"></script> <script> var socket = io() socket.on('connection', (data) => { console.log(data) }) var app = new PIXI.Application() document.body.appendChild(app.view) app.renderer.backgroundColor = 0x061639 app.renderer.autoResize = true app.renderer.resize(window.innerWidth, window.innerHeight) </script> </body> </html>
在客户端代码中,我们首先加载了 Socket.io 客户端库和 PIXI.js 库。随后,我们创建了一个连接到服务器的 Socket.io 客户端,并定义了 connection
事件监听器来接收来自服务器的欢迎消息。然后,我们创建了一个 PIXI 应用,并将其渲染到页面中。最后,我们设置了 PIXI 应用的背景颜色,并使其自适应浏览器窗口大小。
以上代码可以让我们在浏览器中打开页面,看到一个黑色的背景。我们已经成功地连接到了服务器。
实现游戏机制
接下来,我们需要考虑如何实现在线多人游戏的机制。首先,我们需要定义游戏中的对象和规则。
在本文中,我们将创建一个简单的多人坦克游戏,玩家将控制一个坦克,并与其他玩家的坦克保持交战,直至游戏结束。
在游戏中,我们需要定义以下对象:
- 玩家:存储玩家的 ID、坦克的位置、方向和状态信息。
- 子弹:存储子弹的位置、方向和速度信息。
- 坦克:一个矩形,存储坦克的位置、方向、状态与攻击力信息。
接着,我们需要定义客户端和服务器之间所要发送的事件类型。
在本文中,我们需要定义以下事件类型:
join
:表示一个玩家加入游戏房间。leave
:表示一个玩家退出游戏房间。play
:表示一个玩家执行操作,如移动、开火等。update
:表示坦克和子弹位置的更新。kill
:表示一个玩家被击败。end
:表示游戏结束。
客户端和服务器之间的数据流如下图所示:
// javascriptcn.com 代码示例 sequenceDiagram participant Client participant Server Client ->> Server: join loop Gameplay Client ->> Server: play Server ->> Client: update Note over Server: Check for collisions Server ->> Client: kill Note over Server: Check for game over Server ->> Client: update end Server ->> Client: end Client ->> Server: leave
实现多人游戏
基于上述机制,我们可以用 Socket.io 和 PIXI.js 实现多人坦克游戏。以下是简单的示例代码:
服务器端代码
// javascriptcn.com 代码示例 const express = require('express') const app = express() const server = require('http').createServer(app) const io = require('socket.io')(server) app.use(express.static(__dirname + '/public')) const players = {} // 玩家列表 io.on('connection', (socket) => { console.log('a user connected') // 玩家加入游戏 socket.on('join', (player) => { players[socket.id] = player players[socket.id].id = socket.id console.log(players[socket.id].name + ' joined the game') // 将新玩家加入游戏通知其他玩家 socket.broadcast.emit('player joined', players[socket.id]) // 将其他玩家信息发送给新玩家 socket.emit('all players', players) }) // 玩家离开游戏 socket.on('disconnect', () => { console.log('user disconnected') if (players[socket.id]) { console.log(players[socket.id].name + ' left the game') delete players[socket.id] // 将该玩家离开游戏通知其他玩家 socket.broadcast.emit('player left', socket.id) } }) // 玩家操作 socket.on('play', (data) => { players[socket.id].x = data.x players[socket.id].y = data.y players[socket.id].angle = data.angle // 将玩家操作发送给其他玩家 socket.broadcast.emit('play', players[socket.id]) }) // 发送玩家子弹信息 socket.on('fire', (bullet) => { // 将发射子弹信息发送给其他玩家 socket.broadcast.emit('fire', bullet) }) }) server.listen(3000, () => { console.log('listening on *:3000') })
以上编写了一个简单的多人坦克游戏的服务器。这个服务器定义了玩家、子弹、坦克等类别,同时为游戏中的每一个用户连接创建了一个 socket.id
标识,用于在连接期间跟踪连接并在连接断开时删除连接。
服务器还监听了 join
、play
、fire
和 disconnect
等事件,处理客户端相应的动作。
客户端代码
// javascriptcn.com 代码示例 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Online Game</title> </head> <body> <canvas id="canvas"></canvas> <script src="/socket.io/socket.io.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.3.3/pixi.min.js"></script> <script> var socket = io() var app = new PIXI.Application() document.body.appendChild(app.view) var tankTexture = PIXI.Texture.from('tank.png') var bulletTexture = PIXI.Texture.from('bullet.png') var bullets = {} var players = {} socket.on('all players', (data) => { for (var id in data) { addPlayer(id, data[id]) } }) socket.on('player joined', (data) => { addPlayer(data.id, data) }) socket.on('player left', (id) => { app.stage.removeChild(players[id].tank) delete players[id] }) socket.on('play', (data) => { movePlayer(data.id, data) }) socket.on('fire', (data) => { if (data.id in bullets) { return } var bullet = new PIXI.Sprite(bulletTexture) bullet.anchor.set(0.5) bullet.x = data.x bullet.y = data.y - 50 bullet.angle = data.angle bullets[data.id] = bullet app.stage.addChild(bullet) setTimeout(() => { app.stage.removeChild(bullet) delete bullets[data.id] }, 3000) }) app.renderer.backgroundColor = 0x061639 app.renderer.autoResize = true app.renderer.resize(window.innerWidth, window.innerHeight) function addPlayer(id, data) { var tank = new PIXI.Sprite(tankTexture) tank.anchor.set(0.5) tank.x = data.x tank.y = data.y tank.id = id tank.name = data.name tank.angle = 0 players[id] = {} players[id].tank = tank var text = new PIXI.Text(tank.name, { fontSize: 20, fill: '#ffffff' }) text.anchor.set(0.5) text.x = tank.x text.y = tank.y - 50 players[id].text = text app.stage.addChild(tank) app.stage.addChild(text) } function movePlayer(id, data) { var player = players[id] var tank = player.tank tank.x = data.x tank.y = data.y tank.angle = data.angle if (id === socket.id) { socket.emit('play', data) } } window.addEventListener('keydown', (e) => { var data = { x: players[socket.id].tank.x, y: players[socket.id].tank.y, angle: players[socket.id].tank.angle, } if (e.keyCode == 37) { // left players[socket.id].tank.angle -= 5 } if (e.keyCode == 39) { // right players[socket.id].tank.angle += 5 } if (e.keyCode == 38) { // up data.y -= 5 * Math.cos(data.angle * Math.PI / 180) data.x += 5 * Math.sin(data.angle * Math.PI / 180) } if (e.keyCode == 40) { // down data.y += 5 * Math.cos(data.angle * Math.PI / 180) data.x -= 5 * Math.sin(data.angle * Math.PI / 180) } if (e.keyCode == 32) { // space var bullet = { id: socket.id, x: players[socket.id].tank.x, y: players[socket.id].tank.y, angle: players[socket.id].tank.angle } socket.emit('fire', bullet) } movePlayer(socket.id, data) }) socket.emit('join', { name: prompt('What is your name?') }) </script> </body> </html>
以上代码创建了一个简单的多人坦克游戏的客户端。客户端首先加载了 Socket.io 和 PIXI.js 库,并定义了 bullets
和 players
两个用于存储子弹和玩家的对象。
客户端还监听 all players
、player joined
、player left
、play
和 fire
等事件,用于管理多人游戏中的用户连接、玩家加入和离开、玩家移动和射击等行为。
该客户端还监听键盘事件,当玩家按下左键或右键时,会旋转坦克;当玩家按下上键或下键时,会向前或向后移动坦克;当玩家按下空格键时,会发射子弹。所有这些操作都会发送给服务器的 play
和 fire
事件,服务器再广播给其他玩家。
总结
通过使用 Socket.io 和 PIXI.js 库,我们可以创建实时多人游戏,并实现多人游戏中所需的玩家列表、坦克、子弹、操作、更新等。这部分内容需要深入了解 Socket.io 和 PIXI.js 的使用和应用,包括建立服务器和连接客户端、定义事件和数据流、实现游戏机制和多人游戏等。想要成为一个合格的前端开发者,我们需要多花时间深入研究这些底层技术的使用和实现。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/652d17f47d4982a6ebe8e949