Класс вектора

Знание векторной математики при создании динамичных флеш игр (где присутствуют повороты, ускорения и т.д.) есть первейшая необходимость для разработчика. Я с улыбкой вспоминаю те времена, когда я делал свои первые игры, часами вычисляя на бумажке как повернуть морду комолёта, как сделать так, чтобы космолёт двигался с ускорением к точке и не промахивался мимо неё, как сделать так чтобы он ещё мог стрелять в разные стороны, а не только в направлении своего движения… ну и т.д.

После такого непродолжительного вступления, представляю на ваше обозрение мой класс вектора. В нём помимо собственно операций с векторами, находятся ещё разные полезные для игростроя функции. Класс этот продолжает развиваться так что скорее всего я буду выкладывать обновлённые версии.
Класс также задействует математическую библиотечку, выложенную мною ранее. Без неё работать не будет :)

Итак:

package aneg 
{ 
        import aneg.*;  
 
	public class ageVector 
	{
		var x:Number;
		var y:Number;
 
		function ageVector(setX:Number=0, setY:Number=0)
		{
		   x = setX;
		   y = setY;
		}
 
		//Копирует вектор
		function copy( v:ageVector ):void 
		{
			x = v.x;
			y = v.y;
		}
 
		//Устанавливает компоненты вектора
		function set( setX:Number, setY:Number ):void 
		{
			x = setX;
			y = setY;
		}
 
		//Прибавляет вектор v
		function add( v:ageVector ):void 
		{
			x += v.x;
			y += v.y;
		}
 
		//Вычитает вектор v
		function sub( v:ageVector ):void 
		{
			x -= v.x;
			y -= v.y;
		}
 
		//Умножает вектор на число i
		function mulScalar( i:Number ):void 
		{
			x *= i;
			y *= i;
		}
 
		//Равны ли вектора c заданной погрешностью aprox
		function isEqual( v:ageVector , aprox:Number=0.00001):Boolean 
		{
			return (ageMath.aproxEqual(x,v.x,aprox) && ageMath.aproxEqual(y,v.y,aprox));
		}
 
		//Длина вектора
		function len():Number 
		{
			return Math.sqrt( x*x + y*y );
		}
 
		//Длина вектора в квадрате
		function len2():Number 
		{
			return x*x + y*y;
		}
 
		//Ограничить длину вектора максимальной длинной
		function trimLen(maxLen:Number):void 
		{
			if(len2()>maxLen*maxLen)
			{
				normThis();
				mulScalar(maxLen);
			}
		}
 
		//получить проекцию вектора на вектор v
		function ProjOnVec(v:ageVector):ageVector 
		{
			var res:ageVector = v.norm();
			res.mulScalar(ProjOnScalar(v));
			return res;
		}
 
		// скалярная проекция вектора на вектор v
		function ProjOnScalar(v:ageVector):Number 
		{
			return dot(v)/v.len();
		}		
 
		// скалярное произведение векторов
		function dot(v:ageVector):Number 
		{
			return x*v.x + y*v.y;
		}
 
		// нормализация вектора (получить единичный вектор)
		function norm():ageVector 
		{
			var l:Number = len();
			var res:ageVector = new ageVector(x,y);
			if (l) 
			{
				res.x /= l;
				res.y /= l;
			}
			return res;
		}
 
		// нормализация этого вектора 
		function normThis():void 
		{
			var l:Number = len();
			if (l) 
			{
				x /= l;
				y /= l;
			}
		}
 
		// Lerp с другим вектором. Результат записывается в этот же вектор
		//return cx + s*(cy - cx);
		function lerpThis(v:ageVector,s:Number):void 
		{
			var tmpV:ageVector = new ageVector();
			tmpV.copy(v);
			tmpV.sub(this);
			tmpV.mulScalar(s);
			add(tmpV);
		}
 
		//Поворот вектора на угл в радианах
		function rot(ang:Number):void
		{
                        var dx:Number=x;
			x=dx*Math.cos(ang)-y*Math.sin(ang);
			y=y*Math.cos(ang)+dx*Math.sin(ang);
		}
 
		//Поворот вектора на угл в градусах
		function rotDeg(ang:Number):void
		{
                        var dx:Number=x;
			var angR:Number=ang*Math.PI/180;
			x=dx*Math.cos(angR)-y*Math.sin(angR);
			y=y*Math.cos(angR)+dx*Math.sin(angR);
		}
 
		// получить угол в градусах
		function getAngleDeg():Number 
		{
			return Math.atan2(y, x)/Math.PI*180;
		}
 
		// получить угол в радианах
		function getAngle():Number 
		{
			return Math.atan2(y, x);
		}
 
		// получить угол в градусах с нормированным переходом
		function getAngleDegNorm():Number 
		{
			var angle:Number=Math.atan2(y, x)/Math.PI*180;
 
			if(angle<0) angle=360+angle; else
			if(angle>=360) angle=angle-360;
 
			return angle;
		}
 
		// получить угол в радианах  с нормированным переходом
		function getAngleNorm():Number 
		{
			var angle:Number=Math.atan2(y, x);
 
			if(angle<0) angle=Math.PI*2+angle; else
			if(angle>=Math.PI*2) angle=angle-Math.PI*2;
 
			return angle;			
		}
	}
}

