有關(guān)背包等滑動列表drawcall高的問題衡奥,大佬們已經(jīng)提供了很好的解決方案了,美中不足是這種修改渲染遍歷順序的方式,只適用于web端榛搔,不適用于native端。
我這里也提供一個簡單的方法煌往,通過camera拍照添加到列表項節(jié)點祈纯,然后隱藏原節(jié)點其他所有子節(jié)點,從而使一個列表項的drawcall降為1楣号,配合TableView使用最易,能將一個滑動列表的drawcall降為比較可觀的數(shù)量。
這種做法只適用于列表項全部是靜態(tài)的情況炫狱。
按下去的時候藻懒,item的drawcall恢復(fù)為4,松開后變?yōu)?视译。
做法的關(guān)鍵是截圖:
shootItem(itemNode:cc.Node):cc.Texture2D{
let box = itemNode.getBoundingBox();
let pt = cc.v2(box.x+box.width*0.5,box.y+box.height*0.5);
pt = this.camera.node.parent.convertToNodeSpaceAR(itemNode.parent.convertToWorldSpaceAR(pt))
let cameraOrthoSize = box.height*0.5;
this.camera.alignWithScreen = false;
this.camera.node.position = cc.v3(pt.x,pt.y,100);
this.camera.orthoSize = cameraOrthoSize;
this.renderTexture.initWithSize(box.width,box.height)
this.camera.targetTexture = this.renderTexture;
this.camera.enabled = true;
this.camera.render();
this.camera.enabled = false;
let data = this.renderTexture.readPixels();
data = filpYImage(data,box.width, box.height)
let tex = new cc.Texture2D()
tex.initWithData(data,cc.Texture2D.PixelFormat.RGBA8888, box.width, box.height)
return tex
}
相機節(jié)點添加到content同級目錄下嬉荆,放在外面的話會因為剪裁拍不到。修改相機的正交投影視窗大小酷含,使剛好覆蓋目標(biāo)節(jié)點鄙早,然后設(shè)置相機的位置為目標(biāo)節(jié)點同一位置,這樣拍出的照片就剛好是目標(biāo)節(jié)點了椅亚。
下面是完整代碼限番,使用的時候只需要在列表項添加ListCaptureItem組件即可,列表項更新的時候調(diào)用lock方法重新拍照呀舔。
const {ccclass, property,disallowMultiple,menu,requireComponent} = cc._decorator;
@ccclass
@disallowMultiple
@menu("list_capture_item")
/**將列表項拍照保存弥虐,適用于節(jié)點項沒有動畫、沒有重疊的情況 */
export default class ListCaptureItem extends cc.Component {
private capture:cc.Sprite = null;
onLoad(){
let _node = this.node.getChildByName("capture");
if(_node==null){
_node = new cc.Node("capture");
_node.parent = this.node;
this.capture = _node.addComponent(cc.Sprite);
this.capture.spriteFrame = new cc.SpriteFrame();
let widget = _node.addComponent(cc.Widget)
widget.isAlignLeft = true;
widget.isAlignRight = true;
widget.isAlignTop = true;
widget.isAlignBottom = true;
widget.alignMode = cc.Widget.AlignMode.ONCE;
widget.left = 0;
widget.right = 0;
widget.top = 0;
widget.bottom = 0;
}else{
this.capture = _node.getComponent(cc.Sprite);
}
this.lock()
}
private shooter:ListItemCamera = null;
private initShooter(){
if(this.shooter){
return this.shooter;
}
let scroll:cc.ScrollView = null;
let parent = this.node.parent;
while(parent){
scroll = parent.getComponent(cc.ScrollView);
if(scroll){
break;
}
parent = parent.parent;
}
if(scroll&&scroll.content==this.node.parent){
let children = scroll.content.parent.children;
for(let c of children){
this.shooter = c.getComponent(ListItemCamera);
if(this.shooter){
break
}
}
if(this.shooter==null){
let _node = new cc.Node();
_node.parent = scroll.content.parent;
_node.addComponent(ListItemCamera)
this.shooter = _node.getComponent(ListItemCamera);
}
}else{
cc.warn("list_capture_item只應(yīng)該在Scrollview的列表項上")
}
}
onEnable(){
this.node.on(cc.Node.EventType.TOUCH_START,this.onMouseEnter,this)
this.node.on(cc.Node.EventType.TOUCH_CANCEL,this.onMouseLeave,this)
this.node.on(cc.Node.EventType.TOUCH_END,this.onMouseLeave,this)
}
onDisable(){
this.node.off(cc.Node.EventType.TOUCH_START,this.onMouseEnter,this)
this.node.off(cc.Node.EventType.TOUCH_CANCEL,this.onMouseLeave,this)
this.node.on(cc.Node.EventType.TOUCH_END,this.onMouseLeave,this)
}
private onMouseEnter(){
this.unlock();
}
private onMouseLeave(){
this.lock(true);
}
/**拍照,每次UI變化之后要調(diào)用 */
public lock(withOutCapture=false){
this.initShooter();
if(this.shooter==null){
return;
}
this.scheduleOnce(()=>{
let childs = this.node.children;
if(!withOutCapture){
childs.forEach( (child)=>{
child.active = this.capture.node!=child;
})
let tex = this.shooter.shootItem(this.node);
this.capture.spriteFrame.setTexture(tex)
let widget = this.capture.getComponent(cc.Widget)
widget.updateAlignment();
}
childs.forEach( (child)=>{
child.active = this.capture.node==child;
})
})
}
public unlock(){
if(this.shooter==null){
return;
}
let childs = this.node.children;
childs.forEach((child)=>{
child.active = this.capture.node!=child;
})
}
}
@disallowMultiple
/**生成一個照相機媚赖,掛載在scrollview.content同級節(jié)點 */
class ListItemCamera extends cc.Component {
private camera:cc.Camera = null;
private scroll:cc.ScrollView = null;
private get renderTexture(){
if(!this.camera.targetTexture){
let renderTexture = new cc.RenderTexture();
this.camera.targetTexture = renderTexture;
}
return this.camera.targetTexture;
};
onLoad(){
this.camera = this.getComponent(cc.Camera);
if(this.camera==null){
this.camera = this.addComponent(cc.Camera);
}
this.scroll = this.node.parent.parent.getComponent(cc.ScrollView);
if(this.scroll==null){
cc.error("list_item_camera 必須掛在scrollview.content同級")
return;
}
this.camera.alignWithScreen = false;
this.camera.enabled = false;
}
shootItem(itemNode:cc.Node):cc.Texture2D{
let box = itemNode.getBoundingBox();
let pt = cc.v2(box.x+box.width*0.5,box.y+box.height*0.5);
pt = this.camera.node.parent.convertToNodeSpaceAR(itemNode.parent.convertToWorldSpaceAR(pt))
let cameraOrthoSize = box.height*0.5;
this.camera.node.position = cc.v3(pt.x,pt.y,100);
this.camera.orthoSize = cameraOrthoSize;
// if(this.renderTexture.loaded){
// if(Math.abs(this.renderTexture.width-box.width)>Number.EPSILON||Math.abs(this.renderTexture.height-box.height)>Number.EPSILON){
// //@ts-ignore
// this.renderTexture.updateSize(box.width,box.height)
// this.camera.targetTexture = this.renderTexture;
// }
// }else{
this.renderTexture.initWithSize(box.width,box.height)
this.camera.targetTexture = this.renderTexture;
// }
this.camera.enabled = true;
this.camera.render();
this.camera.enabled = false;
let data = this.renderTexture.readPixels();
data = filpYImage(data,box.width, box.height)
let tex = new cc.Texture2D()
tex.initWithData(data,cc.Texture2D.PixelFormat.RGBA8888, box.width, box.height)
return tex
}
}
/**翻轉(zhuǎn)圖片 */
function filpYImage (data:Uint8Array, width:number, height:number) {
// create the data array
let picData = new Uint8Array(width * height * 4);
let rowBytes = width * 4;
for (let row = 0; row < height; row++) {
let srow = height - 1 - row;
let start = srow * width * 4;
let reStart = row * width * 4;
// save the piexls data
for (let i = 0; i < rowBytes; i++) {
picData[reStart + i] = data[start + i];
}
}
return picData;
}