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

- 作者：刘凌歌
- 发布时间：2018-03-08 17:30
- 原文：https://www.ifanr.com/minapp/991990

![](https://s3.ifanr.com/wp-content/uploads/2017/07/minapp-dev-final-feature.jpg)

在[上一篇教程](http://mp.weixin.qq.com/s/l5EFZu2qv9SDoVdZy9VA3g)里，知晓程序为大家详细讲解了如何创建小游戏「跳一跳」的游戏场景。通过介绍，大家一定对于小游戏的开发有了更进一步的认识。

今天我们将为大家讲解事件的绑定以及 EUI 的进一步使用，以及什么叫「工厂方法」。

### 为开始按钮绑定事件

上一篇中，我们为 Button 组件定义了 ID 为 beginBtn，接下来在 BeginScene.ts 文件中声明这个组件的变量。

首先选择 Button 组件「复制自定义」：

![](https://s3.ifanr.com/wp-content/uploads/2018/03/1-12.jpg)

这步操作，使得编辑器已经生成好了组件的代码，我们在 BeginScene.ts 文件中直接粘贴：

![](https://s3.ifanr.com/wp-content/uploads/2018/03/2-2.png)

接下来，我们依旧在这个文件里调用自定义的 init() 初始化方法，为开始按钮绑定点击事件：

![](https://s3.ifanr.com/wp-content/uploads/2018/03/3-4.png)

这里主要使用 Egret 引擎中的 addEventListener() 方法来为 beginBtn 绑定事件，代码如下：

```
// 初始化(给开始按钮绑定点击事件)
private init(){
	this.beginBtn.addEventListener(egret.TouchEvent.TOUCH_TAP,this.tapHandler,this);
}
private tapHandler(){
	// 切换场景
	SceneMange.getInstance().changeScene('gameScene');
}
```

有绑定事件，就会有移除事件：

```
// 移除事件
public release(){
	if(this.beginBtn.hasEventListener(egret.TouchEvent.TOUCH_TAP)){
		this.beginBtn.removeEventListener(egret.TouchEvent.TOUCH_TAP,this.tapHandler,this);
	}
}
```

### 完善场景的切换逻辑

此时距我们点击开始按钮能有效果还差最后一步，那就是在场景控制器 SceneMange.ts 的 changeScene() 中添加释放资源的逻辑：

![](https://s3.ifanr.com/wp-content/uploads/2018/03/4-2.png)

代码如下：

```
// 切换场景
public changeScene(type){
	// 释放资源
	if(type == 'gameScene'){
		this.beginScene.release();
	}
	// 移除所有显示列表中的对象
	this.removeChildren();
	// 添加下一个场景
	this.addChild(this[type]);
}
```

到这里，我们在微信开发者工具中调试代码就可以看到点击「开始游戏」的效果了，不过游戏场景下还是一片空白。

![](https://s3.ifanr.com/wp-content/uploads/2018/03/1-4.gif)

### 初始化游戏场景 EUI

找到项目结构下 resource 目录下的 scene 文件夹下的 GameScene.exml。按照之前的方法，将游戏场景的宽高设置成舞台宽高：宽 640，高 1136。

![](https://s3.ifanr.com/wp-content/uploads/2018/03/5-2.png)

**添加 Group 组件：**拖动组件 – 布局 – Group 组件到 EUI 舞台，并设置其 ID 为 blockPanel，设置约束为上下左右填充整个舞台。

![](https://s3.ifanr.com/wp-content/uploads/2018/03/6-2.png)

**加入背景图片：**拖动组件 – 控件 – Image 控件到舞台，放在 Group 组里，将其作为背景，资源名为「bg\_jpg」，设置约束为上下左右填充整个舞台。

![](https://s3.ifanr.com/wp-content/uploads/2018/03/7-2.png)

接下来我们就要让「小 i」加入舞台了！

**置入「小 i」：**同样的方式拖入 Image 控件，设置 ID 为「player」，添加资源「piece\_png」，宽和高分别为 48 和 130，位置暂时不用约束，后期我们会在代码里去控制。

![](https://s3.ifanr.com/wp-content/uploads/2018/03/8.png)

**添加积分 Lable：**拖入 Lable 控件，ID 设为「scoreLable」，标签为「0」，样式颜色选择黑色，透明度设为「90」，x 值、y 值、宽、高分别为：100、100、51、90。

![](https://s3.ifanr.com/wp-content/uploads/2018/03/9-1.png)

最后我们在 blockPanel 的 Group 上右键选择「复制自定义」，然后粘贴复制的 EUI 组件信息到 gameScene.ts 中去。记得随手 ctrl+s 保存。

![](https://s3.ifanr.com/wp-content/uploads/2018/03/10.png)

### 初始化游戏场景资源

初始化完游戏场景 EUI 后，我们开始初始化 GameScene.ts 游戏场景资源。

首先添加几个变量：

```
// 所有方块资源的数组
private blockSourceNames: Array = [];
// 按下的音频
private pushVoice: egret.Sound;
// 按下音频的SoundChannel对象，用来暂停该音频
private pushSoundChannel: egret.SoundChannel;
// 弹跳的音频
private jumpVoice: egret.Sound;
```

然后我们我们自定义初始化方法 init() 并调用。

```
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(){
}
```

完整示例如下：

![](https://s3.ifanr.com/wp-content/uploads/2018/03/11-2.png)

![](https://s3.ifanr.com/wp-content/uploads/2018/03/12-1.png)

### 工厂方法生成随机的盒子方块

现在，我们已经构建了基本的 UI 框架，下面我们将从代码层面创建盒子。

「跳一跳」小游戏中需要一个接一个的随机方块，这里由于我们是 2D 画面来实现，所以我们找了三个颜色不同的盒子来演示。

在此之前，还是需要预先在 GameScene.ts 中声明一些必要的变量：

```
// 所有方块EUI的数组
private blockArr: Array = [];
// 所有回收方块EUI的数组
private reBackBlockArr: Array = [];
```

如图所示：

![](https://s3.ifanr.com/wp-content/uploads/2018/03/13.png)

**blockArr 这个数组**，是用来存放所有在显示列表中的盒子方块，简单的说，就是所有还在屏幕里面的方块；

**reBackBlockArr 这个数组**，是对象池，用来存放超出屏幕的方块盒子。在新创建盒子模型的时候，先查看对象池有没有可以使用的，有的话就直接使用了。然后把这个 EUI 从 reBackBlockArr 拿出来放到 blockArr 中。

等这个 EUI 超出屏幕的时候，就是该销毁了， 把这个 EUI 从显示列表中删除，并且从 blockArr 拿出来放到 reBackBlockArr 中。

这样就形成了一个循环，游戏整个过程中的 EUI 也就是仅仅几个而已。

```
// 工厂方法,创建一个方块
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;
}
```

如图所示：

![](https://s3.ifanr.com/wp-content/uploads/2018/03/15-976x1024.png)

**工厂方法解析：**

- 创建一个方块盒子 EUI，先去对象池里拿，有的话直接拿出来（记得，拿出来的意思事从对象池里面删除）直接用；
- 如果对象池里面没有的话，就通过 new eui.Image() 方法来创建一个。
- 从资源数组里面随机一个图片资源：Math.floor(Math.random() \* this.blockSourceNames.length); ；
- 把图片资源的纹理添加到方块盒子组件上，然后添加到 blockPanel 这个组件里面，这样显示列表就可以渲染出来这个随机的方块盒子了。

可以看到，在代码注释中写到「设置方块的锚点」。**所谓「设置方块的锚点」，就是把一个点当做「中心」**，我们把盒子在视觉中的中心作为锚点：

![](https://s3.ifanr.com/wp-content/uploads/2018/03/2-8.jpg)

在之前自定义初始化方法 init() 并调用时，我们也已通过以下代码把「小 i」 的「中心」设置在里视觉的脚底：

```
// 设置玩家的锚点
this.player.anchorOffsetX = this.player.width / 2;
this.player.anchorOffsetY = this.player.height - 20;
```

![](https://s3.ifanr.com/wp-content/uploads/2018/03/3-7.jpg)

设置好锚点之后，EUI 对象的 x/y 的值就是相对与这个锚点来说了。

在下一次的教程里，我们将带大家创建游戏起始界面并且进行触摸事件的逻辑实现。

如果在开发过程中你有什么疑问，也可以留言告诉我们。

**关注「知晓程序」微信公众号，回复「开发」，让你的小程序性能再上一层楼。**

![](https://s3.ifanr.com/wp-content/uploads/2018/01/qrcode.gif)
