воскресенье, 6 октября 2013 г.

RTS Mouse

Click and Run - система


function ShootRay() {
    var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    var hit : RaycastHit;
 
    if(Physics.Raycast(ray, hit, Mathf.Infinity)) {
        var moveScript : UnitMoveable = unit.GetComponent("UnitMoveable");
        if (moveScript) {
           moveScript.MoveTo(hit.point);
        }
    }
}



var moveSpeed : float = 2.0f;
private var vDestination : Vector3;
private var isMoving : boolean;
 
function Start () {
    isMoving = false;
}
 
function FixedUpdate () {
    if (isMoving) {
       if (transform.position.Equals(vDestination)) {
         isMoving = false;
       }
       else {
         // Vector will do a linear interpolation between our current position and our destination
         var v : Vector3;
         v = Vector3.Lerp(transform.position,vDestination,Time.fixedDeltaTime * moveSpeed);
 
         // Raycast to the surface below our next destination step to make sure we are standing on it
         // this is probably not efficient for large numbers
         var hit : RaycastHit;
         if (Physics.Raycast(v, Vector3.down, hit, 5.0f)) {
          // collider.bounds.extents.y will be half of the height of the bounding box
          // only useful if your pivot point is in the center, if it's at the feet you don't need this
          v.y = hit.point.y + collider.bounds.extents.y;
         }
         // set our position to the new destination
         transform.position = v;
       }
    }
}
 
function MoveTo (vPoint:Vector3) {
    vDestination = vPoint;
    isMoving = true;
}

понедельник, 19 ноября 2012 г.

Математика гравитации

Статья не относится к юнити, но показывает как можно математически создать Гравитацию



Здесь будут рассмотрены методы создания реалистичных прыжков и маневров в космическом пространстве.

Цель этого документа – дать Вам понять физические законы нашего мира и то, как их с максимальной пользой можно использовать в игре. Здесь не приводятся готовые куски кода, это Вы сможете сделать и сами! Но если Вы, к тому же, будете понимать, как это все устроено, Ваша работа значительно упростится.

Основы

Я бы хотел обратить Ваше внимание на несколько основных понятий, чтобы удостовериться, что мы имеем ввиду одни и те же вещи:

Расстояние
: Полный путь.
Перемещение
: Разница между начальной и конечной точками пути.
Скорость хода
: Изменение перемещения за конечный промежуток времени.
Скорость
: Направление пути и скорость путешествия.
Ускорение
: Изменение скорости за конечный промежуток времени.

Замечание:
Перемещение, скорость и ускорение - векторные величины. (То есть помимо значения они имеют еще и направление).

Сокращение
Единицы измерения
a
: ускорение
m (м)
: метр (мера длины)
M
: масса
m/s (м/c)
: метр в секунду (мера скорости)
s
: перемещение
m/s^2 (м/с^2)
: метр в секунду за секунду (мера ускорения)
s0
: начальное перемещение
N (Н)
: ньютон (мера силы)
t
: время
s (с)
: секунда (мера времени)
v
: скорость
v0
: начальная скорость

Общие представления

Вообразите себе космический корабль, летящий в космосе со скоростью 1000 метров в секунду. Он находится так глубоко в межзвездном пространстве, что вокруг него совершенно ничего нет. Какие же силы действуют на него в этом случае? Да никаких!

Он так и будет лететь под 1000 м/с до тех пор, пока на него не подействуют какие-либо силы. Все объекты изменяют свои скорость или ускорение ТОЛЬКО под действием сторонних сил.

Вы спросите – что это за силы? Внешняя сила может толкать объект в одну сторону или тянуть в обратную. Сила - тоже векторная величина. Соответственно, она также имеет и величину, и направление. К примеру, прямо сейчас сила земного тяготения действует на Вас, толкая к центру Земли.

А единственная причина, по которой объект перемещается в пространстве, если у него есть некоторая скорость.

Предположим теперь, что божественная рука начинает толкать космический корабль вперед. Мы получим силу, приложенную к судну. А при любой приложенной силе, возникает ускорение. С ускорением начинает увеличиваться скорость. И если бог не прекратит толкать корабль, то он в скором времени разгонится до огромных скоростей!

Прыжки

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

Первоначально, позиция Джо будет на полу. Как только нажимается клавиша прыжка, мы просто сообщаем ему очень большую скорость вверх. Затем каждый кадр/секунду/перерисовку экрана/или еще что-нибудь просто уменьшаем его восходящую скорость на определенное значение. Вот и все!