Весь класс можно скачать здесь: http://www.anegmetex.com/devblog/files/ageVector.as

12 комментариев к “Класс вектора

  1. creator

    Интересно, только вот в играх, нужны конкретные функции, а тащить сразу всю библиотеку целиком – это воспитание от Microsoft сказывается ;-)

  2. Oleg Antipov Автор публикации

    Чёт не очень понятно имеются ли в виду функции в классе вектора, или функции математической библиотеки, использованной в классе вектора )

  3. finalboss

    Math.PI*180 и Math.PI/180 можно высчитать заранее, и избавиться от лишней операции :)

  4. Oleg Antipov Автор публикации

    Т.к. Math.PI это константа и 180 это константа, то я больше чем уверен, что компилятор это оптимизирует и считает за меня :cool:

  5. finalboss

    я имел в виду, что сразу написать число 565,4866 или 0,01745 и вообще ничего не считать …

  6. Oleg Antipov Автор публикации

    Да я понял что ты имел ввиду )
    Я же говорю о том, что в итоге компилятор сам посчитает это значение и подставит в формулу, и в скомпилированной программе будет это самое значение 0,01745 и никаких вычислений констант не будет. т.е. получится как раз так как ты сказал )

  7. Newtom

    А в 10 версии Flash класс не скомпилится. Там уже есть зарезервированый класс Vector для однотипных массивов. Надо по другому как-то обзывать класс и все ссылки на него внутри..Советую и тут поменять, все таки скоро все на 10 перейдут, а блог думаю долго существовать будет ;)

  8. Ant.Karlov

    Привет, Олег! Взял я у тебя из класса не глядя полезную функцию rot(ang:Number) для своего аналогичного. А как понадобилась мне эта функция, выяснилось, что расчеты производятся не верно. Долго бился головой о стену пытаясь понять в чем дело и уже было начал думать, что это я троечник хочу от этой формулы то что рассчитывается другой формулой. Даже с формулами в Интернет сверился :) И тут меня осенило в чем проблема. В твоей реализации расчеты производятся сразу в переменные вектора и это вызывает ошибку в расчетах. Нужно результат рассчитывать во временные переменные, а потом после расчета присваивать их вектору.

    // Во второй строке X уже изменился
    // согласно выражению в первой строке и
    // поэтому Y считается уже не верно!
    x=x*Math.cos(ang)-y*Math.sin(ang);
    y=y*Math.cos(ang)+x*Math.sin(ang);

    Воот..

  9. Oleg Antipov Автор публикации

    Привет, Антон. Cпасиб, Zloba мне тоже уже говорил об этом, но я чёт забыл здесь поправить :???:
    Странно, но в Toy Tales я не заметил эффекта от этой ошибки, хотя точно помню что юзал где-то поворот)
    Вообщем должно быть так:
    var dx:Number=x;
    x=dx*Math.cos(ang)-y*Math.sin(ang);
    y=y*Math.cos(ang)+dx*Math.sin(ang);

  10. randomGuy

    Здравствуйте! А откуда расчитывается начало вектора? из начала координат?
    Ведь для задания вектора нужны 2 точки,а здесь задается только одна!

  11. Oleg Antipov Автор публикации

    2 randomGuy

    Ха, вот это очень интересный вопрос. В играх вектор всегда задаётся относительно начала системы координат (далее СК).

    А вот СК может быть очень разной. Может быть СК уровня, может быть СК юнита и т.д.

    Отчего это зависит? Да вообщем-то от конкретных нужд разработчика. Обычно вектором задают или направление или позицию.

    Пример. Нам нужно задать юнит для топ-даун игрушки. Для него важна позиция и направление. Будем задавать примерно так:

    class GameUnit
    {
    var dirVec:Vector;
    var posVec:Vector;
    }

    Здесь dirVec задаёт текущее направление юнита относительно СК юнита (считается что длина вектора всегда равна единице).
    А posVec задаёт позицию юнита относительно СК уровня.

    Вот как то так.

Оставить комментарий

Ваш email не будет опубликован. Обязательные поля отмечены *

80 − = 72

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>