我的带有requestAnimationFrame + drawimage的简单画布使用大约8-9%的cpu是正常的吗?

时间:2016-10-01 15:32:16

标签: javascript html5 canvas typescript


我正在使用一个简单的例子来测试HTML5 Canvas来绘制一些等距的瓷砖。 我正在使用requestAnimationFrame方法。但是,我可以在Chrome任务管理器中看到大约8%的CPU使用率。

PS :我正在使用Typescript

这是我的绘制循环:

private Draw = () => {
        this.Context.clearRect(0, 0, this.Canvas.width, this.Canvas.height);
        this.Context.imageSmoothingEnabled = false;
        this.DrawCtx();
        requestAnimationFrame(this.Draw);
}

DrawCtx使用此函数调用另一个类:

public Draw(MousePosition: Array<number>, ClickPosition: any): void {
        this.MousePosition = MousePosition;
        this.ClickPosition = ClickPosition;

        this.DrawBackground();
        this.ParseMap();
        this.Container.Draw();
        this.DrawTiles();
}

这里是一个drawTiles片段(其他东西只是地图数组的for()

if(!curtile.isDoor && typeof(this.Map.getMap().data[x - 1]) != "undefined" && this.Map.getMap().data[x - 1][y].height != 0 && this.Map.getMap().data[x - 1][y].height == (parseInt(curtile.height) + 1)) {
                            this.Container.drawImage(x + y + 500, this.Resources["1.png"], curtile.left, curtile.top - 24 - ((curtile.height - 1) * 6), 64, 64);
                        } else if(!curtile.isDoor && typeof(this.Map.getMap().data[x][y - 1]) != "undefined" && this.Map.getMap().data[x][y - 1].height != 0 && this.Map.getMap().data[x][y - 1].height == (parseInt(curtile.height) + 1)) {
                            this.Container.drawImage(x + y + 500, this.Resources["2.png"], curtile.left, curtile.top - 24 - ((curtile.height - 1) * 6), 64, 64);
                        } else if(!curtile.isDoor && ((typeof(this.Map.getMap().data[x][y - 1]) != "undefined" && this.Map.getMap().data[x][y - 1].height != 0 && this.Map.getMap().data[x][y - 1].height == curtile.height) || typeof(this.Map.getMap().data[x - 1][y]) != "undefined" && this.Map.getMap().data[x - 1][y].height != 0 && this.Map.getMap().data[x - 1][y].height == curtile.height) && typeof(this.Map.getMap().data[x - 1][y - 1]) != "undefined" && this.Map.getMap().data[x - 1][y - 1].height != 0 && this.Map.getMap().data[x - 1][y - 1].height == (parseInt(curtile.height) + 1)) {
                            this.Container.drawImage(x + y + 500, this.Resources["3.png"], curtile.left, curtile.top - 24 - ((curtile.height - 1) * 6), 64, 64);
                        } else {
                            this.Container.drawImage(x + y + 500, this.Resources["tile.png"], curtile.left, curtile.top - ((curtile.height - 1) * 6), Config.Game.TileWidth, Config.Game.TileHeight);
                        }

和this.Container是我的drawImage索引系统

export default class Container {
    Objects: any = [];
    Context: any;

    constructor(Context: any) {
        this.Context = Context;
    }

    public drawImage(index: number, ...drawArguments: any[]) {
        this.Objects.push({
            index: index,
            args: drawArguments
        });
    }

    public Draw(): void {
        this.Objects.sort(function(a: any, b: any) {
            return (a.index > b.index) ? 1 : ((b.index > a.index) ? -1 : 0);
        });

        for(var i in this.Objects) {
            var object = this.Objects[i];
            this.Context.drawImage.apply(this.Context, object.args);
        }

        this.Objects = [];
    }
}

为什么只为某些drawImages使用~8-9%的CPU?我的代码出了什么问题?或者这是正常的吗?

1 个答案:

答案 0 :(得分:1)

对于速度,一般规则是“在可用的最低级别写入”:Typescript增加了开销,在Javascript中编写需要速度的代码。

不要使用for(in ??)迭代标准for循环,它更快。

不要使用apply,直接调用该函数,它的速度要快6倍(在Chrome上更多)。请注意,这是针对调用操作而不是被调用函数中的代码。

每次调用Draw时,都会创建并销毁一个新数组。这将产生重大影响。重用对象,永远不要在性能循环中取消引用任何内容。即使您必须取消引用放入数组中的所有新对象,也不要在绘制函数的末尾创建一个新对象。只需重置它的长度。 'objects.length = 0'不会产生构造新数组对象的开销。

var currentObjectCount = 0;
var objects = [];

function drawImage(index,...etc)
    var o = objects[currentObjectCount];
    if(o === undefined){
       objects[currentObjectCount] = o = {};
    }
    o.index = index;
    o.args = etc;
    currentObjectCount += 1;
}

在添加对象集currentObjectCount = 0

之前的每一帧的开头

在渲染循环(绘制函数)中,使用currentObjectCount修剪数组以进行排序

objects.length = currentObjectCount;

但是如果你可以摆脱排序,那么不要修剪数组并在for循环中使用currentObjectCount。忽略当前帧不需要的任何对象。在阵列上有额外的未使用的物品没有任何成本,在你需要的时候重新使用旧物品没有任何成本,取消引用成本,构建成本。

你必须真正排序,你可以做的任何类型的预先排序将改善排序。在drawImage调用中使用插入排序,只是一个简单的排序,可以使真正的排序更快。

但是对于渲染,你只需要对重叠进行排序,如果你在任何阶段在对象之间进行距离或碰撞测试,使用该数据来优化排序,保留两个对象数组一个用于排序,另一个可以是呈现未分类。 (我已经写了超过35年的100个2D游戏,从来没有必须在主渲染循环中使用排序,总是有更好的方法)

摆脱传播运营商。它的速度很慢,绘制图像没有那么多变种,因此值得用...

引起的开销

KISS是快速代码使用的规则。保持简单(第二个S是制作首字母缩略词)。保持简单并不意味着代码所在的表面,而是简单到核心。