Programuję prostą grę asteroid w Javie. I znajdź ten problem (nie jest to problem, moje rozwiązanie działa idealnie, ale wygląda brzydko). Chcę tylko wiedzieć, czy istnieje sposób na uproszczenie mojego kodu.

W mojej grze jest kilka obiektów. Statek, Meteor, Pocisk i Moneta. Wszystkie są podklasą GameObject . Aby radzić sobie z kolizjami, w klasie MyGame mam te funkcje.

private void ship_hit_meteor(Ship ship, Meteor meteor){}
private void bullet_hit_meteor(Bullet bullet, Meteor meteor){}
private void ship_hit_coin(Ship ship, Coin coin){}
//...and so on

Aby sprawdzić kolizję, umieściłem wszystkie obiekty w jednym dużym objArray . Następnie iteruję tablicę, aby sprawdzić kolizje. Oto jak to robię: ale wyobraź sobie, że mam 100 rodzajów obiektów.

//inside the collision loop
GameObject a = objArray[i];
GameObject b = objArray[j];
if(a instanceof Ship && b instanceof Meteor ){
    ship_hit_meteor((Ship)a, (Meteor)b);
}
else if(a instanceof Meteor && b instanceof Ship){
    ship_hit_meteor((Ship)b, (Meteor)a);
}
else if(a instanceof Bullet && b instanceof Meteor){
    bullet_hit_meteor((Bullet)a, (Meteor)b);
}
else if(a instanceof Meteor && b instanceof Bullet){
    bullet_hit_meteor((Bullet)b, (Meteor)a);
}
//... end of the loop

Czy jest jakiś sposób, aby to uprościć?

Dzięki.

0
hamdirizal 19 listopad 2019, 17:52
8
Myślę, że to powinno być właściwe miejsce codereview.stackexchange.com
 – 
Tony
19 listopad 2019, 17:55
4
Gdzie jest różnica między Bullet trafieniem Meteor a Meteor trafieniem Bullet?
 – 
GameDroids
19 listopad 2019, 17:55
2
Możesz mieć abstrakcyjną metodę w GameObject zwaną kolizją(), którą implementuje każda podklasa. Niech zajmie inny GameObject, a następnie obsłuży każdy obiekt w implementacji. Tj. w Ship.collision(GameObject a) możesz mieć instrukcję switch dla
 – 
Tyler
19 listopad 2019, 17:57
Niezależnie od tego, kto do kogo trafi, nie utworzyłbym 100 metod w twojej klasie GameObject, ale zaimplementował kilka prostych metod hit(GameObject object) w każdej z twoich pojedynczych klas. Wtedy możesz je przeciążyć. Załóżmy, że w swojej klasie Ship możesz zaimplementować hit(Meteor meteor){...}, a może hit(Bullet bullet). Potem decydujesz, czy zniszczysz statek, czy zredukujesz jego punkty życia, czy cokolwiek. Możesz go po prostu wyzwolić, wywołując a.hit(b) bez faktycznego "wiedzenia" w czasie wykonywania, jaka jest klasa a lub b.
 – 
GameDroids
19 listopad 2019, 18:02
2
Jeśli twój kod działa, to jest poza tematem i powinien zostać poproszony o sprawdzenie kodu, jak wspomniał wcześniej Tony.
 – 
Roddy of the Frozen Peas
19 listopad 2019, 18:03

4 odpowiedzi

Może uda ci się stworzyć interfejs, powiedzmy „SpaceObject”, a wszystkie klasy oddziałujące na nią to implementują. Interfejs ma metodę handleCollision () i klasy powinny ją przesłonić. Tam umieszczasz logikę kolizji, uszkodzenia itp. Do HandlerService (miejsca, w którym żyje twój fragment) po prostu otrzymujesz listę SpaceObjects i wywołujesz ich metodę handleCollision.

0
Svilen Yanovski 19 listopad 2019, 17:57

