PDA

Просмотр полной версии : hitTest линии и квадрата


flazher
06.11.2008, 20:15
Понимаю, что тема не раз уже обсуждалась, но поиск не дал ни одного толкового ответа.
Как определить "правильное" пересечение пунктирной линии с кавдратом? (hitTest, естественно, не подходит). Можно ли это сделать как-то геометрически?

Division
06.11.2008, 20:24
Например, проверить пересечении линии со всеми сторонами прямоугольника по очереди. Вообще ИМХО лучше самостоятельно вывести формулу проверки пересечения, но если будет тяжко, вот: http://algolist.ru/maths/geom/intersect/lineline2d.php

джонатан
06.11.2008, 20:54
Намек:

if(линия._x >= квадрат._x and линия._x <= линия._x + линия._width)

Division
06.11.2008, 20:56
if(линия._x >= квадрат._x and линия._x <= линия._x + линия._width);
джонатан, неверный намёк.

flazher
06.11.2008, 20:58
Вообще ИМХО лучше самостоятельно вывести формулу проверки пересечения
Если я мог бы это сделать, я бы давно это уже сделал :rolleyes:
На вашу ссылку зашел, но там для меня , увы, все как-то непонятно :(
Можете написать пример на флеше?

Division
06.11.2008, 21:38
flazher, сейчас у меня нет времени, может быть завтра смогу набросать что-то. Но лучше ты сам попытайся разобраться с материалом по ссылке.
Там пишут:
Если нужно найти пересечение отрезков, то нужно лишь проверить, лежат ли ua и ub на промежутке [0,1]. Если какая-нибудь из этих двух переменных 0 <= ui <= 1, то соответствующий отрезок содержит точку пересечения. Если обе переменные приняли значения из [0,1], то точка пересечения прямых лежит внутри обоих отрезков.
Это значит, что надо найти ua и ub. Это делается по формуле
http://algolist.ru/maths/geom/intersect/gif/lineline2.gif
После того как найдём ua и ub, если они обе от 0 до 1, то отрезки пересекаются.
С этим понятно?

Да, там же есть пример кода на C. Можешь оттуда перевести.

bootaka
21.11.2008, 08:18
и все-таки, как так сделать? теперь это понадобилось мне.

Добавлено через 35 секунд
:rtfm:и все-таки, как так сделать? теперь это понадобилось мне.

Division
21.11.2008, 12:07
Вот, нашёл:

public static function LineVsLine(v1 : Vector2, v2 : Vector2, v3 : Vector2, v4: Vector2) {
var zn = (v4.y-v3.y)*(v2.x-v1.x)-(v4.x-v3.x)*(v2.y-v1.y);
var ua = ((v4.x-v3.x)*(v1.y-v3.y)-(v4.y-v3.y)*(v1.x-v3.x))/zn;
var ub = ((v2.x-v1.x)*(v1.y-v3.y)-(v2.y-v1.y)*(v1.x-v3.x))/zn;
if ((ua>=0 && ua <=1) && (ub>=0 && ub <=1)) return true;
return false;
}
Функция из моей игрушки отсюда: http://flasher.ru/forum/showthread.php?t=115821 (:
Проверяет пересечение отрезков v1v2 и v3v4.
Смысл в том чтоб представить квадрат в виде отрезков. Для квадрата их будет четыре (: И по очереди проверить пересечение твоего отрезка и отрезков квадрата.
Vector2 - может быть любой класс, имеющий свойства x и y. Могу свой класс скинуть, там уже почти вся нужная математика описана
PS можно было спокойно написать эту функцию самостоятельно, всё что нужно для этого написано в посте 6

goarcade
21.11.2008, 14:59
вот, быстро накидал кода:)
лови:

var p0:MovieClip = createPoint(170,270);
var p1:MovieClip = createPoint(300,100);

var a:MovieClip = createPoint(200,200);
var b:MovieClip = createPoint(300,200);
var c:MovieClip = createPoint(300,300);
var d:MovieClip = createPoint(200,300);

onEnterFrame = function()
{
_root.clear();

var hit:Boolean = true;

var dx:Number = p1._y-p0._y;
var dy:Number = p0._x-p1._x;
var s0:Number = (a._x-p0._x)*dx+(a._y-p0._y)*dy;
var s1:Number = (b._x-p0._x)*dx+(b._y-p0._y)*dy;
var s2:Number = (c._x-p0._x)*dx+(c._y-p0._y)*dy;
var s3:Number = (d._x-p0._x)*dx+(d._y-p0._y)*dy;
if( (s0> 0&&s1> 0&&s2> 0&&s3> 0)||
(s0<=0&&s1<=0&&s2<=0&&s3<=0))hit=false;

beginFill((hit)?0xff0000:0x00ff00);
moveTo(a._x,a._y);
lineTo(b._x,b._y);
lineTo(c._x,c._y);
lineTo(d._x,d._y);
endFill();


lineStyle(1);
moveTo(p0._x,p0._y);
lineTo(p1._x,p1._y);
}
function createPoint(x:Number,y:Number):MovieClip
{
var i:Number = getNextHighestDepth();
var p:MovieClip = createEmptyMovieClip("point"+i.toString(),i);
p.beginFill(0);
p.lineTo(7,0);
p.lineTo(0,7);
p.endFill();
p._x = x;
p._y = y;
p.onPress = function(){this.startDrag();}
p.onMouseUp = function(){this.stopDrag();}
return p;
}

Zik.
21.11.2008, 15:37
Вот
это вы намутили!!! :eek:

flazher
22.11.2008, 13:13
Не устаю приводить в пример это (http://flasher.ru/forum/attachment.php?attachmentid=15738&d=1163182585)

Division
22.11.2008, 13:31
flazher, такой вот pixelcheck будет медленно работать. Думаю для задачи с линией, как в твоём первом посте, он ещё подойдёт, но проигрывает аналитическим методам. Представь что будет, если захочешь проверить на столкновение два очень больших объекта.
По поводу оптимизации в твоём примере. Два объекта сталкиваются, если хотя бы один пиксель у них общий. Так что после нахождения первого общего пикселя, нужно заканчивать циклы.

Zik.
22.11.2008, 14:02
Это вовсе не его пример, он его взял с форума, в исходниках

goarcade
22.11.2008, 15:05
на первой странице, я привел пример кода пересечения квадрата линией(бесконечной).
теперь же вот код пересечения квадрата отрезком:

ловите:)

//точки отрезка:
var p0:MovieClip = createPoint(170,270);
var p1:MovieClip = createPoint(300,100);

//точки квадрата:
var a:MovieClip = createPoint(200,200);
var b:MovieClip = createPoint(300,200);
var c:MovieClip = createPoint(300,300);
var d:MovieClip = createPoint(200,300);

onEnterFrame = function()
{
_root.clear();

var hit:Boolean = true;


var dx:Number = p1._y-p0._y;
var dy:Number = p0._x-p1._x;
var s0:Number = (a._x-p0._x)*dx+(a._y-p0._y)*dy;
var s1:Number = (b._x-p0._x)*dx+(b._y-p0._y)*dy;
var s2:Number = (c._x-p0._x)*dx+(c._y-p0._y)*dy;
var s3:Number = (d._x-p0._x)*dx+(d._y-p0._y)*dy;
if( (s0> 0&&s1> 0&&s2> 0&&s3> 0)||
(s0<=0&&s1<=0&&s2<=0&&s3<=0))hit=false;

s0 = Math.min(
(a._y-d._y)*(p0._x-d._x)+(d._x-a._x)*(p0._y-d._y),
(a._y-d._y)*(p1._x-d._x)+(d._x-a._x)*(p1._y-d._y));

s1 = Math.min(
(b._y-a._y)*(p0._x-a._x)+(a._x-b._x)*(p0._y-a._y),
(b._y-a._y)*(p1._x-a._x)+(a._x-b._x)*(p1._y-a._y));

s2 = Math.min(
(c._y-b._y)*(p0._x-b._x)+(b._x-c._x)*(p0._y-b._y),
(c._y-b._y)*(p1._x-b._x)+(b._x-c._x)*(p1._y-b._y));

s3 = Math.min(
(d._y-c._y)*(p0._x-c._x)+(c._x-d._x)*(p0._y-c._y),
(d._y-c._y)*(p1._x-c._x)+(c._x-d._x)*(p1._y-c._y));

if(hit&&(s0>0||s1>0||s2>0||s3>0))
hit = false;

beginFill((hit)?0xff0000:0x00ff00);
moveTo(a._x,a._y);
lineTo(b._x,b._y);
lineTo(c._x,c._y);
lineTo(d._x,d._y);
endFill();


lineStyle(1);
moveTo(p0._x,p0._y);
lineTo(p1._x,p1._y);
}
function createPoint(x:Number,y:Number):MovieClip
{
var i:Number = getNextHighestDepth();
var p:MovieClip = createEmptyMovieClip("point"+i.toString(),i);
p.beginFill(0);
p.lineTo(7,0);
p.lineTo(0,7);
p.endFill();
p._x = x;
p._y = y;
p.onPress = function(){this.startDrag();}
p.onMouseUp = function(){this.stopDrag();}
return p;
}

bootaka
22.11.2008, 18:23
вот спасибо. мне это как раз и надо было. :)

flazher
22.11.2008, 18:35
Bootaka, вообще-то тему я создал (:D) Но все равно спасибо.