Константа уменьшения скорости – это фактически ускорение вниз. Обратите внимание, что мы не затрагиваем перемещение героя по горизонтали. Так как во время прыжка Вы можете двигать его вперед/назад как обычно.

С другой стороны, в реальной жизни невозможно двигаться вперед/назад при прыжке прямо вверх. Но я считаю, что игры, которые позволяют это делать, более интересны и забавны. Да и кто сказал, что игры должны быть реалистичными во всех отношениях?

Но какова должна быть величина ускорения, которое мы собираемся применить? На Земле ускорение, действующее на героя, будет 9.81 м/с^2 вниз. К сожалению, такая величина, как метр на секунду в квадрате ничего не говорит компьютеру. Ускорение должно быть основано на периоде обновления экрана Вашей игры. Обычно оно рассчитывается экспериментально и доводится до ума методом проб и ошибок в самой игре.

Итак, вот наш псевдокод:

Joe.pos.y = 0; /* Или где там у вас пол */
Joe.vel.y = 0; /* Скорость */
Joe.accel = 10; /* Ускорение */
Joe.jumping = NO;

Loop
  If ( /* Нажата клавиша прыжка */ )
  {
     Joe.vel.y = 100;
     Joe.jumping = YES;
  }

  if (Joe.jumping == YES)          /* Джо в воздухе */
  {
     Joe.vel.y = Joe.vel.y - Joe.accel
     Joe.pos.y = Joe.pos.y + Joe.vel.y
  }

  if (Joe.pos.y <= 0)          /* Проверка, стоит ли Джо на полу */
  {
     Joe.vel.y = 0;
     Joe.jumping = NO;
  }
End Loop

Когда мы нажмем клавишу прыжка, герой сразу же подпрыгнет.

Он будет лететь все выше и выше, но, поскольку скорость постоянно падает, он будет замедляться и вскоре начнет двигаться уже вниз. И двигаться туда он будет все быстрее и быстрее, пока не коснется пола.

Вот скорость и позиция Джо в конце каждой итерации (повторения) цикла:

Итерация 0:
Joe.vel.y = 0
Joe.pos.y = 0
Итерация 1:
Joe.vel.y = 100
Joe.pos.y = 100
Итерация 2:
Joe.vel.y = 90
Joe.pos.y = 190
Итерация 3:
Joe.vel.y = 80
Joe.pos.y = 270
Итерация 4:
Joe.vel.y = 70
Joe.pos.y = 340
Итерация 5:
Joe.vel.y = 60
Joe.pos.y = 400
Итерация 6:
Joe.vel.y = 50
Joe.pos.y = 450
Итерация 7:
Joe.vel.y = 40
Joe.pos.y = 490
Итерация 8:
Joe.vel.y = 30
Joe.pos.y = 520
Итерация 9:
Joe.vel.y = 20
Joe.pos.y = 540
Итерация 10:
Joe.vel.y = 10
Joe.pos.y = 550
Итерация 11:
Joe.vel.y = 0
Joe.pos.y = 550
Итерация 12:
Joe.vel.y = -10
Joe.pos.y = 540
Итерация 13:
Joe.vel.y = -20
Joe.pos.y = 520
Итерация 14:
Joe.vel.y = -30
Joe.pos.y = 490
Итерация 15:
Joe.vel.y = -40
Joe.pos.y = 450
Итерация 16:
Joe.vel.y = -50
Joe.pos.y = 400
Итерация 17:
Joe.vel.y = -60
Joe.pos.y = 340
Итерация 18:
Joe.vel.y = -70
Joe.pos.y = 270
Итерация 19:
Joe.vel.y = -80
Joe.pos.y = 190
Итерация 20:
Joe.vel.y = -90
Joe.pos.y = 100
Итерация 21:
Joe.vel.y =-100
Joe.pos.y = 0

Обратите внимание, что скорость у Джо будет очень большая, когда он коснется пола. Если он не достигнет пола в конце (или пол исчезает, или он прыгает с платформы), то, в конечном счете, Джо будет падать с ускорением.

Посему мы должны задать ограничение его скорости. Это будет самая большая скорость, которой он может достигнуть во время падения. В реальной жизни такая скорость вызвана сопротивлением воздуха. И сделать это очень легко.

Модифицированный псевдокод таков:

Joe.pos.y = 0;
Joe.vel.y = 0;
Joe.accel = 10;
Joe.jumping = NO;

