# Aufbau meines Top Down Shooters



## stulleman (5. Feb 2013)

Hallo zusammen 

Ich bin gerade dabei ein halbwegs "ernsthaftes" Spiel mit Slick2d zu schreiben. Deswegen ist es mir wichtig nicht nur alle Funktionen irgendwie zusammen zu bauen, sodass es am Ende irgendwie funktioniert, sondern das es halbwegs "professionell" ist. Deshalb erhoffe ich mir viele Tipps der Community 

Zu aller erst das Spielprinzip:
Es ist sehr stark an das Spiel Teleglitch angelehnt, nur ohne diese Sicht-Features. Das heißt, es gibt einen Spieler, den man von oben sieht, der ein Inventar mit verschiedenen Gegenständen und Waffen hat. Das Level ist komplett sichtbar, oder vielleicht nur der Raum in dem man sich zur Zeit befindet.
Hält man die rechte Maustaste gedrückt, zielt der Spieler (Falls man eine Waffe in der Hand hat), und mit einem Linksklick wird geschossen oder benutzt. Das heißt dieses Prinzip soll für alle Items gelten, auch wenn es ein Medipack ist. (Rechtsklick halten um das Medipack raus zuholen und Linksklick um es zu benutzen) 

Mein erster Entwurf sieht jetzt so aus:






Die Methoden des Pistole usw. werden dann wie folgt aufgerufen:


```
Item item = inventory. getSelectedItem();
    if(item instanceof Pistol) {
        Pistol pistol = (Pistol) item;
        
        if(leftMousePressed && rightMouseDown) {
            pistol.shoot();
        }
        if(reload) {
            pistol.reload();
        }
    }
```

Ich weiß jetzt schon das dieser Entwurf nur über Umwege funktionieren würde. Zum Beispiel kennt das MediPack den Player überhaupt nicht, kann ihm also auch kein health geben.
Desweiteren habe ich keine Idee wo z.B. die Bullets der Pistolen gespeichert werden? In der Pistole selber? Wie werden die dann geupdated und gerendert?

Ich denke das reicht erstmal und hoffe es gibt genug Stoff zum diskutieren


----------



## Bizarrus (5. Feb 2013)

> Desweiteren habe ich keine Idee wo z.B. die Bullets der Pistolen gespeichert werden? In der Pistole selber?


In der tat. Am besten in jeder "Pistole" bzw bei dir ist es ja "Revolver". Pistole selber würde ich ausschliesslich als Interface nutzen.


----------



## Skanky (5. Feb 2013)

Hiho,

Ich würde für die Items ein Interface (Usable) vorschlagen oder ne Klasse Item von die Pistole/MediPack usw erben, bzw das Interface Implementieren. Im interface/klasse sollte es dann eine Methode void use() geben die dann quasi die jeweilige aktion ausführt. Dann sparst du die die instanceof Prüfung en für jedes Item. Am besten übergibst du gleich da Objekt, welches so sachen wie "reload, leftMousePressed, rigth..." dann kannst du alles in dem item ab frühstücken.

Der Aufruf im Code wäre dann nur noch:

```
inventory.getSelectedItem().use(control);
```

und bei pistole würde die use Methode dann so aussehen:

```
public void use(final ? control) {
    if (control.isLeftMousePressed() && control.isRigthMouseDown()) {
        this.shoot();
    }

    if (control.isReload()) {
        this.reload();
    }
}
```
_Das ? steht für die entsprechende Klasse welche deine Eingaben verwaltet_

Und das ganze halt für jedes Item.

So würde ich das ganze machen  

Grüße Skanky (rico)

die gute EDIT meint:
Ach jetzt sehe ich erst das du ja schon von Item erbst, dann brauchst du da nur noch ne abstracte Methode "use"


----------



## stulleman (5. Feb 2013)

@Skanky


> Ach jetzt sehe ich erst das du ja schon von Item erbst, dann brauchst du da nur noch ne abstracte Methode "use"



Genau das hatte ich vorher gemacht, nur mit dem kleinen Unterschied das ich einen Key-Code und eine boolean Variable die festhält ob pressed oder down, übergeben habe.
Viel besser ist es denke ich wirklich das ganze Input Objekt zu übergeben.

Ein paar Fragen habe ich dennoch dazu. Wann wird use() immer aufgerufen? Soll Player trotzdem noch gucken welche Tasten gedrückt wurden? Wäre das dann nicht unnötigerweise doppelt?
Damit die use()-Methode nämlich einen wirklichen Sinn hat darf sie nur aufgerufen werden, wenn sie wirklich benötigt wird, und das geht nur indem man vorher guckt welche Taste gedrückt wurde.

Vielleicht meintest du ja auch so etwas wie update(input)? Sodass das aktuelle Item in jedem update guckt ob eine Taste gedrückt wurde?

Und @Bizarrus, wenn keiner etwas einzuwenden hat, werde ich das dann auch so machen


----------



## Skanky (5. Feb 2013)

Warum die use() kann doch so oft aufgerufen werden wie sie will, sie macht ja nur was wenn entsprechende Testen gedrückt, bzw Voraussetzungen erfüllt sind.



stulleman hat gesagt.:


> Vielleicht meintest du ja auch so etwas wie update(input)? Sodass das aktuelle Item in jedem update guckt ob eine Taste gedrückt wurde?



Genau das.

