Du bist nicht angemeldet.

Werbeanzeige

Jar

Treue Seele

  • »Jar« ist der Autor dieses Themas

Beiträge: 154

Wohnort: Lübeck

Beruf: Softwareentwickler

  • Private Nachricht senden

1

17.02.2017, 08:05

Modellierung einer Entity in einem ECS, die auf andere Entities verweist

Moin Moin,

bei meinem derzeitigen Projekt arbeite ich mit einem Entity Component System.
Jetzt hoffe ich, dass das geballte Wissen des Forums mir weiter helfen kann.

Und zwar habe ich eine Entity die einen Ort auf einer Karte widerspiegeln soll.

Entity {
LocationComponent // for taging
IdComponent | id
NameComponent | name
PositionComponent | position
SizeComponent | width, height
TextureComponent | texture
}

Nun soll man von einem Ort zum anderen reisen können. Dafür ist jeder Ort mit bis zu vier anderen Orten verbunden.
Die Verbindungen können in alle vier Himmelsrichtungen gehen.

Wie kann ich nun diese vier Himmelsrichtungen innerhalb der Entity unterbringen?
Ich hatte zu Anfang in der LocationComponent eine Map<Direction, LocationId> das wurde dann aber irgendwann sehr unkomfortabel.
Dann habe ich überlegt eine NorthLocationComponent, EastLocationComponent.. usw. einzuführen, aber das wirkt irgendwie aufgebläht.

Zusätzlich ist dann auch noch die Frage wie ich einer Spieler Entity mitteile, an welcher Location sie gerade ist?

Fragen über Fragen. Vielleicht habt ihr ein paar Ideen, die mir weiterhelfen.

Beste Grüße,
Jar

BlueCobold

Community-Fossil

Beiträge: 10 629

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

17.02.2017, 08:17

Was genau war an der Map unkomfortabel? Das sollte doch super gehen, wenn du dazu noch ein paar Methoden (auf keinen Fall direkten public-access) oder Funktionen bereitstellst. Ich sehe das als absolut sauberen Weg. Wahlweise kannst du auch eine Component einfügen, die dann halt die 4 Richtungen als optionale Member hat. Auch das wäre sauber. Unsauber wäre es in der Tat dafür 4 direkte Components reinzuknüppeln.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Jar

Treue Seele

  • »Jar« ist der Autor dieses Themas

Beiträge: 154

Wohnort: Lübeck

Beruf: Softwareentwickler

  • Private Nachricht senden

3

17.02.2017, 08:59

Vielleicht ist mein Verständnis eines Components auch falsch.
Meine Components sind derzeit nur Datenbehälter.

Wenn ich jetzt der LocationComponent die Map zurückgebe müsste ich zwangsweise die Hilfsmethoden in die Component packen.
Kann man das so machen, bzw. wird das üblicherweise so gemacht?

Zur anderen Frage noch, wie würdest du nun der Spieler Entity mitteilen, an welchem Ort sie sich gerade befindet?

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Jar« (17.02.2017, 09:09)


BlueCobold

Community-Fossil

Beiträge: 10 629

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

4

17.02.2017, 12:12

Nun, du hast außer den Components üblicherweise ja auch Systeme, die die Components verarbeiten. Dort steckt dann die Logik. Damit klärt sich auch, wie man dem Spieler mitteilt, wo er ist: Die Daten dafür stecken in einer Component und irgendein System wertet die aus. Welches System das bei dir ist, kann ich natürlich nicht wissen ;)
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Renegade

Alter Hase

Beiträge: 423

Wohnort: Berlin

Beruf: Certified Unity Developer

  • Private Nachricht senden

5

17.02.2017, 14:26

