Grid-Based Movement - Denkansätze

  • Hallo zusammen,


    für mein Spiel-Projekt bräuchte ich mal ein paar Denkansätze, da ich aktuell merke, dass ich mit meinen auf Probleme stoße, sobald mehrere spielbare Charaktere zum Einsatz kommen.
    Stell euch Dungeon-Räume und ein "Grid Based Movement" im Stil von "Zelda - A Link to the past" vor.
    TopDown-Ansicht. Man bewegt sich mit WASD in die vier, jeweiligen Richtungen (nicht diagonal). Es gibt Kisten zum hin und herschieben, sowie Drehkreuze, Löcher im Boden etc.


    Das funktioniert mit einem einzelnen spielbaren Charakter soweit auch alles, aber mit mehreren zwischen denen ich wechseln kann, wirds knifflig.


    Aktuell "bewegt" sich mein Character immer 100 Units in die gewünschte Richtung per Timeline und SetWorldLocation. Um das Laufen zu simulieren, wird eine entsprechende Animation abgespielt.
    Da es sich dabei ja um eine Art Teleportation handelt, muss ich entsprechend per LineTrace Collisionsabfragen machen, ob ne Wand, ne Kiste, ein Loch o.ä. im Wege steht und mein Char an die nächste Stelle laufen kann. Wenn dem so ist (Boolean-Abfrage), wird die entsprechende Richtungstaste quasi "blockiert".


    Das selbe gilt für Blueprint-Actors, meine verschiebaren Kisten als Bsp. oder Drehkreuze, die bei ComponentOverlap meinem Char sagen, ob sie geschoben werden können oder nicht, wenn sie von irgendetwas blockiert werden. Z. Bsp. "BoxCheckNorth" und wenn der Wert True ist, wird beim Char "W" blockiert.
    Diese Werte speicher ich aktuell temporär in einer GameInstance auf die meine Figur dann zugreifen kann.
    Jetzt hätte ich aber gerne weitere Spielfiguren, zwischen denen ich jederzeit hin und her wechseln kann, damit sie sich gegenseitig helfen können, beim Kistenverschieben, Platz freiräumen etc.
    Aber für diese Figuren brauche ich natürlich die selben Abfragen, ob in eine entsprechende Richtung gelaufen werden kann, oder die Kiste geschoben werden dann.


    Ich suche nun hier irgendwie einen anderen Ansatz, anstatt für jede einzelne Figur lauter Boolean-Abfragen erstellen zu müssen, ob sie irgendwo hingehen kann oder etwas schieben kann etc.


    Denn wenn für Figur A gilt, das "W" blockiert ist, gilt es ja nicht auch gleichzeitig für Figur B. Da ja für alle Figuren die selbe Steuerung gilt und sie auf die selben "BoxCheckNorth" ect. BooleanAbfragen in der GameInstance zugreifen. Und es sollen schon teils bis zu 4 Figuren pro Level spielbar sein, zu denen gewechselt werden kann...


    Ein weiteres Problem: Jede Figur kann das selbe tun. Wenn Figur A eine Kiste schiebt, aber Figur B im Wege steht, muss die Kiste das erkennen, dass Figur B gerade nicht aktiv ist und als Hindernis ansehen und dies Figur A mitteilen. Womit ich bei den Collisionsabfragen weitere Möglichkeiten hinzufügen müsste..da PAWN ja für beide Figuren gilt. Denn wenn ich dann zu Figur B wechsel, muss diese dennoch in der Lage sein, die besagte Kiste auch schieben zu können, auch wenn sie vorher noch von der Kiste als Hindernis erkannt wurde.


    Soo und als wäre das alles noch nicht genug, gibt es auch noch eine UNDO-Funktion. Jeder einzelne Schritt kann rückgängig gemacht werden.
    Diese Funktion habe ich aber schon und sie funktioniert soweit auch schon, könnte mit weiteren spielbaren Figuren aber noch komplizierter werden :D
    Mit einer einzelnen Figur ist es so breits schon komplett spielbar. Nur wie gesagt, mit mehreren würde dieses System so ohne weiteres nicht funktionieren...


    Ich hoffe ich konnte ungefähr begreiflich machen, worum es mir geht. Dieses Grid-Based Movement sollte schon beibehalten werden, macht aber natürlich ohne NavMesh und typischem InputAxisMapping vieles komplizierter.
    Wenn ihr Fragen oder Blueprints sehen wollt, sagt bescheid. Ansonsten hättet ihr ne Idee, wie sich das ganze eventuell etwas anders und einfacher umsetzen ließe?

  • Ich würde die Spieler Logik im Player Controller schreiben.
    Alle weiteren Infos zu Objekten in den Objekten deponieren also ganz normal Objektorientiert und dann mit dem Spieler auf das Objekt zugreifen.


    Alle Spieler greifen auf die selbe Logik zu und wenn eine Kiste geschoben werden soll dann sagt dir die Kiste was sie kann und was nicht.
    Die States der Kiste kannst du dann in der Steuerung vom PlayerController einbinden.


    Denke das sollte reichen, ich mach es aktuell so in meinem Projekt und das funktioniert recht gut

  • Ich würde die Spieler Logik im Player Controller schreiben.
    Alle weiteren Infos zu Objekten in den Objekten deponieren also ganz normal Objektorientiert und dann mit dem Spieler auf das Objekt zugreifen.


    Alle Spieler greifen auf die selbe Logik zu und wenn eine Kiste geschoben werden soll dann sagt dir die Kiste was sie kann und was nicht.
    Die States der Kiste kannst du dann in der Steuerung vom PlayerController einbinden.


    Denke das sollte reichen, ich mach es aktuell so in meinem Projekt und das funktioniert recht gut

    Danke für die Antwort!
    Hm würde bedeuten ich müsste sämtliche Functionen und Variablen die ich bereits im Player Character gemacht habe, im Controller neu erstellen oder?
    Den Inhalt kann ich natürlich dann rüberkopieren. Aber dennoch müsste ich sie erstmal alle erstellen dort oder nicht?


  • Alle Spieler greifen auf die selbe Logik zu und wenn eine Kiste geschoben werden soll dann sagt dir die Kiste was sie kann und was nicht.
    Die States der Kiste kannst du dann in der Steuerung vom PlayerController einbinden.

    Das scheint nicht so ganz zu funktionieren... Es kann vorkommen, dass ich pro Level mehrere Kisten habe, welche im Level lediglich dupliziert werden, also den selben Blueprint abgreifen.
    Ausserdem gibt es dann noch zusätzlich verschiedene Kisten-Typen, bzw. varieren sie in der Größe. Ich denke ich bräuchte hier also eine Art Parent-Blueprint, wenn ich das richtig sehe und alle Child-Kisten (egal welchen Kisten-Types) senden ihre Stats an diesen einen Parent, welche dann wiederum in die Steuerung vom PlayerController eingebunden werden müssen. Und es sollte dann nur für die jeweilige, gerade aktive Kiste und die gerade aktive Spielfigur gelten...
    Wäre das so in der Art machbar?

  • Glaube du hast da verstehst du etwas falsch.
    Jede duplizierte Kiste verarbeitet ein eigenes Blueprint, die teilen sich nicht alle eins.
    Ausserdem ist ein Child eine Vererbung, das bedeutet soviel wie das du ein Parent hast (Basismodul sozusagen) und die Childs sind definiertere Module, also die Basis mit mehre Variablen oder weiteren OIbjekten.


    Kann man sich so vorstellen (Parent = Mensch) -> (Child -> Mann) -> (Child2 - Frau) ...also man erstellt andere umfangreichere Versionen die aber alle die Information des Parents beinhalten

  • Also wenn ich Kiste1 in meinem Level plaziere und diese dann dupliziere, Kiste2. Dann hat/nutzt Kiste2 den Blueprint von Kiste1.. oder nicht? Wenn ich im Blueprint von Kiste1 etwas ändere, wird es ja auch direkt auf Kiste2 übertragen. Im LevelBP kann ich zwar Referencen zu beiden Kisten erstellen und dann auf Funktionen/Variablen zugreifen, aber im PlayerController könnte ich jedoch nur zu Kiste1 casten, jedoch nicht zu Kiste2, wenn ich das richtig verstehe.
    Bleibt eigentlich nur noch die GameInstance dann, mit Variablen etc. auf die sowohl jede einzelne Kiste als auch mein PlayerController zugreift um die selben Variablen gemeinsam nutzen zu können oder?

  • Wenn du die Kiste kopierst haben beide das selbe BP ja. Änderungen in Kiste wirken sich auf beide Kisten aus ja.
    Aber wenn du castest, dann castest du doch auf den Typ Kiste und greifst auf die Variablen dieser Kiste zu die bei beiden Kisten unterschiedlich gefüllt sein kann, jedoch heißen die Variablen gleich und die Kisten sind vom gleichen Typen.


    Somit kannst du den Typ Kiste auch casten egal welche Kiste das ist, welche Kiste du abfragst definierst du ja indem du das Objekt bestimmst durch ein Linetrace oder einen Collider der auslößt oder was auch immer.
    Beim Cast definierst du nur von welchem Typ das Objekt ist damit du weißt welche Variablen zur Verfügung stehen etc.


    Denke du solltest dich noch ein wenig in die Grundlagen der Programmierung einlesen, das sind Basics der objektorientierten Programmierung.
    Ich mein du kannst natürlich weiter entwickeln aber wenn man weiß wie instanzierte Objekte und Parent Child Beziehungen funktionieren dann ist das Ganze um ein vielfaches einfacher ;)

  • Verstehen tue ich die Logik hinter objektorientierter Programmierung und Parent Child Beziehungen, nur in meinem Fall funktioniert es nicht.
    Parent Child BPs benutze ich zur Zeit aber auch nicht.
    Ich habe mehrere KistenTypen, sowie mehrere Duplikate dieser pro Level. Wobei das von Level zu Level auch variiert.
    Um die Variablen einer bestimmten Kiste herauszubekommen, müsste ich erst deren Class bestimmen, zu dieser casten und dann das Objekt (die ausgewählten Kiste) bestimmen. Das ganz kann ich per LineTrace herausbekommen ja.


    Aber ich kann die Variable selbst nicht auswählen, solange nicht überhaupt gecastet wurde, da ich das Target nicht bestimmen kann, solange die Actor Class nicht definiert wurde im Editor und die Class und Object würde aber so erst InGame bestimmt.
    Aktuell habe ich 13 verschiedene KistenTypen.
    Ich will ungern proforma bei jedem Schritt, den einer meiner Figuren macht, oder per EventBeginPlay zu sämtlichen dieser Typen casten für den Fall, dass ich dann irgendwann auf eben eine Kiste, von einer dieser KistenTypen treffe, um dann deren Variable auslesen zu können...
    Alles was jede Kiste, egal welche, machen muss, ist meiner Figur mitteilen, ob in die gewünschte Richtung geschoben werden kann. Dazu habe ich vier Boolean-Variablen (North, South, East, West), welche ich nun nach meiner Logik her :D in die GameInstance gesetzt habe.
    Die Kiste sagt North geht nicht, Controller überprüft North in der GameInstance und merkt "Ok, nach North kann nicht geschoben werden" und "blockiert" die W-Taste.


    Wäre doch die einfachste Methode oder nicht?
    Was allerdings noch nicht funktioniert, wenn ich zwischen zwei Figuren wechsel. Steht Figur1 im ComponentBeginOverlap einer Kiste und ich wechsel, werden in der GameInstance sämtliche Werte auf False zurückgesetzt, damit Figur2 auch in jede Richtung laufen kann, falls die Kiste Figur1 vorher gesagt haben sollte, nach North gehts nicht und den Wert auf True gesetzt hat.
    Wechsel ich jedoch dann erneut zurück zu Figur1, muss diese eine Kiste irgendwie erneut die Abfrage ausführen, um den North-Wert wieder auf true zu setzen, da Figur1 sonst einfach weiterlaufen würde...


    Edit: Ok, ich glaube, ich brauche hier noch ein BlueprintInterface. Damit kann ich dann das per LineTrace abgefragte Objekt überprüfen und so im Objekt_BP bei Bedarf ne Funktion auslösen...

  • Warum machste denn kein Array? Das was du willst ist doch ein Schachbrett in beliebiger Größe. Davon erstellst du meinetwegen 10 Stück und kannst so auch dein Undo machen.


    Im Array gibst du Variablen an. B=Blocked, F=Frei, K=Kiste. Dann kannste alles abfragen, was du willst und Multiplayer klappt damit ja auch. Schach halt oder jedes andere Brettspiel.

    Bisher klappt es nun, so wie ich es gemacht habe. Meine Level sind nicht alle Quadratisch und haben unterschiedliche Formen. Hätte aber wohl dennoch mit der Schachbrett-Methode funktioniert irgendwie.
    Ich belasse es aber nun erstmal dabei :)