开发工具

  1. Cocos Dashboard 1.0.20
  2. Cocos Creator 3.4.0
  3. Visual Studio Code 1.63
  4. Microsoft Edge 97.0.1072.69

界面宽度和高度

  1. 当前游戏只有一个场景: 主场景。界面则分为三个部分:主界面(gameStart), 游戏界面(game)和结算界面(gameOver)。
  1. 主菜单 选择 项目 -> 项目设置, 在弹出的 项目设置 窗口 左侧 选中 项目数据, 右侧 窗格中的 设计宽度 改为 640, 设计高度 改为 960, 关闭窗口。

游戏主界面(开始界面)

  1. 资源管理器 中点击选中图片 assets/res/texture/logo, 在 属性检查器 中将图片 logo.png 的属性 Type(图片类型) 更改为 sprite-frame, 保存更改。
  1. 点击 场景编辑器 上方 3D 按钮,切换为 2D 模式。

  2. 层级管理器 点击选中 Canvas 节点,右键 -> 创建 -> 空节点, 命名为 gameStart

  1. 层级管理器 点击选中 Canvas/gameStart 节点,在 属性检查器 中点击 添加组件 -> UI -> Widget
  1. Canvas/gameStart/Widget 的属性 Horizontal Alignment 设为 Horizontal Stretch, Left 的值设为 0, Right 的值设为 0; 属性 Vertical Alignment 设为 Vertical Stretch, Top 的值设为 0, Bottom 的值设为 0
  1. 资源管理器图片类型 已经更改为 sprite-frame 的图片 assets/res/texture/logo 拖动到 层级管理器 下的 Canvas/gameStart 节点。将 logo 节点沿 Y轴 向上拖动到界面上方(例如此处Position, Y:225)
  1. 层级管理器 点击选中 Canvas/gameStart 节点, 右键 -> 创建 -> 2D对象 -> Label(文本), 命名为 tip, 在其 属性检查器 中将 String 属性的值改为 滑动开始游戏, FontSize 属性的值改为 40。并沿 Y轴 向下拖动到合适的位置, 保存场景。

游戏界面

  1. 层级管理器 点击选中 Canvas/gameStart 节点, Ctrl+D 复制节点后命名为 game

  2. 删除 game 节点原有的 logotip 节点。

  3. 资源管理器 中点击选中图片 assets/res/texture/fightBoxScore, 在 属性检查器 中将图片 fightBoxScore.png 的属性 Type 更改为 sprite-frame, 保存更改。

  4. 将更改后的 assets/res/texture/fightBoxScore 拖到 game 节点, 再将它拖到显示区域的左方角。

  5. 层级管理器 点击选中 Canvas/game/fightBoxScore 节点,在 属性检查器 中点击 添加组件 -> UI -> Widget, Horizontal Alignment 设为 Lef, Left 的值设为 20px; Vertical Alignment 设为 Top, Top 的值设为 20px

  1. 资源管理器 中点击选中图片 assets/res/texture/fightIconGold, 在 属性检查器 中将图片 fightIconGold.png 的属性 Type 更改为 sprite-frame, 保存更改。

  2. 将更改后的 assets/res/texture/fightIconGold 拖到 game/fightBoxScore 节点, 然后将其沿 X轴 向左拖动到 fightBoxScore 图片左边的圆形区域内。

  1. 层级管理器 点击选中 Canvas/game/fightBoxScore 节点, 右键 -> 创建 -> 2D对象 -> Label(文本), 命名为 score, 将 HorizontalAlign 属性设为 Left, String 属性的值设为 0, FontSize 属性的值设为 30, Overflow 属性的值设为 CLAMP。 将 cc.UITransform 下的 ContentSize 属性的 W 值改为 150, 最后将这个 score 节点拖动到屏幕合适的位置。

