上一节我们完成了鱼的运动代码的编写,这一节我们主要需要通过预制体和单例实现将鱼放置到场景当中。
看起来将鱼放置到场景中是个很简单的事情,你可以说,上一节我已经知道怎么做出一只游来游去的鱼了,那我一只一只的按照之前的方法将它们放到场景中就可以了啊!
但是,你不知道玩家能够挑战多长的时间,对于小白玩家来说,可能他只能挑战几秒钟的时间,这种情况下你尚可以通过老方法去一个一个的放置鱼,但假设有一个游戏高手,他能够无限长的时间进行游戏,那你的鱼理论上也需要放置无限多个,怎么办?
这个时候我们就需要Prefab预制体了。
Prefab是什么?
它是储存在项目中的一种可以被反复克隆使用的游戏对象,当游戏中需要非常多反复使用的对象、资源时,Prefab可以帮助快速的生成这些相同或者相似的游戏资源。例如子弹、怪物等等。
Prefab拥有以下特点:
- 能够放到多个场景中,也可以在同一个场景中重复多次放置
- 当把Prefab加入到场景时,实际上时创建了一个新的实例,该实例本质上是Prefab的克隆
- 当Prefab选择了自动同步时,无论场景中放置了多少Prefab实例,只要修改Prefab,所有实例都会保持同步。
关于Prefab,可以参考官方文档:
http://docs.cocos.com/creator/manual/zh/asset-workflow/prefab.html
OK,接下来我们来进行Prefab的制作。
在cocoscreator中,prefab的制作很简单,在场景中编辑好节点后,直接使用鼠标,将节点从层级管理器拖到资源管理器,即可创建出一个Prefab。
双击assets中的预制体可以进入预制体编辑中,编辑完预制体后,点击保存或者关闭推出编辑。
接下来,我们创建一个场景的脚本,并且挂载到Canvas下。在场景脚本的Update中,我们去根据游戏进程创建实例鱼。
同时在场景中,我们创建一个空的节点,命名FishPool,用来作为所有鱼的父节点,方便进行节点的管理。
场景脚本代码:
cc.Class({
extends: cc.Component,
properties: {
mPrefab : {
default : null,
type : cc.Prefab
},
mFishPool : {
default : null,
type : cc.Node
},
mHook : {
default : null,
type : cc.Node
},
mDepth : {
default : 0,
type : cc.Float,
visible : false
},
},
// LIFE-CYCLE CALLBACKS:
// onLoad () {},
start () {
},
update (dt) {
var depth = Math.floor(Math.abs(this.mHook.y) / 100);// 100pixel = 1 m
if (depth - this.mDepth > 0)//每1m生成一只鱼
{
var fish = cc.instantiate(this.mPrefab);
fish.x = Math.random() * 640 - 320;//随机X轴坐标
fish.y = this.mHook.y - 480 - 100;//在屏幕可视范围下方提前生成
this.mFishPool.addChild(fish);
}
this.mDepth = depth;
},
});
OK,保存一下,预览效果:
基本符合我们的预期。
不过还有个问题,目前的鱼外观只有一种,看起来很单调,并且每1m生成一只鱼非常的机制并不能做出很好玩的关卡出来。因此我们需要丰富一下,并且将一些数值提取成为配置,交给策划同学来进行配置。
在这之前我们先做一个关卡的配置表出来,需要配置的参数有:深度(到多少深度的时候刷新鱼),鱼的资源路径,鱼的运动速度
我们采用JSON作为配置表的数据格式,当然你也可以采用xml或者csv等,这就需要而外写一些代码进行解析。
实际项目中推荐开发一个小工具方便策划同学通过excel配置,并且一键转换输出为你使用的数据格式。
新建一个JSON文件,我把它命名为Scene.json,写入以下数据
[
{"depth":1,"res":"Fish/fish01","speed":1},
{"depth":2,"res":"Fish/fish02","speed":1},
{"depth":3,"res":"Fish/fish03","speed":1},
{"depth":4,"res":"Fish/fish04","speed":1},
{"depth":5,"res":"Fish/fish05","speed":1},
{"depth":6,"res":"Fish/fish06","speed":1},
{"depth":7,"res":"Fish/fish07","speed":1},
{"depth":8,"res":"Fish/fish08","speed":1},
{"depth":9,"res":"Fish/fish09","speed":1},
{"depth":10,"res":"Fish/fish10","speed":1}
]
在场景脚本的properties中添加属性,并在编辑器中配置
mSceneData : {
default : null,
type : cc.JsonAsset
},
关于使用JSON资源,请参考官方文档:
http://docs.cocos.com/creator/manual/zh/asset-workflow/json.html
接着,我们对场景脚本进行修改:
cc.Class({
extends: cc.Component,
properties: {
mPrefab : {
default : null,
type : cc.Prefab
},
mFishPool : {
default : null,
type : cc.Node
},
mHook : {
default : null,
type : cc.Node
},
mDepth : {
default : 0,
type : cc.Float,
visible : false
},
mSceneData : {
default : null,
type : cc.JsonAsset
},
mIndex : {
default : 0,
visible : false
}
},
// LIFE-CYCLE CALLBACKS:
// onLoad () {},
start () {
},
update (dt) {
this.mDepth = Math.floor(Math.abs(this.mHook.y) / 100);// 100pixel = 1 m
let data = this.mSceneData.json[this.mIndex];
if (data != undefined && this.mDepth >= data.depth)//到达配置的位置时,生成一只鱼
{
var fish = cc.instantiate(this.mPrefab);
cc.loader.loadRes(data.res,cc.SpriteFrame,function(err,spriteFrame){
if (!err)
fish.getComponent(cc.Sprite).spriteFrame = spriteFrame;
});//更换图片外观
fish.x = Math.random() * 640 - 320;//随机X轴坐标
fish.y = this.mHook.y - 480 - 100;//在屏幕可视范围下方提前生成
this.mFishPool.addChild(fish);
this.mIndex++;
}
},
});
我们使用cc.loader.loadRes来进行资源的加载,并在加载结束后进行资源的更换。
具体请参考官方文档中动态加载资源部分的文档:
敲完代码,OK,预览一下:
成功,整个海底世界变得丰富一些了呢。