我正在开发一个 Canvas 库,但我不知道应该如何围绕对象的中心进行旋转。下面是我当前用来渲染它们的函数以及我提供的示例对象。
我觉得有更好的方法来执行 4 个 if
语句,但我无法计算出它的数学原理。目前,我正在获取对象的每个“像素”并将其绕中心旋转,但我看不到扩展的空间。我做错了什么?
//Rendering function
Display.prototype.renderObject = function(object, direction) {
if (typeof object.rotation !== 'number') object.rotation = 0;
for (x=0;x<object.bounds.x;x++) {
for (y=0;y<object.bounds.y;y++) {
rotation = 45;
if (x==0 && y==0) rotation += 0;
if (x==0 && y==1) rotation += 90;
if (x==1 && y==0) rotation += 270;
if (x==1 && y==1) rotation += 180;
display.drawRect(object.color[x][y],
(display.width/2) - (players[playerIndex].position.x * 16) + (object.position.x * 16) - (object.bounds.x * object.scale)/4 - (object.bounds.x/3 * object.scale * Math.cos((object.rotation+rotation)*(Math.PI/180))),
(display.height/2) + (players[playerIndex].position.y * 16) - (object.position.y * 16) - (object.bounds.y * object.scale)/4 - (object.bounds.y/3 * object.scale * Math.sin((object.rotation+rotation)*(Math.PI/180))),
object.scale, object.scale, object.rotation * (direction || 1));
}
}
};
// Example object
block = {
"color": [
["#FFF","#CCC"], // Some colors to make
["#999","#666"] // a shaded illusion
],
"position": {
"x": 0,
"y": 0
},
"bounds": {
"x": 2, // color[0].length
"y": 2 // color.length
},
"rotation": 0, // 0 to 360
"scale": 4 // real pixels per object pixel
}
// Example usage
Display.renderObject(block);
- 编辑 -
也许我需要让它计算每个像素的中心坐标在哪里,然后获取从该中心到对象原点的距离以及每个像素偏移的旋转。
如果 x = 0
且 y = 0
,则为 +45
度(sin 和 -45
)度与 cos+45
度与 sin。如果 (object.bounds.x-1)/2
为我们提供了处理 x 的中心坐标,则 Math.sqrt(Math.pow(x,2)+Math.pow( y,2))
为我们提供了距离对象中心的色 block 的半径。我不知道该去哪里。
最佳答案
我不是 100% 确定你在问什么,但如果是如何围绕点的中心旋转点,你必须平移所有点,以便你反对旋转如果您愿意,可以以 origin
或点 [0, 0]
为中心。
旋转矩阵总是围绕原点旋转,因此没有办法绕过去(没有双关语)。
因此,在旋转点之前,请计算在旋转之前应用的增量值,旋转然后反转增量并再次应用以获取对象及其相对于原点的偏移。
因此第一步是计算增量,以找出需要将点平移多少才能将它们置于中心。
对于矩形来说很简单:就是它的 x 和 y 位置加上它的宽度和高度的一半:
deltaX = x + width * 0.5;
deltaY = y + height * 0.5;
然后您需要将该值减去分数。如何应用此增量取决于您:您可以提前对每个点执行此操作,也可以将其直接注入(inject)公式中。
然后旋转,完成后您只需再次将增量值添加到每个点即可。
这是基于 my article here 的旋转矩阵的较短版本:
var a = rotation * Math.PI / 180; /// calculate angle once
x -= deltaX; /// apply pre-translation
y -= deltaY;
/// rotate and apply post-translation
nx = x * Math.cos(a) + y * Math.sin(a) + deltaX;
ny = y * -Math.sin(a) + x * Math.cos(a) + deltaY;
您使用的 if
似乎来自使用它来优化 Angular 代码;当你使用 0、90 等时,cos 和 sin 会分别产生 1 和 0。然而,您并没有利用这种优化,因为当这些情况发生时,您可以简单地将 x 替换为 y 等。但是,您将然后绑定(bind)到 x 和 y 位置,所以我不确定您在这里想要实现什么目标..
我建议您在计算和应用 sin/cos 时删除它们 - 您可以缓存 sin 和 cos 并将它们用于所有点:
var angle = rotation * Math.PI / 180;
sin = Math.sin(angle),
cos = Math.cos(angle),
...calc deltas here...
...enter loop here, then for each point:...
x -= deltaX;
y -= deltaY;
nx = x * cos + y * sin + deltaX;
ny = y * -sin + x * cos + deltaY;
现在每个点的成本更低,您的计算执行得更快。
希望这有帮助。
关于javascript - 自定义旋转算法需要可扩展性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21081292/