Bei meine Game hab ich ne eigenen Listener implementiert, der die gesamten Input sachen abfängt und den dann für das restliche Programm bereit stellt.

Bei mir läuft das Spiel in etwa so ab (GameLoop):

{while}
   checkInput()
   update()
   move()
   render()
{/while}

In der Update Methode wird dann halt bei Player use() aufgerufen. Ob das aber der "beste" Weg ist weiß ich nicht, bei mir funktioniert das ganz gut. Ich buffere die Eingaben und werte sie dann später da aus wo ich sie brauche.

Ich hoffe ich habe dich jetzt nicht noch mehr verwirrt :autsch:


----------



## stulleman (5. Feb 2013)

Okay, also ich habe jetzt schon Nachteile dieses Entwurfes feststellen müssen.
Z.B. werden die Bullets nur gezeichnet und geupdatet solange sich die zugehörige Waffe auch noch im Inventar befindet.
Habt ihr vielleicht eine Idee wo es noch sinnvoll wäre sie zu speichern?


----------



## Fu3L (5. Feb 2013)

Eigentlich sollte irgendein Teil des Codes feststellen, dass der Spieler eine Taste gedrückt hat, was dazu führt, dass use() aufgerufen wird. use() die ganze Zeit aufzurufen, um dann dort zu prüfen, ob überhaupt etwas benutzt wird, ist eher falschrum implementiert.

Du meinst vermutlich Kugeln, die abgefeuert werden? Kugeln im Magazin brauchen ja nur eine Zahl sein, die in der Waffe gespeichert wird. Sobald du aber eine Kugel abschießt, sollte diese eine Instanz der Klasse Kugel sein und vom Spiel direkt verwaltet werden (auf der gleichen Ebene wie der Spieler oder die Gegner)


----------



## stulleman (5. Feb 2013)

Ja das hatte ich ja auch geschrieben, dass das die falsche Herangehensweise ist, und deswegen eine Vorschlag zur Umbenennung in update() gemacht habe. Ich persönlich fände use() auch besser, aber das ist meiner Meinung nach nicht implementierbar in dem Szenario.
Das das zu beginn nur Zahlen sind ist mir klar. Du schlägst vor das die Bullets in Level gespeichert werden, dazu muss die Pistole aber wieder Zugriff darauf haben müssen, was keine schöne Struktur ergibt...


----------



## Helgon (5. Feb 2013)

Die Bullets sind dann einfach eigene entities und um die alle mit einander zu "verbinden" brauchste dann eben einen entities-manager der sich um alle sich in der szene bwegenden, benutzenden oder was auch immer objekte kümmert


----------



## schalentier (5. Feb 2013)

stulleman hat gesagt.:


> Ich persönlich fände use() auch besser, aber das ist meiner Meinung nach nicht implementierbar in dem Szenario.



Magst kurz skizzieren, warum das nich implementierbar ist?

In den meisten Spielen ist doch die Anzahl der Aktionen, die der Spielen machen kann recht beschraenkt. Das wuerd ich auch so modellieren. Also z.B. koennte man definieren, dass ein Spieler ein Item immer auf zwei Arten "benutzen" kann, z.B. mit der linken und der rechten Hand. Dann gibts dafuer die abstrakten Methoden useLeft() und useRight(). In der update-Methode von Player machst die Keyboard-Ueberpruefung und rufst dann am ausgewaehlten Item useLeft() oder useRight() auf. Die Items wuerden dann so aussehen:

```
class Pistole extends BaseItem {
  public void useLeft() { this.shoot(); }
  public void useRight() { this.reload(); }
}
class MediPack extends BaseItem {
  public void useLeft() { this.heal(); }
  public void useRight() { this.throw(); }
}
```

Zusaetzlich macht eine update() Methode bei Item aber sehr viel Sinn, da Items auch Dinge zeitgesteuert machen koennen (z.B. Cooldown).

Kannst natuerlich auch mehr als die beiden use Methoden machen, je nach Anforderung.



stulleman hat gesagt.:


> Das das zu beginn nur Zahlen sind ist mir klar. Du schlägst vor das die Bullets in Level gespeichert werden, dazu muss die Pistole aber wieder Zugriff darauf haben müssen, was keine schöne Struktur ergibt...



Wie Helgon bereits sagte, du brauchst ne Verwaltungsklasse fuer deine ganzen Entities. Die wuerde ich World nennen und jedes Element der Welt hat ne Referenz auf die World.

Dort gibts dann Factory- und Hilfsmethoden, wie z.B. createShoot( direction ), createItem(...), etc. 

Nur so meine Gedanken ;-)


----------



## stulleman (6. Feb 2013)

Okay nachdem ich mir alle Tipps angeguckt habe, habe ich mir erlaubt von allem etwas in meine Lösung einfließen zu lassen 






Die Level Klasse ist jetzt auch gleichzeitig mein Entity-Manager.
Jedes Item wird immer upgedated (Z.B. für Hitze), können aber nur über use(Input input) benutzt werden.
Das heißt, wenn eine Taste gedrückt wurde, wird das an das selektierte Item weiter gegeben und es muss selber gucken was zu tun ist. Über level.getPlayer() lässt sich dann bequem vom mediPack aus die HP steuern.

Seht ihr noch Probleme? Wenn nicht danke ich euch erstmal für die Tipps!


----------

