收藏
评论

云开发实时数据推送制作小游戏匹配玩家功能

下面是功能介绍:

小程序·云开发新增实时数据推送能力,可以实时监听数据库中的数据变更。该功能有效地解决了即时通信以及实时更新和推送数据的问题,极大地降低在此类场景下的开发成本。

基于是实时数据推送能力,在给定查询条件的情况下,每当数据库更新而导致查询条件对应的查询结果发生变更时,小程序可收到一个更新事件,其中可获取更新内容和更新后的查询结果快照。

许多对战类型的小游戏需要一个匹配玩家界面,下面就从制作一个匹配玩家界面入手,简单介绍一下云开发实时数据推送功能。

1.首先打开微信开发者工具里云开发,在数据库中新建一个集合集合名称:rooms,权限设置:所有用户可读,仅创建者可读写。

2.我们用一个两人对战的例子,来介绍如何实现匹配玩家。当玩家进入匹配状态有两个情况,一是当前已经有队列玩家只需进入队列即可,二是当前没有队列玩家要创建队列。这里定义一下创建队列的人叫做newMen,加入队列的人叫做addMen。如何判定当前是否有队列,下面用一段代码说明下:

const db = wx.cloud.database();
const $ = db.command.aggregate;
db.collection('rooms')
.aggregate()
.match({
 people: $.eq(1)
})
.sort({
 createTimestamp: -1
})
.limit(1)
.end().then(res =>{
    console.log('聚合查询结果rooms',res.list);
    this.initRoom(res.list);
})

这里用的是聚合查询,对集合rooms进行查询,只要当前people字段值为1就说明已经队列,如果查询不到结果就是没有队列需要创建队列,下面就是initRoom()方法进行判断,代码如下:

initRoom(rooms){

       if (!rooms.length) {
 
            this.createEmptyRoom();
 
        else {
 
            console.log('进入队列成功');
 
            this.nowPlayer = 'addMen';
 
            this.docid = rooms[0]._id;
 

            this.roomid = rooms[0].roomid;

            

           this.updatePeopleField();


 
        };



}

从上面代码可以看出,如果查询结果为空就要创建队列。不为空就进入队列,然后执行更新字段操作,后面会详细介绍。下面介绍创建队列createEmptyRoom()方法,代码如下:

createEmptyRoom(){
                    const db = wx.cloud.database();
                    const roomid = Date.now().toString();
                    let room = {
                        roomid,
                        createTimestamp: Date.now().toString(),
                        people: 1,
                    };
                    db.collection('rooms').add({ data: room })
                    .then(res =>{
                        this.nowPlayer = 'newMen';
                        this.docid = res._id;
                        this.roomid = roomid;
                        this.waitJionGame();
                    })
    },

这里向集合rooms添加一个新记录,即创建队列,当前玩家即nowPlayer为newMen。创建队列完成后,我们要监听是否有玩家进入队列,就是有没有addMen进来。这里就要用到上面说的云开发实时数据推送功能了,相关代码如下:


waitJionGame(){
        let docid = this.docid;
        console.log('正在匹配对手...');
        const db = wx.cloud.database();
        this.player = db.collection('rooms')
        .where({
          _id: docid
        })
        .watch({
          onChange: snapshot => {
            const docChange = snapshot.docChanges[0];
            const doc = snapshot.docs[0];
            console.log('监听玩家进入', snapshot);
            if (docChange.dataType === 'update' && doc.people === 2) {
                console.log('匹配成功');
                this.player.close();
            }
          },
          onError: error => {
              console.log(error);
          }
        })
    },

通过对刚才创建的记录进行监听,只要dataType === 'update'即记录有更新操作,并且doc.people === 2,就说明有玩家进入即addMen进入队列,此时就可以关闭监听,执行close()。这时队列创建者即newMen,匹配阶段所有工作都完成了。对于加入队列者即addMen还有一个工作,告诉newMen我已经进入队列了,很简单就是把记录里的people字段更新为2。相关代码如下:

updatePeopleField() {

       let docid = this.docid;

        wx.cloud.callFunction({
          name: 'updateDoc',
          data: {
            collection: 'rooms',
            docid: docid,
            people: 2,
          }
        }).then(res => {
            console.log('更新人数成功',res);
        }).catch(err => {
            console.log(err);
        })
    },

更新队列创建者newMen创建的记录里的字段是一个越权操作,所以要调用云函数。通过云函数更新完成字段后,addMen所有使命都已经完成了。

这就是整个匹配玩家阶段的流程,相关效果可以参考本人开发的游戏--圣兵棋盘。


圣兵棋盘


收藏

3 个评论

  • 倘若。
    倘若。
    2022-03-08

    你好 我想问一下,这个如何进行调试才能够知道是两个人进入了匹配

    2022-03-08
    赞同
    回复
  • 林伊
    林伊
    2019-09-19

    假设多个人同时发起匹配请求,这个时候可能会发生匹配到一起的情况,因为数据库还没更新数据。这种情况要怎么处理?

    如果上面这个情况听起来很极限的话..那假设两个用户匹配成功了,同时向数据库写入一条记录,这个记录是用户的openid。

    逻辑是:openIdArr [ openIdArr.length ] = openid;

    这个时候就会出现openIdArr中实际上只有一条数据,因为两个用户读到的数据库记录中openIdArr长度都是0。

    2019-09-19
    赞同
    回复
  • 明月三千里
    明月三千里
    2019-09-16

    这不就是1024吗。我玩了一局,为啥对面分数是undefined

    2019-09-16
    赞同
    回复
登录 后发表内容