JavaScript:Библиотеки/p5.collide2D

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Черновик


p5.collide2D[1]

Это библиотека, позволяющая определять столкновения между 2D-объектами, созданными с помощью библиотеки p5.js.

Кроме того, библиотека p5.collide2D содержит несколько версий функций из книги «Определение столкновений» (англ. «Collision detection») Джеффри Томпсона. Его код был написан согласно лицензии CC BY-NC-SA 4.0, а это значит, что код этой библиотеки имеет такую же лицензию. О том, как добавить библиотеку в свой скетч p5.js, читайте тут.

Для корректной работы этой библиотеки необходимо, чтобы у функций rectMode() и ellipseMode() были заданы параметры по умолчанию: у первой – «CORNER», а у второй – «CENTER». Все функции p5.collide2D возвращают «true», если объекты столкнулись, и «false», если нет.

Скетчи-примеры

Функции

Вспомогательные функции

  • collideDebug()

Функции для определения столкновений

  • collidePointPoint()
  • collidePointCircle()
  • collidePointRect()
  • collidePointLine()
  • collideRectRect()
  • collideCircleCircle()
  • collideRectCircle()
  • collideLineLine()
  • collideLineCircle()
  • collideLineRect()
  • collidePointPoly()
  • collideCirclePoly()
  • collideRectPoly()
  • collideLinePoly()
  • collidePolyPoly()
  • collidePointTriangle()
  • collidePointArc()

Описание и примеры использования функций

collideDebug(debugMode, size, color)

Включает режим отладки столкновений. Рисует эллипс в точке экрана, где можно применить и рассчитать столкновение между объектами.

Применима для следующих функций:

  • collideLineCircle()
  • collideLineLine()
  • collideLineRect()
  • collideCirclePoly()
  • collideRectPoly()
  • collideLinePoly()
  • collidePolyPoly()
function setup() {
  collideDebug(true);
}

collidePointPoint(x, y, x2, y2, [buffer])

Рассчитывает столкновение одной точки с другой. Опционально можно задать «буферную зону», расширяющую область столкновения.

// Простой пример использования функции collidePointPoint()

var hit = false;
function draw() {
      background(255);
      ellipse(100,100,1,1);       // если используете вариант
                                  // с буферной зоной, 
                                  // поменяйте размер эллипса на 10х10 
      ellipse(mouseX,mouseY,1,1); // если используете вариант
                                  // с буферной зоной,
                                  // поменяйте размер эллипса на 10х10 

	// простой вариант без буферной зоны:
	hit = collidePointPoint(100,100,mouseX,mouseY)

	// вариант с буферной зоной размером 10х10 пикселей:
	//hit = collidePointPoint(100,100,mouseX,mouseY,10)

	print("colliding? " + hit);
       //  "столкновение? "
}

collidePointCircle(pointX, pointY, circleX, circleY, diameter)

Рассчитывает столкновение точки с эллипсом. Для корректной работы этой функции необходимо, чтобы в функции ellipseMode() был задан параметр «CENTER».

var hit = false;
function draw() {
	background(255);
	ellipse(200,200,100,100);
	point(mouseX,mouseY);

	hit = collidePointCircle(mouseX,mouseY,200,200,100)

	print("colliding? " + hit);
  //  "столкновение? "

}

collidePointRect(pointX, pointY, x, y, width, height)

Рассчитывает столкновение между точкой и прямоугольником. Для корректной работы этой функции необходимо, чтобы в функции rectMode() был задан параметр «CORNER».

var hit = false;
function draw() {
  background(255);
	rect(200,200,100,150);

	hit = collidePointRect(mouseX,mouseY,200,200,100,150);

	print("colliding? " + hit);
  	  //  "столкновение? "

}

collidePointLine(pointX, pointY, x, y, x2, y2, [buffer])

Рассчитывает столкновение между точкой и линией. Опционально можно задать буферную зону, расширяющую область столкновения (по умолчанию в параметре «buffer» стоит «0.1»).

var hit = false;
function draw(){
  background(255);
	line(200,300,100,150);
	point(mouseX,mouseY);

  // используем опциональный параметр для буферной зоны 
  // и задаем ему значение «0.5»:
	hit = collidePointLine(mouseX,mouseY,200,300,100,150, 0.5);

	print("colliding? " + hit);
  //  "столкновение? " 
}

collideCircleCircle(circleX, circleY,circleDiameter, circleX2, circleY2, circleDiameter2)

Рассчитывает столкновение между двумя эллипсами. Для корректной работы этой функции необходимо, чтобы в функции ellipseMode() был выставлен параметр «CENTER».

var hit = false;
function draw() {
	background(255);
	ellipse(200,200,100,100);
	ellipse(mouseX,mouseY,150,150);

	hit = collideCircleCircle(mouseX,mouseY,150,200,200,100)

	print("colliding? " + hit);
  //  "столкновение? "

}

collideRectRect(x, y, width, height, x2, y2, width2, height2)

Рассчитывает столкновение между двумя прямоугольниками. Чтобы эта функция работала корректно, в функции rectMode() нужно задать параметр «CORNER».

var hit = false;
function draw() {
  background(255);
	rect(200,200,100,150);
	rect(mouseX,mouseY,50,75);

	hit = collideRectRect(200,200,100,150,mouseX,mouseY,50,75);

	print("colliding? " + hit);
   	  //  "столкновение? " 

}

collideRectCircle(x1, y1, width1, height1, cx, cy, diameter)

Рассчитывает столкновение между прямоугольником и эллипсом. Чтобы эта функция работала корректно, у функции rectMode() нужно задать режим «CORNER», а у ellipseMode() – «CENTER».

var hit = false;
function draw() {
  background(255);
	rect(200,200,100,150);
	ellipse(mouseX,mouseY,100,100);

	hit = collideRectCircle(200,200,100,150,mouseX,mouseY,100);

	print("colliding? " + hit);
  //  "столкновение? "
}

collideLineLine(x1, y1, x2, y2, x3, y3, x4, y4, [calcIntersection])

Рассчитывает столкновение между двумя линиями. Принимает опциональный булев параметр «calcIntersection», включающий/выключающий расчет точки пересечения. Если задать в нем «true», то в случае пересечения функция вернет объект с XY-координатами пересечения, а если пересечения зафиксировано не будет, то эта функция с каждым новым кадром будет возвращать объект с XY-координатами со значением «false». Поддерживает отладку с помощью collideDebug().

// простой пример использования функции collideLineLine()
var hit = false;
function draw(){
  background(255);
  line(200,300,100,150);
  line(mouseX,mouseY,350,50);
  hit = collideLineLine(200,300,100,150,mouseX,mouseY,350,50);

  print("colliding? " + hit);
// "столкновение? "
}


// возвращает объект, содержащий XY-координаты места пересечения,
// используя для этого опциональный параметр «calcIntersection»:
var hit = false;
function draw(){
  background(255);
  line(200,300,100,150);
  line(mouseX,mouseY,350,50);

  hit = collideLineLine(200,300,100,150,mouseX,mouseY,350,50,true);

  print("X-intersection:" + hit.x); 
    //  "X-координата пересечения:"
  print("Y-intersection:" + hit.y);
    //  "Y-координата пересечения:"
}

collideLineCircle(x1, y1, x2, y2, cx, cy, diameter)

Рассчитывает столкновение точки и эллипса. Поддерживает отладку с помощью collideDebug().

var hit = false;
function draw(){
  background(255);
	line(200,300,100,150);
	ellipse(mouseX,mouseY,50,50);
	hit = collideLineCircle(200,300,100,150,mouseX,mouseY,50);

	print("colliding? " + hit);
       //  "столкновение? "
}

collideLineRect(x1, y1, x2, y2, rx, ry, rw, rh, [calcIntersection])

Рассчитывает столкновение между линией и прямоугольником. Принимает опциональный булев параметр «calcIntersection», включающий/выключающий расчет точек пересечения. Если задать в нем «true», то в случае пересечения функция вернет объект, содержащий объекты с XY-координатами пересечений с верхней, нижней, правой и левой сторонами прямоугольника. Если пересечения зафиксировано не будет, то эта функция с каждым новым кадром будет возвращать объект с XY-координатами со значением «false». Поддерживает отладку с помощью collideDebug().

// простой пример использования функции collideLineRect()
var hit = false;
function draw() {
	background(255);
	rect(200,300,100,150);
	line(mouseX,mouseY,350,50);

	hit = collideLineRect(mouseX,mouseY,350,50,200,300,100,150);

	print("colliding? " + hit);
   	  //  "столкновение? "
}


// возвращает объект, содержащий XY-координаты 
// пересечения со всеми четырьмя сторонами прямоугольника,
// при помощи опционального булева параметра «calcIntersection»:
var hit = false;
function draw() {
	background(255);
	rect(200,300,100,150);
	line(mouseX,mouseY,350,50);

	hit = collideLineRect(mouseX,mouseY,350,50,200,300,100,150,true);

  // возвращаем объект, содержащий объекты
  // с XY-координатами пересечения линии
  // с верхней, нижней, правой и левой сторонами прямоугольника:
  print("bottomX: " + hit.bottom.x);
    //  "X-координата пересечения с нижней стороной: "
  print("bottomY: " + hit.bottom.y);
    //  "Y-координата пересечения с нижней стороной: "
  print("topX: " + hit.top.x);
    //  "X-координата пересечения с верхней стороной: "
  print("topY: " + hit.top.y);
    //  "Y-координата пересечения с верхней стороной: "
  print("leftX: " + hit.left.x);
    //  "X-координата пересечения с левой стороной: "
  print("leftY: " + hit.left.y);
    //  "Y-координата пересечения с левой стороной: "
  print("rightX: " + hit.right.x);
    //  "X-координата пересечения с правой стороной: "
  print("rightY: " + hit.right.y);
    //  "Y-координата пересечения с правой стороной: "
}

collidePointPoly(pointX,pointY,vectorArray)

Рассчитывает столкновение точки с полигоном. В параметрах «pointX» и «pointY» задаются XY-координаты расположения точки. В параметре «vectorArray» задается массив объектов p5.Vector, содержащих XY-координаты вершин полигона. Эта функция работает с многосторонними полигонами, а также с «вогнутыми» полигонами (полигонами, чьи стороны пересекаются друг с другом).

var hit = false;
var poly = []; // массив для хранения вершин полигона 
function setup() {
	createCanvas(500,500);
	poly[0] = createVector(123,231);     // задаем XY-позиции
	poly[1] = createVector(10,111);      // вершин полигона
	poly[2] = createVector(20,23);
	poly[3] = createVector(390,33);
}

function draw() {
	background(255);

  // рисуем полигон на основе заданных выше вершин:
	beginShape();
	for(i=0; i < poly.length; i++){
		vertex(poly[i].x,poly[i].y);
	}
	endShape(CLOSE);

	ellipse(mouseX,mouseY,10,10); // рисуем маленький эллипс
                              // в месте курсора мыши

// третий параметр – это массив вершин: 
	hit = collidePointPoly(mouseX,mouseY,poly);

	print("colliding? " + hit);
  //  "столкновение? "
}

collideCirclePoly(x,y,diameter,vectorArray, [interiorCollision])

Рассчитывает столкновение эллипса и полигона. В параметрах «x», «y» и «diameter» задаются XY-координаты и диаметр эллипса, а в параметре «vectorArray» – массив объектов p5.Vector с XY-координатами вершин полигона. Эта функция работает с многосторонними полигонами, а также с «вогнутыми» полигонами (полигонами, чьи стороны пересекаются друг с другом). Также принимает опциональный пятый булев параметр «interiorCollision», включающий/выключающий определение столкновений, если эллипс полностью находится внутри полигона. По умолчанию эта функция выключена, чтобы не рассчитывать столкновение эллипса с краями полигона по два раза (и тем самым сэкономить вычислительные ресурсы). Поддерживает отладку с помощью функции collideDebug().

var hit = false;
var poly = [];
function setup() {
	createCanvas(windowWidth,windowHeight);
	collideDebug(true)
	poly[0] = createVector(123,231);  // задаем XY-координаты 
	poly[1] = createVector(10,111);   // вершин полигона
	poly[2] = createVector(20,23);
	poly[3] = createVector(390,33);
}

function draw() {
	background(255);

  // рисуем полигон на основе заданных выше вершин:
	beginShape();
	for(i=0; i < poly.length; i++){
		vertex(poly[i].x,poly[i].y);
	}
	endShape(CLOSE);

	ellipse(mouseX,mouseY,45,45);

	hit = collideCirclePoly(mouseX,mouseY,45,poly);

	// используйте этот вариант, если нужно рассчитать
// столкновение эллипса, находящегося внутри полигона:
	// hit = collideCirclePoly(mouseX,mouseY,45,poly,true);

	print("colliding? " + hit);
  //  "столкновение? "
}

collideRectPoly(x,y,width,height,vectorArray, [interiorCollision])

Рассчитывает столкновение прямоугольника с полигоном. В параметрах «x», «y», «width» и «height» задаются XY-координаты, ширина и высота прямоугольника. В параметре «vectorArray» – массив объектов p5.Vector, содержащих XY-координаты вершин полигона. Эта функция работает с многосторонними полигонами, а также с «вогнутыми» полигонами (полигонами, чьи стороны пересекаются друг с другом). Также принимает опциональный шестой булев параметр «interiorCollision», включающий/выключающий определение столкновений, если прямоугольник полностью находится внутри полигона. По умолчанию эта функция выключена, чтобы не рассчитывать столкновения с одними и теми же краями по два раза (и тем самым сэкономить вычислительные ресурсы). Поддерживает отладку при помощи collideDebug().

var hit = false;
var poly = [];
function setup() {
	createCanvas(windowWidth,windowHeight);
	collideDebug(true)
	poly[0] = createVector(323,431);     // задаем XY-координаты 
	poly[1] = createVector(210,311);     // вершин полигона
	poly[2] = createVector(220,223);
	poly[3] = createVector(590,233);
}

function draw() {
	background(255);
	push()
	beginShape();
	// рисуем полигон на основе заданных выше вершин:
	for(i=0; i < poly.length; i++){
		vertex(poly[i].x,poly[i].y);
	}
	endShape(CLOSE);

	rect(mouseX,mouseY,45,100);

	hit = collideRectPoly(mouseX,mouseY,45,100,poly);
	
     // используйте этот вариант, если прямоугольник
     // находится полностью внутри полигона:
	// hit = collideRectPoly(mouseX,mouseY,45,100,poly,true);

	print("colliding? " + hit);
      "столкновение? "
}

collideLinePoly(x1, y1, x2, y2, vertices)

Рассчитывает столкновение линии с полигоном. В параметрах «x1», «y1», «x2» и «y2» задаются координаты линии, а в параметре «vertices» – массив объектов p5.Vector с XY-координатами вершин полигона. Эта функция работает с многосторонними полигонами, а также с «вогнутыми» полигонами (полигонами, чьи стороны пересекаются друг с другом). Поддерживает отладку с помощью функции collideDebug().

var hit = false;
var poly = new Array(16);;
function setup() {
	createCanvas(windowWidth,windowHeight);
	collideDebug(true)

	// создаем 16-сторонний полигон:
  var angle = TWO_PI / poly.length;
  for (var i=0; i<poly.length; i++) {
    var a = angle * i;
    var x = 300 + cos(a) * 100;
    var y = 200 + sin(a) * 100;
    poly[i] = createVector(x,y);
  }
}
function draw() {
	background(255);
	beginShape();
	// рисуем полигон на основе заданных выше вершин:
	for(i=0; i < poly.length; i++){
		vertex(poly[i].x,poly[i].y);
	}
	endShape(CLOSE);

	line(10,10,mouseX,mouseY);

	hit = collideLinePoly(mouseX,mouseY,45,100,poly);

	print("colliding? " + hit);
  //  "столкновение? "
}

collidePolyPoly(polygon1, polygon2, [interiorCollision])

Рассчитывает столкновение между двумя полигонами. В параметрах «polygon1» и «polygon2» задаются массивы объектов p5.Vector с XY-координатами вершин двух этих полигонов. Эта функция работает с многосторонними полигонами, а также с «вогнутыми» полигонами (полигонами, чьи стороны пересекаются друг с другом). Также принимает опциональный третий булев параметр «interiorCollision», включающий/выключающий определение столкновений, если один полигон полностью находится внутри другого полигона. По умолчанию эта функция выключена, чтобы не рассчитывать по два раза столкновение с одними и теми же сторонами (и тем самым сэкономить вычислительные ресурсы). Поддерживает отладку с помощью функции collideDebug().

// этот скетч-пример – адаптация кода Джеффри Томпсона

var hit = false;
var poly = new Array(8);
var randomPoly = []
function setup() {
	createCanvas(windowWidth,windowHeight);
	collideDebug(true) // включаем режим отладки

	// создаем полигон с одинаковыми сторонами:
  var angle = TWO_PI / poly.length;
  for (var i=0; i<poly.length; i++) {
    var a = angle * i;
    var x = 300 + cos(a) * 100;
    var y = 200 + sin(a) * 100;
    poly[i] = createVector(x,y);
  }

  // создаем полигон со сторонами случайного размера:
  var a = 0;
  var i = 0;
  while (a < 360) {
    var x = cos(radians(a)) * random(30,50);
    var y = sin(radians(a)) * random(30,50);
    randomPoly[i] = createVector(x,y);
    a += random(15, 40);
    i += 1;
  }
}
function draw() {
	background(255);
 // привязываем позицию полигона 
 // со сторонами случайного размера
 // к позиции мышки: 
  var mouse = createVector(mouseX, mouseY);
  var diff = mouse.sub(randomPoly[0]);

  for (i=0; i < randomPoly.length; i++) {
    randomPoly[i].add(diff);
  }

	beginShape();
	// рисуем полигон на основе заданных выше вершин:
	for(i=0; i < poly.length; i++){
		vertex(poly[i].x,poly[i].y);
	}
	endShape(CLOSE);
	beginShape();
	for(i=0; i < randomPoly.length; i++){
		vertex(randomPoly[i].x,randomPoly[i].y);
	}
	endShape(CLOSE);

	hit = collidePolyPoly(poly,randomPoly,true);
	print("colliding? " + hit);
   	  //  "столкновение? "

}

collidePointTriangle(px, py, x1, y1, x2, y2, x3, y3)

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

var hit = false;
function draw() {
	background(255);
	triangle(300,200,350,300,250,300)
	ellipse(mouseX,mouseY,10,10);

	hit = collidePointTriangle(mouseX,mouseY, 300,200,350,300,250,300)
	print("colliding? " + hit)
  //  "столкновение? "
}

Функции для столкновения с треугольником

Расчет столкновения нужной фигуры (будь то эллипс, прямоугольник, линия или другой треугольник) с треугольником осуществляется при помощи функции для расчета столкновения этой фигуры с полигоном. Соответственно, в качестве полигона должен быть задан трехсторонний полигон (то есть, по сути, треугольник).

Примечание: Вершины треугольного полигона задаются с помощью трех объектов p5.Vector (см. пример ниже).

  • collideCirclePoly() – для расчета столкновения эллипса с треугольником
  • collideRectPoly() – для расчета столкновения прямоугольника с треугольником
  • collideLinePoly() – для расчета столкновения линии с треугольником
  • collidePolyPoly() – для расчета столкновения треугольника с треугольником
var hit = false;
var triPoly = []
function setup() {
	createCanvas(windowWidth,windowHeight);
	collideDebug(true)

	triPoly[0] = createVector(300,200);
	triPoly[1] = createVector(350,300);
	triPoly[2] = createVector(250,300);
}

function draw() {
	background(255);

  // мы можем нарисовать этот треугольник
  // с помощью beginShape() и endShape() 
  // и итерирования через массив «triPoly», но так – проще:
	triangle(300,200,350,300,250,300)
	ellipse(mouseX,mouseY,45,45);

	hit = collideCirclePoly(mouseX,mouseY,45, triPoly)

	print("colliding? " + hit)
  //  "столкновение "
}

collidePointArc(pointX, pointY, arcCenterX, arcCenterY, arcRadius, arcRotationAngle, arcAngle, [buffer])

Рассчитывает столкновение точки с аркой.

var ARC_RADIUS = 100;
var ARC_ANGLE = Math.PI/3;
var ROTATION_ANGLE = -Math.PI / 4;
var hit = false;
function draw() {
	background(220);
	push();
	// перемещаемся к центру холста:
	translate(width / 2, height / 2);
	// вращаем под некоторым углом:
	rotate(ROTATION_ANGLE);
	fill(color(180, 220, 210));
	stroke(10);
	arc(0, 0, 2 * ARC_RADIUS, 2 * ARC_RADIUS, -ARC_ANGLE/2, ARC_ANGLE/2, PIE);
	pop();
	point(mouseX, mouseY);
	hit = collidePointArc(mouseX, mouseY, width / 2, height / 2, ARC_RADIUS, ROTATION_ANGLE, ARC_ANGLE);

	print("colliding? " + hit);
   	  //  "столкновение? " 
}

См.также

Внешние ссылки