首页 > 其他分享 >Cocos Creator 2.x之ScrollView分层渲染

Cocos Creator 2.x之ScrollView分层渲染

时间:2023-12-24 17:31:38浏览次数:36  
标签:node Cocos curr Creator cc ScrollView let nodes 节点

一, 场景设计

Cocos Creator 2.x之ScrollView分层渲染_Cocos

1,ScrollViewPrefab:挂载ScrollViewPrefab脚本。

Cocos Creator 2.x之ScrollView分层渲染_Cocos_02

2,ScrollViewPrefabItem: 挂载ScrollViewPrefabItem脚本。是内容item。

Cocos Creator 2.x之ScrollView分层渲染_分层_03

二,传统做法,加入30个item

Cocos Creator 2.x之ScrollView分层渲染_Cocos_04

三,分层处理, 加入30个item

1, 代码:CommomScrollViewCD


const { ccclass, property } = cc._decorator;

//绘画层
class Draw {
    key: string = ""; //以节点名为标记
    mask: boolean = false; //是否有mask遮盖组件
    layout: boolean = false; //是否有layout组件
    nodes: Array<cc.Node> = []; //绘画节点容器
    localOpacitys: Array<number> = [];
    childrens: Array<Array<cc.Node>> = []; //绘图节点原子节点数据

    next: Draw | null = null;
    prev: Draw | null = null;

    constructor(key: string) {
        this.key = key;
        this.mask = false;
        this.nodes = [];
        this.childrens = [];
    }
}

//绘画层队列
class Queue {
    items: any = {};
    head: Draw | null = null;

    constructor() {
        this.items = {};
        this.head = null;
    }

    get(key: string) {
        return this.items[key];
    }

    set(prev: Draw | null, data: Draw) {
        this.items[data.key] = data;
        if (!this.head) this.head = data;
        else {
            data.next = prev!.next;
            prev!.next = data;
            data.prev = prev;
        }
    }

    clear() {
        Object.keys(this.items).forEach((key) => {
            delete this.items[key];
        });
        this.head = null;
        this.items = {};
    }
}

@ccclass
export default class CommomScrollViewCD extends cc.Component {
    //全局合批队列记录
    private nodes: Array<cc.Node> = [];
    private queues: Array<Queue> = [];
    private aabb0 = cc.rect();
    private aabb1 = cc.rect();
    private worldMat4 = cc.mat4();

    queue: Queue = new Queue(); //优先级分层队列
    children: Array<cc.Node> = []; //记录原节点结构

    @property(cc.Node)
    culling: cc.Node = null;

    update(dt: number) {
        this.nodes.push(this.node);
        this.queues.push(this.queue);
    }

    protected onl oad(): void {
        cc.director.on(
            cc.Director.EVENT_BEFORE_DRAW,
            (dt) => {
                //绘画前拦截修改节点结构
                let nodes = this.nodes;
                let queues = this.queues;
                for (let i = 0; i < nodes.length; i++) {
                    let node = nodes[i];
                    if (node.active && node.isValid) {
                        this.changeTree(node, queues[i]);
                    }
                }
            },
            this
        );

        cc.director.on(
            cc.Director.EVENT_AFTER_DRAW,
            (dt) => {
                //绘画结束后恢复节点结构
                let nodes = this.nodes;
                let queues = this.queues;
                for (let i = 0; i < nodes.length; i++) {
                    let node = nodes[i];
                    if (node && node.isValid) {
                        this.resetTree(node, queues[i]);
                    }
                }

                nodes.length = 0;
                queues.length = 0;
            },
            this
        );
    }

