2013-01-20 17 views
5

Mam listy tablicy jako takie:Jak iterować tylko nad konkretnymi rodzajami elementów?

private List<GameObject> gameObjects = new CopyOnWriteArrayList<GameObject>(); 

GameObject może być jedną z 3 klas: Spaceship, Beam i Asteroid. Wszystkie są podobne, więc trzymam je w jednej tablicy. Jednak statki kosmiczne mają dodatkowo metodę shoot, która jest używana co 100ms w innym wątku (co nazywa się ShootRunnable). Więc chciałbym iterować w nim tylko ponad Spaceship, ponieważ inne nie implementują metody strzelania. Jaki jest najlepszy sposób, aby to osiągnąć?

for (GameObject ob : gameObjects) { 
    if (ob instanceof Spaceship) { 
    ob.shoot(); 
    } 
} 

Czy mogę powtórzyć to przy użyciu czegoś podobnego? Tylko za pomocą odlewu lub czegoś takiego? Proszę pomóż.

Odpowiedz

2

Ścieżka, na której się znajdujesz, jest technicznie wykonalna, choć dobrą zasadą jest, że jeśli zaczniesz używać refleksji, prawdopodobnie zrobisz coś złego. W takim przypadku najmądrzej byłoby mieć dwie kolekcje, jedną dla wszystkich typów gier i jedną dla statków kosmicznych.

+0

O tym też myślałem. Ale wtedy każde działanie związane ze statkiem kosmicznym będę musiał zrobić dwa razy. Więc kiedy dodaję nowy statek kosmiczny, będę musiał dodać go do listy gameObjects i statków kosmicznych? A kiedy go usuniesz, usuń go zarówno z gameObjects, jak i ze statków kosmicznych. :/Ale myślisz, że to najlepszy sposób? –

+0

Prawidłowo. Nie martw się, komputery są szybkie. :) – Will

+0

Ok, więc tak zrobię. Wielkie dzięki –

0

Powinieneś umieścić swoją metodę shoot() w klasie Spaceship, ponieważ żadna asteriod lub promień nie użyje tej metody. Zrób to, powinieneś również zachować co najmniej dwie kolekcje. Jeden z nich powinien zawierać tylko twoje statki kosmiczne.

2

Czy w grze są jakieś inne akcje, które mają miejsce okresowo?

Jeśli tak, można zmienić metodę shoot() na metodę abstrakcyjną (można nazwać periodicAction()) i umieścić ją w klasie GameObject. Klasa Spaceship zaimplementuje tę metodę, strzelając do drugiej klasy z jej specyficznym okresowym zachowaniem i klasą Asteroid, nie robiąc nic.

+0

dodaje niepotrzebną złożoność – Archer

+0

@archer: nie, nie. Powszechną praktyką w tworzeniu gier jest dodawanie funkcji aktualizacji/kroku/kliknięcia/myślenia w każdej jednostce w grze. Przykładem może być kod doom 3 idEntity (linia 172): https://github.com/id-Software/DOOM-3/blob/master/neo/game/Entity.h – Jack

0

wolałbym zrobić w ten sposób:

Iterator<Spaceship> getSpaceships(){ 
    // return Iterator over Spaceship objects through use of instanceof 
} 

... 
Iterator<Spaceship> it = getSpaceships() 
while(iter.hasNext()) it.next().shoot() 

Dla mnie to wygląda bardziej jasne.

+1

"Za każdym razem, gdy sam się piszesz formularza "jeśli obiekt jest typu T1, to zrób coś, ale jeśli jest typu T2, to zrób coś innego," uderz się ". --Scott Meyers, Effective C++ – prasopes

+0

to nie jest mój projektant;) Próbuję tylko zasugerować wykonalne soution – Archer

+0

, ale sugerujesz użycie instanceof, ukrytego tylko wewnątrz iteratora – prasopes

0

Można utworzyć interfejs Action lub metody do GameObject:

public interface Action { 
    void performAction(); 
} 

public abstract class GameObject implements Action { 
    //... 
    public void performAction() { 
     // subclasses should override this method. 
     // otherwise, it will do nothing. 
    } 
} 

a następnie wdrożyć Spaceship:

public class Spaceship extends GameObject { 
    @Override 
    public void performAction() { 
     this.shoot(); 
    } 
} 

Aby Beam i Asteroid, można pozostawić metodę performAction:

Następnie możesz interweniować:

for (GameObject ob : gameObjects) { 
    ob.performAction(); 
} 
Powiązane problemy