游戏结算界面

  1. 层级管理器 点击选中 game 节点, Ctrl+D 复制节点后命名为 gameOver

  2. 删除 gameOver 节点原有的 fightBoxScore 节点。

  3. 层级管理器 点击选中 Canvas/gameOver 节点,右键 -> 创建 -> UI组件 -> Button(按钮), 命名为 reStart, SizeMode 属性的值改为 RAW, Transition 属性的值改为 SCALE

  1. 资源管理器 中的图片 assets/res/texture/fightBtn01 转为 sprite-frame 后,拖到 reStart 节点的 SpriteFrame 属性中。
  1. 层级管理器 点击选中 Canvas/gameOver/reStart/Label 节点, String 属性的值改为 再来一局, FontSize 属性的值改为 50, LineHeight 属性的值改为 60, OverFlow 属性的值改为 None, Color 改为 白色
  1. 层级管理器 点击选中 Canvas/gameOver/reStart 节点, Ctrl+D 复制节点后命名为 returnMain

  2. 资源管理器 中的图片 assets/res/texture/fightBtn02 转为 sprite-frame 后,拖到 returnMain 节点的 SpriteFrame 属性中。

  1. 层级管理器 点击选中 Canvas/gameOver/returnMain/Label 节点, String 属性的值改为 返回主页, FontSize 属性的值改为 40
  1. 分别移动 reStart 节点和 returnMain 节点到合适的位置, 如下图所示:
  1. 层级管理器 点击选中 Canvas/gameOver 节点,右键 -> 创建 -> 2D对象 -> Label(文本), 命名为 scoreTitle, String 属性的值改为 本局得分, FontSize 属性的值改为 40, 向上移动本节点到合适的位置。
  1. 层级管理器 点击选中 Canvas/gameOver/scoreTitle 节点,右键 -> 创建 -> 2D对象 -> Label(文本), 命名为 score, String 属性的值改为 999999, FontSize 属性的值改为 80, LineHeight 属性的值改为 90
  1. 资源管理器 中的图片 assets/res/effect/uiAni/fightBoxSettlement 转为 sprite-frame 后,拖到 Canvas/gameOver 节点, 调整层级排到 Canvas/gameOver/scoreTitle 节点的前面。
  1. 层级管理器 点击选中 Canvas/gameOver/fightBoxSettlement 节点,点击窗口下方的 动画编辑器 选项卡, 然后点击 新建动画剪辑资源 按钮, 在弹出的 创建资源 对话框中输入文件名 fightBoxSettlement.anim, 选择保存位置和图片相同, 点 保存 按钮。
  1. 动画编辑器 选项卡中点击 进入动画编辑模式 按钮, 点击 属性列表 右侧的 + 按钮,选 position, 点击 position 右侧的 菱形 图标, 然后拖动 时间轴0-30 位置, 在 场景编辑器 中拖动 fightBoxSettlement 图片向上移动, 形成一个向上移动的动画效果。

  2. 动画编辑器 选项卡中点击 进入动画编辑 按钮, 点击 属性列表 右侧的 + 按钮,选 cc.Sprite -> color, cc.Sprite.color0-00 位置处的 alpha 值为 0, 在 0-30 位置处的 alpha 值为 255, alpha 的值在 Color 属性中设置, 可以在 0-000-30 之间多增加几个关键帧并设置不同的 alpah 值实现闪烁效果(例如交替显示和隐藏)。

  1. 双击 资源管理器 中的 assets/scene/airPlane.scene 返回场景,将 gameStartgamegameOver 三个节点隐藏(在 属性检查器 中将三个名字前面的 去掉), 保存场景。

面板控制逻辑

  1. 编辑玩家飞机脚本 PlayerPlane, 添加 玩家生命游戏结束 控制, 代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { _decorator, Component, Node, Collider, ITriggerEvent } from 'cc';
import { Constant } from '../framework/Constant';
const { ccclass, property } = _decorator;