    //遍历建立绘图层队,并收集绘画节点
    private getDrawNode(
        prev: Draw | null,
        node: cc.Node,
        queue: Queue,
        active: boolean,
        level: number = 0,
        opacity: number = 1.0
    ) {
        let render: any = node.getComponent(cc.RenderComponent) || node.getComponent(cc.RichText);

        //注意:根据节点的名字进行分层,务必确保名字的唯一性
        let key = node.name; //添加层级前缀加强同名过滤
        if (level == 0) key = "MinesDC"; //自定义收集首节点(允许Item首节点异名)
        let draw = queue.get(key);
        if (!draw) {
            draw = new Draw(key);
            queue.set(prev, draw);
            draw.mask = node.getComponent(cc.Mask) != null;
            draw.layout = node.getComponent(cc.Layout) != null;
        }

        prev = draw;

        if (render) {
            let nodes = draw.nodes;
            let localOpacitys = draw.localOpacitys;

            if (active) {
                //node.active && active
                nodes.push(node); //收集节点
                localOpacitys.push(node.opacity); //保存透明度
                node.opacity = opacity * node.opacity; //设置当前透明度
            }
        }

        opacity = (opacity * node.opacity) / 255.0;

        //遮罩直接打断返回
        if (draw.mask) return prev;
        if (draw.layout)
            //强制新layout世界矩阵
            node["_updateWorldMatrix"]();

        let childs = node.children;
        for (let i = 0; i < childs.length; i++) {
            let isActive = childs[i].active ? active : false;
            prev = this.getDrawNode(prev, childs[i], queue, isActive, level + 1, opacity);
        }

        return prev;
    }

    private getWorldBoundingBox(node: cc.Node, rect: cc.Rect) {
        let _contentSize = node.getContentSize();
        let _anchorPoint = node.getAnchorPoint();

        let width = _contentSize.width;
        let height = _contentSize.height;
        rect.x = -_anchorPoint.x * width;
        rect.y = -_anchorPoint.y * height;
        rect.width = width;
        rect.height = height;

        node.getWorldMatrix(this.worldMat4);
        return rect.transformMat4(rect, this.worldMat4);
    }

    private changeTree(parent: cc.Node, queue: Queue) {
        if (this.culling) {
            this.getWorldBoundingBox(this.culling, this.aabb0);
        }

        //遍历所有绘画节点,按顺序分层
        let nodes = parent.children;
        for (let i = 0; i < nodes.length; i++) {
            let node = nodes[i];
            if (node.activeInHierarchy) {
                //剔除显示范围外的item
                if (this.culling) {
                    this.getWorldBoundingBox(node, this.aabb1);
                    if (!this.aabb0.intersects(this.aabb1)) continue;
                }

                this.getDrawNode(null, node, queue, true);
            }
        }

        //记录item的父节点的子节点结构
        this.children = parent["_children"]; //记录原来节点结构
        let childs: Array<cc.Node> = (parent["_children"] = []); //创建动态分层节点结构

        //拼接动态分层的绘画节点
        let curr = queue.head;
        while (curr) {
            let mask = curr.mask;
            let nodes = curr.nodes;
            let childrens = curr.childrens;
            for (let i = 0; i < nodes.length; i++) {
                childrens[i] = nodes[i]["_children"]; //记录原来节点结构
                !mask && (nodes[i]["_children"] = []); //清空切断下层节点
            }

            //按顺序拼接分层节点
            childs.push(...nodes);
            curr = curr.next;
        }
    }

    private resetTree(parent: cc.Node, queue: Queue) {
        parent["_children"].length = 0; //清空动态分层节点结构
        parent["_children"] = this.children; //恢复原来节点结构

        //恢复原来节点结构
        let curr = queue.head;
        while (curr) {
            let nodes = curr.nodes;
            let childrens = curr.childrens;
            let localOpacitys = curr.localOpacitys;
            for (let i = 0; i < nodes.length; i++) {
                nodes[i]["_children"] = childrens[i]; 
                nodes[i].opacity = localOpacitys[i];
            }
            childrens.length = 0;
            nodes.length = 0;
            curr = curr.next;
        }

        queue.clear();
    }

    protected onDestroy(): void {
        cc.director.targetOff(this);
    }
}

2,ScrollViewPrefab预制体的content的节点中挂载CommonScrollViewCD脚本。

Cocos Creator 2.x之ScrollView分层渲染_CD_05

3,结果

Cocos Creator 2.x之ScrollView分层渲染_优化_06

标签:node,Cocos,curr,Creator,cc,ScrollView,let,nodes,节点
From: https://blog.51cto.com/aonaufly/8956264

