Javascript 对象属性更改时重新绘制画布

Javascript 对象属性更改时重新绘制画布,javascript,html,canvas,Javascript,Html,Canvas,我正在html5画布上构建用于对象管理的小型库。每个对象都有x和y属性,表示对象在画布上的位置。我想将DOM属性修改(当我执行elm.style.left='100px'时,更改会立即反映)复制到我的库中。渲染是在一个特殊的函数中管理的,所以每次修改任何对象时,我都会调用这个函数(+其他一些函数,如设置了碰撞检测,…) 编辑: 我有一个这样的物体: { x: 10, y:10, ... } var universe={ objects:[], requ

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


编辑: 我有一个这样的物体:

{
    x: 10,
    y:10,
    ...
}
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;
    }
}

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

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

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

  • 从javascript代码中
  • 来自用户(鼠标等)
  • 从物理常规
要处理此问题,请设置一个主对象,该主对象包含对象数组和一些状态属性:

var universe={
    objects:[],
    requiresRender:false,
};
然后可以按如下方式组织render()函数:

{
    x: 10,
    y:10,
    ...
}
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;
    }
}
  • 对宇宙物体进行物理学研究
  • 如果物理改变了什么,那么就重新绘制一切
渲染函数示例:

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;
    }

}
物理学的一个方面是,更改一个对象可能会对其他对象产生级联效应

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

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

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

在除普通物理环境外的所有物理环境中,渲染函数还必须限制其解析物理的范围

因此,您的render()函数可能会如下所示:

{
    x: 10,
    y:10,
    ...
}
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;
    }
}
如果javascript更改了任何对象属性,请设置requiresRender标志:

universe.requiresRender=true;
universe.requiresRender=true;
通过使用requiresRender标志,您可以依靠循环定期调用render(),以正确绘制对象

这样,您就不需要每次属性更改都使用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是一个很好的例子:

您能详细介绍一下吗?很抱歉这么说,但您完全误解了我的问题。我已经知道你告诉我的一切。所以请向我解释你的问题:)如果你正在寻找一个浏览器事件,它会通知你画布元素位置的更改,那么DOMAttrModified适用于一些但不是所有的浏览器(你必须进行轮询才能完全跨浏览器兼容)。或者您正在寻找javascript getter/setter?不建议使用这些工具将对象更改自动转换为画布重画。这是因为更改obj.x和obj.y将导致2次重绘。更有效的方法是同时更改obj.x和obj.y,然后进行1次重画。我有render()函数,该函数以对象数组为参数,清除画布并重画所有对象。现在,当我更改这些对象的某些属性(例如高度、x、y等)时,我希望调用render()以立即在画布上显示该更改。。。所以基本上,每次我改变数组中其中一个对象的某些属性时,我都希望得到一个调用的函数。现在,我正在使用setter和getter。如果只是为了渲染,我可以独立完成,但问题是,我实现了一些简单的物理,所以我想与其他对象进行碰撞检查,…我现在更了解您的情况。我改变了我的答案,以便更深入地了解物理引擎是如何处理属性变化的。祝你的项目好运!