基于Laya游戏引擎实现微信小游戏排行榜
我们都知道,微信小游戏和小程序目前风头十足,很多公司都逐渐增加了相关业务线来迅速推广自己的产品和抢占用户群。说到微信小游戏,就不得不提到排行榜这个功能,就目前游戏行业,似乎都离不开排行榜这个重要功能,用户很大一部分留存都是依仗这个看似不起眼的模块。那么,微信小游戏中具体该如何借助laya引擎实现排行榜这个功能呢?我们先来看一下最终的效果图:
按照微信官方的说法,如果我们要使用微信官方提供的好友关系链的数据,我们就不能直接在项目中绘制排行榜,我们需要借助于开放域来绘制排行榜:
如果想要展示通过关系链 API 获取到的用户数据,如绘制排行榜等业务场景,需要将排行榜绘制到 sharedCanvas
上,再在主域将 sharedCanvas 渲染上屏。简单来说,sharedCanvas 是主域和开放数据域都可以访问的一个离屏画布。在开放数据域调用 wx.getSharedCanvas() 将返回 sharedCanvas。更多相关详情可以去看看官网的介绍:https://mp.weixin.qq.com/debug/wxagame/dev/tutorial/open-ability/open-data.html
那么我们来实际动手操作一下吧。
主域绘制
通过效果可以看出来,我们排行榜是一个弹窗形式展示的,由于开放域只负责排行榜UI绘制,所以,除此以外的UI以及交互我们需要在主域绘制和处理。因此,这里的弹窗 dialog
需要在主域绘制,然后将对应的排行榜需要显示的位置信息和长宽映射到开放域,具体代码如下:
/*** 显示排行榜数据*/function onRankInfoLoad(){console.log("查看排行榜~");var dialog = new RankDialogUI();showShareCanvas();// 解决显示对象和鼠标错位而导致的排行榜滑动无效问题var globalPosition = dialog.ranking_list.localToGlobal(new Laya.Point());var originMatrix = Laya.stage._canvasTransform;var mat = new Laya.Matrix(originMatrix.a, 0, 0, originMatrix.d, globalPosition.x * originMatrix.a, globalPosition.y * originMatrix.d);wxPostMessage({command: 0,text: "设置开放域canvas大小",canvasData: {width: rankViewWidth * mat.a, height: rankViewHeight * mat.d, matrix: mat},isLoad: false}, null, function (message) {console.log("再次往开放域发请求");window['wx'].postMessage({command: 1,text: '开放域加载资源',});});Laya.stage.addChild(dialog);dialog.ranking_list.visible = false;dialog.popup();Laya.timer.once(400,this,function(){wxPostMessage({command: 3,text: "获取排行榜数据~"}, null, function (message) {console.log("获取排行榜的回调~");});});dialog.btn_rank_dialog_share.on(Laya.Event.CLICK, this, onGameRankShare);dialog.btn_rank_dialog_back.on(Laya.Event.CLICK, this, onDialogClose);function onDialogClose(){wxPostMessage({command: 4,text: "关闭排行榜~"}, null, function (message) {console.log("关闭排行榜的回调~");});dialog.close();}function onGameRankShare(){console.log("分享排行榜~");window['wx'].showShareMenu({withShareTicket:false,success:function(res){console.log("开启转发成功~");},fail:function(res){console.log("开启转发失败~");},complete:function(res){}});window['wx'].onShareAppMessage(function () {return {title: '我在飞机大战游戏中排名又上升了,快来挑战我吧~'}})window['wx'].shareAppMessage({title: '我在飞机大战游戏中排名又上升了,快来挑战我吧~',imageUrl: canvas.toTempFilePathSync({x: (screenWidth - rankViewWidth)/2 - 10,y: (screenHeight - rankViewHeight)/2+80,width: (rankViewWidth - 30)*4,height: (rankViewHeight - 40)*4,destWidth: 500,destHeight: 600})});}}/*** 设置共享Canvas*/function showShareCanvas(){window['sharedCanvas'].width = rankViewWidth;window['sharedCanvas'].height = rankViewHeight;//主域显示开放域内容???//window['sharedCanvas'].sharedCanvas = window['wx'].getOpenDataContext().canvas;Laya.timer.once(1000, this, function () {var sprite = new Laya.Sprite();sprite.zOrder = 1008;sprite.pos(0, 0);var texture = new Laya.Texture(window['sharedCanvas']);texture.bitmap.alwaysChange = true;//小程序使用,非常费sprite.graphics.drawTexture(texture, (screenWidth - rankViewWidth)/2, (screenHeight - rankViewHeight)/2, texture.width, texture.height);Laya.stage.addChild(sprite);});}
这边主要发送的消息体中携带了command字段,用于在开放域执行不同的功能代码,这边大体分为:资源加载命令、初始化排行榜大小命令、获取关系链(排行榜)数据命令以及关闭排行榜的命令,大家可以根据业务具体需要适当增减。
开放域绘制
根据官方的说明,开放数据域
是一个封闭、独立的 JavaScript 作用域。要让代码运行在开放数据域,需要在 game.json 中添加配置项 openDataContext
指定开放数据域的代码目录。添加该配置项表示小游戏启用了开放数据域,这将会导致一些 限制。这些限制主要包含:
- 无法设置sharedCanvas的宽高
- 只能使用有限的接口(如逐帧动画、Timer、触摸事件以及获取和设置关系链数据等接口)
下面我们一步步来在开放域绘制排行榜。
首先,需要新建一个项目作为开放域,这个项目目录是与主域项目平行的(主域就是未做排行榜之前的项目目录),比如我的项目目录是这样的:
接着,我们需要在开放域中接收主域发送的消息并处理不同的功能命令,UI就不放了,看看具体代码吧:
/*** 监听从主域发过来的消息*/function wxOnMessage(){if(window['wx'] != undefined){window['wx'].onMessage(function (message){dispatchMessage(message);});}else{console.log("微信接口无法使用~");}}/*** 处理消息* @param {*} message */function dispatchMessage(message){switch(message.command){//设置开放域画布大小case 0:sample.setCanvasSize(message.canvasData);break;//加载资源case 1:sample.loadResource();break;//写入排行榜数据case 2:sample.writeRankingData(message.rankingData);break;//获取微信排行榜数据case 3:sample.getRankingData();break;//关闭排行榜case 4:sample.closeRankingDialog();break;default:console.log(JSON.stringify(message));}}/*** 设置开放域画布大小* @param {*} size */_proto.setCanvasSize = function(size){console.log("设置开放域canvas大小~");window['sharedCanvas'].width = size.width;window['sharedCanvas'].height = size.height;//Laya.stage.width = size.width;//Laya.stage.width = size.height;/*** 将主域的canvasTransform映射到开放域*/if(size.matrix!=null){console.log("收到主域的同步canvasTransform了~");}var mainMatrix = size.matrix;var openMatrix = new Laya.Matrix();openMatrix.a = mainMatrix.a;openMatrix.b = mainMatrix.b;openMatrix.c = mainMatrix.c;openMatrix.d = mainMatrix.d;openMatrix.tx = mainMatrix.tx;openMatrix.ty = mainMatrix.ty;//重置矩阵Laya.stage._canvasTransform = openMatrix;//监听舞台的鼠标移动事件Laya.stage.mouseEnabled = true;}/*** 用户自己的排名*/var myRanking = -1;/*** 获取微信排行榜数据*/_proto.getRankingData = function(){window['wx'].getUserInfo({openIdList: ['selfOpenId'],success: (userRes) => {console.log('success', userRes.data);//索引代表各个好友0为自己let userData = userRes.data[0];console.log("取信息索引0" + userData.nickName);//取出所有好友数据window['wx'].getFriendCloudStorage({keyList: [//'击杀排行','第1关','第2关','第3关'],success: res => {console.log("wx.getFriendCloudStorage success", res);let data = res.data;/*data.sort((a, b) => {if (a.KVDataList.length == 0 && b.KVDataList.length == 0) {return 0;}if (a.KVDataList.length == 0) {return 1;}if (b.KVDataList.length == 0) {return -1;}return b.KVDataList[0].value - a.KVDataList[0].value;});*/for (let i = 0; i < data.length; i++) {var playerInfo = data[i];var currentPlayer = res.data[i].nickname;console.log("当前排行玩家昵称为=>"+res.data[i].nickname);var kvList = playerInfo.KVDataList;var scoreSum = 0;if(kvList.length>0){for(var j = 0;j<kvList.length;j++){if(kvList[j].key != null){//将value转化为int再累加scoreSum+=Number(kvList[j].value);}}}if (data[i].avatarUrl == userData.avatarUrl) {//获取群好友的时候,没有自己的名字??data[i].nickName = userData.nickName;myRanking = i+1;console.log("此ID为自己,当前排名第"+myRanking);}//填充总分信息sortData.push({nickName: currentPlayer, avatarUrl: data[i].avatarUrl, totalScore: scoreSum });}sortData.sort((a, b) => {var score1 = Number(a.totalScore);var score2 = Number(b.totalScore);if (score1 > score2) {return -1;}else if(score1 < score2){return 1;}else{return 0;}});showRankingDialog();},fail: res => {console.log("拉取好友信息失败", res);},});},fail: (res) => {console.log("拉取个人信息失败")}});}/*** 加载资源*/_proto.loadResource = function(){Laya.loader.load(["comp/bg_line.png","comp/ranking1.png","comp/ranking2.png","comp/ranking3.png","comp/userholder_img.png"], Laya.Handler.create(null,function(){console.log("开放域资源加载完毕~");sample.rankView = new RankingViewUI();Laya.stage.addChild(sample.rankView);}));}/*** 写入排行榜数据*/_proto.writeRankingData = function(rankingData){console.log("写入排行榜数据~");//KVDataList代表排行数据,可以为多个,多个代表多个排行//key-排行类型,value-排行分数window['wx'].setUserCloudStorage({KVDataList: [//{ key: '击杀排行', value: "" + 1 },{ key: '第'+rankingData.fightLevel+'关', value: rankingData.fightScore+"" },//需要改成动态的值],success: function (res) {console.log('setUserCloudStorage', 'success', res)},fail: function (res) {console.log('setUserCloudStorage', 'fail')}});}var sortData = [];/*** 渲染排行榜列表*/function showRankingDialog(){console.log("拿到好友排行榜信息", sortData);sample.rankView.ranking_list.vScrollBarSkin = "";sample.rankView.ranking_list.array = sortData;sample.rankView.ranking_list.renderHandler = new Laya.Handler(this, onRender);sample.rankView.ranking_list.selectHandler = new Laya.Handler(this, onSelect);}var lastRenderIndex = -1;function onRender(cell, index){if (index == lastRenderIndex) {return;}lastRenderIndex = index;//根据子节点的name获取子节点对象var name = cell.getChildByName("item_rank_name");var ranking = cell.getChildByName("item_rank_text");var userlogo = cell.getChildByName("item_rank_logo");var score = cell.getChildByName("item_rank_score");var rank_icon = cell.getChildByName("item_rank_icon");name.text = sortData[index].nickName;console.log("渲染排行榜当前的用户名为="+sortData[index].nickName+",渲染索引:"+lastRenderIndex);ranking.text = (index+1)+"";userlogo.skin = sortData[index].avatarUrl;score.text = sortData[index].totalScore+"分";if(lastRenderIndex === 0 || lastRenderIndex === 1 || lastRenderIndex === 2){ranking.visible = false;rank_icon.visible = true;rank_icon.skin = "comp/ranking"+(lastRenderIndex+1)+".png";}else{rank_icon.visible = false;ranking.visible = true;}}function onSelect(index){console.log("当前选择的索引是:"+index);}/*** 关闭排行榜*/_proto.closeRankingDialog = function(){//dialog.close();console.log("关闭排行榜~");sortData = [];lastRenderIndex = -1;sample.rankView.removeChildren();sample.rankView = null;}_proto.start = function(){console.log("开始接收主域的消息~");wxOnMessage();} }
可以看到,我们这里通过
wx.onMessage
方法来获取主域发送的数据,然后借助dispatchMessage
方法作消息的分发处理。值得注意的是,我们在设置开放域canvas大小的时候,需要重置坐标矩阵,将主域的排行榜显示位置映射到开放域中来,否则会发生滑动无效的问题。我这里设置的排行榜数据有三条,大家可以根据具体需求来传入,获取到排行榜数据后,需要对它进行排序处理并展示,这里直接借助于laya中的List
控件展示就可以了,对于它用法不熟悉的可以去laya官网了解一下:https://ldc.layabox.com/doc/?nav=zh-js-6-0-0开放域图片加载问题:
用过laya游戏引擎的都知道,我们一般用官方推荐的打包图集的方式来加载游戏中的图片资源,这种方式在主域中是可行的,然而,在开放域中却不能成功加载图片资源。因此,开放域中,我们不需要将图片资源打包成图集,只要像下面这样直接加载图片即可:
/*** 加载资源*/_proto.loadResource = function(){Laya.loader.load(["comp/bg_line.png","comp/ranking1.png","comp/ranking2.png","comp/ranking3.png","comp/userholder_img.png"], Laya.Handler.create(null,function(){console.log("开放域资源加载完毕~");sample.rankView = new RankingViewUI();Laya.stage.addChild(sample.rankView);}));}
然后,我们还需要将对应的图片文件夹拷贝到wx_publish目录下,否则会提示找不到图片资源。
合并主域和开放域
主域和开放域功能代码实现了之后,我们就需要打包成微信小游戏项目了。首先,我们需要先将主域项目发布成微信小游戏,发布目录直接为项目的根目录,如上图的 wx_publish
目录。然后,在该目录下创建src/myOpenDataContext目录。接着,我们需要将开放域项目也发布成微信小游戏,目录可以选择桌面,名称为 wx_open
,发布成功后,进入该目录,将code.js、weapp-adapter.js以及index.js文件复制到 wx_publish/src/myOpenDataContext
目录下,并在 game.json
文件中增加开放域映射目录:
{"deviceOrientation": "portrait","showStatusBar": "false","networkTimeout": {"request": 10000,"connectSocket": 10000,"uploadFile": 10000,"downloadFile": 10000},"openDataContext": "src/myOpenDataContext"
}
到这里,微信小游戏排行榜功能就算实现了,到头来发现,其实实现起来并不难,难的是缺乏资料,此文仅用来抛砖引玉,如有问题欢迎提出。
基于Laya游戏引擎实现微信小游戏排行榜相关推荐
- 白鹭引擎解决微信小游戏切换背景音乐无法播放的问题。
白鹭引擎 版本:5.2.8 描述:白鹭引擎解决微信小游戏切换背景音乐无法播放的问题. main.ts文件中找到如下函数,增加上您的音频对象. egret.lifecycle.onResume = () ...
- Egret白鹭引擎开发微信小游戏之保存图片到相册
玩家在玩小游戏的过程中,很多时候想要保存一下当前的截图.或者保存游戏内精美的画面到相册,一方面是为了记录在游戏中的美好时刻,另一方面则是能够更好地和朋友们分享我在这游戏中获得的荣耀和快乐,因为我们就会 ...
- 极光会客厅:大型H5游戏如何登陆微信小游戏及游戏性能优化分享
上周末,由极光网络主办的首期"极光会客厅"正式开门迎客.在本次的"2D小游戏开发实战技术沙龙"上,极光网络客户端主程陈策以及极光网络项目总监陈源向一众与会者分享 ...
- h5小游戏嵌入到微信小游戏中(以egret为例)
H5小游戏源代码不能直接转换为微信小游戏发布,但是可以把现有的h5小游戏嵌入到微信小游戏中,这里使用egret举例.使用egret创建一个空的微信小游戏,在main.ts中资源加载完成后执行Webvi ...
- 使用Laya引擎开发微信小游戏(下)
本文由云+社区发表 6. 动画 6.1 创建伞兵对象 在src目录下创建一个新目录role,用来存放游戏中角色. 在role里创建一个伞兵Soldier.ts对象文件. module role{exp ...
- 白鹭引擎开发微信小游戏: API 调用教程文档
如何在 Egret 中调用小游戏 API 在 Egret 中是可以直接调用小游戏的 API 的,这篇文档简要介绍如何在 Egret 中使用小游戏的 API. 新增 platform.ts 文件 在 ...
- 白鹭引擎开发微信小游戏新手教程文档
开发环境准备 • Egret Launcher 1.0.32 以上版本(包括 1.0.32) • 白鹭引擎 5.1.2 以上版本(包括 5.1.2) • 准备最新版微信开发者工具.下 ...
- 白鹭引擎开发微信小游戏进阶教程文档
注意: • 因为小游戏特殊机制,涉及到的小游戏接口主要逻辑都需要写在小游戏逻辑代码内,但是可以通过 Egret 代码来调用 • 后续版本 Egret 将会提供调用小游戏接口模板,届时大家可 ...
- 微信小游戏html5教程,微信小游戏白鹭引擎插件使用教程
为了更好的提升微信小游戏的打开速度,提高用户体验,微信正式发布了引擎插件功能,白鹭引擎第一时间支持并正式发布支持该功能的5.2.31版本.以下是白鹭引擎插件使用的详细说明文档及常见问题解答,请诸位开发 ...
最新文章
- AI:2020年6月22日北京智源大会演讲分享之19:00-19:40《 圆桌论坛:人工智能产业的下一个十年》
- dom复制cloneNode节点与插入节点appendChild()
- Boost:以协程的方式实现带有单个默认值的echo服务器的实例
- goldendb基于mysql_中兴通讯GoldenDB在中信银行信用卡核心应用实践
- wireshark 抓包分析 TCPIP协议的握手
- 数据大屏可视化展示系统有什么作用
- 真希望能夠統一一下接口
- 环境php5.2+mysql_php环境搭建问题(简单记录二------php5.2不加载mysql扩展)
- landsat8数据下载相关小知识
- HDU-2819-Swap [二分匹配][输出路径]
- Message from debugger: Terminated due to signal 6
- CSS基础:浅用字体图标(以阿里字体图标库演示)
- android动态壁纸的制作教程,android – 动态壁纸教程
- android uri parcel,Android Intent 使用 Parcel 反序列化出错.
- centOS7 防火墙关闭 远程端口无法访问问题
- Java数据类型系列之包装类
- 《PyQt5高级编程实战》学会使用视图委托
- ansible dnf模块详解
- 计算机最低配置有哪些,win10对电脑配置有哪些要求?win10最低配置要求
- python如何生成指定均值向量和协方差矩阵的多维正态分布数据
热门文章
- c语言break在if中用法,break可用于什么语句 break语句可用于for语句和if语句中 对吗...
- 深度学习中的经典基础网络结构(backbone)总结
- 跟着福禄克工程师一起学习POE知识
- 实验 4 电磁波的传播与辐射
- 路由器密码忘记 五步暴力破解
- python实现0到1之间的随机数
- 连接数据库报错com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure的解决方法
- 网易互娱2018校招游戏研发工程师在线笔试
- Symbian 百科
- STC32G12K128-Beta WS2812控制 RGB与HSV互相转换