内容简介:联机逻辑开发进度:■■□□□□□□□□□□本章结束开发进度:■■■■■□□□□□□□
联机逻辑开发进度:■■□□□□□□□□□□
本章结束开发进度:■■■■■□□□□□□□
上一章的答案:
index.html
:
var app = new Vue({ el: '#app', data: { message: 'Hello Vue!', websock: null, }, created() { this.initWebSocket(); }, destroyed() { this.websock.close() //离开路由之后断开websocket连接 }, methods: { initWebSocket() { //初始化websocket const wsuri = "ws://192.168.3.41:8811"; this.websock = new WebSocket(wsuri); this.websock.onmessage = this.websocketonmessage; this.websock.onopen = this.websocketonopen; this.websock.onerror = this.websocketonerror; this.websock.onclose = this.websocketclose; }, websocketonopen() { //连接建立之后执行send方法发送数据 let actions = {"test": "12345"}; this.websocketsend(actions); }, websocketonerror() {//连接建立失败重连 this.initWebSocket(); }, websocketonmessage(e) { //数据接收 let message = JSON.parse(e.data); }, websocketsend(Data) {//数据发送 this.websock.send(JSON.stringify(Data)); }, websocketclose(e) { //关闭 console.log('断开连接', e); }, } })
- 记得将
192.168.3.41
改为你的IP
地址哦。
Server
类:
public function onWorkerStart($server, $workerId) { echo "server: onWorkStart,worker_id:{$server->worker_id}\n"; } public function onOpen($server, $request) { DataCenter::log(sprintf('client open fd:%d', $request->fd)); } public function onMessage($server, $request) { DataCenter::log(sprintf('client open fd:%d,message:%s', $request->fd, $request->data)); $server->push($request->fd, 'test success'); } public function onClose($server, $fd) { DataCenter::log(sprintf('client close fd:%d', $fd)); }
写完以上代码后,在虚拟机中重新运行 Server
,在浏览器访问前端页面并打开 F12
开发者模式。
前端成功地发出了数据,服务端返回的数据也都接收到了,我们成功打通了游戏前后端。
游戏数据管理
游戏的数据主要有两个存储方式:
Redis
我们首先在 DataCenter
类中新增一个静态变量 $global
,所有的对战数据都将存储在这个变量中。
DataCenter
类:
class DataCenter { public static $global; ... }
目前我们的游戏还没有 Redis
连接方式,需要编写一个 Redis
驱动。
- 在
app
目录下新建Lib
目录,并新建一个Redis.php
文件。 - 使用单例模式编写
Redis
驱动。 - 在
DataCenter
类中,新增一个redis()
方法返回Redis
实例。
Redis
类:
<?php namespace App\Lib; class Redis { protected static $instance; protected static $config = [ 'host' => '127.0.0.1', 'port' => 6379, ]; /** * 获取 redis 实例 * * @return \Redis|\RedisCluster */ public static function getInstance() { if (empty(self::$instance)) { $instance = new \Redis(); $instance->connect( self::$config['host'], self::$config['port'] ); self::$instance = $instance; } return self::$instance; } }
DataCenter
类:
class DataCenter { ... public static function redis() { return Redis::getInstance(); } ... }
到这里为止所有准备都做好了,下面开始正式进入到游戏功能开发。
进入匹配队列
我们首先要做的第一个功能就是游戏匹配。
赵童鞋的想法是:
- 前端发送一个匹配消息到服务端。
- 服务端将玩家的ID放入一个
Redis
队列里。 - 当队列里人数满足条件时,创建一个游戏房间。
- 根据
player_id
获取连接fd
,发送游戏数据。
WebSocket
并不像普通的 HTTP
请求那样,一个功能对应一个接口,那我们要怎么区分发送和接收的消息呢?很简单,我们只要固定发送和接收数据的格式,其中加入一个参数 code
作为功能协议标识,所有的操作都根据发送和接收的 code
来进一步处理。
是不是看上去还挺好理解呢?我们先从前端入手。
- 新增输入框,绑定
Vue
数据属性playerId
,并默认生成一个随机ID。 - 新增按钮,绑定
Vue
方法matchPlayer
,点击按钮时发送code
为600
的数据。 - 在
WebSocket
连接的时候,发送玩家playerId
到服务端。
index.html
... <div id="app"> <label> 玩家ID: <input type="text" :value="playerId"> </label> <button @click="matchPlayer">匹配</button> </div> <script> var app = new Vue({ ... data: { playerId: 'player_' + Math.round(Math.random() * 1000), ... }, ... methods: { //匹配玩家 matchPlayer() { let actions = {"code": 600}; this.websocketsend(actions); }, initWebSocket() { //初始化websocket const wsuri = "ws://192.168.3.41:8811?player_id=" + this.playerId; ... }, ... } }) </script> ...
前端代码不多,下面轮到服务端实现。
服务端将会涉及到三个类,也就是 Server
、 Logic
、 DataCenter
,这三个类的调用顺序是:
-
Server
将用户信息如playerId
保存到DataCenter
-
Server
接收到数据,调用Logic
中的逻辑。 -
Logic
中的逻辑调用DataCenter
进行数据操作。
Server → Logic ↓ ↓ → DataCenter
Server
类
我们采用自顶向下的方法来编写试试,不存在的方法也可以先写出来调用。
先从 Server
开始。从前端代码可以看到,在 WebSocket
建立连接的时候,前端会发送 player_id
到服务端,这个时候我们需要把 player_id
和连接 fd
保存在 DataCenter
中。普通的消息会带有一个 code
用来标识协议码,我们需要根据 code
为 600
时,调用 Logic
匹配。
- 在
Server
类初始化的时候,初始化Logic
对象保存在私有变量$logic
,用于调用Logic
类中的方法。 - 在
onOpen
事件中,保存用户的player_id
和fd
在DataCenter
的setPlayerInfo()
方法中。 - 在
onMessage
事件中,根据当前连接的fd
获取player_id
,当前端发送的消息中的code
为600
时,调用Logic
中的matchPlayer()
方法
- 记得多多阅读官方文档哦: https://wiki.swoole.com/wiki/...
Server
类:
<?php ... class Server { const CLIENT_CODE_MATCH_PLAYER = 600; ... private $logic; public function __construct() { $this->logic = new Logic(); ... } ... public function onOpen($server, $request) { DataCenter::log(sprintf('client open fd:%d', $request->fd)); $playerId = $request->get['player_id']; DataCenter::setPlayerInfo($playerId, $request->fd); } public function onMessage($server, $request) { DataCenter::log(sprintf('client open fd:%d,message:%s', $request->fd, $request->data)); $data = json_decode($request->data, true); $playerId = DataCenter::getPlayerId($request->fd); switch ($data['code']) { case self::CLIENT_CODE_MATCH_PLAYER: $this->logic->matchPlayer($playerId); break; } } ... } ...
Logic
类
下面到 Logic
类, Logic
其实代码不多,他需要实现的就是接收 Server
传递的消息并执行具体的逻辑。
- 新增
matchPlayer()
方法,将Server
传递过来的player_id
放入DataCenter
的匹配队列中。
<?php ... class Logic { public function matchPlayer($playerId) { DataCenter::pushPlayerToWaitList($playerId); } }
DataCenter
类
有了上述两个类的调用,我们的 DataCenter
需求就清晰很多了,需要实现用户信息的存取,需要实现一个队列的进出和长度查询,用于玩家匹配。
- 新增常量
PREFIX_KEY
,作为所有Redis
的key
前缀,区别于其他应用缓存值。 - 为
playerId
和fd
编写setter
、getter
和delete
方法,需要实现playerId
和fd
可以互相查找。 - 实现匹配队列的
push
、pop
、getLength
方法。 - 完成
Server
调用的setPlayerInfo()
方法,保存player_id
和fd
。
本章作为第一个游戏功能开发,请童鞋们尽量完成Homework哦,其他功能如邀请、观战也将会是这个调用流程。
当前目录结构:
HideAndSeek ├── app │ ├── Lib │ │ └── Redis.php │ ├── Manager │ │ ├── DataCenter.php │ │ ├── Game.php │ │ └── Logic.php │ ├── Model │ │ ├── Map.php │ │ └── Player.php │ └── Server.php ├── composer.json ├── composer.lock ├── frontend │ └── index.html ├── test.php └── vendor ├── autoload.php └── composer
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 用Swoole来写个联机对战游戏呀!(五)联机初始化
- 用Swoole来写个联机对战游戏呀!(三)完善游戏功能
- 用Swoole来写个联机对战游戏呀!(四)游戏结束判断
- 用Swoole来写个联机对战游戏呀!(八)创建游戏房间
- 从动物森友会聊主机游戏联机原理
- 用Swoole来写个联机对战游戏呀!(二)单机游戏架构
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Distributed Algorithms
Wan Fokkink / The MIT Press / 2013-12-6 / USD 40.00
This book offers students and researchers a guide to distributed algorithms that emphasizes examples and exercises rather than the intricacies of mathematical models. It avoids mathematical argumentat......一起来看看 《Distributed Algorithms》 这本书的介绍吧!