Hey Jar,
mit "von einem Ort zum anderen Reisen" meinst du sicherlich eine Art Pathfinding von Punkt A zu Punkt B? Wenn ja, wäre doch folgendes möglich:
-CurrentLocationComponent speichert lediglich die aktuelle Position (x,y)
-Sollte durch Input irgend ein Ziel festgelegt werden, erhält die Entity eine neue TargetLocationComponent (x,y des Ziels), hier sollte dann ein InputSystem auswerten, ob die Eingabe auf der Karte ist und ggf. vom Koordinatensystem Input zu Map übersetzen
-Ein System (z.B. MoveEntitySystem) reagiert auf TargetLocationComponents und arbeitet die Daten solange ab, bis die CurrentLocationComponent die selben Werte hat (x und y sind identisch)
-Die allgemeinen Daten über deine Karte solltest du natürlich in einer weiteren Entity speichern, die dann MapEntity o.ä heißt, die ggf. dann TileEntitys speichert (bei Tile-Maps z.B.)
-Auf die MapEntity kann das MoveEntitySystem zugreifen um zu erfahren wie es einen Pfad bestimmt ggf. lohnt sich ein weiteres PathfindingSystem, wenn man es aufdröseln möchte

PS: Mit welcher Sprache/Framework arbeitest du denn, wenn ich fragen darf?
Liebe Grüße,
René

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »Renegade« (17.02.2017, 14:38)


Jar

Treue Seele

  • »Jar« ist der Autor dieses Themas

Beiträge: 154

Wohnort: Lübeck

Beruf: Softwareentwickler

  • Private Nachricht senden

6

17.02.2017, 20:54

@Blue. Ja ich habe auch einige Systeme.
Ich habe aber erstmal nur die für mich wichtigen Details erwähnt.
Mein MapSystem speichert nun auch tatsächlich die Positionen der Spieler.

Nun habe ich folgendes überlegt. Ich habe mir eine JSON Datei erstellt welche die Orte speichert.
Das ganze wird jetzt schon eingelesen und daraus Entities erstellt. Später wird die JSON Datei dann von einem kleinen Editor erstellt.
Dann kann ich die Erstellung der Maps auch jemanden anvertrauen, der nicht programmieren kann.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    {
      "id": 1,
      "name" : "Easttown",
      "x" : 5,
      "y" : 6,
      "neighbors": {
        "WEST": {
          "class": "java.lang.Integer",
          "value": 2
        },
      },
      "id": 2,
      "name" : "Westtown",
      "x" : 5,
      "y" : 2,
      "neighbors": {
        "EAST": {
          "class": "java.lang.Integer",
          "value": 1
        },
      }
    }


@Renegade
Danke für die ganzen Ideen.
Ich habe tatsächlich schon das meiste was du erwähnt hast auch umgesetzt gehabt.
Ich habe allerdings eine MovementComponent erstellt, welche eine Start und eine Ziel Position hat.

In einem InputSystem nehme ich den Input des Spielers entgegen und sendet eine MoveMessage an ein MessageSystem.
Beim MessageSystem können sich andere Systeme für bestimmte Message Typen registrieren.
Das MovementSystem behandelt alle Entities die eine MovementComponent und eine PositionComponent haben und bewegt dann die Entity vom Start zum Ziel.
Pathfinding ist bisher nicht vorgesehen, da es sich um ein "Würfel" Spiel handelt, der Spieler macht seinen Wurf und kann dann von Ort zu Ort ziehen, bis seine Augenzahl aufgebraucht ist.
Die Idee mit der MapEntity finde ich ganz nett und werde mal schauen ob ich das einzubauen kann.

Ich entwickel das ganze in Java mit Libgdx und Ashley als ECS.

Jar

Treue Seele

  • »Jar« ist der Autor dieses Themas

Beiträge: 154

Wohnort: Lübeck

Beruf: Softwareentwickler

  • Private Nachricht senden

7

19.02.2017, 20:49

Ich habe mich diese Wochenende hingesetzt und das System soweit in Code gegossen.

Hier mal ein Screenshot wie das im Debugmodus schon mal aussieht.


Man kann nun die Spielfigur zwischen den Orten hin und herbewegen.
Die Position der Spieler werden im MapSystem gespeichert und aktualisiert, sobald die Spielfigur eine neuen Ort erreicht hat.
Dafür wird eine ReachedLocationMessage gesendet und alle die es interessiert können daraufhin eine Aktion ausführe.
Später soll dann zum Beispiel ein kleines Banner erscheinen, der den Namen der Stadt anzeigt und mögliche Aktionen.

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Jar« (19.02.2017, 21:06)


Renegade

Alter Hase

Beiträge: 423

Wohnort: Berlin

Beruf: Certified Unity Developer

  • Private Nachricht senden

8

19.02.2017, 22:47

