项目链接:https://github.com/cocos-creator/tutorial-first-game/tree/master/polished_project
1.通过脚本属性引用场景节点
通过脚本显式地暴露属性,从而引用场景中需要用到的节点对象。也就是说场景需要用到的节点资源,通通都要留个属性节点作为入口
2.cc.sys.isMobile
// initialize control hint
var hintText = cc.sys.isMobile ? this.touchHint : this.keyboardHint;
this.controlHintLabel.string = hintText;
cc.sys.isMobile属性用于判断当前系统是否为手机设备
3.NodePool对象缓存池类型
cc.NodePool 是用于管理节点对象的对象缓存池
它可以帮助您提高游戏性能,适用于优化对象的反复创建和销毁
constructor(); 使用构造函数来创建一个节点专用的对象池,您可以传递一个组件类型或名称,用于处理节点回收和复用时的事件逻辑
// initialize star and score pool
this.starPool = new cc.NodePool('Star');
this.scorePool = new cc.NodePool('ScoreFX');
get(); 获取对象池中的对象,如果对象池没有可用对象,则返回空
// 使用给定的模板在场景中生成一个新节点
if (this.starPool.size() > 0) {
newStar = this.starPool.get(this); // this will be passed to Star's reuse method
}else {
newStar = cc.instantiate(this.starPrefab);
}
put(); 向缓冲池中存入一个不再需要的节点对象
this.starPool.put(star);
this.scorePool.put(scoreFX);
4.node.active属性
this.gameOverNode.active = false;
node.active = true || false;用来显示或隐藏节点
5.node.addChild(newNode);
每次新创建完预制资源以后,记得把新的节点添加到父节点下面
// 将新增的节点添加到 Canvas 节点下面
this.node.addChild(newStar);
易错点:先设置完属性,然后再添加到父节点
比如下面这段代码会导致精灵无法摘取星星
var newStar = cc.instantiate(this.starPrefab);
// 为星星设置一个随机位置
newStar.setPosition(this.getNewStarPosition());
// pass Game instance to star
newStar.getComponent('Star').init(this);
// 将新增的节点添加到 Canvas 节点下面
this.node.addChild(newStar);
这段代码问题出在this.node.addChild(newStar);精灵之所以无法摘取星星,正是因为newStar节点还没添加到Canvas画布下面,所以newStar还不是Canvas下的子节点,所以newStar.setPosition()、newStar.getComponent()这两个方法执行无效。
只要把this.node.addChild(newStar); 方法放到newStar.setPosition()、newStar.getComponent()这两个方法的前面即可
修改后的代码
// 将新增的节点添加到 Canvas 节点下面
this.node.addChild(newStar);
// 为星星设置一个随机位置
newStar.setPosition(this.getNewStarPosition());
// pass Game instance to star
newStar.getComponent('Star').init(this);
6.如果函数功能不是太多,就不要嵌套太多的函数
如上代码,startTimer()只有两行代码并且该函数只调用了一次,因此把startTimer()函数合并到spawnNewStar(),从而减少代码的冗余性,增强代码的可读性
7.if…else改写成三目运算符
if (this.currentStarX >= 0) {
randX = -Math.random() * maxX;
}else {
randX = Math.random() * maxX;
}
修改后的代码
randX=this.currentStarX >= 0?-Math.random() * maxX:Math.random() * maxX
将if…else改写成三目运算符可以减少更多的代码量
8.通过this.enabled属性来控制游戏开始与关闭
Game.js通过this.enabled属性来控制游戏开关
也可以从Game.js调用this.player.enabled = false;来关闭Player.js
9.this.currentStar.destroy();
node.destroy(); 销毁该对象,并释放所有它对其它对象的引用
通常在游戏GameOver的时候调用destroy()方法,释放一些资源
实际销毁操作会延迟到当前帧渲染前执行。从下一帧开始,该对象将不再可用。 您可以在访问对象之前使用 cc.isValid(obj) 来检查对象是否已被销毁
10.Cocos Creator动画系统
动画系统通常用来做些简单的特效,针对节点做的动画,如果是复杂的角色动画,需要借助spine或者db
11.cc.Sprite.spriteFrame
在时间轴上给spriteFrame属性添加关键帧,从而实现帧帧动画
12.Animation、animation-clip的关系
一个节点添加Animation组件使之成为Animation节点,一个Animation节点可以添加多个clip影片剪辑
以Animation节点作为根节点,只有它的子节点才能添加属性、添加动画。给不同的子节点添加不同的动画,这些子节点最终合成一个clip影片剪辑
13.简单的形变效果
//压扁
var squash = cc.scaleTo(this.squashDuration, 1, 0.6);
//拉长
var stretch = cc.scaleTo(this.squashDuration, 1, 1.2);
//恢复原状
var scaleBack = cc.scaleTo(this.squashDuration, 1, 1);
通过cc.scaleTo();这样一个方法改变Y轴大小,从而实现精灵球从压扁到弹跳再到恢复原状这么一个过程
14.node.parent属性或node.getParent()方法获得父节点
// screen boundaries
this.minPosX = -this.node.parent.width/2;
this.maxPosX = this.node.parent.width/2;
有时需要通过父节点获得一些信息供子节点使用
15.初始化触屏输入监听
初始化触屏输入监听,与键盘输入监听类似
// 初始化触屏输入监听
var touchReceiver = cc.Canvas.instance.node;
touchReceiver.on('touchstart', this.onTouchStart, this);
touchReceiver.on('touchend', this.onTouchEnd, this);
onTouchStart (event) {
var touchLoc = event.getLocation();
if (touchLoc.x >= cc.winSize.width/2) {
this.accLeft = false;
this.accRight = true;
} else {
this.accLeft = true;
this.accRight = false;
}
},
向onTouchStart()方法传入参数event,通过event参数获得当前屏幕点击的位置
var touchLoc = event.getLocation();
cc.log(touchLoc.x);
cc.winSize(); 为当前的游戏窗口的大小
16.相同动作的case可以合并
onKeyDown (event) {
switch(event.keyCode) {
case cc.macro.KEY.a:
this.accLeft = true;
this.accRight = false;
break;
case cc.macro.KEY.d:
this.accLeft = false;
this.accRight = true;
break;
case cc.macro.KEY.left:
this.accLeft = true;
this.accRight = false;
break;
case cc.macro.KEY.right:
this.accLeft = false;
this.accRight = true;
break;
}
},
如上代码case cc.macro.KEY.a和case cc.macro.KEY.left具有相同的行为,case cc.macro.KEY.d和case cc.macro.KEY.right也具有相同的行为,因此可以把相同行为的case合并。修改后的代码如下
onKeyDown (event) {
switch(event.keyCode) {
case cc.macro.KEY.a:
case cc.macro.KEY.left:
this.accLeft = true;
this.accRight = false;
break;
case cc.macro.KEY.d:
case cc.macro.KEY.right:
this.accLeft = false;
this.accRight = true;
break;
}
},
把case cc.macro.KEY.a和case cc.macro.KEY.left合并,case cc.macro.KEY.d和case cc.macro.KEY.right合并之后,又减少了更多的代码
17.update()方法中,什么时候需要乘上dt
update()方法中,dt是一个重要的时间变量,dt的使用对物体运动的速度有很大的影响
从以上代码得出一些结论,末速度Vt = V0+at; 路程S = Vt;
因此,我们只要根据物理常识,就知道什么时候需要乘上dt
18.有两种引用js文件的方式
①通过组件化方式
②通过require()引用js文件
const Player = require('Player');
至于什么时候使用组件化、什么时候使用require(); 这两种引用js文件方式还是有区别的
①如果既需要获得节点的信息,又要获得节点对应的js文件,此时应该使用组件化引用方式
②如果仅仅需要js文件里的属性和方法,那就用require()方式更快捷