用egret + p2 做一个类似投球的小游戏,坑大致如下:

1、p2引擎与egret坐标不同注意转换,横坐标没什么,纵坐标egret.y = stageHeight - body.position[1]*factor

2、p2物体的原点为中心点,而egret显示对象的原点为左上角,设置display.anchorOffsetX = display.width/2;display.anchorOffsetY = display.height/2

3、p2的单位与egret像素单位的factor设置为50,计算body坐标或display坐标时注意实时更新

4、p2的碰撞检测代码如下,注意一定要给body设置个id,而且id必须是number

  1. this._world.on("beginContact", this.contact);
  2. contact = (evt) => {
  3. var bodyA:p2.Body = evt.bodyA;
  4. var bodyB:p2.Body = evt.bodyB;
  5.  
  6. if (!bodyA || !bodyB) {
  7. return;
  8. }
  9. var bodyIdA = bodyA.id;
  10. var bodyIdB = bodyB.id;
  11. //这里一定要用id来确定碰撞的body
  12. }

  

5、摩擦系数、弹性等属性可通过设置不同材质来设置,全局反弹系数用defaultContactMaterial,材质定义个id,然后body设置其material即可

  1. private init(){
  2. // 创建物理世界
  3. this._world = new p2.World();
  4. this._world.gravity = [0, Constants.WORLD_GRAVITY];
  5. //默认所有弹性
  6. this._world.defaultContactMaterial.restitution = 0.5;
  7. //不同材质的系数
  8. let m1 = new p2.Material(Constants.BALL_MATERIAL);
  9. let m2 = new p2.Material(Constants.NET_MATERIAL);
  10. let m3 = new p2.Material(Constants.BASKET_MATERIAL);
  11. let m1_m2 = new p2.ContactMaterial(m1,m2,<p2.ContactMaterialOptions>{restitution:0.01,friction:0});
  12. this._world.addContactMaterial(m1_m2);
  13. let m1_m3 = new p2.ContactMaterial(m1,m3,<p2.ContactMaterialOptions>{restitution:0.6,friction:0.3});
  14. this._world.addContactMaterial(m1_m3);
  15. }
  16.  
  17. createBody(){
  18. // 创建球
  19. let box = new p2.Body({mass:1});
  20. var boxShape:p2.Shape = new p2.Circle({
  21. radius: 10,
  22. material: new p2.Material(Constants.BALL_MATERIAL)
  23. });
  24. box.addShape(boxShape);
  25. let sp = new egret.Shape();
  26. sp.graphics.beginFill(0xfff000);
  27. sp.graphics.drawCircle(0,0,10);
  28. sp.graphics.endFill();
  29. sp.anchorOffsetX = sp.width/2;
  30. sp.anchorOffsetY = sp.height/2;
  31. box.displays = [sp];
  32.  
  33. //创建篮筐
  34. let basket = new p2.Body({mass:1});
  35. var basketShape:p2.Shape = new p2.Circle({
  36. radius: 10,
  37. material: new p2.Material(Constants.BASKET_MATERIAL)
  38. });
  39. basket.addShape(basketShape);
  40. let sp1 = new egret.Shape();
  41. sp1.graphics.beginFill(0xfff000);
  42. sp1.graphics.drawCircle(0,0,10);
  43. sp1.graphics.endFill();
  44. sp1.anchorOffsetX = sp1.width/2;
  45. sp1.anchorOffsetY = sp1.height/2;
  46. basket.displays = [sp1];
  47. }

6、可以将world.step()向前走一段时间,然后记录刚体位置,画出轨迹即可实现模拟运动,但是正常step的时候第一帧必须设置与模拟的step帧保持一致,否则可能会出现错位和模拟与实际位置不符情况

  1. /**
  2. * 模拟运动
  3. */
  4. private simulate_move():void {
  5. for (var i:number = 0; i < 10; i++) {
  6. this._world.step(40 / 1000);
  7. // 记录位置
  8. this._ball.updateDisplayPosition();
  9. }
  10. }
  11. //正常step
  12. private loop(timestamp:number):boolean {
  13. var pass = 40;
  14. if (this._timestamp > 0) {
  15. pass = timestamp - this._timestamp;
  16. }
  17.  
  18. this._timestamp = timestamp;
  19. if (pass < 10) {
  20. return;
  21. }
  22.  
  23. if (pass > 1000) {
  24. return;
  25. }
  26.  
  27. this.step(pass);
  28. }