Chociaż nie mam pojęcia o Javie, ale myślę, że twój kod wymaga zastanowienia się nad organizacją podprogramów. Wolałbym raczej zdefiniować dla każdego obiektu 1 własną procedurę „uderzenia”. W głównym przepływie sprawdź pierwszy obiekt z poprawną listą nazw obiektów, po czym wywołaj odpowiednie "object.hitting" z parametrem 2. Sprawdzanie poprawności parametru wypisuje pojedynczą liczbę lub 0, a możesz tutaj " przełączanie ”ponownie.

0
Zoltán Gergely Kis 19 listopad 2019, 18:14

Jeśli masz 100 typów obiektów, napiszesz 5050 metod, jeśli napiszesz oddzielną metodę dla każdej kombinacji typów obiektów. (formuła jest metodami n(n-1)+n, jeśli istnieje n typów). I to nawet nie bierze pod uwagę, jak wysłać do właściwego, z czym tutaj się zmagasz.

Lepszym podejściem byłoby posiadanie ogólnej metody obsługi kolizji, która wie, jak radzić sobie ze wszystkimi kolizjami w oparciu o właściwości kolidujących obiektów. Takie właściwości można następnie wyrazić jako metody, razem z metodami dodatkowymi, które pozwalają logice kolizji manipulować zderzającymi się obiektami. na przykład

public interface Collides {
    // properties
    int damageDealtOnImpact();
    boolean isReward();
    boolean isIndestructible();
    boolean isDestroyedOnImpact();

    // impact methods
    void damage(int damage);
    void destroy();
    void split();
    void changeCourse(Vector impactVector);

    // ... and so on, whatever you need
}

W ten sposób dodawanie typów obiektów powinno być stosunkowo bezbolesne. Chociaż czasami mogą być potrzebne nowe właściwości dla nowych typów obiektów. W takim przypadku wpłynie to na ogólną metodę obsługi kolizji i może być konieczne zaimplementowanie dodatkowych właściwości w istniejących obiektach. Ale to przebija dodawanie 101 nowych metod i wysyłanie do nich.

1
bowmore 20 listopad 2019, 10:14

Najpierw sprawdzasz kolizje za pomocą jakiejś biblioteki z czterema drzewami bez odniesienia do typu obiektu.

Zobacz tę odpowiedź Quadtree do wykrywania kolizji 2D oraz Sprawna (i dobrze wyjaśniona) implementacja Quadtree do wykrywania kolizji 2D

Wtedy… możesz samodzielnie filtrować kolizje.

https://www.iforce2d.net/b2dtut/collision-filtering

Więc skonfiguruj identyfikatory obiektów

public static final short xUSER_SHIP      = 0x0001;
public static final short xUSER_BULLET    = 0x0002;

I maski kategorii kolizji tworzone przez logiczne LUB wszystkiego, co koliduje

public static final short USER_SHIP_MASK = xPICKUP | xWALL | xENEMY_SHIP;

(pamiętając, że musisz stwierdzić, że A uderza B ORAZ, że B uderza A.

A następnie wdrażasz, przechodząc przez listę kolizji

bool collide =
          (filterA.maskBits & filterB.categoryBits) != 0 &&
          (filterA.categoryBits & filterB.maskBits) != 0;

Jednak zrobienie tego wszystkiego wymaga dużo pracy. Możesz preferować ziarnistą siatkę kursu dla każdego kwadratu, która jest większa niż jakikolwiek pojedynczy obiekt (moneta, asteroida itp.). Każdy obiekt aktualizuje swoją pozycję x,y na tej głównej siatce. Dla każdego obiektu, sprawdź otaczające go kwadraty na siatce kursu (może zachodzić na swojego bezpośredniego właściciela, ale nie może ominąć otaczające komórki) w celu sprawdzenia kolizji „wykrywanie kolizji w oparciu o siatkę” lub „wykrywanie kolizji w oparciu o kafelki”. To będzie najłatwiejsze i możesz wdrożyć samodzielnie, jak chcesz. jeśli traktujesz wszystko jako kolidujące kręgi, jest jeszcze łatwiej.

0
londonBadger 19 grudzień 2019, 14:26