联机逻辑开发进度:□□□□□□□□□□□□
本章结束开发进度:■■□□□□□□□□□□
Swoole开发环境
教程使用Swoole 4.3.0
版本开发,但并没有使用协程等功能,只是使用了WebSocket Server
,理论上安装旧版也是没问题的。环境需要大家自行安装,这个也是学习的一个过程。
以下是一些有可能有帮助的资料:
CentOS
中一键安装PHP
开发环境:https://lnmp.org/install.htmlSwoole
安装教程:https://wiki.swoole.com/wiki/...Redis
安装教程:https://redis.io/downloadphp-redis
扩展包:http://pecl.php.net/package/r...
童鞋们也可以像我一样在Windows
使用PHPStorm
进行开发,再通过一些方法如共享文件夹
、WinSCP
等工具将项目在CentOS
中运行起来。
安装swoole-ide-helper扩展
使用PHPStorm
来开发Swoole
项目的童鞋,如果不想面向运气编程的话,最好安装一个swoole-ide-Helper
扩展来协作开发。
在项目根目录运行以下命令:
composer require --dev "eaglewu/swoole-ide-helper:dev-master"
安装完毕我们就可以愉快地编写Swoole
代码了。
服务端基本架构
赵童鞋设想的基本架构需要三个层,他们分别是:
- 网络层:管理
Swoole WebSocket
对象,主要负责接收前端消息,传递到逻辑层进行处理。 - 逻辑层:接收网络层传递的消息,主要负责游戏房间创建、玩家移动、结束检测等游戏逻辑。
- 数据层:用于管理玩家ID、房间ID、匹配队列等数据。
管理这三个层分别需要三个类:Server
、Logic
、DataCenter
。
其中最重要的就是Server
类,它的作用就是作为服务端和客户端的消息交换中心,我们先来写一个初始化的Server
类,在项目app
目录新建Server.php
。
- 使用面向对象的方式实现一个
WebSocket Server
类。 - 分别绑定
start
、workerStart
、open
、message
、close
回调方法 - 在类中引入
composer
自动加载机制。 - 为
WebSocket
对象设置4个worker
进程。
Swoole Websocket
:https://wiki.swoole.com/wiki/...
Server
类:
<?phprequire_once __DIR__ . '/../vendor/autoload.php';class Server{ const HOST = '0.0.0.0'; const PORT = 8811; const CONFIG = [ 'worker_num' => 4, ]; private $ws; public function __construct() { $this->ws = new \Swoole\WebSocket\Server(self::HOST, self::PORT); $this->ws->set(self::CONFIG); $this->ws->on('start', [$this, 'onStart']); $this->ws->on('workerStart', [$this, 'onWorkerStart']); $this->ws->on('open', [$this, 'onOpen']); $this->ws->on('message', [$this, 'onMessage']); $this->ws->on('close', [$this, 'onClose']); $this->ws->start(); } public function onStart($server) { swoole_set_process_name('hide-and-seek'); echo sprintf("master start (listening on %s:%d)\n", self::HOST, self::PORT); } public function onWorkerStart($server, $workerId) { echo "server: onWorkStart,worker_id:{$server->worker_id}\n"; } public function onOpen($server, $request) { } public function onClose($server, $fd) { } public function onMessage($server, $request) { }}new Server();
我们来运行一下Server.php
文件,顺便检验一下Swoole
扩展是否运行正常,在项目app
目录下,运行php Server
。
- 后面所有启动
Server
操作都是基于CentOS
环境
[root@localhost app]# php Server.php master start (listening on 0.0.0.0:8811)server: onWorkStart,worker_id:0server: onWorkStart,worker_id:1server: onWorkStart,worker_id:2server: onWorkStart,worker_id:3
如果输出以上信息,就代表Server
运行成功。
Logic
类和DataCenter
类属于游戏管理类,在Manager
文件夹下新建Logic.php
和DataCenter.php
文件,并在Datacenter
类中增加一个格式化输出日志的log()
方法。
Logic
类:
<?phpnamespace App\Manager;class Logic{}
DataCenter
类:
<?phpnamespace App\Manager;class DataCenter{ public static function log($info, $context = [], $level = 'INFO') { if ($context) { echo sprintf("[%s][%s]: %s %s\n", date('Y-m-d H:i:s'), $level, $info, json_encode($context, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); } else { echo sprintf("[%s][%s]: %s\n", date('Y-m-d H:i:s'), $level, $info); } }}
前端初始化
前端我们将会使用Vue
框架来开发,项目只使用到了v-if
、v-for
、<template>
、WebSocket
技术。如果没有接触过前端框架的童鞋,可以尝试阅读官方文档。
Vue
官方文档:https://cn.vuejs.org/v2/guide/v-if
:https://cn.vuejs.org/v2/guide...v-for
:https://cn.vuejs.org/v2/guide...<templater>
:https://cn.vuejs.org/v2/guide...
在项目根目录创建frontend
文件夹,并在其中创建index.html
文件,进行前端初始化。
- 使用
CDN
的形式引入Vue
框架。 - 根据
Vue
官方文档,编写一个HelloWorld
页面。
index.html
:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>HideAndSeek</title> <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script> <link rel="icon" href="data:;base64,="></head><body><div id="app"> {{ message }}</div><script> var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } })</script></body></html>
前端的HelloWorld
页面我们也有了,但是我们要怎么通过HTTP
请求获取到这个页面呢?这时候就需要使用Swoole
的Static Handler
功能。
Swoole Static Handler
文档:https://wiki.swoole.com/wiki/...
- 根据官方文档添加
Swoole Static Handler
配置。 - 为
Server
新增一个监听端口8812
,用于处理HTTP请求。
Server
类:
const FRONT_PORT = 8812;const CONFIG = [ ... 'enable_static_handler' => true, 'document_root' => '/mnt/htdocs/HideAndSeek_teach/frontend',];public function __construct(){ ... $this->ws->listen(self::HOST, self::FRONT_PORT, SWOOLE_SOCK_TCP); ...}
记得将代码中的document_root
改为自己项目的前端目录哦。
添加完以上代码后,在虚拟机中运行Server
,并尝试通过浏览器访问http://虚拟机ip:8812/index.html
浏览前端页面。
看到以上画面就代表访问成功。
WebSocket初始化
现在项目的服务端有了,前端页面有了,就差一个桥梁把他们连接起来,这个桥梁就是WebSocket
通信机制,项目使用到了简单的websock.onmessage
、websock.onopen
、websock.onerror
、websock.onclose
。
以下是一些有可能有帮助的资料。
- 阮一峰
WebSocket
教程:http://www.ruanyifeng.com/blo... Vue
生命周期:https://cn.vuejs.org/v2/guide...Swoole WebSocket onMessage
: https://wiki.swoole.com/wiki/...
- 为
Vue
实例新增data
属性websock
,在Vue
实例创建完毕后,初始化WebSocket
连接服务端并绑定上述四个方法。 - 在
WebSocket
对象建立连接后,立刻发送消息到服务端。 - 服务端接收到客户端发送的消息后,通过客户端的
fd
返回一条消息。 - 服务端增加客户端连接日志输出。
- 在页面关闭时,断开
WebSocket
连接。
- 不清楚
fd
是什么的童鞋可以参考Swoole
官方文档:https://wiki.swoole.com/wiki/...
本章项目初始化就到这里啦,请童鞋们尽量完成自己的Homework后,再进入下一章的学习。
当前项目结构:
HideAndSeek├── app│ ├── 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