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);
// "столкновение? "
}