Kolizja Rectangle w XNA

0

Problem trapi mnie od bardzo długiego czasu i nie jestem pewien czy jestem za młody żeby to zrozumieć, czy po prostu pomijam jakąś ważną część, ale za nic nie mogę zrozumieć jak napisać prostą, działającą kolizję używając Rectangle - jak w prostych platformówkach, pomijając fakt skoków itp. - po prostu, aby jeden Rectangle, używając WSAD mógł poruszać się po TiledMap'ie zbudowanej z Rectangle oznaczających ściany - i przez nie, normalnie w świecie - nie przenikał.

List<Rectangle> levelHitboxes = new List<Rectangle>();

Lista Rectangle oznaczających ściany. Każdy rectangle ma swoją pozycję w świecie i wymiary równe 32x32.

Vector2 position; // Pozycja gracza
Rectangle playerHitbox; // Hitbox gracza

Gracz również jest Rectangle'm o wymiarach 32x32, gdzie jego X i Y oznacza Vector2 position.

Próbowałem wiele razy umieścić kolizję, która wygląda mniej więcej tak:

// Dla skrótu - pozycje ściany
int RLEFT = rect.X;
int RRIGHT = rect.X + rect.Width;
int RUP = rect.Y;
int RDOWN = rect.Y + rect.Height;
// Dla skrótu - pozycje gracza
int PLEFT = playerHitbox.X;
int PRIGHT = playerHitbox.X + playerHitbox.Width;
int PUP = playerHitbox.Y;
int PDOWN = playerHitbox.Y + playerHitbox.Height;
foreach(Rectangle rect in levelHitboxes){
if(playerHitbox.Intersects(rect)){
    if(PRIGHT > RLEFT && PLEFT < RLEFT){
        // Collision RIGHT
        collisionRight = true;
    }
    if(PLEFT < RRIGHT && PRIGHT > RRIGHT){
        // Collision LEFT
        collisionLeft = true;
    }

    if(PDOWN > RUP && PUP < RUP){
        // Collision DOWN
        collisionBot = true;
    }
    if(PUP < RDOWN && PDOWN > RDOWN){
        // Collision TOP
        collisionTop = true;
    }
}
}

Kolizja świruje tylko w dwóch osiach (X i Y), gdy działa tylko jedna, wszystko jest jak należy. Przykładem jest dotknięcie góry ściany przez dół gracza i nagle odpala się kolizja Left Right i Top, gdzie gracz nie dotyka swoją prawą oraz lewą stroną niczego.
Czytałem sporo na temat kolizji w Internecie, może nie dokładnie, sam nie wiem, ale nigdy nie znalazłem sensownego rozwiązania. Nie chcę zbytnio korzystać z dodatkowych bibliotek czy silników, chciałbym poznać sam dogłębne rozwiązanie tego problemu, bo wydaje mi się, że nie jest aż takie trudne, ale brakuje mi tego "klucza".

0

Jeśli dobrze rozumiem to powinno być tak:

if(PRIGHT>=RRIGHT){
        // Collision RIGHT
        collisionRight = true;
    }
    if(PLEFT<=RLEFT){
        // Collision LEFT
        collisionLeft = true;
    }
 
    if(PDOWN>=RDOWN){
        // Collision DOWN
        collisionBot = true;
    }
    if(PUP<=RUP){
        // Collision TOP
        collisionTop = true;
    }
0

@dam1an
Nie koniecznie to zadziała. Oto przykład z zastosowaniem Twojego sposobu:
user image

Jako że mamy pętle foreach, to dla każdego Rectangle sprawdzana jest kolizja.
Gracz jest zaznaczony na biało.
Załóżmy że aktualnie badamy przypadek 1, gdzie aktywna ściana zaznaczona jest na czerwono, a ściana z przypadku 2 na szaro. Gracz się z nim styka, czyli następuje kolizja która jest zaznaczona niebieską linią, wtedy collisionRight = true; i tutaj jest OK.
Teraz sprawdzamy przypadek 2, gdzie aktywna jest inna ściana zaznaczona na czerwono, a ściana z przypadku 1 na szaro. Gracz się z nią nie styka, ale z instrukcji

if(PRIGHT >= RRIGHT)

wychodzi prawda, ponieważ gracz jest dalej niż prawa strona ściany, dlatego nadal mamy collisionRight = true; mimo, że kolizji nie ma.

Ten problem jest zarówno w instrukcji if(playerHitbox.Intersects(rect)) jak i bez niej. Z "Intersects" problem jest taki, iż nagle wszystkie zmienne (collision: top, bot, left, right) stają się True i gracz nie może ruszyć się w ogóle.

Dlatego dodaje jeszcze PLEFT < PRIGHT, żeby sprawdzić czy gracz w ogóle dotyka ściany.

0

Jest mnóstwo informacji o sprawdzaniu takiej kolizji na internecie. Wystarczy poszukać w google.
Możesz też sobie to rozrysować na kartce i pomyśleć, bo akurat kolizje takich obiektów są trywialne do sprawdzenia.

Najlepiej sprawdzaj kiedy kolizja NIE występuje.

1 użytkowników online, w tym zalogowanych: 0, gości: 1