好问题!我喜欢 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 值,您可以使用分段值来拾取适当的精灵图像。
多多!
那么它是如何工作的呢?我们的segment表达式看起来确实有点神秘。
观察一:我们要将围绕该点的圆分成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 文件中,然后在任何浏览器中打开)
(see as a live demo on 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>