Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 15 von 17

Thema: [RL] Ronnar bastelt ein Weihnachtsspiel

  1. #1
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258

    [RL] Ronnar bastelt ein Weihnachtsspiel

    Gleich vorne weg: Ich bin kein Softwareentwickler und mein letztes Spiel habe ich vor über 25 Jahren in Turbo Pascal geschrieben. Seitdem habe ich an der einen oder anderen Mod gearbeitet, aber nie ein komplett eigenständiges Spiel von Grund auf entwickelt.

    Vor ein paar Wochen gab es dann bei HumbleBundle die GameMaker Engine für 15 $ inklusive aller Exportmodule (z.B. Linux, Windows, Android, iOS, HTML5, usw.). Das Paket würde sonst über 900 EUR bei Steam kosten oder 800 $ vom Hersteller. Langer Rede kurzer Sinn: Ich konnte nicht widerstehen und hab’s mir gekauft.

    Von GameMaker gibt es übrigens auch eine freie Version, allerdings mit weniger Exportfunktionen und anderen Einschränkungen.

    Damit ich motiviert bin auch tatsächlich ein kleines Spiel zum Lernen der Engine fertigzustellen, fange ich hier die Story an.

    Angefangen habe ich mit ein paar Tutorial-Videos, z.B. https://youtu.be/hzMNunoPd0o und dem Handbuch.

    Danach war mir ungefähr klar, was ich machen will:

    • 2D
    • Ich nutze die Drag&Drop Funktion der GameMaker Engine nicht oder so wenig wie möglich. Schließlich will ich was programmieren und nicht zusammenklicken.
    • Das Spiel soll bis Weihnachten fertig sein

  2. #2
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258
    Jedes gute Spiel braucht ein Design! Und ein schlechtes Spiel von mir braucht natürlich auch ein Design!

    Jetzt könnte ich natürlich mit euch einen Design Thinking Workshop machen und das ideale Spiel für die Civforum-Zielgruppe ermitteln.

    Oder ich beschließe einfach: Ist mir egal, ob es am Ende jemand gefällt! Soll ja mir Spaß machen es zu programmieren.

    Daher bestimme ich ganz alleine die Grundidee:

    1. Das Spiel soll Weihnachten fertig werden, daher wird das Thema weihnachtlich sein.
    2. Geschenke – jeder liebt es welche zu bekommen. Und zu Weihnachten passt es auch!
    3. Wir sind im CivForum, daher muss irgendwie Civilization auftauchen.

    Welches Genre könnte denn dazu passen?

    • Shooter? Passt nicht zu Weihnachten, außerdem mag ich die nicht.
    • Survival? Womöglich gar mit Rentier-Zombies? Nein, besser auch nicht.
    • Side-Scroller oder Jump-and-Run? Die gibt es für GameMaker wie Sand am Meer.
    • TBS oder Grand Strategy? Super – nur etwas zu ambitioniert für mein erstes Projekt.
    • RPG? Ebenfalls nicht zu schaffen bis Weihnachten.
    • Hidden Object? Bäh, langweiliges rumklicken bis man alle Objekte gefunden hat. Obwohl … als erstes Projekt vielleicht gar nicht so übel.

    Hidden Object also … mal sehen …

    Geschenkpakete suchen? Auf Zeit? Und wenn man ein Schrottgeschenk aufmacht gibt’s Strafsekunden oben drauf? Also wenn man statt CIV z.B. ein Beyond Earth auspackt oder Socken…

    Bild

    Damit steht das Konzept – die Umsetzung kann doch auch nicht so schwer sein, oder?
    Angehängte Grafiken Angehängte Grafiken

  3. #3
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258
    Jetzt wäre es mit GameMaker ein leichtes einen Raum zu erstellen und die Objekte dort per Hand zu platzieren und ein Event festzulegen was beim drauf klicken passieren soll.

    Aber dann haben wir bei jedem Start genau den gleichen Raum und die Geschenke jedes Mal an derselben Stelle. Spätestens im dritten Durchlauf hat sich jeder gemerkt, dass die kratzigen Socken von Oma im Päckchen rechts hinter dem Weihnachtsbaum sind.

    Also dürfen die Pakete nicht statisch im Raum angeordnet werden. Zufällig verteilen bringt aber auch nichts – dann wären sie irgendwo im Raum, aber nicht gut versteckt.

    Ich brauche also zwei Listen:
    • Eine für die Geschenke mit ihren Attributen
    • Eine für die Verstecke (mindestens so viele Verstecke wie Geschenke)

    Am einfachsten würde ich die Listen direkt in GameMaker anlegen, z.B. über DS_Lists.

    Da ich solche Werte aber ungerne im Coding verstecke und als Modder den einfachen Zugang zu den Daten liebe, muss es eine externe Datenquelle sein. Da kenne ich persönlich nur XML und JSON. Wobei ich täglich im Beruf mit XMLs zu tun habe, meine Erfahrungen mit JSON aber praktisch Null sind.

    Daher entscheide ich mich natürlich für … JSON! Und ausnahmsweise hat es nichts damit zu tun, dass ich dieses Projekt komplizierter machen will, als es eigentlich sein müsste. Aber GameMaker bringt Unterstützung für JSON bereits mit, während ich einen XML Parser erst selber schreiben müsste.

    Geschenkeliste

    Für den Anfang lege ich 7 Attribute für jede Geschenkschachtel fest:
    • ID – brauche ich eigentlich im Spiel nicht, aber für Debugging-Zwecke kann das nützlich werden
    • Name des Geschenks
    • Grafik für das verpackte Geschenk
    • Grafik für die leere Schachtel
    • Grafik für das ausgepackte Geschenk
    • Beschreibung
    • Zeitstrafe fürs Auspacken

    In Tabellenform dann ungefähr so:

    Bild

    Später kommt vielleicht noch mehr dazu, aber für den Anfang sollte das als Datenstruktur ausreichen. Korrigiert mich, falls euch gleich noch was einfällt was mit rein sollte!

    Verstecke

    Für die möglichen Verstecke komme ich auf 4 Attribute:
    • Eindeutige ID aus den selben Gründen wie für das Geschenk
    • X-Koordinate im Raum
    • Y-Koordinate im Raum
    • Tiefe im Raum (negativ ist bei GameMaker weiter vorne)

    Bild

    Es wird zwar ein 2D-Spiel, dennoch brauche ich die Z-Koordinate (Depth), um Geschenke hinter oder vor anderen Objekten platzieren zu können.
    Da ich noch keinen Raum mit Objekten gebaut habe, trage ich einfach 4 zufällig gewählte Koordinaten ein.

    In JSON sehen die beiden Listen dann so aus:

    Geschenke:

    Code:
    [
      {
        "ID":1,
        "NAME":"CIV V",
        "IMG_BOXED":"spr_GiftBox1",
        "IMG_UNBOXED":"spr_GiftBoxOpen1",
        "IMG_GIFT":"spr_CIV5",
        "DESCRIPTION":"Naja, Civ 5 eben ...",
        "PENALTY": 0
      },
      {
        "ID":2,
        "NAME":"CIV IV",
        "IMG_BOXED":"spr_GiftBox2",
        "IMG_UNBOXED":"spr_GiftBoxOpen2",
        "IMG_GIFT":"spr_CIV4",
        "DESCRIPTION":"Stack of death for the win!",
        "PENALTY": 0
      }
      {
        "ID":3,
        "NAME":"Zonk",
        "IMG_BOXED":"spr_GiftBox3",
        "IMG_UNBOXED":"spr_GiftBoxOpen3",
        "IMG_GIFT":"spr_Zonk",
        "DESCRIPTION":"Ätsch",
        "PENALTY": 10
      }  
    ]

    Verstecke:

    Code:
    [
      {
        "GIFT_POS": 1,
    	"GIFT_X": 60,
    	"GIFT_Y": 60,
    	"GIFT_DEPTH": -1000
      },
      {
        "GIFT_POS": 2,
    	"GIFT_X": 200,
    	"GIFT_Y": 200,
    	"GIFT_DEPTH": -1000
      },
      {
        "GIFT_POS": 3,
    	"GIFT_X": 800,
    	"GIFT_Y": 400,
    	"GIFT_DEPTH": -1000
      },
      {
        "GIFT_POS": 4,
    	"GIFT_X": 1000,
    	"GIFT_Y": 60,
    	"GIFT_DEPTH": -1000
      },
      {
        "GIFT_POS": 4,
    	"GIFT_X": 500,
    	"GIFT_Y": 250,
    	"GIFT_DEPTH": -1000
      },  {
        "GIFT_POS": 5,
    	"GIFT_X": 60,
    	"GIFT_Y": 400,
    	"GIFT_DEPTH": -1000
      }  
    ]
    Angehängte Grafiken Angehängte Grafiken

  4. #4
    Rebellenschreck Avatar von Großadmiral Thrawn
    Registriert seit
    08.06.13
    Ort
    Bologna
    Beiträge
    5.047
    Wär doch mal was interessantes für den Adventskalender, dein kleines Spielchen
    PBEM[296]Der letzte Kaiser
    PBEM[295] Im Osten nichts Neues

    PBEM[294] Ich einfach unerschrecklich

    Hier könnte Ihre Werbung stehen!

    Achtung Spoiler:
    Oder auch nicht


  5. #5
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258
    Zitat Zitat von Großadmiral Thrawn Beitrag anzeigen
    Wär doch mal was interessantes für den Adventskalender, dein kleines Spielchen
    Ja, das meinte Shakka auch Warten wir mal ab wie weit ich komme. Ziel ist aber schon, dass es auch im Browser laufen wird.

  6. #6
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258

    Aller Anfang ist ...

    Nun gibt es also kein zurück mehr. GamerMaker gestartet und ein neues Projekt angelegt „XMas_Civforum“. Na toll – schon bei der Vergabe des Projektnamens kein kreativer Geistesblitz.

    Hat jemand einen Vorschlag?

    Im Menu auf der linken Seite könnt ihr alle Bestandteile des Spieles sehen. Oder sollte ich sagen, werdet ihr irgendwann sehen können?
    • Sprites: Alles an Grafiken, was ins Spiel soll. Von Objekten bis zu UI-Elementen.
    • Sounds: Von Musik bis Soundeffekte
    • Backgrounds: Hintergrundbilder
    • Paths: Mit Wegfindung muss ich mich nicht rumschlagen, hier wird es leer bleiben
    • Scripts: Hier kann man Coding ablegen, welches man von anderen Stellen aus aufrufen kann
    • Shader: Habe ich mich noch gar nicht mit beschäftigt. Lasse ich vermutlich weg
    • Fonts: Schriftarten – kennt jemand gute, frei verfügbare Schriftarten?
    • Time Lines: Habe ich mich noch gar nicht mit beschäftigt. Brauche ich vermutlich nicht
    • Objects: Die Dreh- und Angelpunkte des Spiels. Objekte können UI-Elemente, Spieler oder unsere Geschenkschachteln sein. Oder komplett unsichtbar und nur dazu da Funktionen aufzurufen. Onjekte können in Räumen platziert werden.
    • Rooms: Definieren den sichtbaren Bereich und können Objekte und Hintergrundbilder beinhalten. Jedes Spiel hat mindestens einen Raum, es können aber natürlich auch mehrere sein.
    • Included Files: Alles was nicht in die anderen Kategorien passt, aber dennoch ins Spiel soll.
    • Extensions: Brauche ich hoffentlich nicht
    • Macros: Abkürzungen für die Faulen oder Vergesslichen


    Bild


    Erste Aktion: Ich füge die beiden JSON Dateien mit den Listen für die Geschenke und die Verstecke in der Rubrik „Included Files“ hinzu.

    Zweite Aktion: Ich bin sowas von vergesslich. Ich müsste alle paar Minuten nachschauen ob der Name des Sprites für das verpackte Geschenk nun an 2., 3. oder 4. Stelle steht.

    So würde ich später auf die Grafikdatei des 2. Geschenks wie folgt zugreifen müssen:

    GiftData[# 1, 2]

    # 1 würde auf das zweite Geschenk verweisen, weil die Zählung bei 0 beginnt.
    2 wäre dann der Name des Sprites für das verpackte Geschenk

    Wie gesagt, ich bin vergesslich. Um es mir einfacher zu machen und den Code auch verständlicher zu machen lege ich für alle Einträge aus den beiden JSON-Dateien entsprechende Makro-Einträge an (s. Screenshot).

    Beispiel-Macro: IMG_BOXED = 2
    Dadurch wird der Code für mich schon viel verständlicher:
    GiftData[# i, IMG_BOXED]
    Angehängte Grafiken Angehängte Grafiken

  7. #7
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258

    Sprites & Räume

    Sprites

    Das wird mein schwierigstes Thema werden. Ich bin sowas von künstlerisch unbegabt. Aber ohne Sprites wird nichts zu sehen sein im Spiel. Da muss ich wohl durch.

    Für den Start besorge ich mir aus einer frei verfügbaren Sprite-Sammlung ein paar verschieden große Schachteln. Weil ich auf die Schnelle keine offenen Schachteln finde, spiegele ich die 3 Schachteln vertikal und lade sie als „spr_GiftBoxOpen“ hoch

    Dann noch schnell ein Default-Sprite erstellt – einfach ein rotes X. Das kann ich als Platzhalter verwenden, wenn ich etwas ausprobieren will. Ode als Initialwert für Objekte, dann sehe ich gleich ob was schiefgeht beim Laden der JSON-Dateien.


    Bild

    Auf die Sprites für die ausgepackten Geschenke verzichte ich vorerst. Das wird noch dauern bis ich dazu komme die Seitenleiste mit den Geschenken zu bauen.

    Raum

    Damit sich überhaupt etwas tut, muss ich einen Raum anlegen:


    Bild


    Ich stelle mal 1024x768 ein. Wie groß das Suchbild später sein soll, wird sich erst noch ergeben. Die Grundgeschwindigkeit im Spiel stelle ich auf 60 ein. Das heißt 60 mal pro Sekunde prüft das Spiel alle Bedingungen und Eingaben des Benutzers und berechnet ein neues Bild. Im Idealfall bekommen wir also 60 FPS.

    Hintergrundbild habe ich noch keines, daher stelle ich einfach einen schwarzen Hintergrund ein.

    Alle anderen Einstellungen zu Kamera, Physik (z.B. Gravitation im Raum) ignoriere ich. Die werden wir vermutlich nicht benötigen.
    Angehängte Grafiken Angehängte Grafiken

  8. #8
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258

    Die ersten Code-Zeilen: Einlesen der JSON-Dateien

    Einlesen der JSON-Dateien

    Endlich geht es los! Die Vorbereitungen sind abgeschlossen, ich kann die ersten Code-Zeilen schreiben!

    Da beim Einlesen der JSON-Dateien natürlich viel schiefgehen kann – ich habe schließlich keinerlei Ahnung von GameMaker oder JSON-Dateien – initialisiere ich alle Attribute unseres künftigen Objektes „Geschenk“ mit Standardwerten:

    Bild

    Falls also irgendwo das rote X statt einer Geschenkschachtel auftauchen wird, ist etwas schiefgelaufen.
    Ich speichere als Skript scr_Gift_Create. Später kann ich dieses Skript dann bei der Erzeugung der Geschenkschachteln aufrufen.
    Ein weiteres Skript wird angelegt: scr_Load_JSON. Es soll die beiden JSON-Dateien einlesen und in GameMaker-Objekte umwandeln.
    Code:
    var GiftJsonFile = file_text_open_read("xmas_gifts.json");
    var GiftData = "";
    while (!file_text_eof(GiftJsonFile))
    {
        GiftData += file_text_read_string(GiftJsonFile);
        file_text_readln(GiftJsonFile);
    }
    file_text_close(GiftJsonFile);
    Der erste Teil ist einfach: Datei öffnen und Zeile für Zeile einlesen, bis das Ende der Datei erreicht wird. Sämtlicher Text wird hintereinander kopiert in die Variable GiftData geschrieben.
    Die JSON-Datei benötige ich nicht mehr (der Inhalt wurde in GiftData kopiert) und kann wieder geschlossen werden.

    Code:
    var GiftJsonMap = json_decode(GiftData);
    In GameMaker können Wertepaare wie die aus dem JSON-File in einer DS_MAP Datenstruktur gespeichert werden. Praktischerweise gibt es eine Funktion json_decode, die diese Wertepaare aus der JSON-Struktur ausliest und konvertiert.
    Aus einer langen Textkette (GiftData) wurden nun strukturierte Datenpaare (GiftJasonMap).
    Allerdings gibt es noch ein Problem: Die Datenpaare kommen mehrfach vor. IMG_BOXED ist dreimal enthalten.
    Praktischer wäre eine sortierte Liste mit Geschenken. Dazu habe ich im Handbuch folgenden Trick für die Konvertierung gefunden:
    Code:
    var GiftList = ds_map_find_value(GiftJsonMap, "default");
    Eine sortierte Liste, damit lässt sich arbeiten. Aber Moment! Sortiert wollte ich sie eigentlich nicht haben. Ich wollte doch eine zufällige Verteilung der Geschenke. Bevor ich später eine komplizierte Zufallsfunktion schreiben muss, würfeln wir doch einfach die Reihenfolge der Elemente in der Liste zufällig durcheinander. Auch dafür gibt es eine Standardfunktion:
    Code:
    randomize();
    ds_list_shuffle(GiftList);
    Der randomize() Befehl ist eigentlich nicht nötig. Allerdings erhält man dann im Debugging-Modus bei jedem Start die gleiche Zufallszahl. Ich will aber wissen, ob meine zufällige Verteilung funktioniert. Daher will ich auch im Debugging-Modus (echte) Zufallszahlen.
    Als nächstes will ich globale Variablen für die Geschenke anlegen und mit den ausgelesenen Werten füllen.
    Sagte ich schon, dass ich es kompliziert mag? Ohne JSON-Dateien hätte ich direkt mit diesem Schritt anfangen können …
    Also zuerst rausfinden wie viele Elemente die Liste enthält, und dann in einer Schleife durch alle Elemente und die Werte auf die globale Variable übertragen.
    Code:
    global.totalGifts = ds_list_size(GiftList);
    global.GiftData = ds_grid_create(global.totalGifts,7);
    for (var i = 0; i < global.totalGifts; i++)
    {
        var GiftEntry = ds_list_find_value(GiftList, i);
        global.GiftData[# i, ID] = GiftEntry[? "ID"];
        global.GiftData[# i, NAME] = GiftEntry[? "NAME"];
        global.GiftData[# i, IMG_BOXED] = GiftEntry[? "IMG_BOXED"];
        global.GiftData[# i, IMG_UNBOXED] = GiftEntry[? "IMG_UNBOXED"];
        global.GiftData[# i, IMG_GIFT] = GiftEntry[? "IMG_GIFT"];
        global.GiftData[# i, DESCRIPTION] = GiftEntry[? "DESCRIPTION"];
        global.GiftData[# i, PENALTY] = GiftEntry[? "PENALTY"];
    }
    Zum Schluss noch die nicht mehr benötigten Datenstrukturen löschen, sonst gibt es ein hübsches Memory-Leak. Was ich so gelesen habe, soll es reichen mit ds_map_destroy die oberste Struktur zu löschen. Untergeordnete Listen sollen dann ebenfalls gelöscht werden. Ich gehe auf Nummer sicher und lösche beides einzeln.

    Code:
    ds_list_destroy(GiftList);
    ds_map_destroy(GiftJsonMap);
    Genau dasselbe mache ich anschließend mit der zweiten JSON-Datei mit den Koordinaten der möglichen Verstecke:

    Achtung Spoiler:
    Code:
    var GiftPosJsonFile = file_text_open_read("gift_positions.json");
    var GiftPosition = "";
    while (!file_text_eof(GiftPosJsonFile))
    {
        GiftPosition += file_text_read_string(GiftPosJsonFile);
        file_text_readln(GiftPosJsonFile);
    }
    file_text_close(GiftPosJsonFile);
    
    var GiftPosJsonMap = json_decode(GiftPosition);
    var GiftPosList = ds_map_find_value(GiftPosJsonMap, "default");
    
    //Liste zufällig umsortieren
    ds_list_shuffle(GiftPosList); 
    
    global.totalGiftPositions = ds_list_size(GiftPosList);
    global.GiftPosition = ds_grid_create(global.totalGiftPositions,4);
    for (var i = 0; i < global.totalGiftPositions; i++)
    {
        var GiftPosEntry = ds_list_find_value(GiftPosList, i);
        global.GiftPosition[# i, GIFT_POS] = GiftPosEntry[? "GIFT_POS"];
        global.GiftPosition[# i, GIFT_X] = GiftPosEntry[? "GIFT_X"];
        global.GiftPosition[# i, GIFT_Y] = GiftPosEntry[? "GIFT_Y"];
        global.GiftPosition[# i, GIFT_DEPTH] = GiftPosEntry[? "GIFT_DEPTH"];
    }
    ds_list_destroy(GiftPosList);
    ds_map_destroy(GiftPosJsonMap);
    Angehängte Grafiken Angehängte Grafiken

  9. #9
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258
    Vermutlich würde das ganze Einlesen der JSON-Dateien und die Konvertierung auch einfacher gehen. Ich habe so den Verdacht, dass JSON => DS_MAP => DS_LIST => DS_GRID nicht so ganz ideal ist und ich das abkürzen könnte.

    Egal, für heute Nacht ist Schluss und beim nächsten Mal zeige ich euch das Ergebnis - oder zumindest die vermutlich zahlreich produzierten Fehlermeldungen

  10. #10
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258

    Der erste Test

    Der erste Test

    Bevor ich weitermache, will ich testen ob das Lesen der JSON-Dateien funktioniert.

    Dazu benötige ich ein Objekt, welches das Skript scr_Load_JSON aufrufen wird. Wenig kreativ nenne ich es obj_Loader:


    Bild


    Sichtbar soll es nicht sein, daher weise ich kein Sprite zu und nehme den Haken bei „visible“ weg.

    Als Event füge ich „Create“ hinzu: Dieses Event wird immer aufgerufen, wenn eine Instanz eines Objektes erzeugt wird. Auf der rechten Seite kann ich eine resultierende Aktion hinzufügen. Dafür gibt es viele vorgefertigte Aktionen, die mit Drag&Drop einfach eingefügt werden könnten.

    Stattdessen rufe ich das vorbereitete Skript scr_Load_JSON als vorerst einzige Aktion auf.

    Projekt speichern und das erste Mal das Spiel testen. Als Zielsystem wähle ich Windows aus. Und ich werde praktisch sofort nach dem Compilieren mit dieser Fehlermeldung begrüßt:


    Bild


    Wie erwartet, irgendwo in meinem JSON-Loader steckt ein Fehler. „Data structure with index does not exist“.

    Ich habe zuerst keine Ahnung woran der Fehler liegt und baue ein paar Debug-Meldungen ein.

    Code:
    show_debug_message(GiftData);
    Das Einlesen der JSON-Dateien zum Beispiel klappt noch einwandfrei. Der Inhalt von GiftData entspricht genau der Quelldatei.

    Es kostet mich sicherlich 1 Stunde, beschert mir ein paar zusätzliche graue Haare, aber ich finde einfach keinen Fehler im Code. Dennoch klappt die Konvertierung in eine Liste nicht.
    Dann schaue ich mir die JSON-Datei nochmals an. Wer nicht hochscrollen mag, hier ist sie nochmals:

    Achtung Spoiler:

    Code:
    [
      {
        "ID":1,
        "NAME":"CIV V",
        "IMG_BOXED":"spr_GiftBox1",
        "IMG_UNBOXED":"spr_GiftBoxOpen1",
        "IMG_GIFT":"spr_CIV5",
        "DESCRIPTION":"Naja, Civ 5 eben ...",
        "PENALTY": 0
      },
      {
        "ID":2,
        "NAME":"CIV IV",
        "IMG_BOXED":"spr_GiftBox2",
        "IMG_UNBOXED":"spr_GiftBoxOpen2",
        "IMG_GIFT":"spr_CIV4",
        "DESCRIPTION":"Stack of death for the win!",
        "PENALTY": 0
      }
      {
        "ID":3,
        "NAME":"Zonk",
        "IMG_BOXED":"spr_GiftBox3",
        "IMG_UNBOXED":"spr_GiftBoxOpen3",
        "IMG_GIFT":"spr_Zonk",
        "DESCRIPTION":"Ätsch",
        "PENALTY": 10
      }


    Tja, wirklich ein saublöder Fehler. Wieso hat es mir gestern niemand gesagt? Ihr seid gemein

    Was der Fehler ist?

    Achtung Spoiler:

    Elemente in JSON müssen mit Komma getrennt werden. In meiner Datei fehlt zwischen ID 2 und ID 3 aber nach der geschweiften Klammer das Komma.


    Schnell korrigiert und neu gestartet. Und tatsächlich: Das Programm wird ohne Fehler kompiliert und ein komplett schwarzes Spielfeld begrüßt mich.

    Soweit, so gut. Als nächstes dann ein Prototyp für die Platzierung der Geschenke im Raum.
    Angehängte Grafiken Angehängte Grafiken

  11. #11
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258
    Geschenke!

    Endlich kann ich mich an das eigentliche Spiel machen.
    Als Prototyp will ich 3 Geschenke in zufällig aus der Liste ausgewählte Verstecke platzieren. Danach soll ein Mausklick auf ein Geschenk ausgewertet werden und die Grafik der Geschenkschachtel ändern.

    Das neue Objekt obj_GiftBox ist schnell angelegt:


    Bild


    Ich wähle als Sprite eine der vorhandenen Geschenkschachteln aus. Die Geschenke sollen natürlich sichtbar sein, der „visible“ Haken wird also auch gesetzt.

    Wieder lege ich ein Create-Event an und rufe dort das Skript scr_Gift_Create auf. Als Erinnerung: Das Skript initialisiert nur die Variablen für unsere Geschenkbox mit Standardwerten und macht sonst nichts.
    Der normale Weg in GameMaker wäre nun, die Geschenk-Objekte per Hand im Raum zu positionieren. Dann wäre keinerlei Programmierung notwendig.

    Ich dagegen muss meine eigene Funktion schreiben, um die Geschenk-Objekte ins Spiel zu bringen ("Spawner").

    Beim Laden der JSON-Dateien habe ich die Anzahl der Elemente in globalen Variablen abgelegt. Zur Sicherheit prüfe ich, ob die Anzahl der Verstecke mindestens der Anzahl der Geschenke entspricht.

    Code:
    if global.totalGiftPositions >= global.totalGifts
    {
    Danach startet dann eine Schleife über alle Geschenke

    Code:
        for (i=0; i kleiner global.totalGifts; i+=1)
        {
          var theGift = instance_create(global.GiftPosition[# i, GIFT_X],global.GiftPosition[# i, GIFT_Y],obj_GiftBox);
    Das kleiner muss natürlich ein < sein, aber das mag unser Forum irgendwie nicht.

    Zuerst wird eine neue Instanz des Objektes obj_GiftBox angelegt und zwar an den X/Y Koordinaten aus der Versteckliste. So bekommt das erste Geschenk aus der Liste auch das erste Versteck aus der Liste. Das kann ich mir erlauben, da beide Listen ja bereits zuvor zufällig durcheinander gewürfelt worden sind.

    Durch das instance_create wird im Hintergrund dann auch automatisch unser Skript scr_Gift_Create ausgeführt, welches am Create-Event des Objektes obj_GiftBox hängt.

    Die Variablen sind also alle bereits initialisiert und können mit den passenden Werten versehen werden:

    Code:
          theGift.myID = global.GiftData[# i, ID];
          theGift.myName = global.GiftData[# i, NAME];
          theGift.myIMG_BOXED = asset_get_index(global.GiftData[# i, IMG_BOXED]);
          theGift.myIMG_UNBOXED = asset_get_index(global.GiftData[# i, IMG_UNBOXED]);
          theGift.myIMG_GIFT = asset_get_index(global.GiftData[# i, IMG_GIFT]);
          theGift.myDESCRIPTION = global.GiftData[# i, DESCRIPTION];
          theGift.myPENALTY = global.GiftData[# i, PENALTY];
          theGift.depth = global.GiftPosition[# i, GIFT_DEPTH];
    Jetzt hilft es allerdings wenig, wenn die passende Grafik für das Geschenk in der Variablen theGift.myIMG_BOXED schlummert. Sie sollte auch verwendet werden!

    Ich überschreibe also die Platzhaltergrafik mit hoffentlich der richtigen Box und ergänze noch eine Debugger-Meldung, die mir die ID des Geschenks und des Versteckes ausgeben soll. So kann ich immer sehen, welche Kombinationen das Spiel auswürfelt.

    Code:
          theGift.sprite_index = theGift.myIMG_BOXED;
          show_debug_message("Gift ID: " + string(theGift.myID) + " / Position ID: " + string(global.GiftPosition[# i, GIFT_POS]));   
        };
    };
    Die geschriebene Funktion speichere ich als scr_Gift_Spawn.

    Bild



    Jetzt muss der Spawner natürlich zum Start des Raumes auch aufgerufen werden.

    Am einfachsten hänge ich den Aufruf in das Loader-Objekt, gleich nach dem Einlesen der JSON-Dateien:

    Bild


    Für Testzwecke füge ich noch ein weiteres Event in den Loader ein: Immer wenn die Taste R gedrückt wird, soll der Raum neu aufgebaut werden. So kann ich hoffentlich die Verteilung der Geschenke einfach überprüfen.

    Bild


    Ob das alles klappt, erfahrt ihr in der nächsten Folge!
    Angehängte Grafiken Angehängte Grafiken

  12. #12
    Altes Mann Avatar von goethe
    Registriert seit
    01.11.03
    Ort
    Ullem
    Beiträge
    34.393
    wow, da machst du dir ja eine irre Arbeit


    You can check out any time you like, but you can never leave


  13. #13
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258
    Zitat Zitat von goethe Beitrag anzeigen
    wow, da machst du dir ja eine irre Arbeit
    Sobald es Arbeit wird schmeiße ich das Handtuch, versprochen!
    Ich will einfach nur mal wissen wie schwer es ist so kleine Spiele zu erstellen. Schließlich erscheinen jeden Tag Dutzende neue Spiele, so schwer kann das also nicht sein.

    Und hier also das Ergebnis der bisherigen Arbeit:

    Achtung Spoiler:
    Bild


    Es hat geklappt! 3 Geschenkschachteln erscheinen beim Start des Programmes und bei jedem Druck auf die Taste R erscheinen sie an anderer Stelle. Und niemals übereinander und immer 3 verschiedene Schachteln.

    Angehängte Grafiken Angehängte Grafiken

  14. #14
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258
    Auspacken

    Als nächstes will ich mit einem Mausklick das Geschenk auspacken und das verwendete Sprite für die Schachtel dabei ändern.

    Die Prüfung, ob ein Mausklick auf eine Schachtel erfolgt, nimmt mir GameMaker ab. Im Objekt obj_GiftBox lege ich ein neues Event „Left Released“ (linke Maustaste losgelassen) an. Das wird nur ausgelöst, wenn die Maus sich auch über dem Objekt befindet.


    Bild


    Als Aktion wähle ich dieses Mal die direkte Eingabe von Code an Stelle der Variante eine vorgefertigte Funktion aufzurufen. Das weicht natürlich vom bisherigen Muster ab, aber ich will ja alle Möglichkeiten ausprobieren.
    GameMaker bietet die Möglichkeit Codeblöcke zu benennen. Normalerweise steht ein generisches „Execute a piece of code“. Durch einen Kommentar mit /// kann der Codeblock benannt werden.

    Code:
    /// Unboxing!

    Als nächstes will ich wissen, ob die Geschenkschachtel noch zu ist. Ursprünglich wollte ich dazu eine Variable am Geschenk einführen und den Status als true/false ablegen. Aber dann dachte ich mir, wozu eigentlich? Das verwendete Sprite der Geschenkschachtel hat doch die gewünschte Information schon.

    Code:
    // check if box closed
    if sprite_index == myIMG_BOXED
       {
    // change sprite to unpacked giftbox
       sprite_index = myIMG_UNBOXED;
        }
    Das war jetzt aber doch etwas primitiv. Wenn Box zu, mach sie auf. So einfach kann das sein.

    Dann nutze ich doch die Gelegenheit und probiere gleich noch ein paar der verfügbaren Special Effects aus. GameMaker bietet da einige vorgefertigte, vom Regenschauer über Explosionen bis funkelnde Sterne.

    Ich probiere eine Kombination aus einer weiß-gelben Explosionswolke mit einem Feuerwerk aus 10 farbigen Raketensalven, wobei die Farben jeder Salve zufällig gewählt werden sollen.

    Bild


    Jetzt musste ich noch ein Tool suchen, welches mir ein animiertes GIF direkt aus dem Spiel macht, sonst seht ihr die Effekte nicht. Ich habe mich für LiceCap entschieden, ist super einfach zu benutzen.


    Bild


    Das war’s für heute, jetzt muss ich mich daran machen ein paar ordentliche Sprites für die Geschenke, die geöffneten Pakete, Weihnachtsbaum und Einrichtungsgegenstände zu erstellen oder in freien Quellen welche zu finden.

    Aufgabenliste:

    • Sprites für Pakete & Geschenke erstellen
    • Sprites für Einrichtung & Weihnachtsbaum erstellen
    • Raum & Objekte erstellen
    • Verstecke festlegen und in JSON speichern
    • Minimales UI bauen mit Stoppuhr, Spielernamen, …
    • Sidepanel mit den gefundenen und geöffneten Geschenken erstellen
    • Startmenu bauen wo der Spieler den Namen eingeben und das Spiel starten kann
    • Testen, testen, testen
    Angehängte Grafiken Angehängte Grafiken

  15. #15
    Ad Astra Avatar von Ronnar
    Registriert seit
    27.10.08
    Beiträge
    3.258
    Fail fast, fail early!

    Klingt blöd, stimmt aber manchmal. Gestern habe ich mich an den Sprites versucht, um einen Raum zu erstellen. Die Ergebnisse sahen schlimmer aus als von einem 5jährigen gemalt.

    Sprites aus freien Quellen gibt es zwar, aber dann muss ich verschiedene Stile mischen. Das sieht dann auch furchtbar aus.

    Alternative wäre ein fertig eingerichteter, weihnachtlicher Raum. Schöne Bilder gibt es da genügend. Aber die Einrichtungsgegenstände (Weihnachtsbaum, Sofa, …) freizustellen und einzeln als Objekte ins Spiel zu bringen ist eine Menge Aufwand. Und das wäre notwendig, um die Geschenke dahinter verstecken zu können.

    Der Zeitplan ist in Gefahr, schließlich kann ich fast den ganzen November nicht an diesem Projekt arbeiten (Urlaub ohne Computer oder Smartphone ). Also muss es eigentlich die nächsten 2-3 Wochen weitgehend fertig werden.

    Es müssen also neue Ideen her, die ich in kleinen Prototypen ausprobieren werde. Mehr als einen Abend (2h) darf ich pro Prototyp für die Umsetzung nicht brauchen.

    Was könnte ich also ändern, ohne die Grundidee komplett über den Haufen zu schmeißen und dennoch einen gewissen Anspruch an die grafische Qualität zu wahren?

    Idee 1: Vorhang auf!

    Als Strategiespieler kennt man das natürlich: Fog of War!

    Wie wäre es also den kompletten Raum als Hintergrundbild zu nehmen, die Geschenke darüber zu positionieren …

    Bild


    … und dann den hässlichen Gesamteindruck durch eine Art Kriegsnebel zu verdecken?

    Nur sah der Nebel in meinen Tests nicht so richtig weihnachtlich aus. Aber wer sagt, dass es wie ein Nebel den Hintergrund verdecken muss. Es könnte ja auch aussehen wie ein erleuchtetes Fenster, durch das der weihnachtlich dekorierte Raum gerade noch zu erkennen ist. Dann presst man sich die Nase an der Scheibe platt und kann vielleicht das eine oder andere Geschenk im Zimmer entdecken.

    Bild


    Ja, das macht doch schon viel mehr her! Das weckt Lust zu entdecken, was man nur verschwommen erahnen kann. Ok, die Geschenke schweben noch in der Luft und schimmern zu stark durch. Aber ich habe auch noch keinerlei Zeit darauf verwendet die Positionen festzulegen oder die Farben der Geschenke. Und auch die Transparenz der Fenster ist nur mit einem ersten Näherungswert so eingestellt, dass man den Raum erahnen kann.

    Und den Einblick durch das Fenster bekommt man durch eine sternförmige Fläche (Weihnachten!) rings um den Cursor:


    Bild


    Das umzusetzen hat mich inklusive der Suche nach geeigneten Bildern 2 Stunden gekostet.

    Wie gefällt euch der Prototyp? Ist das eine Richtung in der ich weitermachen soll?

    Wenn ja, zeige ich auch gerne wieder wie ich das programmiert habe. Ist eigentlich nur 1 neues Objekt, 2 Sprites (Fenster + sternförmiges Guckloch) und vielleicht 25 Zeilen Code.
    Angehängte Grafiken Angehängte Grafiken

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •