Pull to refresh

Базовая теория столкновения объектов, спрайтов на Javascript

HTML *
Sandbox
В этой статье я рассмотрю такие приемы как:
  • Пересечение габаритов объектов
  • Принадлежность точки полигону

И рассмотрим пример реализации механики игры «Астероиды».

Пересечение габаритов объектов


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

function MacroCollision(obj1,obj2){
  var XColl=false;
  var YColl=false;

  if ((obj1.x + obj1.width >= obj2.x) && (obj1.x <= obj2.x + obj2.width)) XColl = true;
  if ((obj1.y + obj1.height >= obj2.y) && (obj1.y <= obj2.y + obj2.height)) YColl = true;

  if (XColl&YColl){return true;}
  return false;
}


Как видно из исходного кода в основе определения столкновение идет определение пересечения проекций прямоугольников на осях X и Y. При пересечении функция возвращает true, иначе false.

Принадлежность точки полигону


Давайте представим, что мы делаем такую игру как «Астероиды». Каждый астероид представляет собой неправильный многоугольник (полигон). Пуля игрока — круг. Учитывая соотношения масштабов астероида и пули, можно пренебречь размером пули, сократив до центральной точки круга. Таким образом нахождение столкновения сводится к определению принадлежности точки полигону.

function pointInPoly(polyCords, pointX, pointY)
{
	var i, j, c = 0;
 
	for (i = 0, j = polyCords.length - 1; i < polyCords.length; j = i++)
	{
 
		if (((polyCords[i][1] > pointY) != (polyCords[j][1] > pointY)) && (pointX < (polyCords[j][0] - polyCords[i][0]) * (pointY - polyCords[i][1]) / (polyCords[j][1] - polyCords[i][1]) + polyCords[i][0]))
		{
			c = !c;
		}
 
	}
 
	return c;
}


В качестве входных параметров функции — массив из вершин полигона и координаты точки. Описание работы данной функции описано на английском языке тут.

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

Пример:
Bullet = function(x,y)
{
  //Координаты
  this.x=x; 
  this.y=y;

  //Габариты
  this.width=10;
  this.height=10;

  this.tick = function (){
     //Перебираем астеройды
     for (var i=0; i<Asteroids.length; i++){

        if (MacroCollision(this,Asteroids[i])){
           if (pointInPoly(Asteroids[i].shapeXY, this.x+5, this.y+5))
           {
                …
                //Столкновение
                …
           }
        }
   
     }

  }
  …
}


То что получилось, можно скачать тут, а рабочий пример тут. Управление WSAD+пробел, клик по карте — добавление астеройда.

UPDATE: Скриншот того, что в итоге получилось в качестве примера.
Tags:
Hubs:
Total votes 41: ↑36 and ↓5 +31
Views 30K
Comments 10
Comments Comments 10