07 - 飞机大战开发Day3
今天继续完善飞机大战项目,今天的工作量如下:
- 实现按照波次同时刷新多种敌人
- 飞机子弹的碰撞系统
实现按照波次同时刷新多种敌人
准备多种敌人
首先要准备敌人的数据,即enemyData.json
:
// enemyData.json
[
{
"id": 2001,
"name": "normalEnemy",
"mainImgPath": "enemy10",
"hp": 5
},
{
"id": 2002,
"name": "normalEnemy",
"mainImgPath": "enemy11",
"hp": 10
}
]
该数据文件指定了敌人的id
,名称(种类),图片路径和血量。为了能够顺利读取该数据文件,别忘了修改DataManager.js
。
然后要写逻辑,目前还没区分敌人种类,所以它们的逻辑都是在NormalEnemy.js
中的:
// NormalEnemy.js
// 初始化血量
setHp: function(hp) {
this.hp = hp;
this.hpLabel.string = this.hp;
}
// 初始化贴图和碰撞箱
setSpriteFrame: function (spriteFrame) {
if (spriteFrame instanceof cc.SpriteFrame) {
// 设置贴图
let sprite = this.node.getComponent(cc.Sprite);
sprite.spriteFrame = spriteFrame;
// 设置碰撞箱
let collider = this.node.getComponent(cc.BoxCollider);
collider.size.width = this.node.width;
collider.size.height = this.node.height;
} else {
console.log('[NormalEnemy]: 贴图设置错误! (不是cc.SpriteFrame类型)');
}
}
// 受伤了更新血量
hurt: function (hp) {
this.hp -= hp;
if (this.hp <= 0) {
this.node.removeFromParent();
} else {
this.hpLabel.string = this.hp;
}
}
最后在EnemyManager.js
中实现创建单个敌人的逻辑:
// EnemyManager.js
createEnemy: function (enemyData) {
let enemyNode = cc.instantiate(this.enemyPrefab[0])
enemyNode.parent = this.node;
// Todo: 敌人分类
if (enemyData.name === 'normalEnemy') {
let enemyJs = enemyNode.getComponent('NormalEnemy');
let mainSpriteFrame = this.resMgr.getSpriteFrameByName(enemyData.mainImgPath);
enemyJs.setSpriteFrame(mainSpriteFrame);
enemyJs.setHp(enemyData.hp);
enemyJs.move();
}
}
准备多种波次
可在关卡数据levelData.json
中添加波次信息:
// levelData.json
{
"id": 1001,
"name": "Level1",
"bgPath": "level_1",
"waves": [
{
"enemyId": [
2001,
2002
],
"repeat": [
8,
4
],
"interval": [
3,
2
],
"delay": 10
},
{
"enemyId": [
2002
],
"repeat": [
3
],
"interval": [
1
],
"delay": 3
}
]
}
其中,waves
数组中每一个元素代表一波中出现的敌人,包含敌人们的id
、个数repeat
、出生间隔interval
和波次间的等待时间delay
。
接下来就能在EnemyManager.js
中编写解析这些信息的逻辑了:
// EnemyManager.js
scheduleWaves: function () {
let interval = 0, delay = 0.1, repeat = 0, id = '', enemyData = {};
let maxDelay = -1;
let debugWaveCnt = 1;
for (let wave of this.wavesData) {
console.log('Wave ' + debugWaveCnt + ': ');
console.log(wave);
for (let i = 0; i < wave.enemyId.length; ++i) {
interval = wave.interval[i];
repeat = (wave.repeat[i] - 1 < 0) ? 0 : (wave.repeat[i] - 1);
id = wave.enemyId[i];
enemyData = this.dataMgr.getEnemyDataById(id);
// todo: 按波次安排敌人刷新
maxDelay = Math.max(interval * repeat, maxDelay);
delay += 0.5;
}
debugWaveCnt++;
delay += (wave.delay + maxDelay);
}
}
实现按波次安排敌人刷新
需要用到Cocos2D提供的schedule()
接口:
// EnemyManaget.js
// todo: 按波次安排敌人刷新
let createEnemyForScheduleArr = [];
createEnemyForScheduleArr.push((enemyData) => {
const data = enemyData; // 创建一个独有变量, 非常好GPT
return (() => {
// console.log(data);
this.createEnemy(data);
});
});
console.log('\ncreateEnemyForSchedule(' + id + ')\ninterval: ' + interval + ', repeat:' + repeat + ', delay: ' + delay);
this.schedule(createEnemyForScheduleArr[i](enemyData), interval, repeat, delay);
这里用到了闭包函数(感谢GPT的帮助),由于schedule()
接口的回调函数不允许有参数,而想要创建敌人还需传入它的信息enemyData
,于是便能用闭包函数和箭头函数这两个知识点去“生成”符合条件的回调函数。这里会生成一个没有参数的函数,它会利用闭包内的敌人信息来生成敌人。
飞机子弹的碰撞系统
和之前小鸟项目一样,就不说了。
让子弹/敌人消失的函数:self/this.node.removeFromParent();
。
明天干什么
可能进一步拓展游戏功能,例如玩家飞机种类选择,飞机&子弹进化;敌人种类增加,Boss战等。