7、可设置刚体的sleepSpeedLimit和sleepTimeLimit来判断刚体是否可处于sleeping状态,然后通过world.broadphase.result判断sleeping状态下与哪些body处于碰撞状态,注意这个result是不断变化的,最好在sleeping的第一次就判断

  1. if (this.sleepState == p2.Body.SLEEPING || this.sleepState == p2.Body.SLEEPY) {
  2. let arr = this.world.broadphase.result;
  3. let num = 0;
  4. for(let i = 0;i < arr.length;i++){
  5. if(arr[i].id == Constants.BODY_ID.BALL){
  6. num++;
  7. }
  8. if(arr[i].id == Constants.BODY_ID.BASKET_1 + Constants.BODY_ID.NET){
  9. num++;
  10. }
  11. if(arr[i].id == Constants.BODY_ID.BASKET_1 + Constants.BODY_ID.TOPMASK){
  12. num++;
  13. }
  14.  
  15. }
  16. if(num >= 3){
  17. console.log("sleepy and reset 了");
  18. this.resetStatus();
  19. }
  20. }

8、可通过applyImpulse给body一个初始速度,来实现发射状态,钢体之间碰撞与不碰撞用this._world.enableBodyCollision(body1, body2);和this._world.disableBodyCollision(body1,body2);来设置

9、微信小游戏的sharedcanvas绘制可能会闪屏,解决方法game.js和egret都设置成60帧

10、微信小游戏sharedCanvas绘画的时候最好用相对坐标,不然可能会出现缩放的问题,取windowWidth和windowHeight,然后根据主屏幕的宽高比计算排行榜的大小和位置,接着进行相对运算,下面的代码是根据

屏幕宽度适配的(fixedWidth),为防止绘画出现高低不齐,故保持了宽高比的windowHeight,这里的排行榜我是放到egret的一个UI里的,不是主屏幕,如果是整个贴在主屏幕则可以不用保持主舞台宽高比的windowHeight,

