在对象属性更改上重绘画布

时间:2014-05-06 08:39:41

标签: javascript html5 canvas

我正在html5 canvas上构建用于对象管理的小型库。每个对象都有x和y属性,说明对象应该在画布上的位置。我想复制DOM属性修改(当我做elm.style.left ='100px',更改立即反映)到我的库。渲染是在特殊函数中管理的,所以我想在每次修改任何对象时调用此函数(+其他一些函数,如设置的碰撞检测,......)。

<小时/> 编辑: 我有一个像这样的对象:

{
    x: 10,
    y:10,
    ...
}

当我obj.x = 20;时,我需要用新的对象坐标重绘画布。

1 个答案:

答案 0 :(得分:0)

[根据提问者评论更改了答案]

您可能会从多个来源发生对象属性更改:

  • 来自您的javascript代码,
  • 来自用户(鼠标等),
  • 来自物理常规

要处理此问题,请设置一个包含对象数组和一些状态属性的主对象:

var universe={
    objects:[],
    requiresRender:false,
};

然后你可以像这样组织你的render()函数:

  • 在universe.objects上做物理
  • 如果物理改变了什么,那么重绘一切

渲染函数示例:

function render(universe){

    // if there's no work to do then return

    if(!universe.requiresRender){ return; }

    // do physics resolutions

    doPhysics(universe.objects);

    // if any source changed any objects properties then redraw

    if(universe.requiresRender){    
        ctx.clearRect(0,0,canvas.width,canvas.height);
        for(var i=0;i<universe.objects.length;i++){
            // redraw  object[i] now
        }
        universe.requiresRender=false;
    }

}

doPhysics()函数根据您的物理变化对象属性:

function doPhysics(objects){

    // do your physics now (collision tests, etc)
    // (don't redraw here...just change object properties)

    // if you changed any property on any object 
    // then request re-rendering
    universe.requiresRender=true;

}

物理学的一个方面是改变1个物体可能会对其他物体造成连锁效应。

例如,矩形A可能会与矩形B发生碰撞,因此A会反弹B.当A反弹时,它可能会进一步与矩形C发生碰撞。

这意味着您可能必须递归调用doPhysics()来解析所有对象交互。

通常没有足够的时间/资源来解决所有对象交互,因此物理引擎通常会执行固定数量的物理重复,而不是尝试完全解析所有对象交互。

在除了琐碎的物理环境之外,渲染函数还必须限制它解析物理的程度。

所以你的render()函数可能看起来像这样:

var universe={
    objects:[],
    requiresRender:false,
    physicsIterations=3,
};


function render(universe){

    // if there's no work to do then return

    if(!universe.requiresRender){ return; }

    // do the required number of physics resolutions

    for(var i=0;i<universe.physicsIterations;i++){
        doPhysics(universe.objects);
    }

    // if any source changed any objects properties then redraw

    if(universe.requiresRender){    
        ctx.clearRect(0,0,canvas.width,canvas.height);
        for(var i=0;i<universe.objects.length;i++){
                // redraw  object[i] now
        }
        universe.requiresRender=false;
    }
}

如果用户更改了任何对象属性,请设置requiresRender标志:

universe.requiresRender=true;

如果您的javascript更改了任何对象属性,请设置requiresRender标志:

universe.requiresRender=true;

通过使用requiresRender标志,您可以依赖循环来定期调用render()以保持正确绘制对象。

这样,您不需要对每个属性更改进行render()(每次属性更改都会降低性能)。

您可以使用requestAnimationFrame有效地将渲染与硬件显示的刷新周期同步。因此requestAnimationFrame可以实现高效渲染。

此requestAnimationFrame循环每秒最多执行60次。

function loop(time){

    // keep the loop going
    requestAnimationFrame(loop);

    // use javascript to make any desired object property changes

    // do a render 
    render();

}

同时

您可以查看物理引擎如何处理属性更新+物理+重绘。

Box2d就是一个很好的例子:http://box2d-js.sourceforge.net/