Хороший вопрос!Мне понравился ответ 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 скорости спрайта, вы можете использовать значение сегмента, чтобы подобрать соответствующее изображение спрайта.
Tadaa!
Так как же это работает? Наше сегментное выражение выглядит немного загадочным.
Замечание один : мы хотим разбить круг вокруг точки на8 сегментов одинакового углового размера.360/8 = 45 градусов на сегмент.Четыре из 8 сегментов центрированы на одной из двух сторон осей x и y, нарезанных под углом 45/2 = 22,5 градуса каждая.
Наблюдение два: Уравнение прямой на плоскости, a*x + b*y + c = 0
, когда превращено в неравенство, a*x + b*y + c > 0
может использоваться для проверки, на какой стороне линии расположена точка.Все наши четыре линии пересекают начало координат (x = 0, y = 0), и, следовательно, сила c = 0.Кроме того, все они находятся под углом 22,5 градуса от оси x или y.Это дает нам четыре линейных уравнения:
y = x * tan (22,5);у = -х * загар (22,5);x = y * tan (22,5);x = -y * tan (22,5)
Превратившись в неравенства, получим:
x * tan (22,5) - y> 0;x * tan (22,5) + y> 0;у * загар (22,5) - х> 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>