cocosCreator笔记 之 脚本访问节点及组件

cocosCreator版本: 3.7


简介


cocosCreator的工作流程是通过节点–组件来实现的,节点作为场景中的基本单位, 而不同功能的组件挂载在节点之上,来完成页面的搭建。

Node_1
Scene
组件1_1
组件1_2
Node_2
组件t2_1
组件2_2
Node_3
组件3_1
组件3_2

简单的理解: 场景由多个节点构成,节点作为实体,不同功能的组件挂载到节点上。
更多参考:节点和组件

比如Canvas节点的组成组件部分:
请添加图片描述

  • UITransform UI变换组件,设置组件的尺寸、锚点以及点击事件相关
  • Canvas 画布组件,继承于RenderRoot2D组件,作为渲染和数据收集入口
  • Widget UI布局组件,用于屏幕适配相关
  • mainScene脚本 必须继承于Component,才能作为脚本组件添加到编译器中

在3.x中,当添加不同类型的UI组件对象时,编译器都会默认的增加UITransform组件。


脚本访问节点及组件


访问当前节点和节点下的组件

访问当前脚本的所在节点,可以使用this.node来访问, 而获取节点下的组件可以使用getComponent来访问

更多参考:访问节点和其他组件

// 获取当前节点
let node = this.node;
// 获取当前节点下的其他组件
let button = this.node.getComponent(Button);
let label = this.node.getComponent(Label);

继承于Component的脚本也可以通过getComponent来获取,获取成功后可以调用脚本中public属性的方法。

// 直接输入脚本的名字即可, 脚本自动添加import获取脚本的路径相关
// 脚本名也可以使用字符串,比如:"DemoScript",但vsCode代码编译器会提示找不到脚本的对应方法,虽不影响运行,但不推荐
let script = this.node.getComponent(DemoScript);
if (script) {
  script:refresh();
}

节点基本属性

在2.x版本中,没有UITransform的组件, 像大小,锚点相关直接通过Node就可以获取到。
在3.x版本中,官方新增了该组件,在设置大小的同时,也处理触摸事件等机制。
请添加图片描述
参照着上图,其实可以知道,通过this.node可以获取位置,旋转,缩放等信息;

// 激活相关,假设为激活状态
// 由true设为false, 生命周期回调为onDisalbe
// 由false设为true, 生命周期回调为onEnable, update, lateUpdate
this.node.active = true;
// 节点是否被销毁或有效
let isValid = this.node.isValid;
// 位置相关
this.node.setPosition(new Vec3(100, 50, 0));
this.node.position = new Vec3(100, 50, 0);
const pos = this.node.position;
this.node.setPosition(pos.x, pos.y, 100);
// 旋转相关
this.node.setRotationFromEuler(90, 0, 0);
// 缩放相关
this.node.setScale(2, 2, 2);

通过UITransform获取大小,锚点等信息

import { _decorator, Component, Node, UITransform } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('Demo')
export class Demo extends Component {
	onLoad() {
    // 获取UITransform组件
    let transform = this.node.getComponent(UITransform);
    // 获取节点宽度
    let width = transform.width;
    // 获取节点锚点
    let anchorX = transform.anchorX;
    // 通过节点大小包围盒获取大小等
    let size = transform.getBoundingBox().size;
  }
}

针对于getBoundingBox() 这里稍微说明下,如果物体是静态的,通过它获取大小是没有问题的;

但如果项目中使用了物理引擎,且物体保持旋转,不要使用它,会出现获取大小错误的情况, 简单了解下就行了。

透明度

在cocos2d-x中,透明度的获取在节点中通过 setOpacity就可以获取到,但在creator中,透明度的获取有两种方式:

  • 针对于精灵组件相关,通过颜色的设置就来获取透明度相关
  • 针对于非精灵组件,需要通过属性检查器 -> 添加组件 -> 添加UIOpactiy组件来设置透明度

这种的设计方式可能是为了渲染的优化。

请添加图片描述

层级

