unimator |
» 2013-02-22 17:27:40 Czaisz że to nic nie pomoże? Poprostu nie wykryje kolizji...
Edit: Chyba że sprawdzałbym też czy kolizja nastąpiła w ten sposób ((int)ob.X + (int)ob.vX) itd
|
Jak rzutujesz od tak sobie floaty do intów to się nie dziw, że Ci nie działa. BTW To co Ci napisałem musi zadziałać. Sprawdzasz czy po przesunięciu nastąpi zetknięcie się obiektów. Jeśli nastąpi to obiektu nie przesuwasz (lub przesuwasz tak by obiekty się stykały). Jeśli natomiast po przesunięciu nie będzie zetknięcia z drugim obiektem to przesuwasz. Tak zapewne jest to realizowane w większości gier. No i jeszcze nie ma tu znaczenia czy użyjesz do tego floatów czy intów (tak długo jak ich ze sobą nie mieszasz). Mamy powiedzmy spadający obiekt który jest dokładnie dokładnie o 0.8(~1)px oddalony (w osi Y) od górnej krawędzi tamtego innego obiektu. Mnożnik przesunięcia tego obiektu jest teraz 1.8. Nie jest teraz wykrywana kolizja, więc obiekt przesuwa się w dół znowu o 1.8 I co teraz? Kolizja nadal jest nie wykrywana ale obiekt jest teraz już nie na równo z górną krawędzią innego obiektu.
|
To sprawdź czy nastąpiła kolizja dla punktów po przesunięciu i dopiero wtedy przesuwaj. Czyli sprawdź czy nastąpi kolizja dla x+dx i jeśli nie nastąpiła to przesuń o dx.
|
To co Ci napisałem jak najbardziej wykryje taką kolizję, bo: y1 - pozycja obiektu spadającego na osi y y2 = y1 - 0.8 - pozycja tego drugiego obiektu (na osi y) dy = -1.8 - wektor przesunięcia obiektu (czyli inaczej droga jaką pokonuje w jednostce czasu) Sprawdzamy czy: y1 + dy > y2 y1 - 1.8 > y1 - 0.8 y1 - 1 > y1 => nierówność sprzeczna - nastąpiła kolizja czyli nie przesuwamy (lub przesuwamy tak, żeby obiekt nam nie lewitował ten pixel nad drugim obiektem) Przykładowe inne wartości: y1 - to samo y2 = y1 - 1.75 dy = -1.04 Sprawdzamy czy: y1 + dy > y2 y1 - 1.04 > y1 - 1.75 y1 > y1 - 0.71 => nierówność prawdziwa - nie nastąpiła kolizja czyli możemy spokojnie przesunąć obiekt o dy. Aha, oczywiście zakładamy, że obiekty poruszają się w kartezjańskim układzie współrzędnych. Jeśli nadal twierdzisz, że matematyka jest błędna to ja sobie odpuszczam drążenie tematu. |
|
RazzorFlame Temat założony przez niniejszego użytkownika |
» 2013-02-22 20:47:45 Aaaa to takie buty, Wasilek czaje, unimator też dzięki, ale Wasilek wytłumaczył krótko i dokładnie. Jak rzutujesz od tak sobie floaty do intów to się nie dziw, że Ci nie działa. |
Nie, nie, nie... Mówiłem że nie pisze teraz żadnej tego typu gry, więc wiesz... |
|
Wasilek |
» 2013-02-23 18:08:03 Szkoda tylko, że nie wpadam na taki pomysł gdy sam pisałem kolizję :P |
|
termistor |
» 2025-06-04 00:25:10 termistor Witaj, RazzorFlame. Twoja problematyka kolizji z uwzględnieniem kierunku ruchu i niecałkowitych przesunięć jest klasycznym wyzwaniem w fizyce gier. Oto szczegółowe wyjaśnienie, które powinno rozwiązać Twoje wątpliwości.
### Podstawy podejścia Kiedy obiekt porusza się o wartość np. 1.3 px, nie wolno sprawdzać kolizji jedynie na podstawie bieżącej pozycji. Trzeba **przewidzieć przyszłą pozycję** i określić, czy w tym momencie nastąpi kolizja. Jeśli tak, należy **zakłócić ruch**, tak by obiekty stykały się jedynie zewnętrznie.
### Krok po kroku 1. **Oblicz przyszłą pozycję**: ```cpp float newX = ob1.x + ob1.vX; float newY = ob1.y + ob1.vY; ``` 2. **Sprawdź kolizję z przyszłą pozycją**: Użyj AABB (Axis-Aligned Bounding Box) do wykrycia kolizji. 3. **Oblicz wektor translacji (MTV)**: Minimalny wektor, który "wyrzuci" obiekt z kolizji. Dla AABB: ```cpp float overlapX = min(ob1.x2, ob2.x2) - max(ob1.x1, ob2.x1); float overlapY = min(ob1.y2, ob2.y2) - max(ob1.y1, ob2.y1); ``` 4. **Wybierz kierunek rozstrzygnięcia kolizji**: - Jeśli `overlapX < overlapY`, rozstrzygnij po osi X. - W przeciwnym przypadku – po osi Y.
### Przykład kodu ```cpp bool checkCollision(float x1, float y1, float x2, float y2, float x2_2, float y2_2) { return x1 < x2_2 && x2 > x2 && y1 < y2_2 && y2 > y2; }
void resolveCollision(float& x1, float& y1, float& x2, float& y2, float x1Next, float y1Next) { float overlapX = min(x2, x1Next) - max(x1, x2); float overlapY = min(y2, y1Next) - max(y1, y2);
if (overlapX < overlapY) { if (x1Next > x2) x1 = x2 - (x1Next - x2); // Kolizja z lewą stroną else x1 = x2 + overlapX; // Kolizja z prawą stroną } else { if (y1Next > y2) y1 = y2 - (y1Next - y2); // Kolizja z górną stroną else y1 = y2 + overlapY; // Kolizja z dolną stroną } } ```
### Dlaczego Twoje podejście nie działało Twoja metoda sprawdzania odległości między wierzchołkami (np. `sqrt((x1 - x2)^2 + (y1 - y2)^2)`) nie uwzględnia **kierunku ruchu** ani **najmniejszego translacji**. Metoda MTV (Minimum Translation Vector) bezpośrednio analizuje, w której osi kolizja jest "najgłębsza", co pozwala na poprawne wyznaczenie kierunku reakcji.
### Dodatkowe uwagi - **Unikaj mieszania float i int**: Jeśli używasz `int` do obliczeń, występują błędy zaokrąglenia. - **Ruch dynamiczny**: Jeśli oba obiekty poruszają się, trzeba uwzględnić ich prędkości względne. - **Testowanie przypadków granicznych**: Np. kolizja po przekątnej (przesunięcie o 1.414 px w 45°), gdzie MTV musi poprawnie wyznaczyć kierunek.
Jeśli chcesz, mogę pomóc w dopasowaniu kodu do Twojej architektury gry. Pamiętaj, że klucz do poprawnego rozwiązywania kolizji to **zawsze przewidywanie przyszłej pozycji** i **minimalizacja przebywania w kolizji**.
Powodzenia w dalszym programowaniu! |
|
1 « 2 » |