Autor Wątek: Kolizja w arcanoidzie.  (Przeczytany 1504 razy)

Offline PRG3D

  • Użytkownik

# Maj 30, 2007, 13:19:34
Witam.

Robiąc wykrywanie kolizji w grze arcanoid natknąłem się na pewien problem. Zrobiłem kolizje piłka - tacka, tacka - ściany, piłka - ściany. Musze teraz zrobić kolizje piłka - klocek. I tu się pojawia problem. Po wykryciu kolizji musze sprawdzić w którą ściankę klocka walnęła piłka. Kolizje wykryje, ale nie potrafię określić w którą ściankę ma uderzyć. Jakby ktoś miał jakiś pomysł to bardzo proszę o jak najszybszą odpowiedź.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Wyszo

  • Użytkownik

# Maj 30, 2007, 13:29:21
Najprościej, czy sensownie?

Metoda najprostsza:

Patrzysz na klocek w ten sposób:

x to klocek, dookoła niego jest 9 obszarów wyznaczanych przez proste, w których zawierają się krawędzie klocka

_|_|_
_|x|_
_|_|_

Teraz po prostu sprawdzasz, w którym z obszarów znajduje się środek piłeczki i w ten sposób wiesz, gdzie jest piłka w stosunku do klocka. Błędy tej metody są oczywiste (nieładny kod, działa tylko dla ruchu piłki w 4 kierunkach), ale to najprostsze podejście.

HIsTronIC

  • Gość
# Maj 30, 2007, 13:30:01
Może powinieneś sprawdzić, z której strony leciała piłeczka przed kolizją. Wtedy mógłbyś porównać współrzędne piłeczki względem cegły. Bo jeśli leciała by z góry i z prawej strony to wiadomo, że nie uderzyła by o lewy, ani dolny bok cegły.

Offline Wyszo

  • Użytkownik

# Maj 30, 2007, 13:38:12
No właśnie jeden ze sposobów to taki, jak podał Hi_Tronic - zapisujesz prostą v, do której należy wektor prędkości piłeczki. Sprawdzasz, gdzie jest piłka, tak jak napisałem w 2 poście, dzięki temu wybierasz dwa boki a i b, z którymi piłeczka mogła się zderzyć. Zapisujesz równania prostych, do których należą a i b, wyliczasz punkty kolizji prostej v z a oraz v z b i sprawdzasz, który z punktów znajduje się bliżej środka piłeczki - jest to punkt kolizji. W zależności od tego, czy leży on na prostej a czy b uzyskasz, w który bok uderzyła piłeczka.

To podejście sprawdza się dla ruchu piłki w każdym kierunku, ale jest troszkę trudniejsze do napisania.

Offline Netrix

  • Redaktor
    • Netrix’s devBlog

# Maj 30, 2007, 15:46:59
Ja zrobiłem inaczej, nie sprawdzałem, z której strony się odbija tylko sprawdzałem kierunek, jeśli poziom to zmieniałem prędkość piłki w pionie na przeciwną.

Offline ziomber

  • Użytkownik

  • Zbanowany
# Maj 30, 2007, 15:56:57
glupim pomyslem moze byc:

Klocek ma 4 wierzcholki
sprawdzamy najpierw czy kolidujemy z tymi punktami (czy dystans jest mniejszy od promienia kuli) dalej sprawdzamy odleglosc od kazdego z boków  tak to wyglada w 3D
function ClosestPointOnLine (vA, vB, vPoint : t3dpoint) : t3dpoint;
//Returns the closest point on a line to a given point

var
  vVector1, vVector2, vVector3 : t3dpoint;
  vClosestPoint : t3dpoint;
  D, T : Single;

