Области Вороного
В этой статье http://noregret.org/tutor/n/collision/#2.2 описаны Области Вороного , но как их реализовать не могу найти, может кто подскажет?
Нужно для того что бы определить к какой части многоугольника окружность находиться ближе или проще говоря в какую часть блока летит шарик. |
Берём для примера прямоугольник. Дальше мы считаем его проекцию на Ох. Она делит эту ось координат на три части: от минус бесконечности до начала проекции, от начала проекции до конца проекции, от конца проекции до плюс бесконечности. Обозначим их, для примера, -1, 0, 1. После этого мы проверяем, какой из частей принадлежит координата X центра окружности. Тоже самое делаем с осью Oy. Итого у нас получается девять возможных комбинаций. В зависимости от каждой из этих комбинаций мы берём нужную точку прямоугольника.
|
Вот примерный код, хотя я не тестировал его.
function distance(x1, y1, x2, y2) { // считаем расстояние между двумя точками return Math.sqrt(Math.power((x2-x1), 2) + Math.power((y2-y1), 2)) } /* Проверка на столкновение. x1, y1 -- координаты левой верхней точки прямоугольника. x2, y2 -- координаты правой нижней точки прямоугольника. x, y -- координаты центра окружности r -- радиус окружности. */ function isCollision(x1, y1, x2, y2, x, y, r) { var compX, compY; // выбираем точку X прямоугольника, которая ближе всего к центру окружности. if (x <= x1) { // если X центра слева от проекции на Ox... compX= x1; } else if (x < x2) { // ...принадлежит проекции compX= x; } else { // ...справа от проекции compX= x2; } // выбираем точку Y прямоугольника, которая ближе всего к центру окружности. if (y <= y1) { // если y центра слева от проекции на Oy... compY= y1; } else if (y < y2) { // ...принадлежит проекции compY= y; } else { // ...справа от проекции compY= y2; } return r <= distance(x, y, compX, compY); } |
schmetterling, спасибо, буду разбираться)
|
Цитата:
|
schmetterling, сразу поверхностно глянул на код , а теперь сел дальше мучатся со своим арканоидом, и понял что ваш код в общем работает так же как и мой)
вот из тестового варианта (y <= Bl_bottom && y >= block.y - ball.R) && (x >= block.x - ball.R && x <= Bl_right) код ниже это просто черновик <!DOCTYPE HTML> <html> <head> </head> <body> <canvas width="500" height="500"></canvas> <script> var canva = document.body.children[0]; var ctx = canva.getContext("2d"); var ball = { x:20, y:280, R:20, Draw: function (x, y) { ctx.clearRect(this.x - this.R, this.y - this.R, this.R *2,this.R *2); ctx.beginPath(); ctx.fillStyle = "red"; ctx.arc(x,y, this.R,0, (Math.PI / 180)* 360, false); ctx.fill(); this.y = y; this.x = x; } }; var block = { width:150, height:30, Draw: function (x, y) { ctx.beginPath(); ctx.fillStyle = "green"; ctx.fillRect(x,y,this.width, this.height); this.y = y; this.x = x; } }; block.Draw(150,100); var valX = -10 , valY = -10; var Bl_bottom = block.y + block.height + ball.R ; var Bl_right = block.x + block.width + ball.R ; var one = false; function action(){ if(ball.x < 0 + ball.R || ball.x > canva.width - ball.R){ valX = -valX; }; if(ball.y < 0 + ball.R || ball.y > canva.height - ball.R){ valY = -valY; //y = canva.height - ball.R; } var x = ball.x; var y = ball.y ; if((y <= Bl_bottom && y >= block.y - ball.R) && (x >= block.x - ball.R && x <= Bl_right)){ if(!one) drawOs(x,y); if(!one){// запускаем еще один мячик ball.x = 200; ball.y = 200; action(); one = true; } return; }; x += valX; y += valY; ball.Draw(x,y); setTimeout(action,1000/60); }; action(); function drawOs(x,y){ ctx.beginPath(); ctx.moveTo(block.x - ball.R ,Bl_bottom); ctx.lineTo(x,y); ctx.stroke(); ctx.beginPath(); ctx.moveTo(Bl_right ,Bl_bottom); ctx.lineTo(x,y); ctx.stroke(); ctx.beginPath(); ctx.moveTo(block.x - ball.R,block.y - ball.R); ctx.lineTo(x,y); ctx.stroke(); ctx.beginPath(); ctx.moveTo(Bl_right,block.y - ball.R ); ctx.lineTo(x,y); ctx.stroke(); }; </script> </body> </html> проблема в столкновение с углом, в примере выше видно что если сталкивается не с углом все работает. |
Вот картинка, тут понятно, что идёт не так)
![]() |
schmetterling,я и так это понял;)
и вообще уже знаю как поправить, просто показал если кто то будет писать арканоид и будет читать эту тему и мучатся) вот так должен выглядить блок <!DOCTYPE HTML> <html> <head> </head> <body> <canvas width="500" height="500"></canvas> <script> var canva = document.body.children[0]; var ctx = canva.getContext("2d"); var block = { width:150, height:30, Draw: function (x, y) { ctx.beginPath(); ctx.fillStyle = "green"; ctx.fillRect(x,y,this.width, this.height); this.y = y; this.x = x; boundary(); } }; block.Draw(150,100); function boundary() { var rad = 20; ctx.beginPath(); ctx.moveTo(block.x,block.y - rad); ctx.lineTo(block.x + block.width , block.y - rad); ctx.stroke(); ctx.beginPath(); ctx.moveTo(block.x+ block.width + rad,block.y); ctx.lineTo(block.x+ block.width + rad , block.y + block.height); ctx.stroke(); ctx.beginPath(); ctx.moveTo(block.x, block.y + block.height + rad); ctx.lineTo(block.x + block.width , block.y + block.height + rad); ctx.stroke(); ctx.beginPath(); ctx.moveTo(block.x- rad,block.y); ctx.lineTo(block.x - rad , block.y + block.height); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = "blue"; ctx.moveTo(block.x,block.y); ctx.arc(block.x,block.y, rad,(Math.PI / 180)* -90, (Math.PI / 180)* -180, true); ctx.fill(); ctx.beginPath(); ctx.fillStyle = "blue"; ctx.moveTo(block.x +block.width,block.y); ctx.arc(block.x +block.width, block.y, rad,(Math.PI / 180)* -90, (Math.PI / 180)* 0, false); ctx.fill(); ctx.beginPath(); ctx.fillStyle = "blue"; ctx.moveTo(block.x + block.width, block.y + block.height); ctx.arc(block.x + block.width, block.y + block.height, rad,(Math.PI / 180)* 0, (Math.PI / 180)* 90, false); ctx.fill(); ctx.beginPath(); ctx.fillStyle = "blue"; ctx.moveTo(block.x ,block.y + block.height); ctx.arc(block.x ,block.y + block.height, rad,(Math.PI / 180)* 180, (Math.PI / 180)* 90, true); ctx.fill(); } </script> </body> </html> но я так и не понял раз 15 перечитывал коммент http://javascript.ru/forum/events/33...tml#post216503 как правильно определить окружность ... |
просто не пойму фишки кода не увеличиваю блок на радиус шарик вроде нормально входит в угол, но наверно просто так кажется ...
<!DOCTYPE HTML> <html> <head> </head> <body> <canvas width="500" height="500"></canvas> <script> var canva = document.body.children[0]; var ctx = canva.getContext("2d"); var ball = { x:20, y:280, R:20, Draw: function (x, y) { ctx.clearRect(this.x - this.R, this.y - this.R, this.R *2,this.R *2); ctx.beginPath(); ctx.fillStyle = "red"; ctx.arc(x,y, this.R,0, (Math.PI / 180)* 360, false); ctx.fill(); this.y = y; this.x = x; } }; var block = { width:150, height:30, Draw: function (x, y) { ctx.beginPath(); ctx.fillStyle = "green"; ctx.fillRect(x,y,this.width, this.height); this.y = y; this.x = x; } }; block.Draw(150,100); var valX = -10 , valY = -10; var Bl_bottom = block.y + block.height ; var Bl_right = block.x + block.width ; !function action(){ if(ball.x < 0 + ball.R || ball.x > canva.width - ball.R){ valX = -valX; }; if(ball.y < 0 + ball.R || ball.y > canva.height - ball.R){ valY = -valY; //y = canva.height - ball.R; } var x = ball.x ; var y = ball.y ; if((y <= Bl_bottom && y >= block.y ) && (x >= block.x && x <= Bl_right)){ //if(isCollision(block.x ,block.y , Bl_right, Bl_bottom ,x,y, ball.R)){ drawOs(x,y); return; }; x = ball.x + valX; y = ball.y + valY; ball.Draw(x,y); setTimeout(action,1000/60); }(); function drawOs(x,y){ ctx.beginPath(); ctx.moveTo(block.x ,Bl_bottom); ctx.lineTo(x,y); ctx.stroke(); ctx.beginPath(); ctx.moveTo(Bl_right ,Bl_bottom); ctx.lineTo(x,y); ctx.stroke(); ctx.beginPath(); ctx.moveTo(block.x ,block.y ); ctx.lineTo(x,y); ctx.stroke(); ctx.beginPath(); ctx.moveTo(Bl_right,block.y ); ctx.lineTo(x,y); ctx.stroke(); }; function distance(x1,y1,x2,y2){ return Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2)); }; </script> </body> </html> |
кажеться понял, но разберусь уже завтра)
|
cyber, в случае, если у вас шарик будет соприкасаться с углом, вам нужно считать расстояние между центром и углом) И проверять, не меньше ли оно радиуса.
|
нет все таки не разобрался)
если брать углы за окружность <!DOCTYPE HTML> <html> <head> </head> <body> <canvas width="500" height="500"></canvas> <script> var canva = document.body.children[0]; var ctx = canva.getContext("2d"); var block = { width:150, height:30, Draw: function (x, y) { ctx.beginPath(); ctx.fillStyle = "green"; ctx.fillRect(x,y,this.width, this.height); this.y = y; this.x = x; boundary(); } }; block.Draw(150,100); function boundary() { var rad = 20; ctx.beginPath(); ctx.moveTo(block.x,block.y - rad); ctx.lineTo(block.x + block.width , block.y - rad); ctx.stroke(); ctx.beginPath(); ctx.moveTo(block.x+ block.width + rad,block.y); ctx.lineTo(block.x+ block.width + rad , block.y + block.height); ctx.stroke(); ctx.beginPath(); ctx.moveTo(block.x, block.y + block.height + rad); ctx.lineTo(block.x + block.width , block.y + block.height + rad); ctx.stroke(); ctx.beginPath(); ctx.moveTo(block.x- rad,block.y); ctx.lineTo(block.x - rad , block.y + block.height); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = "blue"; ctx.moveTo(block.x,block.y); ctx.arc(block.x,block.y, rad,(Math.PI / 180)* -90, (Math.PI / 180)* -180, true); ctx.fill(); ctx.beginPath(); ctx.fillStyle = "blue"; ctx.moveTo(block.x +block.width,block.y); ctx.arc(block.x +block.width, block.y, rad,(Math.PI / 180)* -90, (Math.PI / 180)* 0, false); ctx.fill(); ctx.beginPath(); ctx.fillStyle = "blue"; ctx.moveTo(block.x + block.width, block.y + block.height); ctx.arc(block.x + block.width, block.y + block.height, rad,(Math.PI / 180)* 0, (Math.PI / 180)* 90, false); ctx.fill(); ctx.beginPath(); ctx.fillStyle = "blue"; ctx.moveTo(block.x ,block.y + block.height); ctx.arc(block.x ,block.y + block.height, rad,(Math.PI / 180)* 180, (Math.PI / 180)* 90, true); ctx.fill(); } </script> </body> </html> расчитывать пересечение двух окружностей , то возникает проблема когда шарик на шаге n не пересекается с окружностью , а на шаге n+1 он нужен дальше окружности.. проверял так var d = (x - block.x)*(x - block.x) + (y - block.y + block.height) * (y - block.y + block.height); if(d < (ball.R + ball.R ) * (ball.R + ball.R) && d > (ball.R - ball.R) * (ball.R - ball.R)) и блин не как не могу понять как автор этой статьи так просто расчитывает пересечения с углами |
Цитата:
Кстати арканоид хороший способ подучить геометрию)) П.с сор что туплю, понимаю что достал уже) |
Цитата:
|
schmetterling,хм, запутался.
Так как расчитываю координаты следущие, то если шарик залетает на блок нужно уменьшать растояние до того на котором он только столкнется , а не пересечет и не могу найти как определить ту точку в которой он будет сталкиваться а не пересекать(проблема только с углами)? |
cyber, ну вы же координаты последующие как-то вычисляете? Вот и проверяете каждый раз пересечение круга и блока для вычисленных координат. Если пересеклись -- значит, текущая точка и есть точка столкновения.
|
schmetterling,можно на ты ?
я делаю так: что бы найти растояние до нужной точки я от радиуса отнимаю растояние между точками В и А и прибавляю его к А. ![]() но работает как то не так... |
Цитата:
Цитата:
|
schmetterling, не совсем понял.
Если новые координаты внутри блока, а если отразить раньше то сильно заметно.. |
В общем набросал кое-что, но сюда код не помещается, поэтому кладу на дропбокс: Collisions.
Управление: стрелочки - перемещение шарика WSAD - поворот и изменение длины вектора движения Иногда шарик проходит углы насквозь. Иногда даже зависает. Писать красиво и модульно мне было некогда, поэтому говнокод. В данный момент только статическая трассировка, может в другой раз заставлю картинку двигаться самостоятельно. |
Дзен-трансгуманист, спасибо, буду разбираться
|
вот пока то что у меня есть http://learn.javascript.ru/play/8nu3s
<!DOCTYPE HTML> <html> <head> </head> <body> <canvas width="500" height="500"></canvas> <script> var canva = document.body.children[0]; var ctx = canva.getContext("2d"); var ball = { // x:20, // y:280, x:50, y:40, R:20, Draw: function (x, y) { ctx.clearRect(this.x - this.R, this.y - this.R, this.R *2,this.R *2); ctx.beginPath(); ctx.fillStyle = "red"; ctx.arc(x,y, this.R,0, (Math.PI / 180)* 360, false); ctx.fill(); this.y = y; this.x = x; } }; var block = { width:150, height:30, Draw: function (x, y) { ctx.beginPath(); ctx.fillStyle = "green"; ctx.fillRect(x,y,this.width, this.height); this.y = y; this.x = x; } }; block.Draw(150,100); var valX = -10 , valY = -10; var Bl_bottom = block.y + block.height + ball.R ; var Bl_right = block.x + block.width + ball.R ; var stop = false; !function action(){ if(ball.x < 0 + ball.R || ball.x > canva.width - ball.R){ valX = -valX; }; if(ball.y < 0 + ball.R || ball.y > canva.height - ball.R){ valY = -valY; } var x = ball.x + valX; var y = ball.y + valY; if((y <= Bl_bottom && y >= block.y - ball.R) && (x >= block.x - ball.R && x <= Bl_right)){ var pos = getPosit(); if(pos == "angle") { // проверка на столкновение с одним из 4х углов if(distance(x,y,block.x, block.y + block.height) <= ball.R || distance(x,y,block.x, block.y ) <= ball.R || distance(x,y,block.x + block.width, block.y + block.height) <= ball.R|| distance(x,y,block.x+ block.width, block.y) <= ball.R){ valY = - valY; valX = - valX; return; } } if(pos == "x") { valX = - valX; } if(pos == "y") { valY = - valY; } // return; }; ball.Draw(x,y); setTimeout(action,1000/60); }(); function getPosit() { var x,y; if(ball.x <= block.x){ x = "left"; } else if(ball.x >= block.x + block.width){ x = "right"; } else x = "on"; if(ball.y >= block.y + block.height){ y = "bottom"; } else if(ball.y <= block.y){ y = "top"; } else y = "on"; if((x == "right" || x == "left") && (y == "on")) { return "x"; } else if((y == "bottom" || y == "top") && x == "on"){ return "y"; } else return "angle"; } function distance(x1,y1,x2,y2){ return Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2)); }; </script> </body> </html> сделал остановку когда новые координаты шарика будут равны углу или внутри угла. |
Дзен-трансгуманист, я понимаю что это уже наглость, но не могу разобраться в твоем коде, какой метод отвечает за рисование шариков которые рисуются на векторе?
|
cyber,
drawPath в области видимости TracerView, строчки 489-500 (потом рисуются линии). Это типа как приватная функция, только вместо контекста this я передаю экземпляр класса явно в аргументе object. |
Я сейчас понял, что трейсер возвращает только путь в виде набора точек, но не возвращает новый вектор движения после всех столкновений. Без этого, конечно, шарик самостоятельно никуда не полетит.
И наверное я неправильно поступил, что мастер-объектом движения сделал вектор [x,y]. Так теряется некоторая точность преобразований, причем, чем больше столкновений за один ход - тем больше потери точности. Надо было хранить и обрабатывать его как [длина,азимут]. Не знаю, дойдут ли у меня руки править это, но, честно говоря, не очень-то хочется, поскольку не люблю поддерживать код, написанный второпях буквально за один день. Такие вещи надо продумывать и делать основательно, а не на коленке. ;) |
Дзен-трансгуманист,хм, не совсем понял как ты расчитываешь расстояние от угла до центра шарика?
|
Дзен-трансгуманист,да вообщем я понимаю как все работает, но у меня проблемы с реализацией из за пробелов в школьной геометрии
Допустим по формуле Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2)); я определил что на шаге n+1 шарик будет внутри блока, то нужно установить такие координаты при которых шарик не пересечет угол. Вроде просто, а не фига не получается . |
Цитата:
|
Цитата:
|
Цитата:
Значить не я один вместо повторение учу что то новое из школьной программы))) П.с я тоже троечником был) |
Дзен-трансгуманист, хм, а если найти угол падения, а через него угол отражения?
|
cyber,
Все равно нужна нормаль. На отрезках она во всех точках одинакова, а на углах зависит от направления удара. |
Дзен-трансгуманист, как то так http://habrahabr.ru/post/105882/ там есть под раздел "Вычисление отражённого луча" ?
|
cyber,
Хороший пост. И? |
Дзен-трансгуманист,мне он тоже показался хорошим:)
но я не совсем понял как получить новые координаты из градуса угла ![]() |
cyber,
Где ты там видишь градус?) Это пост об алгебре, нет там никаких градусов.) Точка в формуле - это скалярное произведение, если че. |
Дзен-трансгуманист, wtf , ну меня и лагануло)
прочитал статью на хабре, потом начал читать эту http://www.ecto.ru/details/reflex_drop/ и получился бред в голове) |
cyber,
Если смотреть на мой код с такой точки зрения, то у меня там действительно много избыточных вычислений. Это еще одна причина, почему я не хочу его править, ибо проще написать новый с нуля. |
вроде тут все понятно http://www.ecto.ru/details/reflex_drop/, но как найти нормаль я так и не понял..
|
Дзен-трансгуманист, смысел писать целый скрипт, что бы только показать что делать с углами?
|
Часовой пояс GMT +3, время: 15:53. |