@ccclass('PlayerPlane')
export class PlayerPlane extends Component {

public lifeValue = 5; //玩家飞机生命
public isDie = false;

private _currLife = 0;

onEnable() {
// 获取碰撞组件
const collider = this.getComponent(Collider);
// 监听触发事件
collider.on('onTriggerEnter', this._onTriggerEnter, this);
}

onDisable() {
const collider = this.getComponent(Collider);
// 停止监听触发事件
collider.off('onTriggerEnter', this._onTriggerEnter, this);
}

public init() {
this._currLife = this.lifeValue;
this.isDie = false;
}

private _onTriggerEnter(event: ITriggerEvent) {
// 获取分组
const collisionGroup = event.otherCollider.getGroup();
// 遇到敌方飞机或敌方子弹,玩家飞机掉血
if (collisionGroup === Constant.CollistionType.ENEMY_PLANE
|| collisionGroup === Constant.CollistionType.ENEMY_BULLET) {
// 现在玩家飞机发生碰撞只在控制台输出文件
this._currLife--;
console.log('player plane reduce blood:', this._currLife);
if (this._currLife <= 0) {
this.isDie = true;
}
}
}
}

  1. 编辑 gameManager 脚本, 添加用于界面控制的代码, Animation 需要手动添加引用

首先:

1
2
@property(Node)
public playerPlane: Node = null; // 玩家飞机

改为

1
2
@property(SelfPlane)
public playerPlane: SelfPlane = null; // 玩家飞机

然后 this.playerPlane 改为 this.playerPlane.node

编辑后的 gameManager 脚本代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416

import { _decorator, Component, Node, Prefab, instantiate, math, Vec3, BoxCollider, Label, Animation, macro } from 'cc';
import { Bullet } from '../bullet/Bullet';
import { BulletProp } from '../bullet/BulletProp';
import { EnemyPlane } from '../plane/EnemyPlane';
import { PlayerPlane } from '../plane/PlayerPlane';
import { Constant } from './Constant';
const { ccclass, property } = _decorator;