begin
  //First, we create a vector from our end point vA to our point vPoint
  vVector1.X := vPoint.X - vA.X;
  vVector1.Y := vPoint.Y - vA.Y;
  vVector1.Z := vPoint.Z - vA.Z;

  //Now we create a normalized direction vector from end point vA to end point vB
  vVector2.X := vB.X - vA.X;
  vVector2.Y := vB.Y - vA.Y;
  vVector2.Z := vB.Z - vA.Z;
  vVector2 := Normalize (vVector2);

  //Now we use the distance formula to find the distance of the line segment
  D := n3ddistance(vA, vB);

  //Using the dot product, we project the vVector1 onto the vector vVector2. This essentially
  //gives us the distance of our projected vector from vA
  T := Dot(vVector2, vVector1);

  //If our projected distance from vA, "t",  is greater than or equal to 0, it must be closest to the end point
  //vA.  So we return this end point.
  if (T<=0) then
  begin
    Result := vA;
    exit;
  end;

  //If our projected distance from vA, "t", is greater than or equal to the magnitude or distance of the line
  //segment, it must be closest to the end point vB, so we return vB.
  if (T >=D) then
  begin
    Result := vB;
    exit;
  end;

  //Here we create a vector that is of length T and in the direction of vVector2
  vVector3.X := vVector2.X * T;
  vVector3.Y := vVector2.Y * T;
  vVector3.Z := vVector2.Z * T;

  //To find the closest point on the line, we just add vVector3 to the original end point vA
  vClosestPoint.X := vA.X + vVector3.X;
  vClosestPoint.Y := vA.Y + vVector3.Y;
  vClosestPoint.Z := vA.Z + vVector3.Z;

  Result := vClosestPoint;
end;

pozniej sprawdzamy dokladnie gdzie kulka jest najblizej (jak mamy kolizje) [czyli czy mamy kolizjez punktem czy te bokiem, wybieramy to najbliższe i mamy kolizje)


Drugim pomysłem jest, żeby stowrzyć wirtualne klocki tak, ze mamy klocek i wirtualny klocek (ten wirtualny jest wiekszy od tego co widzimy na ekranie gdzies tak o promien kuli (zobacz obrazek) to szare to klocek ktory widzimy, a to wieksze to ten wirutalny
pozniej tylko test czy kulka jest w srodku wirtualnego klocka. (i ta funkcja jak valudate = true, sprawdza czy przypadkiem podano prawidlowe wartosci. X,y - pozycja kuli. Tutaj podaje sie dwa punkty X1,Y1 i X2,Y2, które tworzą prostokąt (bounding box)

function n2disPointinRect(X, Y, X1, Y1, X2, Y2 : single; validate : boolean)        : Boolean;
var
maxx,minx : single;
maxy,miny : single;
begin
result := false;
if validate = true then   begin
if x1 > x2 then begin maxx := x1; minx := x2; end else begin maxx := x2; minx := x1; end;
if y1 > y2 then begin maxy := y1; miny := y2; end else begin maxy := y2; miny := y1; end;
if ((X > MINX) and (X < MAXX) and (Y > MINY) and (Y < MAXY)) then
  Result := true;

end else
begin
if ((X > x1) and (X < x2) and (Y > y1) and (Y < y2)) then
  Result := true;
end;
end;

tylko ze tutaj bedzie maly haczyk, bo trzeba odpowiednio dobrac wielkosci zeby przez przypadek nam klockow wyzej polozonych nie zbijal tylko pilka zeby sie odbijala.

Wiecej pomyslow nie mam :X
« Ostatnia zmiana: Maj 30, 2007, 16:05:13 wysłana przez ziomber »

Offline PRG3D

  • Użytkownik

# Maj 30, 2007, 16:52:05
No właśnie jeden ze sposobów to taki, jak podał Hi_Tronic - zapisujesz prostą v, do której należy wektor prędkości piłeczki. Sprawdzasz, gdzie jest piłka, tak jak napisałem w 2 poście, dzięki temu wybierasz dwa boki a i b, z którymi piłeczka mogła się zderzyć. Zapisujesz równania prostych, do których należą a i b, wyliczasz punkty kolizji prostej v z a oraz v z b i sprawdzasz, który z punktów znajduje się bliżej środka piłeczki - jest to punkt kolizji. W zależności od tego, czy leży on na prostej a czy b uzyskasz, w który bok uderzyła piłeczka.

To podejście sprawdza się dla ruchu piłki w każdym kierunku, ale jest troszkę trudniejsze do napisania.

Myślałem nad takim czymś, ale nie za bardzo widzę to w akcji. To będzie dość powolne(chyba), nie można jakoś szybciej?

Offline Wyszo

  • Użytkownik

# Maj 30, 2007, 17:32:14
Zapewniam, że to będzie działało błyskawicznie. Nie będzie żadnego spadku wydajności bo obliczeń jest dosłownie kilka na klatkę.