【muzzik教程】50行代码,教你优化列表draw call!【网格、横、纵 全包揽】

是的,这是由版本2.3.4编写,3.0及以后需要修改部分代码,晚上回去我看看

好的,改好后发出来一下,我不知道怎么改,谢谢了

我用的也是这个,几千多条,一开始全部加载,但是只有前面20多个时候opacity255其它都是0,所以drawcall不会太高

好吧应该是1000多条~以前也是用别的,发现还是这个比较方便一点

发现了一个问题:就是当页面存在editbox的时候,聚焦输入出现软键盘,关闭输入的时候,列表会变空白或者部分空白 这是一个测试录屏,cocos 2.4.5 设备:华为畅想20
https://husangamerelease.yingzhongshare.com/1624613608790243.mp4

推荐一个DrawCall优化好帮手


:smiley:问题已经解决了哈 感谢。。。

没想错的话,如果你的字体很大,这个drawcall不一定能到4哦。
另外,极限情况应该是把所有图标放在一个scrollview里,文本放到一个scrollview里,然后两边scrollview绑定偏移量。这种优化应该是可以把drawcall降低到2次吧,如果你再魔改一下引擎,把那个图放到生成的字体纹理里,甚至可以减少到只有1次drawcall

把透明度从0调整到255会导致列表的移动感觉不流畅

调整透明度不会影响流畅,应该是其他原因造成的

我刚刚在项目中用你说的方法试了一下,drawCall确实会降低很多,电脑上很流畅android打包后列表移动就感觉流畅的不如之前了

虽然我想说用循环做更好

不过这个思路不错

怎么加入群阿 想进群

请教一下cocos creator3.1.2 调用不了_calculWorldMatrix 这个方法,没这个api, 求教一下,cocos creator3.1.2应该 怎么实现_calculWorldMatrix 这个方法

3.x 实现

import {
	Color,
	color,
	Component,
	error,
	mat4,
	Mat4,
	Node,
	Rect,
	Renderable2D,
	ScrollView,
	UIOpacity,
	UITransform,
	_decorator,
} from "cc";

const { ccclass, property, menu } = _decorator;

/**列表draw call优化组件 */
@ccclass
@menu("tool/list_optimize")
export default class list_optimize extends Component {
	/* ***************private*************** */
	private _scroll_view: ScrollView;
	private _ui_transform: UITransform;
	private _temp1_color = color();
	private _temp1_m4 = mat4();
	private _temp2_m4 = mat4();
	/* --------------------------------segmentation-------------------------------- */
	onLoad() {
		this._scroll_view = this.node.getComponent(ScrollView);
		this._ui_transform = this.node.getComponent(UITransform);
		if (!this._scroll_view) {
			error("不存在ScrollView组件!");
			return;
		}
		this._event_update_opacity();
		// 事件监听
		{
			this.node.on("scrolling", this._event_update_opacity, this);
			this._scroll_view.content.on(
				Node.EventType.CHILD_REMOVED,
				this._event_update_opacity,
				this
			);
			this._scroll_view.content.on(
				Node.EventType.CHILD_ADDED,
				this._event_update_opacity,
				this
			);
		}
	}
	/* ***************功能函数*************** */
	/**获取在世界坐标系下的节点包围盒(不包含自身激活的子节点范围) */
	private _get_bounding_box_to_world(node_: any): Rect {
		node_.getWorldMatrix(this._temp2_m4);
		Mat4.fromRTS(
			this._temp1_m4,
			this.node.getRotation(),
			this.node.getPosition(),
			this.node.getScale()
		);
		let width = this._ui_transform.contentSize.width;
		let height = this._ui_transform.contentSize.height;
		let rect = new Rect(
			-this._ui_transform.anchorPoint.x * width,
			-this._ui_transform.anchorPoint.y * height,
			width,
			height
		);
		Mat4.multiply(this._temp2_m4, this._temp2_m4, this._temp1_m4);
		rect.transformMat4(this._temp2_m4); // query child's BoundingBox
		return rect;
	}
	/**检测碰撞 */
	private _check_collision(node_: Node): boolean {
		let rect1 = this._get_bounding_box_to_world(this._scroll_view.content.parent);
		let rect2 = this._get_bounding_box_to_world(node_);
		// 保险范围
		{
			rect1.width += rect1.width * 0.5;
			rect1.height += rect1.height * 0.5;
			rect1.x -= rect1.width * 0.25;
			rect1.y -= rect1.height * 0.25;
		}
		return rect1.intersects(rect2);
	}
	/**设置节点透明度 */
	private set_node_opacity(node_: Node, opacity_n_: number): void {
		let rander_comp = node_.getComponent(Renderable2D);
		if (rander_comp) {
			Color.copy(this._temp1_color, rander_comp.color);
			this._temp1_color.a = opacity_n_;
			rander_comp.color = this._temp1_color;
		} else {
			(node_.getComponent(UIOpacity) || node_.addComponent(UIOpacity)).opacity = opacity_n_;
		}
	}
	/* ***************自定义事件*************** */
	private _event_update_opacity(): void {
		this._scroll_view.content.children.forEach(v1 => {
			this.set_node_opacity(v1, this._check_collision(v1) ? 255 : 0);
		});
	}
}

@xhzth70911 @1321519915

2赞

是真好用!!!

不知道是不是我的使用方式不对,我挂在scrollview节点上,刚打卡页面初始会透明度全 为0,要有滑动才显示内容,是哪里不对吗?cocos版本是2.4.6。

onLoad内执行的首次更新,如果更新时scrollView内的item不在可视区域内那么就会这样,检查下item的坐标

噢噢,我关闭的时候没有还原item的坐标,现在设置了scrollToTop就可以了,谢谢!

先mark一下。。