好问题!我喜欢 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);
这将值设置segment
在 0 到 7 之间。这是一个包含 2000 个随机点的示例(答案末尾的完整源代码)。使用精灵速度的 x,y 值,您可以使用分段值来获取适当的精灵图像。
多多!
那么这是如何工作的呢? 我们的段表达式看起来确实有点神秘。
观察一:我们想将围绕该点的圆分成 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;
上面示例的完整源代码:(只需将其放入新的 html 文件中,然后在任何浏览器中打开)
(参见 jsbin 上的现场演示)
<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>