Перенеся свои опыты по разработке двигательных поведенческих примитивов бегающих квадратиков на canvas, я наконец, чувствую, насколько просто и удобно, вкупе с объектным подходом, здесь все делать.
Первичное действие в анимации - движение предмета по прямой к установленной точке и я рассмотрю три способа это реализовать.
Первый способ я бы назвал "шашечками" - это передвижение по восьми возможным направлениям, где дистанция до цели определяется длиной наибольшей проекции на одну из осей координат. Способ предельно прост и каждый шаг четко укладывается в единицы системы координат, однако, не очень естественно выглядит предмет, нарезающий крутые углы по пути к цели.
Функции писались, как внутренние модификаторы объекта, поэтому this - это движущийся объект, а target - координаты цели. Переменная speed просто хранит количество единиц измерения на один шаг.
if (this.x<target.x) this.x+=this.speed;
if (this.x>target.x) this.x-=this.speed;
if (this.y<target.y) this.y+=this.speed;
if (this.y>target.y) this.y-=this.speed;
Следующий способ - тригонометрическое уравнение прямой. Путевая линия, конечно, строится, однако, функциональная зависимость вертикальной координаты от горизонтальной делает движение неравномерным в различных участках координатной плоскости и при часто выпадающих обстоятельствах, объект никогда не совместится с целевой точкой.
var k = (target.y - this.y)/(target.x - this.x);
var b = (target.x*this.y - this.x*target.y)/(target.x - this.x);
if (this.x<target.x) this.x+=this.speed;
else this.x-=this.speed;
this.y = k*this.x+b;
Третий способ - движение по диагонали воображаемого прямоугольника, соединяющей объект и точку. Диагональ - или гипотенуза прямоугольного треугольника определяется по всем известной формуле. Далее представим на данной линии меньший прямоугольник, с диагональю, равной желаемой длине шага. По теореме подобия треугольников определим величины координат x и y.
var distance = Math.round(Math.sqrt(Math.pow(Math.abs(this.x-target.x),2) + Math.pow(Math.abs(this.y-target.y),2)));
this.x+=((target.x-this.x)*this.speed)/distance;
this.y+=((target.y-this.y)*this.speed)/distance;
На данный момент я остановился на последнем варианте, как наиболее "прямом" и логичном. Примеры применения этих способов представлены ниже.