| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- // 导入 Cocos Creator 核心模块
- const { _decorator, Component, EventTouch, find, instantiate, Node, Animation, Prefab, Size, UITransform, v3, Vec3, AnimationClip } = cc;
- /**
- * 视图工具类 - 提供节点查找、组件操作、坐标转换、预制创建等常用功能
- */
- const ViewUtil = {
- /**
- * 查找节点
- * @param {Node} curNode 当前节点
- * @param {string} path 从当前节点开始的路径
- * @returns {Node|null} 找到的节点(未找到返回null)
- **/
- findNode(curNode, path) {
- if (!curNode) {
- console.error(`当前节点为空:${path}`);
- return null;
- }
- let node = find(path, curNode);
- if (node) {
- return node;
- }
- console.error(`未找到节点:${path},当前节点:${curNode.name}`);
- return null;
- },
- /**
- * 查找组件
- * @param {Node} curNode 当前节点
- * @param {string} path 从当前节点开始的路径
- * @param {Function} type 组件构造函数(如 cc.Button)
- * @returns {Component|null} 找到的组件(未找到返回null)
- */
- findComponent(curNode, path, type) {
- let node = this.findNode(curNode, path);
- if (node) {
- return node.getComponent(type);
- }
- console.error(`未找到组件:${path}`);
- return null;
- },
- /**
- * 添加组件(若节点已存在该组件则直接返回,否则新增组件)
- * @param {Node} curNode 当前节点
- * @param {string} path 从当前节点开始的路径
- * @param {Function} type 组件构造函数(如 cc.Button)
- * @returns {Component|null} 添加/获取的组件(失败返回null)
- */
- addComponent(curNode, path, type) {
- let node = this.findNode(curNode, path);
- if (node) {
- let compt = node.getComponent(type) || node.addComponent(type);
- return compt;
- }
- console.error(`添加组件失败:${path}`);
- return null;
- },
- /**
- * 把Node当前的节点树结构根据Node命名转成一个Map对象,重名的组件会覆盖
- * Node的name不应该包含空格键,否则将跳过
- * @param {Node} parent 被遍历的Node组件
- * @param {Map} obj 绑定的Map对象 (可选)
- * @returns {Map|null} 存储节点名与节点对应关系的Map
- */
- nodeTreeInfoLite(parent, obj) {
- let map = obj || new Map();
- let items = parent.children;
- for (let i = 0; i < items.length; i++) {
- let _node = items[i];
- if (_node.name.indexOf(" ") < 0) {
- map.set(_node.name, _node);
- }
- ViewUtil.nodeTreeInfoLite(_node, map);
- }
- return map;
- },
- /**
- * 正则搜索节点名字,符合条件的节点将会返回
- * @param {RegExp} reg 正则表达式
- * @param {Node} parent 要搜索的父节点
- * @param {Array<Node>} nodes 返回的数组(可选)
- * @returns {Array<Node>} 符合正则条件的节点数组
- */
- findNodes(reg, parent, nodes) {
- let ns = nodes || [];
- let items = parent.children;
- for (let i = 0; i < items.length; i++) {
- let _name = items[i].name;
- if (reg.test(_name)) {
- ns.push(items[i]);
- }
- ViewUtil.findNodes(reg, items[i], ns);
- }
- return ns;
- },
- /**
- * 节点之间坐标互转
- * @param {Node} a A节点
- * @param {Node} b B节点
- * @param {Vec3} aPos A节点空间中的相对位置
- * @returns {Vec3} 转换到B节点空间的位置
- */
- calculateASpaceToBSpacePos(a, b, aPos) {
- const world = a.getComponent(UITransform).convertToWorldSpaceAR(aPos);
- return b.getComponent(UITransform).convertToNodeSpaceAR(world);
- },
- /**
- * 屏幕转空间坐标
- * @param {EventTouch} event 触摸事件
- * @param {Node} space 转到此节点的坐标空间
- * @returns {Vec3} 转换后的节点空间坐标
- */
- calculateScreenPosToSpacePos(event, space) {
- const uil = event.getUILocation();
- const worldPos = v3(uil.x, uil.y);
- return space.getComponent(UITransform).convertToNodeSpaceAR(worldPos);
- },
- /**
- * 显示对象等比缩放
- * @param {number} targetWidth 目标宽
- * @param {number} targetHeight 目标高
- * @param {number} defaultWidth 默认宽
- * @param {number} defaultHeight 默认高
- * @returns {Size} 等比缩放后的尺寸
- */
- uniformScale(targetWidth, targetHeight, defaultWidth, defaultHeight) {
- const widthRatio = defaultWidth / targetWidth;
- const heightRatio = defaultHeight / targetHeight;
- let ratio;
- widthRatio < heightRatio ? ratio = widthRatio : ratio = heightRatio;
- return new Size(Math.floor(targetWidth * ratio), Math.floor(targetHeight * ratio));
- },
- // /**
- // * 从资源缓存中找到预制资源名并创建一个显示对象
- // * (建议使用GameComponent里的同名方法,能自动管理内存释放)
- // * @param {string} path 资源路径
- // * @param {string} bundleName 资源包名(默认使用resLoader的默认包名)
- // * @returns {Node|null} 创建的预制节点(未找到资源返回null)
- // */
- // createPrefabNode(path, bundleName = resLoader.defaultBundleName) {
- // // 通过路径与类型获取已缓存资源
- // const p = resLoader.get(path, Prefab, bundleName);
- // if (p) {
- // return instantiate(p);
- // }
- // console.warn(`未找到预制资源:${path},是否在预加载common文件夹之前调用?`);
- // return null;
- // },
- // /**
- // * 异步加载预制并创建预制节点
- // * (建议使用GameComponent里的同名方法,能自动管理内存释放)
- // * @param {string} path 资源路径
- // * @param {string} bundleName 资源包名(默认使用resLoader的默认包名)
- // * @returns {Promise<Node|null>} 创建的预制节点Promise
- // */
- // createPrefabNodeAsync(path, bundleName = resLoader.defaultBundleName) {
- // return new Promise(async (resolve, reject) => {
- // try {
- // const p = await resLoader.loadAsync(bundleName, path, Prefab);
- // if (p) {
- // resolve(instantiate(p));
- // } else {
- // console.error(`名为【${path}】的资源加载失败`);
- // resolve(null);
- // }
- // } catch (error) {
- // console.error(`预制资源异步加载异常:${path}`, error);
- // resolve(null);
- // }
- // });
- // },
- // /**
- // * 添加节点动画
- // * @param {string} path 资源路径
- // * @param {Node} node 目标节点
- // * @param {boolean} onlyOne 是否唯一(默认true,避免重复播放)
- // * @param {boolean} isDefaultClip 是否播放默认动画剪辑(默认false)
- // */
- // addNodeAnimation(path, node, onlyOne = true, isDefaultClip = false) {
- // if (!node || !node.isValid) {
- // return;
- // }
- // let anim = node.getComponent(Animation);
- // if (anim == null) {
- // anim = node.addComponent(Animation);
- // }
- // const clip = resLoader.get(path, AnimationClip);
- // if (!clip) {
- // return;
- // }
- // if (onlyOne && anim.getState(clip.name) && anim.getState(clip.name).isPlaying) {
- // return;
- // }
- // if (isDefaultClip) {
- // anim.defaultClip = clip;
- // anim.play();
- // return;
- // }
- // // 播放完成后恢复播放默认动画
- // anim.once(Animation.EventType.FINISHED, () => {
- // if (anim.defaultClip) {
- // anim.play();
- // }
- // }, this);
- // if (anim.getState(clip.name)) {
- // anim.play(clip.name);
- // return;
- // }
- // anim.createState(clip, clip.name);
- // anim.play(clip.name);
- // }
- };
- // 导出工具类,供其他文件导入
- module.exports = { ViewUtil };//使用 CommonJS 模块导出方式
|