Loop
  if ( /* Нажата клавиша прыжка */ )
  {
     Joe.vel.y = 100;
     Joe.jumping = YES;
  }

  if (Joe.jumping == YES)             /* Джо в воздухе */
  {
     if (Joe.vel.y > -100)          /* Ограничим скорость до -100 */
     {
             Joe.vel.y = Joe.vel.y - Joe.accel
             Joe.pos.y = Joe.pos.y + Joe.vel.y
     }
  }

  if (Joe.pos.y <= 0)          /* Проверка, стоит ли Джо на полу */
  {
     Joe.vel.y = 0;
     Joe.jumping = NO;
  }
End Loop

Теперь новые итерации цикла не будут уменьшать скорость, когда она на пределе (-100). Таким образом, мы добавили ограничение.

Другие измерения

Хорошо, вышеупомянутый пример работает, но некоторые игровые спрайты могут перемещаться не только вверх или вниз. Они движутся в стороны во время прыжка.

Легко! Это получится, когда значения скорости и ускорения по X и Y будут независимыми! Так, в то время, пока Вы работаете с позицией и скоростью Джо по Y, координаты по X можно изменять обычным образом.

Получится, что герой будет двигаться по параболе, как и в реальном мире.

Аналогично для 3-х измерений. X, Y, Z скорости и ускорения не должны зависеть друг от друга.

Космонавтика

Другой пример применения кинематики - игра типа «Астероиды». Вы летите в среде, где g=0, но возможен толчок вперед в любом направлении.

В этом случае гравитация не играет большой роли. Но что мы используем взамен? А мы используем толчок космического корабля как наше ускорение. Просто разобьем наш вектор ускорения на x и y составляющие, и применяем методы, описанные выше.

Чтобы сделать это, напишем псевдокод:

pos.x = 0;  pos.y = 0;
vel.x = 0;  vel.y = 0;
acc.x = 0;  acc.y = 0;

Loop
  if (/* Нажата клавиша ускорения */ )
  {
     resolve_direction_vector;
     acc.x = scale_x * 10;
     acc.y = scale_y * 10;
  }

  vel.x = vel.x + acc.x;
  vel.y = vel.y + acc.y;

  pos.x = pos.x + vel.x;
  pos.y = pos.y + vel.y;
End Loop

Тут мы добавили функцию, которой раньше не было: resolve_direction_vector. Она необходима, так как корабль может двигаться в любом направлении. Эта функция получает на вход вектор ускорения и разбивает его на два направления: scale_x и scale_y.

                          ^
                         /|
         Оригинальный   / |
         вектор        /  |
         ускорения    /   |
                     /    |
                    /     |  Y вектор
                   /      |
  Начальная       / *     |
  позиция   -    X--------|

                  X вектор

* = Угол поворота корабля относительно оси X

Зная величину данного угла (от 0 до 360), мы можем определить переменные scale_x и scale_y. Есть разные способы сделать это, но наиболее простой (и, соответственно, не оптимизированный) - тригонометрический:

scale_x = cos(angle);
scale_y = sin(angle);

Тригонометрические функции сами позаботятся об отрицательных значениях. То есть если судно лицом на запад (угол = 180 градусов), то scale_x и scale_y примут значения -1 и 0 соответственно.  Таким образом, наш космический корабль ускорится в отрицательном направлении X.

А как быть, если судно направлено на северо-восток (угол = 45)? Мы получим:

scale_x = .707
scale_y = .707

Это означает, что судно ускоряется на 7.07 в направлении Y, и на 7.07 в направлении X. Иллюзия, которая возникает при таком подходе, ускорение корабля на 10 в направлении 45 градусов.

Возможно, Вы захотите ограничить максимальную скорость судна, иначе оно будет двигаться быстрее, чем игрок сможет его увидеть.

Вот, к примеру, некоторые люди любят «поля затухания». Это означает, в конечном счете, что судно замедляется само по себе. Для сего нужно просто изменять скорость в сторону нуля каждую итерацию. (Если скорость положительна - вычитать; если скорость отрицательна - добавлять).

Реальные уравнения

В этой главе мы разберемся с уравнениями, более приближенными к реальности. Если Вы хотите создавать более сложную кинематику, то глава эта, безусловно, для Вас. Для того чтобы получше уяснить ее содержание, можете прочитать учебник по общей физике.

Мы определим три ключевые переменные, относящиеся к объекту: перемещение, скорость и ускорение. Сила связана с ускорением, следующим способом: (между прочим, это второй закон Ньютона в упрощенной форме)

;Прим. 1
;
; F = M * a
;
Сила равняется произведению массы на ускорение.

Так в нашем примере с космическим кораблем, рука бога может заставить маленький перехватчик с небольшой массой ускоряться гораздо быстрее, чем огромный дредноут с большой массой.

