节点和组件
经过前面的脚本编写及属性挂载,对脚本和组件现在应该有了清晰的认知
在 Cocos Creator 中,节点(Node) 是承载组件的实体,我们通过将具有各种功能的 组件(Component) 挂载到节点上,来让节点具有各式各样的表现和功能。
在Cocos Creator中,在层级管理器中的都是节点,在节点中挂载的脚本、Widget等都是组件
节点
节点创建
代码创建图片
let spriteNode = new cc.Node; // 创建一个图片节点
let spriteCompent = spriteNode.addComponent(cc.Sprite); // 添加图片组件
// 加载资源并赋值给图片组件
cc.resources.load("Image/icon2", cc.SpriteFrame, function (err, spriteFrame: cc.SpriteFrame) {
if (err) {
return
}
spriteCompent.spriteFrame = spriteFrame;
});
// 添加到当前场景的 【Canvas】节点中
var scene = cc.director.getScene();
spriteNode.parent = scene.getChildByName('Canvas');
代码创建label
{
// let labelNode = new cc.Node;
let labelNode = new cc.Node('CustomLabelNode'); // 创建一个名字为CustomLabelNode的节点
let labelCompoment = labelNode.addComponent(cc.Label);
labelCompoment.string = '这是一个label';
labelNode.position = cc.v3(100,50);
labelCompoment.fontSize = 15;
labelCompoment.fontFamily = 'Arial';
labelCompoment.node.color = cc.Color.WHITE;
let scence = cc.director.getScene()
labelNode.parent = scence.getChildByName('Canvas');
}
实例化预制件
1、定义属性并进行关联
// 一般是用这中方式声明
@property({
type: cc.Prefab,
displayName: '预制件',
tooltip: '鼠标放上去的提示文字',
})
prefab_image: cc.Prefab = null;
// properties: {
// prefab_image: {
// default: null;
// type: cc.Prefab;
// displayName: '名字';
// },
// }
2、实例化
在关联了预制件之后,直接实例化
{ // 实例化节点
let prefab = cc.instantiate(this.prefab_image);
prefab.position = cc.v3(-100, 0);
var scence = cc.director.getScene();
prefab.parent = scence.getChildByName('Canvas');
}
1、普通创建
let labelNode = new cc.Node;
2、创建一个指定名称的
let labelNode = new cc.Node('CustomLabelNode');
3、创建预制件: 先确保属性已经被关联
cc.instantiate(this.prefab_image);
节点拷贝
在iOS中,如果要拷贝一个对象,一般是直接 obj.copy.
在Cocos Creator中,拷贝一个对象,相当于是在已有的节点中,再实例化一次(和节点实例化差不多)。
// 实例化原始的节点
let prefab = cc.instantiate(this.prefab_image);
prefab.position = cc.v3(-100, 0);
var scence = cc.director.getScene();
prefab.parent = scence.getChildByName('Canvas');
// 拷贝节点
let prefabCopy = cc.instantiate(prefab);
// 可以先屏蔽这行
// prefabCopy.position = cc.v3(-200, 0);
prefabCopy.parent = scence.getChildByName('Canvas').getChildByName('Main Camera').getChildByName('ground');
在这段拷贝中,为了方便区分其位置信息,将父节点设置为ground。
在拷贝中,不设置positon,发现其positon信息是原来节点的位置信息。
如果只设置positon,不设置其present,发现并没有显示在界面中
在节点拷贝中,
其位置信息也会被拷贝
。
其父节点信息并不会被拷贝
。
节点查找及多层查找
一般来说,在脚本中,如果需要查找节点
// 当前脚本所在的节点
let node = this.node;
查找其父节点
let node = this.node.parent;
如果节点在属性检查器,或者是一个预制件 ,比如这个场景的结构
场景的节点查找
var scence = cc.director.getScene(); // 当前场景
var node = scence.getChildByName('Canvas'); // 场景下的Canvas节点
node = node.getChildByName('Main Camera'); // Canvas节点下的Main Camera节点
node = node.getChildByName('TestLabel'); // Main Camera点下的TestLabel节点
let label = node.getComponent(cc.Label); // TestLabel节点中的label组件
label.string = 'test';
这种多层结构,可以用另一个快捷写法对于这种情况,路径的第一级就是第一级的节点:Canvas
let findNode = cc.find('Canvas/Main Camera/TestLabel');
let label = findNode.getComponent(cc.Label);
label.string = 'test1';
预制件的节点查找
预制件的节点查找第一级是从Background
开始
{ // 实例化组件
let prefab = cc.instantiate(this.prefab_image);
prefab.position = cc.v3(-100, 0);
var scence = cc.director.getScene();
prefab.parent = scence.getChildByName('Canvas');
let preNode = cc.find('Background/Label',prefab); // 查找里面的label节点
let label = preNode.getComponent(cc.Label); // 取出label节点的label组件
label.string = '改了';
}
节点销毁
销毁destroy()
在iOS中,对象被销毁是在其超过作用域时,由系统将其销毁,或者设置obj = nil
;
在Cocos Creator 中,主动销毁 可以直接使用 this.prefabtest.destroy();
@property({
type: cc.Node,
})
prefabtest: cc.Node = null;
nodeTest() {
{ // 实例化组件
let prefab = cc.instantiate(this.prefab_image);
prefab.position = cc.v3(-100, 0);
var scence = cc.director.getScene();
prefab.parent = scence.getChildByName('Canvas');
// 延时1s执行销毁这个节点
this.scheduleOnce(this.destroyNode,1)
}
destroyNode () {
// 销毁
this.prefabtest.destroy();
// 延时1s后,尝试再把这个节点加入父节点
this.scheduleOnce(this.restoreUse,1)
}
restoreUse () {
var scence = cc.director.getScene();
this.prefabtest.parent = scence.getChildByName('Canvas');
}
再最后加入父节点的时候,发现并没有加到父节点上。但是此时这个节点是还在的,其active = false
移除removeFromParent
removeFromParent
通常需要传入一个false
,否则默认会清空节点上绑定的事件和 action 等。
移除removeFromParent
和iOS的 removeForSuperView
差不多。将此节点移除父节点。
用上面销毁的代码中,把destroy() 替换成removeFromParent(), 发现先移除,在添加,最终成功被添加到父节点上。
destroy 和 removeFromParent 的区别
调用一个节点的 removeFromParent
后,它并不会从内存中释放,因为引擎内部仍会持有它的数据。因此如果一个节点不再使用,请直接调用它的 destroy
而不是 removeFromParent
,否则会导致内存泄漏。
总之,如果一个节点不再使用,destroy
就对了,不需要 removeFromParent
也不需要设置 parent
为 null
。
组件
组件的创建和获取
添加系统节点
以创建一个按钮的过程来看添加过程。
// 创建一个节点(Node)
let buttonNode = new cc.Node;
// 在节点上添加Button组件 ,使其具有按钮能力
let buttonComponent = buttonNode.addComponent(cc.Button); // 节点上加一个button的组件
// 添加图片
// 1、创建节点
// 2、创建Sprite组件(承载图片用Sprite)
// 添加图片组件
let imageNode = new cc.Node;
let imageComponent = imageNode.addComponent(cc.Sprite);
imageNode.parent = buttonNode;
cc.resources.load("Image/icon2", cc.SpriteFrame, function (err, spriteFrame: cc.SpriteFrame) {
if (err) {
console.error('Failed to load image:', err);
return;
}
imageComponent.spriteFrame = spriteFrame;
});
// 添加label
// 1、创建节点
// 2、创建label组件
let labelNode = new cc.Node;
let labelCompoment = labelNode.addComponent(cc.Label);
labelCompoment.string = '按钮';
labelNode.parent = buttonNode;
// 获取组件
let label = labelNode.getComponent(cc.Label); // 取出label节点的label组件
label.string = '改了按钮';
buttonNode.parent = this.node.parent;
添加自定义脚本组件
1、自定义脚本名CustomNode.ts
2、脚本中的类名CustomNodeClass
// 文件名:CustomNode
const { ccclass, property } = cc._decorator;
@ccclass
export default class CustomNodeClass extends cc.Component {
// @property(cc.Prefab)
// buttonPrefab: cc.Prefab = null;
start() {
console.log('加载了CustomNode组件');
}
}
// 用脚本名称添加组件
let customNodeCompent = buttonNode.addComponent('CustomNode');
// 用类名添加组件
// 1、导入文件
// 2、用类名加载组件
import CustomNodeClass from "./CustomNode";
let customNodeCompent = buttonNode.addComponent(CustomNodeClass);
在上面这个实例中,可以看出,
1、添加组件之前都是先创建了一个节点
2、
node.addComponent(cc.Label);
的方式添加组件
3、node.getComponent(cc.Label);
的方式获取4、
node.addComponent('CustomNode');
参数为脚本名称
5、node.getComponent('CustomNode');
参数为脚本名称6、
node.addComponent(CustomNodeClass);
参数为脚本中的类名称 需要先导入脚本文件
7、node.getComponent(CustomNodeClass);
参数为脚本中的类名称