相关文章

  • Spring的Bean后置处理器之AnnotationAwareAspectJAutoProxyCreator
    本文能帮你回答以下几个问题;AnnotationAwareAspectJAutoProxyCreator后置器的作用是什么?SpringAOP自动增强bean是如何实现的。如何在spring上下文添加AnnotationAwareAspectJAutoProxyCreator?如何利用ProxyFactory硬编码实现一个bean的增强?AnnotationAwareAspectJAutoProx......
  • 【教程】步兵 cocos2dx 加密和混淆
    文章目录摘要引言正文代码加密具体步骤代码加密具体步骤测试和配置阶段IPA重签名操作步骤总结参考资料 摘要本篇博客介绍了针对iOS应用中的Lua代码进行加密和混淆的相关技术。通过对Lua代码进行加密处理,可以确保应用代码的安全性,同时提高性能表现。文......
  • 【终极教程】Cocos2dx服务端重构(优化cocos2dx服务端)
    【终极教程】Cocos2dx服务端重构(优化cocos2dx服务端)文章目录概述问题概述1.代码混淆代码加密具体步骤测试和配置阶段IPA重签名操作步骤2.缺乏文档3.缺乏推荐的最佳实践4.性能问题总结 概述Cocos2dx是一个非常流行的跨平台游戏引擎,开发者可以使用这个引擎来开......
  • 【教程】使用ipagurd打包与混淆Cocos2d-x的Lua脚本
    【教程】使用ipagurd打包与混淆Cocos2d-x的Lua脚本文章目录摘要引言正文1.准备工作2.使用ipaguard处理Lua文件3.运行ipagurd进行混淆代码加密具体步骤测试和配置阶段IPA重签名操作步骤4.IPA重签名与发布总结 摘要本文将介绍如何使用ipagurd工具对Cocos2d-......
  • 【教程】cocos2dx资源加密混淆方案详解
    ​ 【教程】cocos2dx资源加密混淆方案详解1,加密,采用blowfish或其他2,自定是32个字符的混淆code3,对文件做blowfish加密,入口文件加密前将混淆code按约定格式(自定义的文件头或文件尾部)写入到文件4,遍历资源目录,对每个文件做md5混淆,混淆原始串=“相对路径”+“文件名”+混......
  • centos 6.10 安装 qtCreator6.0.2
    centos6.10安装qtCreator6.0.2在centos6.10上源码编译安装qtCreator6.0.2下载地址下载后解压然后执行下面命令cdqt-creator-opensource-src-6.0.2mkdirbuild&&cdbuildcmake..makeset(CMAKE_PREFIX_PATH/home/fla/soft/qt5.15.11/lib/cmake/Qt5)SET(CMAKE......
  • cocoscreator使用总结
    1.背景图的大小超过父节点的大小,要使背景图不超过父节点,可以在父节点上增加一个mask组件2.layout组件可以设置垂直或水平布局,垂直时可以设从上到下或从下到上,水平布局可以设置从左向右,从右向左,可以方便用来设置文字在右下角之类的3.ScrollView的bar可以移除,view里面......
  • Cocos 飞机大战 (难点分析 制作)
    前言自己也写了3个cocos项目,觉得前面确实有点难,但是熟悉上手之后应该就是好多了,就是熟能生巧吧下面就是我的一个项目分析和难点  就是我们常玩的打飞机先看下效果图我在手机上的截图 就是拖到触屏飞机进行射击和躲避子弹,感觉还行吧哈哈难点 1.就是物体直接......
  • cocos creator ScrollView不滚动问题
    拖放默认的ScrollView可以,可以滚动显示文字,结构如下:ScrollView scrollBar(滚动条结点,不显示滚动条时,可直接删除,删除后把ScrollView里面的VertticalScrollBar值清了) bar view(视图结点) content item(具体文本)content......
  • COCOS 保姆入门级
    前沿游戏最近是越来越火了,流行的2个unity和cocos,已经成为主流前端去学的话还是cocos比较友好,因为是TS,JS来写脚本的,最近自己也很沉迷cocos,算是入门了,能写几个简单的游戏demo了,现在先写一些知识点 1.组件实例+节点节点是组间实例的载体,组件实例不能离开节点而单独的......