Javascript 旋转一组对象,同时保持其方向不变

Javascript 旋转一组对象,同时保持其方向不变,javascript,html,canvas,rotation,Javascript,Html,Canvas,Rotation,基本上,我有一个容器对象,其中包含相对于其父对象修改的“子对象”,我希望通过更改父对象的旋转值来旋转所有对象,同时保持单个子对象的方向稳定。(例如,旋转整个对象)我觉得我没有很好地解释这一点,所以这里有两个例子。PhysicsJS:(参见第一个示例,使用0.7和球——注意碰撞后旋转0或7时,对象的整体形状是如何保持的。PhaserJS()中的机器人示例也是如此。现在,为了看看是否可以,我尝试用我自己的库复制前面提到的PhysicsJS示例--(为简洁起见简化) 参考标记的兴趣点——这是我旋转画布

基本上,我有一个容器对象,其中包含相对于其父对象修改的“子对象”,我希望通过更改父对象的旋转值来旋转所有对象,同时保持单个子对象的方向稳定。(例如,旋转整个对象)我觉得我没有很好地解释这一点,所以这里有两个例子。PhysicsJS:(参见第一个示例,使用0.7和球——注意碰撞后旋转0或7时,对象的整体形状是如何保持的。PhaserJS()中的机器人示例也是如此。现在,为了看看是否可以,我尝试用我自己的库复制前面提到的PhysicsJS示例--(为简洁起见简化)

参考标记的兴趣点——这是我旋转画布的地方。如果对象有父对象,它将按父对象的值加上对象的值旋转——否则,只按对象的值旋转。我尝试了一些不同的组合,如

•父对象
•对象-父对象

…我通过PhysicsJS和Phaser的资料寻找一些正确方向的线索,但毫无结果

如何旋转组但不更改其布局?

嵌套变换 若要使用要应用于组中所有成员的变换来变换组周围的一组对象,然后仅使用其自己的变换渲染每个成员。在每个成员通过其局部变换进行变换之前,需要保存当前变换,以便可以将其用于下一个组成员。在渲染每个组成员结束时组成员必须将转换还原回其上的组的状态

数据结构

group = {
    origin : { x : 100, y : 100},
    rotate : 2,
    scale : { x : 1, y : 1},
    render : function(){ // the function that draws to the canvas
        ctx.strokeRect(-50,-50,100,100);
    },
    groups : [ // array of groups
    {   
        origin : { x : 100, y : 100},
        rotate : 2,
        scale : { x : 1, y : 1},
        render : function(){... }// draw something 
        groups : [] // could have more members
    }],  // the objects to be rendered
}
递归渲染

呈现嵌套转换最好通过递归完成,其中renderGroup函数检查任何子组并调用自身来呈现该组。这使得以最少的代码生成复杂的嵌套对象非常容易。树是递归的一个简单示例,终止条件是到达最后一个节点。但是如果允许嵌套组成员引用树中的其他成员,则很容易出错。这将导致Javascript阻塞页面并导致崩溃

function renderGroup(group){
    ctx.save();
    // it is important that the order of transforms us correct
    ctx.translate(group.origin.x, group.origin.y);
    ctx.scale(group.scale.x, group.scale.y);
    ctx.rotate(group.rotate);
    // draw what is needed
    if(group.render !== undefined){
        group.render();
    } 

    // now draw each member of this group.groups
   for ( var i = 0 ; i < group.groups.length; i ++){
        // WARNING this is recursive having any member of a group reference 
        // another member within the nested group object will result in an 
        // infinite recursion and computers just don't have the memory or 
        // speed to complete the impossible 
        renderGroup(group.groups[i]); // recursive call 
    };
   // and finally restore the  original transform
   ctx.restore();
}
函数renderGroup(组){
ctx.save();
//重要的是,我们的顺序是正确的
ctx.translate(group.origin.x,group.origin.y);
ctx量表(x组,y组);
ctx旋转(组旋转);
//画出需要的东西
if(group.render!==未定义){
group.render();
} 
//现在绘制此组的每个成员。组
对于(变量i=0;i
这就是嵌套转换的方式以及W3C打算如何使用渲染的方式。但我绝不会这样做。由于需要使用保存和恢复,这是帧速率的杀手,因为ctx.getTransform支持非常有限(仅Chrome)。由于无法获得必须镜像的变换,因此无需进行镜像,因为在维护矩阵时,可以应用许多优化。使用setTransform和一点数学,在画布上以四分之一或更差的帧速率实时获得1000个精灵

演示

使用安全递归运行示例

以鼠标所在位置为中心绘制嵌套对象

该演示只是一个递归渲染,取自我所拥有的一些其他代码,并对其进行了裁剪以适应此演示。它扩展了递归渲染以允许动画和渲染顺序。请注意,比例是不均匀的,因此迭代越深,会有一些倾斜

//改编自QuickRunJS环境。
//===========================================================================
//简单鼠标
//===========================================================================
var mouse=(函数(){
函数preventDefault(e){e.preventDefault();}
变量鼠标={
x:0,y:0,按钮AW:0,
bm:[1,2,4,6,5,3],//用于设置和清除按钮原始位的掩码;
mouseEvents:“mousemove,mousedown,mouseup”。拆分(“,”)
};
函数mouseMove(e){
var t=e.type,m=mouse;
m、 x=e.offsetX;m.y=e.offsetY;
如果(m.x===未定义){m.x=e.clientX;m.y=e.clientY;}
如果(t==“mousedown”){m.buttonRaw |=m.bm[e.which-1];
}else如果(t==“mouseup”){m.buttonRaw&=m.bm[e.which+2];}
e、 预防默认值();
}
mouse.start=函数(元素,blockContextMenu){
if(mouse.element!==未定义){mouse.removeMouse();}
mouse.element=元素;
mouse.mouseEvents.forEach(n=>{element.addEventListener(n,mouseMove);});
如果(blockContextMenu===true){
元素addEventListener(“上下文菜单”,preventDefault,false);
mouse.contextmenublock=true;
}        
}
mouse.remove=函数(){
if(mouse.element!==未定义){
mouse.mouseEvents.forEach(n=>{mouse.element.removeEventListener(n,mouseMove);});
if(mouse.contextmenublock==true){mouse.element.removeEventListener(“contextmenu”,preventDefault);}
mouse.contextmenublock=未定义;
mouse.element=未定义;
}
}
返回鼠标;
})();
//===========================================================================
//全屏画布
//===================
function renderGroup(group){
    ctx.save();
    // it is important that the order of transforms us correct
    ctx.translate(group.origin.x, group.origin.y);
    ctx.scale(group.scale.x, group.scale.y);
    ctx.rotate(group.rotate);
    // draw what is needed
    if(group.render !== undefined){
        group.render();
    } 

    // now draw each member of this group.groups
   for ( var i = 0 ; i < group.groups.length; i ++){
        // WARNING this is recursive having any member of a group reference 
        // another member within the nested group object will result in an 
        // infinite recursion and computers just don't have the memory or 
        // speed to complete the impossible 
        renderGroup(group.groups[i]); // recursive call 
    };
   // and finally restore the  original transform
   ctx.restore();
}