Phi*_*sen 2 math 2d vector angle
背景:我的鸟类视图JavaScript游戏中每个精灵都有8张图像,分别代表顶部,右上角,右下角等,具体取决于玩家的太空飞行速度.
问题:给定值sprite.speed.x和sprite.speed.y(例如可能是4和-2.5,或者2和0),如何获得正确的度数角度?鉴于该角度,我可以查找哪个度数值表示哪个精灵图像.或许还有一种更简单的方法.(目前我只是使用类似"如果x低于零使用左图像"等等,这将导致几乎所有时间都使用对角线图像.)
四处搜寻,我发现......
angle = Math.atan2(speed.y, speed.x);
Run Code Online (Sandbox Code Playgroud)
......但不知怎的,我仍然缺少一些东西.
PS:可以忽略零速度,这些精灵只会使用最后一个有效方向图像.
非常感谢您的帮助!
Ore*_*ner 10
好问题!我喜欢tom10的答案(在标记上,+1),但是想知道它是否可以在没有太多三角函数的情况下完成.这是一个简短的解决方案,然后是解释.
// slope is a constant, 0.414...; calculate it just once
var slope = Math.tan(Math.PI/8);
// do this for each x,y point
var s1 = x * slope + y > 0 ? 0 : 1;
var s2 = y * slope + x > 0 ? 0 : 1;
var s3 = y * slope - x < 0 ? 0 : 1;
var s4 = x * slope - y > 0 ? 0 : 1;
var segment = 4 * s4 + 2 * (s2 ^ s4) + (s1 ^ s2 ^ s3 ^ s4);
Run Code Online (Sandbox Code Playgroud)
这将设置segment0到7之间的值.这是一个带有2000个随机点的示例(答案结尾处的完整源代码).使用精灵速度的x,y值,您可以使用段值来拾取适当的精灵图像.

Tadaa!
那么这是如何工作的呢? 我们的细分表达确实看起来有点神秘.
观察一:我们希望将该点周围的圆分割成8个相等角度尺寸的区段.360/8 =每段45度.8个区段中的4个以x和y轴的两侧中的一侧为中心,每个区域以45/2 = 22.5度切割.

观察二:平面上的直线方程a*x + b*y + c = 0,当变成不等式时,a*x + b*y + c > 0可用于测试点位于线的哪一侧.我们所有的四条线都穿过原点(x = 0,y = 0),因此强制c = 0.此外,它们都与x轴或y轴成22.5度角.这让我们得到了四线方程:
y = x*tan(22.5); y = -x*tan(22.5); x = y*tan(22.5); x = -y*tan(22.5)
变成我们得到的不平等:
x*tan(22.5) - y> 0; x*tan(22.5)+ y> 0; y*tan(22.5) - x> 0; y*tan(22.5)+ x> 0
测试给定点的不等式让我们知道每条线的每一侧:


观察三:我们可以结合测试结果来获得我们想要的段数模式.这是一个视觉细分:
在序列:4 * s4,2 * (s2 ^ s4)并且总和4 * s4 + 2 * (s2 ^ s4)

(^符号是Javascript XOR运算符.)
这是s1 ^ s2 ^ s3 ^ s4第一个单独的,然后添加到4 * s4 + 2 * (s2 ^ s4)

额外的功劳:我们可以调整计算只使用整数运算吗?是 - 如果已知x和y是整数,我们可以将不等式的两边乘以某个常数(并舍入),从而得到完全整数数学.(但是,这会丢失在Javascript上,其数字始终是双精度浮点数.):
var s1 = x * 414 + y * 1000 > 0 ? 0 : 1;
var s2 = y * 414 + x * 1000 > 0 ? 0 : 1;
var s3 = y * 414 - x * 1000 < 0 ? 0 : 1;
var s4 = x * 414 - y * 1000 > 0 ? 0 : 1;
Run Code Online (Sandbox Code Playgroud)
我们上面的示例的完整源代码:(只需将其放入新的html文件中,并在任何浏览器中打开)
<html>
<head>
<style type="text/css">
.dot { position: absolute; font: 10px Arial }
.d0 { color: #FF0000; }
.d1 { color: #FFBF00; }
.d2 { color: #7fcc00; }
.d3 { color: #00FF7F; }
.d4 { color: #00FFFF; }
.d5 { color: #5555FF; }
.d6 { color: #aF00FF; }
.d7 { color: #FF00BF; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
var $canvas = $("#canvas");
var canvasSize = 300;
var count = 2000;
var slope = Math.tan(Math.PI/8);
$canvas.css({ width: canvasSize, height: canvasSize });
for (var i = 0; i < count; ++i) {
// generate a random point
var x = Math.random() - 0.5;
var y = Math.random() - 0.5;
// draw our point
var $point = $("<div class='dot'></div>")
.css({
left: Math.floor((x + 0.5) * canvasSize) - 3,
top: Math.floor((y + 0.5) * canvasSize) - 6 })
.appendTo($canvas);
// figure out in what segment our point lies
var s1 = x * slope + y > 0 ? 0 : 1;
var s2 = y * slope + x > 0 ? 0 : 1;
var s3 = y * slope - x < 0 ? 0 : 1;
var s4 = x * slope - y > 0 ? 0 : 1;
var segment = 4 * s4 + 2 * (s2 ^ s4) + (s1 ^ s2 ^ s3 ^ s4);
// modify the point's html content and color
// (via its CSS class) to indicate its segment
$point
.text(segment)
.addClass("d" + segment);
}
});
</script>
</head>
<body>
<div id="canvas" style="position: absolute; border: 1px solid blue">
</div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1413 次 |
| 最近记录: |