@ccclass('GameManager')
export class GameManager extends Component {
@property(PlayerPlane)
public playerPlane: PlayerPlane = null; // 玩家飞机

@property(Prefab)
public bullet01: Prefab = null; // 子弹1
@property(Prefab)
public bullet02: Prefab = null; // 子弹2
@property(Prefab)
public bullet03: Prefab = null; // 子弹3
@property(Prefab)
public bullet04: Prefab = null; // 子弹4
@property(Prefab)
public bullet05: Prefab = null; // 子弹5

@property
public shootTime = 0.3; // 射击周期(间隔时间)
@property
public bulletSpeed = 1; // 子弹速度

@property(Node)
public bulletRoot: Node = null; // 子弹管理节点

// 敌机
@property(Prefab)
public enemy01: Prefab = null; // 敌机1
@property(Prefab)
public enemy02: Prefab = null; // 敌机2
@property
public createEnemyTime = 1; // 敌机生成时间
@property
public enemy01Speed = 0.5; // 敌机1速度
@property
public enemy02Speed = 0.7; // 敌机2速度

// 子弹类型道具
@property(Prefab)
public bulletPropM: Prefab = null;
@property(Prefab)
public bulletPropH: Prefab = null;
@property(Prefab)
public bulletPropS: Prefab = null;
@property
public bulletPropSpeed = 0.3; // 子弹类型道具速度

// ui
@property(Node)
public gamePage: Node = null;
@property(Node)
public gameOverPage: Node = null;
@property(Label)
public gameScore: Label = null;
@property(Label)
public gameOverScore: Label = null;
@property(Animation)
public overAnimation: Animation = null; // Animation 要手工添加导入

public isGameStart = false;

private _currShootTime = 0;
private _isShooting = false;
private _currCreateEnemyTiime = 0; // 当前敌机的生成时间
private _combinationInterval = Constant.Combination.PLAN1; // 组合的间隔状态
private _bulletType = Constant.BulletPropType.BULLET_M; // 子弹道具类型

private _score: number = 0;

start() {
this._init();
}

update(deltaTime: number) {
if (!this.isGameStart) {
return;
}

if (this.playerPlane.isDie) {
this.gameOver();
return;
}

this._currShootTime += deltaTime;
if (this._isShooting && this._currShootTime > this.shootTime) {
// 判断子弹道具的类型
if (this._bulletType === Constant.BulletPropType.BULLET_H) {
this.createPlayerBulletH();
} else if (this._bulletType === Constant.BulletPropType.BULLET_S) {
this.createPlayerBulletS();
} else {
this.createPlayerBulletM();
}
this._currShootTime = 0;
}
this._currCreateEnemyTiime += deltaTime;

// 判断组合方式创建相应的敌机
if (this._combinationInterval === Constant.Combination.PLAN1) {
if (this._currCreateEnemyTiime > this.createEnemyTime) {
this.createEnemyPlane();
this._currCreateEnemyTiime = 0;
}
} else if (this._combinationInterval === Constant.Combination.PLAN2) {
// 第二阶段,前两种组合随机出现
// 这里乘以 0.9 是缩短敌机出现的间隔时间
if (this._currCreateEnemyTiime > this.createEnemyTime * 0.9) {
// 用于随机出现组合1或组合2
const randomCombination = math.randomRangeInt(1, 6);
if (randomCombination === Constant.Combination.PLAN2) {
this.createCombination01();
} else {
this.createEnemyPlane();
}
this._currCreateEnemyTiime = 0;
}
} else {
// 第三阶段,三个组合随机出现
// 这里乘以 0.9 是缩短敌机出现的间隔时间
if (this._currCreateEnemyTiime > this.createEnemyTime * 0.8) {
// 用于随机出现组合1或组合2
const randomCombination = math.randomRangeInt(1, 7);
if (randomCombination === Constant.Combination.PLAN2) {
this.createCombination01();
} else if (randomCombination === Constant.Combination.PLAN3) {
this.createCombination02();
} else {
this.createEnemyPlane();
}
this._currCreateEnemyTiime = 0;
}
}
}

//创建玩家飞机的子弹
public createPlayerBulletM() {
// 实例材质类型的子弹, 实例出来的对象不在场景中
const bullet = instantiate(this.bullet01);
bullet.setParent(this.bulletRoot); // 子弹挂载到子弹管理节点中

let pos = this.playerPlane.node.position; // 获取玩家飞机位置
// 子弹出现的位置为飞机 Z轴 -7
bullet.setPosition(pos.x, pos.y, pos.z - 7);
// 获取 Bullet类 (子弹预制根节点添加 Bullet 脚本)
const bulletComp = bullet.getComponent(Bullet);
bulletComp.show(this.bulletSpeed, false); // 设置子弹速度
}

// S型子弹为前方同时发射两颗
public createPlayerBulletH() {
let pos = this.playerPlane.node.position; // 获取玩家飞机位置

// 左边的子弹
const bullet1 = instantiate(this.bullet03);
bullet1.setParent(this.bulletRoot); // 子弹挂载到子弹管理节点中
// 子弹出现的位置为飞机 Z轴 -7
bullet1.setPosition(pos.x - 2.5, pos.y, pos.z - 7);
// 获取 Bullet 组件 (脚本类)
const bulletComp1 = bullet1.getComponent(Bullet);
// bulletComp.bulletSpeed = this.bulletSpeed; // 设置子弹速度
bulletComp1.show(this.bulletSpeed, false); // 玩家飞机的子弹速度

// 右边的子弹
const bullet2 = instantiate(this.bullet03);
bullet2.setParent(this.bulletRoot); // 子弹挂载到子弹管理节点中
// 子弹出现的位置为飞机 Z轴 -7
bullet2.setPosition(pos.x + 2.5, pos.y, pos.z - 7);
// 获取 Bullet 组件 (脚本类)
const bulletComp2 = bullet2.getComponent(Bullet);
// bulletComp.bulletSpeed = this.bulletSpeed; // 设置子弹速度
bulletComp2.show(this.bulletSpeed, false); // 玩家飞机的子弹速度
}

// S型子弹为三发
public createPlayerBulletS() {
let pos = this.playerPlane.node.position; // 获取玩家飞机位置
// 中间子弹
const bullet1 = instantiate(this.bullet05);
bullet1.setParent(this.bulletRoot); // 子弹挂载到子弹管理节点中
// 子弹出现的位置为飞机 Z轴 -7
bullet1.setPosition(pos.x, pos.y, pos.z - 7);
// 获取 Bullet 组件 (脚本类)
const bulletComp1 = bullet1.getComponent(Bullet);
// bulletComp.bulletSpeed = this.bulletSpeed; // 设置子弹速度
bulletComp1.show(this.bulletSpeed, false); // 玩家飞机的子弹速度

// 左边子弹
const bullet2 = instantiate(this.bullet05);
bullet2.setParent(this.bulletRoot); // 子弹挂载到子弹管理节点中
// 子弹出现的位置为飞机 Z轴 -7
bullet2.setPosition(pos.x - 4, pos.y, pos.z - 7);
// 获取 Bullet 组件 (脚本类)
const bulletComp2 = bullet2.getComponent(Bullet);
// bulletComp.bulletSpeed = this.bulletSpeed; // 设置子弹速度
bulletComp2.show(this.bulletSpeed, false, Constant.Direction.LEFT); // 玩家飞机的子弹速度

// 右边子弹
const bullet3 = instantiate(this.bullet05);
bullet3.setParent(this.bulletRoot); // 子弹挂载到子弹管理节点中
// 子弹出现的位置为飞机 Z轴 -7
bullet3.setPosition(pos.x + 4, pos.y, pos.z - 7);
// 获取 Bullet 组件 (脚本类)
const bulletComp3 = bullet3.getComponent(Bullet);
// bulletComp.bulletSpeed = this.bulletSpeed; // 设置子弹速度
bulletComp3.show(this.bulletSpeed, false, Constant.Direction.RIGHT); // 玩家飞机的子弹速度
}

// 是否处理触摸状态,触摸才发射子弹
public isShooting(value: boolean) {
this._isShooting = value;
}

public createEnemyPlane() {
// math 是 cc 带的数字模块
const whichEnemy = math.randomRangeInt(1, 3);
let prefab: Prefab = null;
let speed = 0;
if (whichEnemy === Constant.EnemyType.TYPE1) {
prefab = this.enemy01;
speed = this.enemy01Speed;
} else {
prefab = this.enemy02;
speed = this.enemy02Speed;
}

// 实例化预制
const enemy = instantiate(prefab);
enemy.setParent(this.node); // 预制挂载到组件中
const enemyComp = enemy.getComponent(EnemyPlane);
enemyComp.show(this, speed, true);

// 敌机随机出现的X轴(左右)坐标范围
const randomPos = math.randomRangeInt(-25, 26);
enemy.setPosition(randomPos, 0, -50);
}

// 敌机出现组合1:5架飞机一字型同时出现
public createCombination01() {
const enemyArray = new Array<Node>(5);
for (let i = 0; i < enemyArray.length; i++) {
enemyArray[i] = instantiate(this.enemy01);
const element = enemyArray[i];
element.parent = this.node;
element.setPosition(-20 + i * 10, 0, -50);
const enemyComp = element.getComponent(EnemyPlane);
enemyComp.show(this, this.enemy01Speed, false);
}
}

// 敌机出现组合1, 7架飞机V字型出现
public createCombination02() {
const enemyArray = new Array<Node>(7);
// 7 架敌机的初始坐标
const combinationPos = [
-21, 0, -60,
-14, 0, -55,
-7, 0, -50,
0, 0, -45,
7, 0, -50,
14, 0, -55,
21, 0, -60,
];
for (let i = 0; i < enemyArray.length; i++) {
enemyArray[i] = instantiate(this.enemy02);
const element = enemyArray[i];
element.parent = this.node;
const startIndex = i * 3;
element.setPosition(combinationPos[startIndex],
combinationPos[startIndex + 1],
combinationPos[startIndex + 2]);
const enemyComp = element.getComponent(EnemyPlane);
enemyComp.show(this, this.enemy02Speed, false);
}
}

// 敌机发射子弹
public createEnemyBullet(targetPos: Vec3) {
// 实例材质类型的子弹, 实例出来的对象不在场景中
const bullet = instantiate(this.bullet01);
bullet.setParent(this.bulletRoot); // 子弹挂载到子弹管理节点中

// 子弹出现的位置为飞机 Z轴 -7
bullet.setPosition(targetPos.x, targetPos.y, targetPos.z + 6);
const bulletComp = bullet.getComponent(Bullet);
// 敌机的子弹速度 要比敌机大一些
bulletComp.show(1, true);

// 获取子弹的碰撞器组件
const colliderComp = bullet.getComponent(BoxCollider);
// 设置敌机子弹的碰撞矩阵
colliderComp.setGroup(Constant.CollistionType.ENEMY_BULLET);
// 设置碰撞掩码 与 玩家飞机 碰撞
colliderComp.setMask(Constant.CollistionType.PLAYER_PLANE);

}

// 更换玩家子弹类型
public changeBulletType(type: number) {
this._bulletType = type;
}

// 创建子弹道具
public createBulletProp() {
const randomProp = math.randomRangeInt(1, 4);
console.log('create bullet prop:', randomProp);
let prefab: Prefab = null;
if (randomProp === Constant.BulletPropType.BULLET_H) {
prefab = this.bulletPropH;
} else if (randomProp === Constant.BulletPropType.BULLET_S) {
prefab = this.bulletPropS;
} else {
prefab = this.bulletPropM;
}

// 实例化子弹道具预览
const prop = instantiate(prefab);
prop.setParent(this.node);

// const prop = PoolManager.instance().getNode(prefab, this.node);

prop.setPosition(15, 0, -50); // 道具的起始位置
const propComp = prop.getComponent(BulletProp);
propComp.show(this, -this.bulletPropSpeed);
}


public returnMain() {
this._currShootTime = 0;
this._currCreateEnemyTiime = 0; // 当前敌机的生成时间
this._combinationInterval = Constant.Combination.PLAN1; // 组合的间隔状态
this._bulletType = Constant.BulletPropType.BULLET_M;
this.playerPlane.node.setPosition(0, 0, 15);
this._score = 0;
}

public gameReStart() {
this.gameStart();
this._currShootTime = 0;
this._currCreateEnemyTiime = 0; // 当前敌机的生成时间
this._combinationInterval = Constant.Combination.PLAN1; // 组合的间隔状态
this._bulletType = Constant.BulletPropType.BULLET_M;
this.playerPlane.node.setPosition(0, 0, 15);
}

public gameStart() {
this.isGameStart = true;
this.playerPlane.init();
this._changePlaneModel();
this._score = 0;
this.gameScore.string = this._score.toString();
}

public gameOver() {
this._isShooting = false;
this.isGameStart = false;
this.gamePage.active = false;
this.gameOverPage.active = true;
this.gameOverScore.string = this._score.toString();
this.overAnimation.play(); // 播放游戏结束的动画
this.gameScore.string = "0";
// this.playerPlane.init();
this.unschedule(this._modeChanged); // 取消定时器
this._destoryAll();
}

public addScore() {
this._score++;
this.gameScore.string = this._score.toString();
}


private _destoryAll() {
let children = this.node.children;
let length = children.length;
// 销毁对象时要从后往前,不能从前往后
for (let index = length - 1; index >= 0; index--) {
const child = children[index];
child.destroy();
}

children = this.bulletRoot.children;
length = children.length;
// 销毁对象时要从后往前,不能从前往后
for (let index = length - 1; index >= 0; index--) {
const child = children[index];
child.destroy();
}
}

private _init() {
// 用于按下的时候即发射第一颗子弹
this._currShootTime = this.shootTime;
this._changePlaneModel();
}

// 定时器函数
private _changePlaneModel() {
// this.schedule()四个参数:回调, 间隔时间,重复次数, 延迟时间
this.schedule(this._modeChanged, 10, macro.REPEAT_FOREVER);
}

// 改变组合状态
private _modeChanged() {
this._combinationInterval++;
this.createBulletProp(); // 创建子弹道具
}
}
  1. 编辑 assets/script/ui/UIManager 脚本, 添加 三个界面 节点 和 两个按钮 的方法, 以及修改原来的其他方法添加控制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