以下是整个openDataContext的index.js

  1. /**
  2. * 资源加载组,将所需资源地址以及引用名进行注册
  3. * 之后可通过assets.引用名方式进行获取
  4. */
  5. const assetsUrl = {
  6. line:"openDataContext/assets/line.png"
  7. };
  8.  
  9. class openDataContextMain{
  10. constructor(){
  11. this.init();
  12. }
  13.  
  14. init(){
  15. //获取canvas渲染上下文
  16. this.context = sharedCanvas.getContext("2d");
  17. this.context.globalCompositeOperation = "source-over";
  18. this.sWidth = sharedCanvas.width;
  19. //根据宽度适配的 防止画的排行榜出现向下错位
  20. this.sHeight = this.sWidth*1330/750;
  21. this.assets = {};
  22. this.userData = null;
  23. this.friendData = null;
  24. this.groupData = null;
  25. if(!this.hasLoadRes){
  26. this.preloadAssets();
  27. }
  28. else{
  29. this.addOpenDataContextListener();
  30. }
  31. }
  32. //资源加载
  33. preloadAssets(){
  34. let preloaded = 0;
  35. let count = 0;
  36. for (let asset in assetsUrl) {
  37. count++;
  38. const img = wx.createImage();
  39. img.onload = () => {
  40. preloaded++;
  41. if (preloaded == count) {
  42. // console.log("加载完成");
  43. this.hasLoadRes = true;
  44. this.addOpenDataContextListener();
  45. }
  46. }
  47. img.src = assetsUrl[asset];
  48. this.assets[asset] = img;
  49. }
  50. }
  51. //添加监听
  52. addOpenDataContextListener() {
  53. console.log('增加监听函数')
  54. wx.onMessage((data) => {
  55. console.log(data);
  56. if(data.command == 'init'){
  57. //获取用户游戏信息
  58. this.ownOpenId = data.openid;
  59.  
  60. //获取用户好友游戏信息
  61. if(!this.friendData){
  62. wx.getFriendCloudStorage({
  63. keyList:['score'],
  64. complete: res => {
  65. if (res.errMsg == "getFriendCloudStorage:ok"){
  66. this.friendData = this.sortFriendData(res.data);
  67. }
  68. }
  69. });
  70. }
  71. //获取用户群组里的排行
  72. // if(!this.groupData){
  73. // wx.getGroupCloudStorage({
  74. // success: res => {
  75. // if (res.errMsg == "getGroupCloudStorage:ok"){
  76. // this.groupData = data;
  77. // }
  78. // },
  79. // fail:error=>{
  80. // console.log(error);
  81. // }
  82. // });
  83. // }
  84. }
  85. else if (data.command == 'friend') {
  86. this.drawFriendRank(data.page);
  87. } else if (data.command == 'group') {
  88. this.drawGroupRank(data.page);
  89. }
  90. });
  91. }
  92. //对好友数据进行排序组装
  93. sortFriendData(arr){
  94. if(!arr || arr.length == 0) return null;
  95. let len = arr.length;
  96. for(let i = 0;i < len;i++){
  97. let data = arr[i];
  98. let klist = data.KVDataList;
  99. for(let j = 0;j<klist.length;j++){
  100. let obj = klist[j];
  101. if(obj.key == 'score'){
  102. data[obj.key] = obj.value;
  103. break;
  104. }
  105. }
  106. }
  107. //排序
  108. arr.sort((a,b)=>{
  109. if (a.score > b.score) return -1;
  110. if (a.score < b.score) return 1;
  111. return 0;
  112. });
  113.  
  114. return arr;
  115. }
  116. //获取自己的排名信息
  117. getOwnRank(){
  118. let len = this.friendData.length;
  119. for(let i = 0;i < len;i++){
  120. if (this.friendData[i].openid == this.ownOpenId){
  121. return [i+1,this.friendData[i]];
  122. }
  123. }
  124. return null;
  125. }
  126. //画好友排行榜
  127. drawFriendRank(page = 1){
  128. this.context.clearRect(0,0,this.context.canvas.width,this.context.canvas.height);
  129. if(!this.friendData || this.friendData.length == 0) return;
  130. let len = this.friendData.length;
  131. if(page > Math.ceil(len/7)){
  132. page--;
  133. }
  134.  
  135. let itemWidth = this.sWidth * 2/3;
  136. let itemHeight = this.sHeight * 900/1330;
  137. let mid = itemHeight/9.8;
  138. let lx = itemWidth/600;
  139. let ly = mid/10;
  140. let fontSize = itemWidth/25;
  141. let i = (page-1)*7;
  142. let max = page*7;
  143. for(;i < max;i++){
  144. let obj = this.friendData[i];
  145. if(!obj) break;
  146. let yy = (i%7) * mid;
  147. this.context.fillStyle = '#65b5f7';
  148. this.context.font = fontSize + 'px Arial bold';
  149. this.context.textAlign = 'center';
  150. this.context.fillText(''+(i+1),20*lx,yy+ly*5);
  151. let image = wx.createImage();
  152. image.src = obj.avatarUrl;
  153. this.drawImage(image,80*lx,yy + ly*1,70*lx,70*lx);
  154. this.context.fillStyle = '#a1a1a1';
  155. this.context.fillText(obj.nickname,250*lx,yy+5*ly);
  156. this.context.fillText(obj.KVDataList[0].value,500*lx,yy+5*ly);
  157. this.drawImage(this.assets['line'], 0, yy+ly*9,560*lx,ly/5);
  158. }
  159.  
  160. //绘制自己的排名
  161. let rank = this.getOwnRank();
  162. if(!rank) return;
  163. let robj = rank[1];
  164. let myy = 8.4*mid;
  165. this.context.fillText('' + rank[0], 20 * lx, myy + ly * 5);
  166. let image = wx.createImage();
  167. image.src = robj.avatarUrl;
  168. this.drawImage(image, 80 * lx, myy + ly * 1, 70 * lx, 70 * lx);
  169. this.context.fillStyle = '#a1a1a1';
  170. this.context.fillText(robj.nickname, 250 * lx, myy + 5 * ly);
  171. this.context.fillText(robj.KVDataList[0].value, 500 * lx, myy + 5 * ly);
  172. this.drawImage(this.assets['line'], 0, myy + ly * 9, 560 * lx, ly / 5);
  173. }
  174. //画群排行榜
  175. drawGroupRank(page = 1){
  176. this.context.clearRect(0, 0, this.context.canvas.width, this.context.canvas.height);
  177. this.context.fillStyle = '#ff0000';
  178. this.context.font = '50px Arial';
  179. this.context.fillText('世界排行榜', 10, 10);
  180. }
  181. //画图片
  182. drawImage(image, x, y, width, height) {
  183. if (image.width != 0 && image.height != 0 && this.context) {
  184. if (width && height) {
  185. this.context.drawImage(image, x, y, width, height);
  186. } else {
  187. this.context.drawImage(image, x, y);
  188. }
  189. }
  190. }
  191. }
  192.  
  193. const openDCM = new openDataContextMain();
  194. openDCM.addOpenDataContextListener();