Sieht interessant aus. Was muss man denn in deinem Spiel als König tun - gameplay-mäßig?
Benutzt du für dein MessageSystem dann wiederum Componenten um die Entitäten zu kennzeichnen, welche zuhören, oder machst du das anders?
Liebe Grüße,
René

Jar

Treue Seele

  • »Jar« ist der Autor dieses Themas

Beiträge: 154

Wohnort: Lübeck

Beruf: Softwareentwickler

  • Private Nachricht senden

9

20.02.2017, 08:42

Irgendwann wirds dazu noch eine Projektvorstellung geben.
Als König muss man nichts machen, denn dann ist das Spiel vorbei :) Es geht eher darum der König zu werden.

Ich zitiere mal aus meinem Designpapier:

Zitat

Beginnend mit dem Wunsch des kinderlosen Königs einen Nachfolger zu suchen, lädt er die edelsten, weisesten und mutigsten Helden des Landes ein. Der Held, der die meisten glorreichen Taten bis zum Dahinscheiden des Königs vollbracht hat, wird neuer König werden.[...]

Man zieht dabei über das Spielfeld und gelangt an verschiedene Orte, die unterschiedliche Herausforderungen bereithalten.

Zitat

Schätze sammeln, [...] Ungeheuer besiegen und Prinzessinnen oder Prinzen befreien[...]

Das MessageSystem benachrichtigt andere Systeme falls eine für sie relevante Nachricht eingegangen ist.

Ein System registriert sich über eine Referenz beim MessageSystem.
Weiterhin muss das System dann die Methoden des Interfaces MessageListener<T extends Message> implementieren.
Derzeit ist das nur eine notify(T message) Methode.
Gleichzeitig kann man aber auch Nachrichten mithilfe der send(...) Methode an das MessageSystem schicken, welches die Nachricht dann in einer Queue ablegt.

Das MessageSystem benachrichtigt dann bei jedem Update alle registrierten MessageListener und wirft die Nachricht aus der Queue.
Im Prinzip ist es nur ein Baustein, der nicht für spezielle Entities zuständig ist, sondern der einfach in jedem Frame einmal ausgeführt wird.


Bisher wird die Position des Spielers immer mit der ID des derzeitigen Ortes verknüpft. Das nächste TODO ist jetzt die Pfade zwischen den Orten als eigene Entities zu implementieren und dann die Position des Spielers auf eine Entity zu Mappen. Dann kann man anhand der Spieler ID herausfinden bei welcher Entity er sich befindet. So erhoffe ich mir Ereignisse an bestimmte Pfade zu hängen, wie "Ein Bandit will dich überfallen" oder ähnliches. Vielleicht fällt euch dazu noch eine Idee ein wie man das besser machen könnte.

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Jar« (20.02.2017, 12:52)


Renegade

Alter Hase

Beiträge: 423

Wohnort: Berlin

Beruf: Certified Unity Developer

  • Private Nachricht senden

10

21.02.2017, 16:13

Ich würde für die Transition auch eine eigene Entity erstellen. Dazu gibt es nebst deiner ID eine TransitionComponent die zwei benachbarte IDs aufführt. Eben die verbundenen Orte. Hier könnte dann deine BanditComponent hinein, die einen Zufallswert erhält um zu entscheiden ob das Event ausgelöst werden soll. Oder vielleicht etwas abstrakter mit einer ProbabilityComponent und einer EventComponent. So können Systeme die für Zufall und das Auslösen von Ereignissen zuständig sind auch getrennt sein. Wäre ja denkbar das Events immer, oder nur unter bestimmten Bedingungen, ausgelöst werden müssen.

Du kannst ECS auch sehr gut verwenden um dir den Message Mediator zu sparen. Verwende dafür eine Klasse Pool die Entities in sich trägt (Aggregation). Systeme werden ebenfalls beim Pool eingetragen (Aggregation) und reagieren auf Ereignisse wie Add oder Remove von Components im Pool. Die Components dienen dann ebenfalls als Message/Flags/Events von Entitäten oder zwischen Systemen. Damit die Systeme/Entitäten funktionieren wird dann allgemein nur noch der Pool initialisiert/geupdated.
Liebe Grüße,
René

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Renegade« (21.02.2017, 16:25)


Werbeanzeige