Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

11

29.08.2018, 21:27

Ich würde ein EnumRegistry-Interface bauen. Jede Profession ist gleichzeitig auch ein Typ und implementiert dazu ein Interface.
interface PseudoEnum {
String name();
}

Dann kannst Du solche Methoden in der Registry einbauen:
<T extends PseudoEnum> Set<T> getEnumValues( Class<T> pseudoEnumInterface )
<T extends PseudoEnum> T resolveEnumName( String enumValueName, Class<T> pseudoEnumInterface )
<T extends PseudoEnum> void register( Class<T> pseudoEnumInterface, T enumValue )

Jetzt haben wir immer noch das Problem des statischen Zugriffs. Das kann man ganz ok über einen Context lösen. Dieser kann, wenn es sonst zu unpraktisch ist, per ThreadLocal zugänglich sein.
class GameContext {
EnumRegistry getEnumRegistry()
AssetManager getAsssetManager()
...
}

GameContext.get().getEnumRegistry()....
oder mit statischen Platzhaltern, die das ganze verschleiern dann:
GameContext.getEnumRegistry()


Wenn Du's per ThreadLocal machst, kannst Du relativ elegant den ganzen Stress mit GameContext rumreichen sparen. Wenn Du es richtig robust machen willst, kannst Du den GameContext AutoCloseable machen. Erzeugt man sich wie auch immer einen GameContext wird er in einen Stack in einer ThreadLocal geschrieben. Wenn er geschlossen wird, wird auch der Stack gepoppt. Schon kannst Du sogar in einem Thread mehrere GameContexte übereinander legen und recht robust verwenden. Beim Starten von Runnables in anderen Threads müsstest Du noch überlegen, wie Du dort den GameContext rüberbekommst, aber das ist ja keine Raketentechnik. Pass bei der Implementierung ein bisschen auf: https://plumbr.io/blog/locked-threads/ho…th-threadlocals

Viele größere Frameworks und Bibliotheken nutzen so ein Context-ThreadLocal-Pattern, um Aufrufketten in einen Kontext zu bringen ohne dass die gesamte Anwendung dann in diesem Kontext läuft. Von Transaktionen und EntityManagern bis Service-Registries wird so ein bisschen "by magic" Zeug rumgereicht, ohne dass es als Parameter übergeben wird.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

12

29.08.2018, 21:55

Boar, echt jetzt? Bin ich der Einzige, der die Lösungsvorschläge immer gruseliger findet?
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]

Nimelrian

Alter Hase

Beiträge: 1 216

Beruf: Softwareentwickler (aktuell Web/Node); Freiberuflicher Google Proxy

  • Private Nachricht senden

13

29.08.2018, 22:10

Nein, bist du nicht^^
Ich bin kein UserSideGoogleProxy. Und nein, dieses Forum ist kein UserSideGoogleProxyAbstractFactorySingleton.

14

29.08.2018, 22:11

@BlueCobold Das ist ein nettes Beispiel, aber was das mit meinem Problem zu tun haben soll, ist mir leider völlig schleierhaft.

Über deinen vorigen Codeschnipsel habe ich allerdings noch einmal nachgedacht. Dort sind zwar die Typen als Enums statisch und die Daten dynamisch ladbar, das Problem ist allerdings die Verbindung, also wie ich von einem Enum auf die zugehörigen Daten komme. Dazu folgendes Beispiel (ich bitte zu entschuldigen, das hier plötzlich von SocialStatus die Rede ist, aber hieran ließ sich die Problematik besser deutlich machen):

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public enum SocialStatusType {
    NON_CITIZEN, CITIZEN;
}

public class SocialStatus {
    public SocialStatusType type;
    public int fortuneRequirement;
}

public class Player {
    public SocialStatusType statusType;
    public int fortune;
}

// Hier passiert das eigentlich Interessante
public class DoStuffClass {
    private void processPlayer(Player player) {
        // Den nächst-höheren Sozialstatus erhalten
        SocialStatusType superiorStatusType = SocialStatusType.values()[player.statusType.type.ordinal() + 1];

        // Wenn der Spieler dessen Fortune-Requirement erreicht -> neuer Status
        if (player.fortune > ABC) {
            player.statusType = superiorStatusType;
        }

    }
}


An der mit ABC markierten Stelle müsste ich vom superiorStatusType die Daten erhalten, also auf dessen SocialStatus-Objekt zugreifen. Das ich die Daten aber nicht an alle möglichen Klassen übergeben möchte, ist ja gerade eine der Anforderungen an die Types.