11、微信的授权现在改成必须通过授权按钮才能授权,很多情况下,与后端通信的逻辑应该是先获取openId,然后传给自己的服务器,服务器返回一个自己服务器的id,这个过程一般会保存用户信息,但是wx.login()没有返回

userinfo,只返回一个code,code用来获取openid的,怎么办呢?我的逻辑是:

  1. wx.login()获取code
  2. 通过code获取openid
  3. 通过wx.getSetting()判断是否授权,如果授权则通过openid去自己服务器获取userinfo信息,否则创建授权按钮,在用户点击允许的时候把返回的userinfo更新到自己的服务器

部分代码:

  1. //前面省略login和get openid
  2. wx.getSetting({complete:(res)=>{
  3. if(res.errMsg == 'getSetting:ok'){
  4. let obj = res.authSetting;
  5. if(obj['scope.userInfo'] == true){
  6. // console.log('已经授权');
  7. }
  8. else{
  9. createAuthorButton();
  10. }
  11. console.log("getSetting:%o",res);
  12. }
  13. else{
  14. wx.showModal('错误信息',res.errMsg);
  15. }
  16. }});
  17.  
  18. createAuthorButton(x:number, y:number, width:number, height:number) {
  19. if (egret.Capabilities.runtimeType != "wxgame") {
  20. return;
  21. }
  22.  
  23. let button = wx.createUserInfoButton({
  24. type: 'text',
  25. text: '',
  26. style: {
  27. left: x,
  28. top: y,
  29. width: width,
  30. height: height,
  31. backgroundColor: '#ff0000',
  32. color: '#ffffff',
  33. textAlign: 'center',
  34. fontSize: 16,
  35. opacity: 0
  36. }
  37. });
  38. button.onTap((res) => {
  39. if(res.errMsg == 'getUserInfo:ok'){
  40. button.hide();
  41. button.destroy();
  42. WxApi.showShareMenu();
  43. updateUserInfo(res);
  44. }
  45. });
  46. }

12、小游戏转发带参数与不带参数注意参数格式,包括主动转发和被动转发,查api这个都知道

13、微信开发者工具预览上传的时候会报错资源上传失败等,解决方法重启开发者工具再预览上传

14、egret发布的小游戏,egret.js 和 eui.js库比较大,解决方法是通过终端发布命令发布微信小游戏:egret publish --target wxgame

15、忘记一个p2的问题,p2可能会undefine,更改p2引擎暴露下p2

16、有时会遇到微信开发者工具不能编译,不能运行,重启右上角清缓存也不行,win10,我的解决方法是关闭工具并删除如下这个文件夹

总结下来大致就这些破问题,避免踩坑,如果还不行的话,删库跑路也未尝不可,毕竟家里的几亩地在那闲着呢,要不搬砖的随时欢迎!扯远了,其实只要多角度,多方面去思考问题,解决的方法还是很多的。