在编译器中,层级的设定通过层级管理器会进行默认的排版,但如果在脚本中设定的话,注意:

// 2.x版本, 通过Node下的 zIndex 属性来设置
this.node.zIndex = 10;
// 3.x版本,通过Node下的 setSiblingIndex 方法来设置
this.node.setSiblingIndex(10);

节点的层级修改影响的是子节点在父节点中的顺序,而不是节点的渲染顺序。频繁的调用会带来一些性能损耗,在循环遍历中容易导致子节点未被遍历的情况存在。

let children = this.node.children;
for (let i = 0; i < children.length; i++) {
	let zOrder = (i%2 == 0) ? 999 : 0;
	children[i].setSiblingIndex(zOrder);
}

层级的动态改变,一般多用于触摸移动事件中。

节点相关

节点的子节点获取,主要接口有:

  • getChildByUuid(uuid: string): Node 通过uuid获取子节点
  • getChildByName(name: string): Node 通过名称获取子节点
  • getChildByPath(path: string): Node 通过路径获取子节点

对于节点的操作主要有:

// 获取子节点的数组相关,不包含子节点的子节点
let children = this.node.children;
for (let i = 0; i < children.length; ++i) {
   let child = children[i];
}
// 获取当前节点的子节点
let childNode = this.node.getChildByName("titleText");
// 获取当前节点的子节点的某个组件
let labelComponent = childNode.getComponent(Label);
let transform = childNode.getComponent(UITransform);

// 创建节点,但它不会主动添加到场景中,需要手动添加
let node = new Node("Box");
node.setPostion(0, 0, 0);
director.getScene().addChild(node);

注: 在实际的项目开发中,推荐使用 @property(Node) 获取节点, 而不是使用getChildByName,原因在于后者必须在代码运行的过程中才能获取

克隆节点,接口使用instantiate,多用于对预制体Prefab的克隆,放置到列表容器中

import { _decorator, Component, instantiate, Prefab, ScrollView } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('UI_ShopLayer')
export class UI_ShopLayer extends Component {
  // 在编译器中声明属性,
  @property(Prefab)
  itemPrefab: Prefab = null; 
  @property(ScrollView)
  scroll: ScrollView = null;
  
  onLoad() {
    // 删除容器的子元素
    this.scroll.content.removeAllChildren();
    // 遍历进行克隆节点
    for (let i = 0; i < 10; ++i) {
      let item = instantiate(this.itemPrefab);
      // 方式1,通过addChild进行添加
      this.scroll.content.addChild(item);
      // 方式2,通过parent来设置
      item.parent = this.scroll.content;
    }
  }
}

注: 两种方式从性能角度来考虑,没有明显的却别,本质上调用的底层方法都是一样的。addChild 直观易懂,node.parent 简洁; 增加子节点都需要注意避免频繁的变更和克隆,这样会出现效率问题

更换节点的父节点相关

// 父节点为parentNode, 子节点为this.node
// 方法1
this.node.parent = parentNode;
// 方法2, 注意removeFromParent的参数要为false, 否则会清空节点上绑定的事件和action等
this.node.removeFromParent(false);
parentNode.addChild(this.node);

销毁节点相关

/*
它并不是立即被移除,而是在当前帧逻辑更新结束后,执行
不要使用removeFromParent,它并不会从内存中释放,引擎内部仍会持有它的数据
如果一个节点不再使用,使用destroy就对了,否则会导致内存泄漏

需要注意:
* 如果逻辑比较复杂,销毁的话,可以通过setTimeout设置毫秒添加下延迟
* 如果使用的是定时器相关,建议增加判定: if (this.node && this.node.isValid) 的判定
* 总之一句话:小心无大错
*/
setTimeout(() => {
	this.node.destroy();
}, 1000);

注: 调用onDestory 根据生命周期回调,先onDisableonDestory;如果是定时器的销毁就放在onDestory中,因为节点未销毁中还可能会使用

最后祝大家生活愉快!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鹤九日

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值