热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

用Swoole来写个联机对战游戏呀!(六)游戏匹配机制

联机逻辑开发进度:■■□□□□□□□□□□本章结束开发进度:■■■■■□□□□□□□

联机逻辑开发进度:■■□□□□□□□□□□

本章结束开发进度:■■■■■□□□□□□□

上一章的答案:

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 开发者模式。

用Swoole来写个联机对战游戏呀!(六)游戏匹配机制

前端成功地发出了数据,服务端返回的数据也都接收到了,我们成功打通了游戏前后端。

游戏数据管理

游戏的数据主要有两个存储方式:

Redis

我们首先在 DataCenter 类中新增一个静态变量 $global ,所有的对战数据都将存储在这个变量中。

DataCenter 类:

class DataCenter
{
    public static $global;
    ...
}

目前我们的游戏还没有 Redis 连接方式,需要编写一个 Redis 驱动。

  1. app 目录下新建 Lib 目录,并新建一个 Redis.php 文件。
  2. 使用单例模式编写 Redis 驱动。
  3. DataCenter 类中,新增一个 redis() 方法返回 Redis 实例。

Redis 类:

 '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 来进一步处理。

是不是看上去还挺好理解呢?我们先从前端入手。

  1. 新增输入框,绑定 Vue 数据属性 playerId ,并默认生成一个随机ID。
  2. 新增按钮,绑定 Vue 方法 matchPlayer ,点击按钮时发送 code600 的数据。
  3. WebSocket 连接的时候,发送玩家 playerId 到服务端。

index.html

...
...

前端代码不多,下面轮到服务端实现。

服务端将会涉及到三个类,也就是 ServerLogicDataCenter ,这三个类的调用顺序是:

  • Server 将用户信息如 playerId 保存到 DataCenter
  • Server 接收到数据,调用 Logic 中的逻辑。
  • Logic 中的逻辑调用 DataCenter 进行数据操作。
Server    →    Logic

↓            ↓

→        DataCenter

Server

我们采用自顶向下的方法来编写试试,不存在的方法也可以先写出来调用。

先从 Server 开始。从前端代码可以看到,在 WebSocket 建立连接的时候,前端会发送 player_id 到服务端,这个时候我们需要把 player_id 和连接 fd 保存在 DataCenter 中。普通的消息会带有一个 code 用来标识协议码,我们需要根据 code600 时,调用 Logic 匹配。

  1. Server 类初始化的时候,初始化 Logic 对象保存在私有变量 $logic ,用于调用 Logic 类中的方法。
  2. onOpen 事件中,保存用户的 player_idfdDataCentersetPlayerInfo() 方法中。
  3. onMessage 事件中,根据当前连接的 fd 获取 player_id ,当前端发送的消息中的 code600 时,调用 Logic 中的 matchPlayer() 方法
  • 记得多多阅读官方文档哦: https://wiki.swoole.com/wiki/...

Server 类:

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 传递的消息并执行具体的逻辑。

  1. 新增 matchPlayer() 方法,将 Server 传递过来的 player_id 放入 DataCenter 的匹配队列中。
 
 

DataCenter

有了上述两个类的调用,我们的 DataCenter 需求就清晰很多了,需要实现用户信息的存取,需要实现一个队列的进出和长度查询,用于玩家匹配。

  1. 新增常量 PREFIX_KEY ,作为所有 Rediskey 前缀,区别于其他应用缓存值。
  2. playerIdfd 编写 settergetterdelete 方法,需要实现 playerIdfd 可以互相查找。
  3. 实现匹配队列的 pushpopgetLength 方法。
  4. 完成 Server 调用的 setPlayerInfo() 方法,保存 player_idfd

本章作为第一个游戏功能开发,请童鞋们尽量完成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来写个联机对战游戏呀!(六)游戏匹配机制


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 我们


推荐阅读
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
  • uniapp开发H5解决跨域问题的两种代理方法
    本文介绍了uniapp开发H5解决跨域问题的两种代理方法,分别是在manifest.json文件和vue.config.js文件中设置代理。通过设置代理根域名和配置路径别名,可以实现H5页面的跨域访问。同时还介绍了如何开启内网穿透,让外网的人可以访问到本地调试的H5页面。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • 代理模式的详细介绍及应用场景
    代理模式是一种在软件开发中常用的设计模式,通过在客户端和目标对象之间增加一层中间层,让代理对象代替目标对象进行访问,从而简化系统的复杂性。代理模式可以根据不同的使用目的分为远程代理、虚拟代理、Copy-on-Write代理、保护代理、防火墙代理、智能引用代理和Cache代理等几种。本文将详细介绍代理模式的原理和应用场景。 ... [详细]
author-avatar
沉醉不知归路1222
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有