微信小游戏egret开发包括p2引擎小结的更多相关文章

  1. 微信小游戏 Egret开发数据域官方Demo下载地址

    随着引擎的升级,伴随而来就是各种问题,使用官方调试过的Demo,少走弯路. Mark下 官方Demo

  2. 微信小游戏 egret.getDefinitionByName获取不到

    使用getDefinitionByName获取类定义 输出为null,获取不了 增加window["LoadingUI"] = LoadingUI 获取成功 总结: 这样无论是游戏 ...

  3. 微信小游戏 Three.js UI 2D text 简单方案

    在微信小游戏中使用 THREE.js 引擎,没有合适的 UI 库可用,只能自己动手.图片啥的都还好,text 不好弄.text 要计算 width 和 height,不然事件响应范围不对. funct ...

  4. 使用Laya引擎开发微信小游戏(上)

    本文由云+社区发表 使用一个简单的游戏开发示例,由浅入深,介绍了如何用Laya引擎开发微信小游戏. 作者:马晓东,腾讯前端高级工程师. 微信小游戏的推出也快一年时间了,在IEG的游戏运营活动中,也出现 ...

  5. 使用Laya引擎开发微信小游戏

    在支持微信小游戏的游戏引擎中,Cocos,Egret,Laya都对小游戏的开发提供了很多强大的支持.前段时间正好抽空研究了一下这块的内容,现做一个总结,针对如何使用Laya引擎开发微信小游戏给大家做一 ...

  6. 一、微信小游戏开发 --- 初次在微信开发者工具里跑Egret小游戏项目

    尝试下Egret的小游戏开发,学习,学习,干IT,不学习,就得落后啊... 相关教程: Egret微信小游戏教程 微信公众平台-微信小游戏教程 微信公众平台-微信小游戏接入指南 开发版本: Egret ...

  7. 微信小游戏开发之四:使用three.js引擎

    一.前言 微信小游戏中最魔性的'跳一跳'就是基于three.js 引擎开发的 源码放到github上了:GitHub地址   请自行下载. 二.下载 three.min.js 打开页面,复制代码到本地 ...

  8. Egret白鹭开发微信小游戏排行榜功能

    推荐阅读: 我的CSDN 我的博客园 QQ群:704621321 我的个人博客 最近事情特别多,今天终于实现了排行榜功能,记录下来大家一起学习学习. 一.调用默认排行榜 首先我们需要了解: 1.白鹭开 ...

  9. Egret白鹭开发微信小游戏分享功能

    今天给大家分享一下微信分享转发功能,话不多说,直接干 方法一: 1.在egret中打开Platfrom.ts文件,添加代码如下(当然,你也可以直接复制粘贴) /** * 平台数据接口. * 由于每款游 ...

随机推荐

  1. Cisco路由器的dhcp服务的配置的命令

    Router(config)#IP DHCP POOL Jason Router(dhcp-config)#net 172.16.10.0 255.255.255.0 Router(dhcp-conf ...

  2. 【Python开发】使用pyplot模块绘图

    快速绘图 使用pyplot模块绘图¶ matplotlib的pyplot模块提供了和MATLAB类似的绘图API,方便用户快速绘制二维图表.我们先看一个简单的例子: 05-matplotlib/mat ...

  3. PTA(Basic Level)1058.A+B in Hogwarts

    If you are a fan of Harry Potter, you would know the world of magic has its own currency system -- a ...

  4. [转帖]Java 8新特性探究(八)精简的JRE详解

    Java 8新特性探究(八)精简的JRE详解 https://my.oschina.net/benhaile/blog/211804 精简版的api   撸了今年阿里.网易和美团的面试,我有一个重要发 ...

  5. C++多线程基础学习笔记(七)

    一.std::async和std::future的用法 std::async是一个函数模板,std::future是一个类模板 #include <iostream> #include & ...

  6. CodeForce20C

    这是一个裸的最短路的模板题,但是它需要输出路径. 用dijkstra的话首先敲一个最短路的板子,其次开一个数组p[]来记录路径,但是怎么存呢?我们需要记录每一个点的前驱,因为如果记录后边的话,一个点可 ...

  7. WINDOWS7 系统中建立文件夹映射

    如何在WIN7中建立文件夹映射,还有以及MKLINK的具体使用方法: 步骤如下: 1.以映射d盘1文件夹为例: 2.按win+r,输入cmd,点击确定: 3.提示符后输入mklink /J " ...

  8. 微信小程序,预览在开发工具上显示正常,手机预览二维码报request->fail错误,打开手机的调试功能又正常。

    这里错误很明显是属于网址错误,开发工具和手机调试都能走request->success: 唯独常规模式下无法显示. 最开始调试过很多方法,没找出原因.最后到小程序开发设置才发现,自己未配置服务器 ...

  9. LoadRunner之使用JSEESIONID访问网站

    LoadRunner使用笔记 JSESSIONID的含义:https://www.cnblogs.com/caiwenjing/p/8081391.html 1.使用JSESSIONID访问网站 Ac ...

  10. 在Powershell中使用Group-Object和-GroupBy

    使用Group-Object(group)按组统计 PS C:\> Get-Command -Module Microsoft.PowerShell.LocalAccounts | group ...