cover_image

开发 | 傻瓜式操作带你初始化「跳一跳」游戏场景

cloud小程序微信教程开发小游戏跳一跳初始化场景方块锚点
凌歌

<p><img class="aligncenter size-large" src="https://images.ifanr.cn/wp-content/uploads/2017/07/minapp-dev-final-feature.jpg" width="1200" height="750" /></p> <p>在<span style="color: #605eac;"><a style="color: #605eac;" href="http://mp.weixin.qq.com/s/l5EFZu2qv9SDoVdZy9VA3g">上一篇教程</a></span>里,知晓程序为大家详细讲解了如何创建小游戏「跳一跳」的游戏场景。通过介绍,大家一定对于小游戏的开发有了更进一步的认识。</p> <p>今天我们将为大家讲解事件的绑定以及 EUI 的进一步使用,以及什么叫「工厂方法」。</p> <h3><span style="color: #605eac;">为开始按钮绑定事件</span></h3> <p>上一篇中,我们为 Button 组件定义了 ID 为 beginBtn,接下来在 BeginScene.ts 文件中声明这个组件的变量。</p> <p>首先选择 Button 组件「复制自定义」:</p> <p><img class="aligncenter size-full wp-image-992013" src="https://images.ifanr.cn/wp-content/uploads/2018/03/1-12.jpg" alt="" width="1000" height="652" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/1-12.jpg 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/1-12-360x235.jpg 360w, http://www.ifanr.com/wp-content/uploads/2018/03/1-12-768x501.jpg 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p>这步操作,使得编辑器已经生成好了组件的代码,我们在 BeginScene.ts 文件中直接粘贴:</p> <p><img class="aligncenter size-full wp-image-992015" src="https://images.ifanr.cn/wp-content/uploads/2018/03/2-2.png" alt="" width="1000" height="786" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/2-2.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/2-2-360x283.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/2-2-768x604.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p>接下来,我们依旧在这个文件里调用自定义的 init() 初始化方法,为开始按钮绑定点击事件:</p> <p><img class="aligncenter size-full wp-image-992017" src="https://images.ifanr.cn/wp-content/uploads/2018/03/3-4.png" alt="" width="1000" height="979" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/3-4.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/3-4-360x352.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/3-4-768x752.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p>这里主要使用 Egret 引擎中的 addEventListener() 方法来为 beginBtn 绑定事件,代码如下:</p> <pre><code>// 初始化(给开始按钮绑定点击事件) private init(){ this.beginBtn.addEventListener(egret.TouchEvent.TOUCH_TAP,this.tapHandler,this); } private tapHandler(){ // 切换场景 SceneMange.getInstance().changeScene('gameScene'); }</code></pre> <p>有绑定事件,就会有移除事件:</p> <pre><code>// 移除事件 public release(){ if(this.beginBtn.hasEventListener(egret.TouchEvent.TOUCH_TAP)){ this.beginBtn.removeEventListener(egret.TouchEvent.TOUCH_TAP,this.tapHandler,this); } }</code></pre> <h3><span style="color: #605eac;">完善场景的切换逻辑</span></h3> <p>此时距我们点击开始按钮能有效果还差最后一步,那就是在场景控制器 SceneMange.ts 的 changeScene() 中添加释放资源的逻辑:</p> <p><img class="aligncenter size-full wp-image-992018" src="https://images.ifanr.cn/wp-content/uploads/2018/03/4-2.png" alt="" width="1000" height="788" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/4-2.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/4-2-360x284.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/4-2-768x605.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p>代码如下:</p> <pre><code>// 切换场景 public changeScene(type){ // 释放资源 if(type == 'gameScene'){ this.beginScene.release(); } // 移除所有显示列表中的对象 this.removeChildren(); // 添加下一个场景 this.addChild(this[type]); }</code></pre> <p>到这里,我们在微信开发者工具中调试代码就可以看到点击「开始游戏」的效果了,不过游戏场景下还是一片空白。</p> <p><img class="aligncenter size-full wp-image-992012" src="https://images.ifanr.cn/wp-content/uploads/2018/03/1-4.gif" alt="" width="1000" height="720" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/1-4.gif 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/1-4-360x259.gif 360w, http://www.ifanr.com/wp-content/uploads/2018/03/1-4-768x553.gif 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <h3><span style="color: #605eac;">初始化游戏场景 EUI</span></h3> <p>找到项目结构下 resource 目录下的 scene 文件夹下的 GameScene.exml。按照之前的方法,将游戏场景的宽高设置成舞台宽高:宽 640,高 1136。</p> <p><img class="aligncenter size-full wp-image-992019" src="https://images.ifanr.cn/wp-content/uploads/2018/03/5-2.png" alt="" width="1000" height="907" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/5-2.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/5-2-360x327.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/5-2-768x697.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p><strong>添加 Group 组件:</strong>拖动组件 &#8211; 布局 &#8211; Group 组件到 EUI 舞台,并设置其 ID 为 blockPanel,设置约束为上下左右填充整个舞台。</p> <p><img class="aligncenter size-full wp-image-992020" src="https://images.ifanr.cn/wp-content/uploads/2018/03/6-2.png" alt="" width="1000" height="907" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/6-2.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/6-2-360x327.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/6-2-768x697.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p><strong>加入背景图片:</strong>拖动组件 &#8211; 控件 &#8211; Image 控件到舞台,放在 Group 组里,将其作为背景,资源名为「bg_jpg」,设置约束为上下左右填充整个舞台。</p> <p><img class="aligncenter size-full wp-image-992021" src="https://images.ifanr.cn/wp-content/uploads/2018/03/7-2.png" alt="" width="1000" height="907" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/7-2.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/7-2-360x327.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/7-2-768x697.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p>接下来我们就要让「小 i」加入舞台了!</p> <p><strong>置入「小 i」:</strong>同样的方式拖入 Image 控件,设置 ID 为「player」,添加资源「piece_png」,宽和高分别为 48 和 130,位置暂时不用约束,后期我们会在代码里去控制。</p> <p><img class="aligncenter size-full wp-image-992022" src="https://images.ifanr.cn/wp-content/uploads/2018/03/8.png" alt="" width="1000" height="907" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/8.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/8-360x327.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/8-768x697.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p><strong>添加积分 Lable:</strong>拖入 Lable 控件,ID 设为「scoreLable」,标签为「0」,样式颜色选择黑色,透明度设为「90」,x 值、y 值、宽、高分别为:100、100、51、90。</p> <p><img class="aligncenter size-full wp-image-992024" src="https://images.ifanr.cn/wp-content/uploads/2018/03/9-1.png" alt="" width="1000" height="907" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/9-1.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/9-1-360x327.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/9-1-768x697.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p>最后我们在 blockPanel 的 Group 上右键选择「复制自定义」,然后粘贴复制的 EUI 组件信息到 gameScene.ts 中去。记得随手 ctrl+s 保存。</p> <p><img class="aligncenter size-full wp-image-992025" src="https://images.ifanr.cn/wp-content/uploads/2018/03/10.png" alt="" width="1000" height="907" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/10.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/10-360x327.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/10-768x697.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <h3><span style="color: #605eac;">初始化游戏场景资源</span></h3> <p>初始化完游戏场景 EUI 后,我们开始初始化 GameScene.ts 游戏场景资源。</p> <p>首先添加几个变量:</p> <pre><code>// 所有方块资源的数组 private blockSourceNames: Array = []; // 按下的音频 private pushVoice: egret.Sound; // 按下音频的SoundChannel对象,用来暂停该音频 private pushSoundChannel: egret.SoundChannel; // 弹跳的音频 private jumpVoice: egret.Sound;</code></pre> <p>然后我们我们自定义初始化方法 init() 并调用。</p> <pre><code>private init() { this.blockSourceNames = ["block1_png", "block2_png", "block3_png"]; // 初始化音频 this.pushVoice = RES.getRes('push_mp3'); this.jumpVoice = RES.getRes('jump_mp3'); // 添加触摸事件 this.blockPanel.touchEnabled = true; this.blockPanel.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.onKeyDown, this); this.blockPanel.addEventListener(egret.TouchEvent.TOUCH_END, this.onKeyUp, this); // 设置玩家的锚点 this.player.anchorOffsetX = this.player.width / 2; this.player.anchorOffsetY = this.player.height - 20; } // 按下的事件逻辑 private onKeyDown(){ } // 放开的事件逻辑 private onKeyUp(){ }</code></pre> <p>完整示例如下:</p> <p><img class="aligncenter size-full wp-image-992027" src="https://images.ifanr.cn/wp-content/uploads/2018/03/11-2.png" alt="" width="1000" height="907" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/11-2.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/11-2-360x327.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/11-2-768x697.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p><img class="aligncenter size-full wp-image-992028" src="https://images.ifanr.cn/wp-content/uploads/2018/03/12-1.png" alt="" width="1000" height="949" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/12-1.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/12-1-360x342.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/12-1-768x729.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <h3><span style="color: #605eac;">工厂方法生成随机的盒子方块</span></h3> <p>现在,我们已经构建了基本的 UI 框架,下面我们将从代码层面创建盒子。</p> <p>「跳一跳」小游戏中需要一个接一个的随机方块,这里由于我们是 2D 画面来实现,所以我们找了三个颜色不同的盒子来演示。</p> <p>在此之前,还是需要预先在 GameScene.ts 中声明一些必要的变量:</p> <pre><code>// 所有方块EUI的数组 private blockArr: Array = []; // 所有回收方块EUI的数组 private reBackBlockArr: Array = [];</code></pre> <p>如图所示:</p> <p><img class="aligncenter size-full wp-image-992029" src="https://images.ifanr.cn/wp-content/uploads/2018/03/13.png" alt="" width="1000" height="949" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/13.png 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/13-360x342.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/13-768x729.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p><strong>blockArr 这个数组</strong>,是用来存放所有在显示列表中的盒子方块,简单的说,就是所有还在屏幕里面的方块;</p> <p><strong>reBackBlockArr 这个数组</strong>,是对象池,用来存放超出屏幕的方块盒子。在新创建盒子模型的时候,先查看对象池有没有可以使用的,有的话就直接使用了。然后把这个 EUI 从 reBackBlockArr 拿出来放到 blockArr 中。</p> <p>等这个 EUI 超出屏幕的时候,就是该销毁了, 把这个 EUI 从显示列表中删除,并且从 blockArr 拿出来放到 reBackBlockArr 中。</p> <p>这样就形成了一个循环,游戏整个过程中的 EUI 也就是仅仅几个而已。</p> <pre><code>// 工厂方法,创建一个方块 private createBlock(): eui.Image { var blockNode = null; if (this.reBackBlockArr.length) { // 回收池里面有,则直接取 blockNode = this.reBackBlockArr.splice(0, 1)[0]; } else { // 回收池里面没有,则重新创建 blockNode = new eui.Image(); } // 使用随机背景图 let n = Math.floor(Math.random() * this.blockSourceNames.length); blockNode.source = this.blockSourceNames[n]; this.blockPanel.addChild(blockNode); // 设置方块的锚点 blockNode.anchorOffsetX = 222; blockNode.anchorOffsetY = 78; // 把新创建的block添加进入blockArr里 this.blockArr.push(blockNode); return blockNode; }</code></pre> <p>如图所示:</p> <p><img class="aligncenter size-large wp-image-992031" src="https://images.ifanr.cn/wp-content/uploads/2018/03/15-976x1024.png" alt="" width="976" height="1024" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/15-976x1024.png 976w, http://www.ifanr.com/wp-content/uploads/2018/03/15-360x378.png 360w, http://www.ifanr.com/wp-content/uploads/2018/03/15-768x806.png 768w, http://www.ifanr.com/wp-content/uploads/2018/03/15.png 1000w" sizes="(max-width: 976px) 100vw, 976px" /></p> <p><strong>工厂方法解析:</strong></p> <ul> <li>创建一个方块盒子 EUI,先去对象池里拿,有的话直接拿出来(记得,拿出来的意思事从对象池里面删除)直接用;</li> <li>如果对象池里面没有的话,就通过 new eui.Image() 方法来创建一个。</li> <li>从资源数组里面随机一个图片资源:Math.floor(Math.random() * this.blockSourceNames.length); ;</li> <li>把图片资源的纹理添加到方块盒子组件上,然后添加到 blockPanel 这个组件里面,这样显示列表就可以渲染出来这个随机的方块盒子了。</li> </ul> <p>可以看到,在代码注释中写到「设置方块的锚点」。<strong>所谓「设置方块的锚点」,就是把一个点当做「中心」</strong>,我们把盒子在视觉中的中心作为锚点:</p> <p><img class="aligncenter size-full wp-image-992014" src="https://images.ifanr.cn/wp-content/uploads/2018/03/2-8.jpg" alt="" width="1000" height="306" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/2-8.jpg 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/2-8-360x110.jpg 360w, http://www.ifanr.com/wp-content/uploads/2018/03/2-8-768x235.jpg 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p>在之前自定义初始化方法 init() 并调用时,我们也已通过以下代码把「小 i」 的「中心」设置在里视觉的脚底:</p> <pre><code>// 设置玩家的锚点 this.player.anchorOffsetX = this.player.width / 2; this.player.anchorOffsetY = this.player.height - 20;</code></pre> <p><img class="aligncenter size-full wp-image-992016" src="https://images.ifanr.cn/wp-content/uploads/2018/03/3-7.jpg" alt="" width="1000" height="272" srcset="http://www.ifanr.com/wp-content/uploads/2018/03/3-7.jpg 1000w, http://www.ifanr.com/wp-content/uploads/2018/03/3-7-360x98.jpg 360w, http://www.ifanr.com/wp-content/uploads/2018/03/3-7-768x209.jpg 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p> <p>设置好锚点之后,EUI 对象的 x/y 的值就是相对与这个锚点来说了。</p> <p>在下一次的教程里,我们将带大家创建游戏起始界面并且进行触摸事件的逻辑实现。</p> <p>如果在开发过程中你有什么疑问,也可以留言告诉我们。</p> <p><strong>关注「<span style="color: #605eac;">知晓程序</span>」微信公众号,回复「<span style="color: #605eac;">开发</span>」,让你的小程序性能再上一层楼。</strong></p> <p><img class="size-full wp-image-963729 aligncenter" src="https://images.ifanr.cn/wp-content/uploads/2018/01/qrcode.gif" alt="" width="750" height="375" srcset="http://www.ifanr.com/wp-content/uploads/2018/01/qrcode.gif 750w, http://www.ifanr.com/wp-content/uploads/2018/01/qrcode-360x180.gif 360w" sizes="(max-width: 750px) 100vw, 750px" /></p>