Вот связь между перемещением, скоростью и ускорением:

;Прим. 2
;
;  s = s0 + v0*t + 0.5*a*t^2
;
Текущее перемещение равно начальному перемещению, плюс начальная скорость, помноженная на время, плюс половина произведения ускорения на время в квадрате.

;Прим. 3
;
; v = v0 + a*t
;
Текущая скорость равняется начальной скорости плюс произведение ускорения на время.

;Прим. 4
;
; v^2 - v0^2 = 2*a*s
;
Текущая скорость, возведенная в квадрат, минус начальная скорость в квадрате равняется удвоенному произведению ускорения на перемещение.

Практически все проблемы движения в физике могут быть решены этими четырьмя «волшебными» уравнениями. Они все основаны на постоянном ускорении (которое удовлетворяет большинству компьютерных игр).

Как эти уравнения работают?

Давайте возьмем мяч и подбросим его вертикально верх. Это одномерный случай, так как мяч только взлетает или падает. Пусть s0 - это высота, с которой мы подкидываем мяч. В данном случае, предположим, что s0=0 (мяч кидаем с уровня пола).

Итак, мы его подбросили. В момент, когда мы выпускаем мяч (t = 0) нам известно:

s0 = 0; v0 = 10 м/с прямо вверх (36 километров в час); a =?

Хм, а каково ускорение? Для любого объекта близ поверхности Земли, сила  гравитации может быть найдена из:

;Прим. 5
;
; Fg = M*g
;

Где М - масса, и g - гравитационная константа. Для Земли g = 9.81 м/с^2. Теперь немного математики. Объединим уравнения 1 и 5:

;
; Fg = M*a  ->  M*g = M*a  ->  g = a
;

Ага! Массы сократились! Это интересно. Получается, для любого падающего объекта, ускорение не зависит от массы. Это значит, что бегемот будет падать с такой же скоростью, как и пинг-понговый шарик? Да, это так… в вакууме. Но я отошел в сторону...

(Это обуславливается тем, что в атмосфере на падающие объекты действует сопротивление воздуха, пропорциональное площади взаимодействия с объектом. Так что, в действительности, шарик упадет раньше. Комментарий Иванова Сергея).

Значит, ускорение мяча равняется g, или 9.81 м/с^2. Но ускорение это действует вниз, так что мы говорим = -g.

Используя пример 3, мы получаем:

  v  =  v0 + a*t  =  10 м/с +  (-9.81 м/с^2) * 0 с  =  10 м/с.

Если мы используем пример 2, мы также получим s = 0. Неплохо, да? Давайте посмотрим, что будет на 0.5 секунды позже:

  v  =  10 + (-9.81) * 0.5 с  = 5.1 м/с

Мяч замедлился, как мы и ожидали. В конце концов, он остановится. Чтобы найти время этого момента, мы просто устанавливаем v = 0 и решаем уравнение относительно t.

  v  =  0  =  10 + (-9.81) * t

Из этого находим t = 1.019 секунды. Таким образом, через 1.019 секунды после того, как мы бросаем мячик вверх, он останавливается в воздухе.

Отлично, мы знаем, что мяч остановится, но на какой высоте? Чтобы найти ее, используем пример 2:

  s  =  0  +  10 * 1.019 + 0.5 * (-9.81) * 1.019^2  =  5.1 метров

Результат - на 5.1 метров выше того места, где мы выпустили мяч.

Теперь мяч должен упасть, но как быстро? С какой скоростью?

  s = 0.            Используем пример 4. После некоторых вычислений найдем
  v = sqrt( v0^2 ). Легко, не так ли? v = v0. Вот и уладили.

Но существуют два решения для этого уравнения. + v0 и -v0. Что это еще означает? Это означает, всякий раз, когда шарик находится в позиции s = 0, он или поднимается в v0, или опускается в v0. Мы знаем, что он поднимался, когда мы подкинули его, теперь и скорость его падения должна быть той же.

И, наконец, мы находим за какое время мяч упадет. Используем пример 3:

  v  =  -v0  =  v0 + (-9.81) * t

Результат: t = 2.038 секунды. Если мы бросим мяч со скоростью 10 м/с, то через 2.038 секунды, тот же самый мяч упадет в наши руки.

Целью этой главы было лишь показать, как эти уравнения работают. При программировании же, Вам не удастся так просто использовать их, поскольку необходимо следить за личным t каждого объекта. Каждый раз, когда что-то прыгает, Вы должны сбрасывать этот t на 0.




Статья взята с сайта http://pmg.org.ru/galaxy2d/gravity.htm