Monat: März 2025

  • Kleine Drachen für mehr Bewegung

    2025-03-26 -Übertrag

    Um etwas mehr Bewegung ins Bild zu bekommen, habe ich kleine Drachen animiert. Sie haben nur den Zweck das Bild des Spiels etwas aufzulockern.

    Feen Drachen

    Anfangs hatte ich erst eine Spezies Drachen geplant, daraus entwickelten sich dann -im momentanen Stand- drei weitere. Ich plane später noch viele mehr zu erstellen, da es spaß macht neue Feen-Drachen zu interpretieren.

    Für den Anfang habe ich drei Feen-Drachen erstellt mit stark unterschiedlichen Farben. Das hat dabei geholfen, die Funktion für die Automatische Aufteilung zu schreiben. Die kleinen Drachen werden ins Bild gerufen anhand einer Einzelnen Variable. Das Heist, ich setze State.Schmetterlinge = 149 und jeder der Drachen bekommt 49 Partner seine Spezies. Die restlichen Zwei Drachen die übrig bleiben werden auf die Erste Spezies gerechnet. Am ende sind 49 Monarchfalter-Drachen, 49 Hummel-Drachen und 52 Schwalbenschwanz-Drachen im Bereich der Kamera des Spielers.

    Die Große Nummer ist hier nur zur Veranschaulichung, ich nutze im Spiel 3 bis 15 Schmetterlinge je nach Fortschritt im Spiel. Die Anzahl der Drachen wird auch ein Karma-System, ich plane die Drachen zu erhöhen wenn der Spieler sich positiv gegenüber der Spielwelt verhält. Wenn der Spieler sich negativ verhält ist auch ein Event mit dem System geplant, aber das muss noch durchgeplant werden.

    Die Feen-Drachen werden despawnt wenn sie ausherhalb der Kamera des Spielers sind und werde an einer zufälligen Stelle am Rand der Kamera respawnt. Damit verhindere ich, das die Drachen außerhalb der Kamera Speicherplatz verbrauchen und dass sie sich alle auf einer Seite der Karte aufhalten.

    Verhalten zum User Interface

    Im Spiel sind die kleinen Drachen über dem Spieler angeordnet, so sehen sie aus als ob sie fliegen. Allerdings ist auch wichtig, dass sie unter der Textbox oder anderer User Interface Elemente sind. Sonst würden sie die Lesbarkeit des User Interface behindern.

    Das habe ich damit gelöst, das Game und User Interface in eigenen Szenen sind, welche unterschiedlichen Z-Index haben.

    Die Textbox wurde in einem anderen Artikel behandelt:
    RPG – Textbox und wie sie eingebaut wurde

    func spawnBox():

    if State.Shared_Character_Position != null:

    if global_position.x >= State.Shared_Character_Position.x + spawnBoxVector.x or global_position.x <= State.Shared_Character_Position.x – spawnBoxVector.x or global_position.y >=  State.Shared_Character_Position.y + spawnBoxVector.y or global_position.y <= State.Shared_Character_Position.y – spawnBoxVector.y:

    if $“..“.rollPosition == 0:

    global_position = Vector2(State.Shared_Character_Position.x + spawnBoxVector.x -10, randi_range(State.Shared_Character_Position.y – spawnBoxVector.y, State.Shared_Character_Position.y + spawnBoxVector.y)) #Rechts

    elif $“..“.rollPosition == 1:

    global_position = Vector2(State.Shared_Character_Position.x – spawnBoxVector.x +10,randi_range(State.Shared_Character_Position.y – spawnBoxVector.y, State.Shared_Character_Position.y + spawnBoxVector.y)) #Links

    elif  $“..“.rollPosition == 2:

    global_position = Vector2(randi_range(State.Shared_Character_Position.x – spawnBoxVector.x, State.Shared_Character_Position.x + spawnBoxVector.x),State.Shared_Character_Position.y + spawnBoxVector.y -10) #Unten

    elif $“..“.rollPosition == 3:

    global_position = Vector2(randi_range(State.Shared_Character_Position.x – spawnBoxVector.x, State.Shared_Character_Position.x + spawnBoxVector.x),State.Shared_Character_Position.y – spawnBoxVector.y +10) #Oben

    Spawn Zone

    Um die Drachen geringer zu Halten und diese nicht auf der gesamten Karte zu bewegen, habe ich eine Spawn und Despawn Zone erstellt. Diese Zone ist einfach gesagt ein Kasten aus Koordinaten hinter welchem keine Drachen sind, dieser Kasten bewegt sich mit dem Spieler.

    Als erstes wird geschaut ob der Drache auserhalb der Box ist, wenn ja wird dieser an eine andere Position gesetzt.

    Die Position wir alle 0.2 Sekunden mit einem Timer neu gewürfelt um etwas Rechenleistung zu sparen. Aus dem Würfeln kann eine Zahl von 0 bis 3 entstehen welche die Himmelsrichtung der neuen Position bestimmt.

    Mit der neuen Position werden sie einige Pixel weiter zur Mitte gesetzt, um zu schnelles Despawnen und Respawnen zu verhindern.

    Fazit

    Die kleinen Drachen geben durch ihre einfache kleine Animation etwas Bewegung ins Spiel, welche vorher gefehlt hat. Das System im Hintergrund bietet Möglichkeiten zur Weiterentwicklung, wie das oben angesprochene Karma System welches bisher nur in meinem Kopf existiert. Feen-Drachen sind auch mal eine nette Abwechslung und kommen hin und wieder mal in meinen Art und Development Streams vor, da es nicht zu viel Arbeit ist diese ins Spiel mit zu integrieren. Mit den erstellten Feen-Drachen Assets plane ich noch weitere Projekte, allerdings ist das in fernerer Zukunft.

  • RPG – Textbox und wie sie eingebaut wurde

    2025-03-20 – Übertrag

    Um die Geschichte besser erzählen zu können, habe ich eine Textbox erstellt. Zuerst hatte ich mich informiert, wie so etwas geht, anhand eines Youtube Videos.
    Das Video erstellt eine rudimentäre Textbox, diese ist schonmal gut, aber genügt meinen Anforderungen nicht.

    Charaktere

    Für bessere Immersion braucht die Textbox noch das Bild und den Namen des Sprechers. Manchmal verändert sich der Sprecher, in meinem Spiel muss man auf die Kachel der Hütte des Sprechers um mit ihm zu interagieren. Es wurde auch eine kleine Animation auf die Kachel gesetzt um der Overworld noch etwas mehr Bewegung und Leben zu geben.

    Der Charakter hier ist Pheus, seine Hütte wird direkt zu Begin des Spiels in der Mitte der Karte erstellt. Er ist der Mentor in der Geschichte, und hilft Taja -der Heldin- wieder auf die Beine. Seine Hütte ist direkt im Blickfeld des Spielers wenn man das Spiel das erste mal startet.

    Mehr zu Taja!

    Mit einem identifizierbaren Kacheltyp kann ich auch ein Modul schreiben, welches darauf prüft ob der Spieler Interaktion nutzt wenn er auf PHEUS_HUETTE steht.

    func checkForTalker():

    if State.Map_Array[State.Shared_Player_Position.x][State.Shared_Player_Position.y] == „PHEUS_HUETTE“:

    So lassen sich auch mehrere Charaktere erstellen, welche auf unterschiedlichen Kacheln aktiviert werden.

    Den Dialog selbst lade ich aus einer JSON Datei. Die Dialog-Textblöcke in der JSON Datei sind Indexiert, und werden runtergebrochen auf Textblöcke die für die Textbox verarbeitbar sind.

    Ich nutzte eine JSON Datei um einen Zentralen Punkt zu haben wo die Textausgaben gespeichert sind, um diese im Laufe der Entwicklung einfacher verändern zu können.

    Code Logik

    Das laden des Textes aus der JSON Datei braucht eine kleine Funktion, welche die Datei öffnet, den Inhalt in einer Variable kopiert und dann wieder schließt.

    ressource ist hier der Pfad zur JSON Datei.

    Den Text herunterzubrechen war eine kleine Herausforderung, da es zuerst mitten im Wort runtergebrochen wurde. Ich habe das dann gelöst mit:

    var lastSpace = clip48.rfind(“ „)

    rfind(“ „) sucht das letzte Leerzeichen und speichert dessen Position, später habe ich dann einfach die Brüche an dieser Position gemacht.

    Ich habe die Struktur so geschrieben, dass die Texte welche der Charakter sagt indexiert sind. Zum Beispiel ist Index 0 der Erste Satz welcher zu Taja am Start des Spiels gesagt wird:
    „Pheus“: {
    „0“: „Ich bin Pheus, ich habe dich aus dem Wasser an der Küste gefischt und dir wieder auf die Beine geholfen!“,

    Ich setzte im Spiel später Milestones welche nach Abschluss mancher Story Beats gesetzt werden, mit diesen wird dann auch Progression im Dialog gemacht.

    Schwierigkeiten

    Die meisten Schwierigkeiten entstanden durch die Abfolge, also Wann was passiert. Ich hatte zum Beispiel eine Lange Zeit den Text doppelt ausgegeben bekommen.
    Bis ich dahinter kahm, dass ich den Charakter nochmal anspreche, da ich auf dessen Feld stehe und die Aktionstaste für Fortfahren in seinem Text nutze ist viel Zeit vergangen.
    Lösungsansätze hierfür waren: einen Switch zu erstellen, der bei verlassen des Feldes erst wieder auf true geht. Sowie ein Timer -welchen ich letztendlich behalten habe- der das ansprechen einige Sekunden verhindert.

    Der Timer wird gestartet wenn der Text gelesen wurde.

  • Ein Minispiel in Rundenbasiertem Kampf

    2025-03-10 – Übertrag

    Mein Spiel arbeitet mit einem Rundenbasierten Kampfsystem. Um es etwas interaktiver zu gestalten, wurde eine Minispiel zum verteidigen entwickelt.
    Im Kampfbildschirm (das Bild links) wenn der Gegner angreift, soll ein Minispiel erscheinen. Das Minispiel soll den Schaden des Gegners am Spieler negieren oder reduzieren.

    hier ist die ursprüngliche Idee des Minispiels. Eine Hit-box in der Mitte und Projektile welche darauf zufliegen. Je mehr Projektile durchkommen, desto mehr schaden macht der Gegner am Spieler.

    Von Links nach Rechts sind die einzelnen Phasen der Entwicklung zu sehn. Bild 1 ist die Erst Umsetzung, hier sind die Projektile noch zu klein und der Schild (blau) ist ebenfalls zu klein. In dieser Phase war auch das meiste Testen nötig um die Logik der Bewegung hinzubekommen. Ich bin auf einige Hürden gestoßen im Bereich Skalierung. Wenn sich die Bildschirmgröße veränderte, änderten sich auch die Ziel- und Startpositionen der Projektile so, dass das Spiel keinen Sinn ergab.

    Ich habe den Kreis um den Schild herum in Punkte aufgeteilt, die als Startpositionen der Projektile dienen.
    Die größten Probleme entstanden, weil ursprünglich nicht global_position() genutzt wurde, sondern position().
    Der unterschied der beiden ist, position() arbeitet nur lokal in der Szene, also nutzt nur die Maße vom ursprünglichen Spielfeld.
    golabal-position() nutzt die Maße des Screens im Spiel.

    Bild Zwei, ist die zweite Phase, hier wurden nach der Fertigstellung der groben Logik und den ersten Tests, Fehler behoben und das Spiel schon etwas angenehmer gestaltet.
    Zum Beispiel sind die Projektile länger, was dem Schild erlaubt, diese auch von der Seite zu treffen und zu neutralisiere.
    Zusätzlich habe ich den Schild vergrößert, damit das Minispiel einfacher wird.

    Hier wurde auch mit Spiel-Modi getestet, zur Linken startet die Bewegung jeweils zur Hälfte, zur Rechten startet das Movement Spiralförmig. Beide geben eine Unique Challenge, auf welche sich der Spieler einstellen muss.

    In Bild 3 habe ich wieder kleine Fehler behoben und am Aussehen gearbeitet. Ich habe einen Meiner Art-Streams dafür genutzt um ein Passendes Hintergrundbild und Projektile zu entwerfen. Ursprünglich hatte ich ein Amulett als Hintergrund, aber entschied mich dagegen, da ein Schild für ein Verteidigungs-Event weit mehr passt.

    Meine Bilder werden wenn sie fertig sind, gescannt und mit einem Bildbearbeitungsprogramm überarbeitet, damit sie in einem Digitalen Spiel gut aussehen.
    Zur Linken sind die Original Assets auf Aquarelle-Papier, ich nutze für meine Kunst Aquarelle Farbe und Microns, also Marker für Line-Art.

    Zum Schluss habe ich noch einen Indikator für den Sieg hinzugefügt und das gesamte Modul in die Kampfszene eingebunden. hier gab es die Probleme welche vorhin genannt wurden mit der Skalierung.

    Fürs erste ist das Modul fertig, es ist angedacht noch Gegner-Spezifische Projektile zu machen, und eventuell das gesamte Minispiel hinter ein Item zu setzten welches man erst ausrüsten muss.

    Vielen dank fürs lesen!
    ich streame so etwas auf Twitch, wenn Interesse besteht, schau doch mal vorbei

  • über Mimik in einem Comic

    2025-03-08 – Übertrag

    über Mimik in Comics

    Die Basisemotionen sind ein kulturübergreifendes, universelles Ausdrucksmedium. Man kann dieses Medium nutzen um eine Geschichte zu erzählen.
    Deshalb erstelle ich hier mit Wasserfarben einige Expression Boards und Leitfäden für die Zeichnung meiner Charaktere – hier Taja -. um sie später einfacher replizieren zu können und im Vorfeld zu sehen wie die Einzelnen Gesichtsausdrücke wirken, oder diese noch etwas Arbeit benötigen.

    hier probiere ich eine Herangehensweise welche sich möglichst einfach replizieren lässt, um den Charakter immer und immer wieder zu zeichnen. Teile des Gesichts werden in einfache Geometrische Formen heruntergebrochen und Guidelines gezogen.

    Von den Basisemotionen kann man später noch sekundäre Emotionen ableiten wie Stolz, Dankbarkeit, Eifersucht. Die grobe Zeichnung wird, wie hier, noch mit Tinten Line-Art übermalt uns später mit Wasserfarben ausgemalt. Am ende habe ich ein Referenz-Bild mit den Sechs Basisemotionen, welches später hilft, dass sich der Charakter nicht zu sehr verändert über Zeit.

    In diese Phase teste ich auch andere Perspektiven und wie ich diese erstelle, hier kann man sehn das ich die Schnauze etwas kürze im zweiten Versuch.

    Ich coloriere die Bilder meist noch, um ein richtiges „Feeling“ zu bekommen wie die Bilder später wirken.
    Dies sind einige der Ursprünglichen Rohentwürfe von Taja. Einige der Bilder haben auch Notizen wie sie entworfen wurden. Mit jedem neuen Entwurf entwickelt sich der Charakter hier weiter, von der Ersten Idee bis zur letzten Verbesserung. Die oberen Drei Bilder sind Jeweils verschiedene Versuche, die unteren drei sind Iterationen des Bildes oben rechts.

    Wichtig ist auch gute Referenz im Vorfeld zu suchen, oder wenn man etwas braucht wie einen Bestimmten Gesichtsausdruck, wenn man herausfinden möchte wo sich welche Falte im Gesicht verzieht. Wenn ich Charakter-Kreation streame, nehmen ich mit etwas Zeit im Vorfeld des Streams um geeignete Referenz zu suchen und eine Idee zu festigen. So ist der Ablauf im Stream viel „Smoother“.