@Chromanoid Vielen Dank für deine Antwort! EnumRegistry und ThreadLocal sind zwei gute Stichworte, aber das wirkt auf den ersten Blick schon sehr komplex. Ich werde mal ein bisschen herumprobieren, ob das zu meinem Anwendungsfall passt.
Pewn - eine Plattform für alle, die an Indie-Spielen interessiert sind

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »damios« (29.08.2018, 22:16)


15

30.08.2018, 00:51

Finde ich überhaupt nicht. Man braucht bei Spielen meist X Singleton-artige Dienste. Entweder man reicht die Referenzen immer durch, man hinterlegt die als Singleton, man nutzt Dependency-Injection oder man baut sich ein Context-Object. Das muss man aber überall durchreichen, oder man nimmt halt ein ThreadLocal-Konstrukt um den Kontext durch die verschiedenen Ebenen zu bringen. Ziemlich viele Frameworks machen das so oder so ähnlich. Hier mal ein Beispiel aus dem Activiti-BPM-Projekt: https://github.com/Activiti/Activiti/blo…xt/Context.java Spiele sind ähnlich krakenartig, was den Informationsbedarf zwischen einzelnen Komponenten angeht. Und man möchte meist auch an vielen Stellen gar nicht wissen, was alles gerade vorgeht.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

16

30.08.2018, 07:49

@BlueCobold Das ist ein nettes Beispiel, aber was das mit meinem Problem zu tun haben soll, ist mir leider völlig schleierhaft.
Das ist natürlich sehr traurig. Fällt dir keine "Is-a" Relation in Bezug auf Programmierung ein?
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]

Tobiking

1x Rätselkönig

  • Private Nachricht senden

17

30.08.2018, 08:02

Finde ich überhaupt nicht. Man braucht bei Spielen meist X Singleton-artige Dienste. Entweder man reicht die Referenzen immer durch, man hinterlegt die als Singleton, man nutzt Dependency-Injection oder man baut sich ein Context-Object. Das muss man aber überall durchreichen, oder man nimmt halt ein ThreadLocal-Konstrukt um den Kontext durch die verschiedenen Ebenen zu bringen.

In Sprachen wo es Frameworks zur Automatisierung von DI gibt würde ich nichts anderes wählen. Kein Durchreichen, identisches Vorgehen bei Singleton und nicht Singleton, zentral konfiguriert und problemlos beim Testen.

18

30.08.2018, 09:06

Finde ich überhaupt nicht. Man braucht bei Spielen meist X Singleton-artige Dienste. Entweder man reicht die Referenzen immer durch, man hinterlegt die als Singleton, man nutzt Dependency-Injection oder man baut sich ein Context-Object. Das muss man aber überall durchreichen, oder man nimmt halt ein ThreadLocal-Konstrukt um den Kontext durch die verschiedenen Ebenen zu bringen.

In Sprachen wo es Frameworks zur Automatisierung von DI gibt würde ich nichts anderes wählen. Kein Durchreichen, identisches Vorgehen bei Singleton und nicht Singleton, zentral konfiguriert und problemlos beim Testen.
Na da gibt's ja 1001 Framework in Java, oder was meinst Du? Damit das ganze auch schön auf Android läuft usw. würde ich in diesem Fall vielleicht https://google.github.io/dagger/ empfehlen. Ansonsten fand ich Guice auch sehr schön.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

19

30.08.2018, 09:14

Wir reden hier schon noch über ein recht einfaches Thema von primitiven Daten, die eine hierarchische Vererbungsstruktur aufweisen, ja?

Bevor wir klären, wie der TE also an seine Daten heran kommt, sollten wir vielleicht mal klären, wo er meint dieses überhaupt überall zu brauchen und auf welche Art und Weise. Mir hängt die ganze Zeit so ein übler Geruch von schlecht strukturiertem Code in der Nase und wenn ich die Ideen anschaue, wie man die Daten abbilden könnte, wird das ganze echt nicht besser. Es geht hier erstmal nur um eine Menge von Berufen, von denen jeder seine eigenen Eigenschaften hat. Das ist aus meiner Sicht ein absolut klassisches Beispiel von Vererbung. Und ob er auf diese Daten wirklich zentral injektiert an tausend Stellen zugreifen muss, halte ich erst mal für sehr fraglich.

Ich werde im Moment den Eindruck von Overengineering einfach nicht los.
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]

20

30.08.2018, 09:53

Wenn ich das richtig sehe, gibt es keine eigenen Klassen je Beruf. Es gibt eine Berufstypklasse und eine Berufsklasse, die Berufstyp und die Erfahrung darin zuordnet.

Wenn ich das Problem richtig verstehe, geht es darum in einer Datei gespeicherte Werte zu laden und allen Teilen des Programms zur Verfügung zu stellen. Das wurde bisher über statische Variablen gelöst - die machen aber Ärger beim Test-Schreiben.

Werbeanzeige