import { _decorator, Component, Node, Touch, EventTouch, Input } from 'cc';
import { GameManager } from '../framework/GameManager';
const { ccclass, property } = _decorator;

@ccclass('UIManager')
export class UIManager extends Component {

@property
public playerPlaneSpeed = 1;
@property(Node)
public playerPlane: Node = null;

// 添加游戏控制脚本
@property(GameManager)
public gameManager: GameManager = null;

@property(Node)
public gameStart: Node = null;
@property(Node)
public game: Node = null;
@property(Node)
public gameOver: Node = null;

start() {
this.node.on(Input.EventType.TOUCH_START, this._touchStart, this);
this.node.on(Input.EventType.TOUCH_MOVE, this._touchMove, this);
this.node.on(Input.EventType.TOUCH_END, this._touchEnd, this);
this.gameStart.active = true; // 显示开始界面
}

// 重新开始按钮对应代码
public reStart() {
this.gameOver.active = false;
this.game.active = true;
this.gameManager.gameReStart();
}

// 返回主页按钮代码
public returnMain() {
this.gameOver.active = false;
this.gameStart.active = true;
this.gameManager.returnMain();
}

private _touchMove(touch: Touch, event: EventTouch) {
if(!this.gameManager.isGameStart){
return;
}

// touch.getDelta() 获取当前触点值与上一次触点值的差值
let delta = touch.getDelta();
let pos = this.playerPlane.position; // 获取当前节点的位置
// 在速度前乘以 0.01 是用于调整移动的速度
this.playerPlane.setPosition(
pos.x + 0.01 * this.playerPlaneSpeed * delta.x,
pos.y,
pos.z - 0.01 * this.playerPlaneSpeed * delta.y);
}

// 开始触摸屏幕的回调方法
private _touchStart(touch: Touch, event: EventTouch) {
if (this.gameManager.isGameStart) {
this.gameManager.isShooting(true); // 触摸屏幕时玩家飞机开始射击
} else {
this.gameStart.active = false;
this.game.active = true;
this.gameManager.gameStart();
}
}

private _touchEnd(touch: Touch, event: EventTouch) {
if (!this.gameManager.isGameStart) {
return;
}
// 停止触摸时玩家飞机结束射击
this.gameManager.isShooting(false);
}
}

  1. 层级管理器 点击选中 Canvas/gameOver 节点,在其 属性检查器 中名字前 打勾 设为显示。

  2. 层级管理器 点击选中 Canvas/gameOver/reStart 节点,ClickEvents 属性的值改为 1, 点击 ClickEvents 左边的 三角形 符号展开, 把 Canvas 节点拖动到 cc.Node 处,右边第一个下拉项选择 UIMain, 第二个下拉项选择 reStart, 实现按钮与脚本中方法的绑定。

  1. 同样的方法完成 returnMain 按钮与对应方法的绑定。
  1. gameOver 节点添加组件 Event -> BlockInputEvents, 阻止结束后还能控制玩家飞机。
  1. 再次将 Canvas/gameOver 节点设为不显示, 保存场景。

  2. 层级管理器 点击选中 Canvas 节点, 绑定三个界面到相应属性中。

  1. 层级管理器 点击选中 gameManager 节点, 绑定对象到相应节点( PlayerPlane 因为在代码中修改了类型, 也要重新绑定)。
  1. 保存场景, 运行预览。

===END===