Du bist nicht angemeldet.

Werbeanzeige

Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 695

Wohnort: Gießen

  • Private Nachricht senden

1

06.10.2019, 22:08

Gridbasiertes Level in externe Datei auslagern

Hallo,
ich möchte gerne Level für ein gridbasiertes Spiel erstellen (ich benutze Unity). Dort hat jede Zelle verschiedene Attribute, die vorhanden sein können, aber nicht müssen. Es gibt derzeit Trigger, Obstacles und WorldObjects.

- Trigger können beispielsweise Lichtschalter, Lagerfeuer oder ein tiefes Loch sein
- Obstacles sind nicht passierbare Hindernisse, also beispielsweise Bäume oder Zäune
- WorldObjects sind die beweglichen Dinge, die auf der Zelle stehen, also der Spieler oder Gegner

Grundsätzlich können sich Trigger und Obstacles jeweils an den Außenseiten oder in der Mitte befinden. Ausgehend von der Koordinate könnte sich also etwas auf

- (0 | 0) => Mitte
- (-1 | 0) => Links
- (1 | 0) => Rechts
- (0 | 1) => Oben
- (0 | -1) => Unten

befinden. WorldObjects befinden sich nur in der Mitte. Es können sich beliebig viele Objekte an einer Seite oder in der Mitte befinden. Das macht zwar wenig Sinn, liegt aber meiner Meinung nach beim Leveldesigner, wenn er einen Trigger (Schalter) an einen Zaun setzen möchte. Aus rein technischer Sicht gibt es beim Grid 3 Ebenen.

- 1. Ebene: Der technische Boden, also die Logik der Zelle
- 2. Ebene: Der dargestellte Boden, also eigentlich nur die Bodentextur
- 3. Ebene: Die Dinge, die sich auf der Zelle befinden

Ich habe einmal begonnen, ein 2x2 Demo Grid zu erstellen (ein Leveleditor folgt)

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
{
    "name": "Level One",
    "cells": [
        [
            {
                "groundTexture": "grass",
                "obstacles": [
                    {
                        "x": 0,
                        "y": -1,
                        "type": "static",
                        "model": "fence",
                        "rotation": 90
                    }
                ],
                "triggers": [],
                "worldObjects": [
                    {
                        "type": "player",
                        "model": "player",
                        "rotation": 90
                    }
                ]
            },
            {
                "groundTexture": "grass",
                "obstacles": [
                    {
                        "x": 0,
                        "y": 0,
                        "type": "static",
                        "model": "tree",
                        "rotation": 0
                    }
                ],
                "triggers": [],
                "worldObjects": []
            }
        ],
        [
            {
                "groundTexture": "grass",
                "obstacles": [],
                "triggers": [
                    {
                        "x": 0,
                        "y": 0,
                        "type": "death",
                        "model": "campfire",
                        "rotation": 0
                    }
                ],
                "worldObjects": []
            },
            {
                "groundTexture": "grass",
                "obstacles": [],
                "triggers": [],
                "worldObjects": []
            }
        ]
    ]
}


Nun ergeben sich noch folgende Dinge:

- Vielleicht kann man sich die Rotation der Obstacles und Trigger sparen, weil man diese auch beim Deserialisieren berechnen könnte.
- Die Terminologie mit den WorldObjects passt nicht, weil eigentlich stehen die Obstacles wie Bäume oder Zäune ja auch auf der Zelle ...
- Bei der Angabe von "type": "..." fehlt mir noch die Information, was es genau ist. Gleichzeitig möchte ich aber auch nicht zu technisch werden. Ein Baum oder ein Zaun ist ein Obstacle, heißt static würde ausreichen. Trotzdem könnten beide beispielsweise eine unterschiedliche Animation abspielen. Bei einem Feuer würde der Spieler verbrennen, beim Loch hineinfallen. Heißt, ich müsste schon noch eine Information unterbringen, welche Klasse/Logik genau zu laden ist.
- Es könnte ja sein, dass eine Zelle größer als 1x1 ist. Ein Haus könnte 2x3 Zellen beanspruchen. Wie würde man das unterbringen? Alle Zellen verbinden sich zu einer Gruppe, indem die "Kindzellen" nur auf die eigentliche Zelle verweisen?

Hat jemand Erfahrung damit und kann helfen? Vielleicht würdet ihr das Ganze ja ganz anders lösen :) Ich möchte es nur gerne direkt richtig machen und mir keine Wege verbauen.

Sacaldur

Community-Fossil

Beiträge: 2 326

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

2

07.10.2019, 09:30

Welches Ziel verfolgst du damit, die Level in Dateien abzulegen? Ich frage, weil es Vor- und Nachteile mit sich bringt. Sofern du die Vorteile nicht wirklich brauchst, solltest du aufgrund der Nachteile vielleicht doch lieber dazu übergehen, die Level in Szenen zu definieren, da du dort mehr Freiheiten hast und nicht in solche Probleme rennst, wie "wie handhabe ich Häuser?"

In den meisten Gridbasierten Spielen hat man meist einerseits den regulären Teil, wo für jedes Feld auch ein Wert definiert sein muss (Tilemaps), als auch einen "irregulären" Teil, also bspw. Objekte, die nicht in einem Raster/einem Array von Arrays abgelegt sind, sondern in einer Liste mit der zusätzlichen Information der Position und Größe. (Beim Game Boy Advance, um ein Beispiel zu nennen, hätte man die Layer, die 8x8 Tiles beinhalten, und Sprites, die unabhängig der Layer und Pixel-genau positioniert werden können und Breite und Höhe zwischen 8 und 64 Pixel haben können, also 1 bis 8 Felder.)

Zu den Typen: welche Wertebereiche haben diese? Im Beispiel sehe ich "static" für obstacles, "death" für Trigger und "player" für WorldObjects. Um zu wissen, was das beste Design für das Levelformat ist, muss bekannt sein, was dieses unterstützten muss. Die Animationen sollten aus dem model entnommen werden können.

Zur Namenswahl: häufig wird auch "Mob" (für Movable Object) für Objekte verwendet, die sich nicht am Grid orientieren (und nicht statisch sind). Sollten Obstacles auch mal nicht statisch sein, könnte es vielleicht sinnvoll sein, keine Unterscheidung zwischen Obstacles und WorldObjects vorzunehmen. Trigger können auch nur solange getrennt betrachtet werden, wie es immer Bereiche sind, in die man reinläuft, um etwas auszulösen. Allerdings ist auch hier eine Abgrenzung schwierig, weil es mal bspw. bewegliche Objekte geben kann, die intern wie Trigger gehandhabt werden müssen (bspw. ein Hase der gefangen werden soll).
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 695

Wohnort: Gießen

  • Private Nachricht senden

3

07.10.2019, 21:19

Welches Ziel verfolgst du damit, die Level in Dateien abzulegen? Ich frage, weil es Vor- und Nachteile mit sich bringt. Sofern du die Vorteile nicht wirklich brauchst, solltest du aufgrund der Nachteile vielleicht doch lieber dazu übergehen, die Level in Szenen zu definieren, da du dort mehr Freiheiten hast und nicht in solche Probleme rennst, wie "wie handhabe ich Häuser?"


Eigentlich ist der einzige Grund Bequemlichkeit, da es wahrscheinlich ca. 100 Level geben könnte. Außerdem muss der Erschaffer des Levels dann nicht mühsam alles per Hand reinziehen und kann über die Datei schneller Änderungen vornehmen.

In den meisten Gridbasierten Spielen hat man meist einerseits den regulären Teil, wo für jedes Feld auch ein Wert definiert sein muss (Tilemaps), als auch einen "irregulären" Teil, also bspw. Objekte, die nicht in einem Raster/einem Array von Arrays abgelegt sind, sondern in einer Liste mit der zusätzlichen Information der Position und Größe. (Beim Game Boy Advance, um ein Beispiel zu nennen, hätte man die Layer, die 8x8 Tiles beinhalten, und Sprites, die unabhängig der Layer und Pixel-genau positioniert werden können und Breite und Höhe zwischen 8 und 64 Pixel haben können, also 1 bis 8 Felder.)


Also das gridbasierte Spiel ist optisch voxelbasiert (3D), aber das sollte zu 2D ja keinen Unterschied machen, die Logik bleibt ja gleich. Aber zusätzlich noch Dinge einzufügen, die komplett unabhängig von der Karte sind, ist ein guter Ansatzpunkt :)


Zu den Typen: welche Wertebereiche haben diese? Im Beispiel sehe ich "static" für obstacles, "death" für Trigger und "player" für WorldObjects. Um zu wissen, was das beste Design für das Levelformat ist, muss bekannt sein, was dieses unterstützten muss. Die Animationen sollten aus dem model entnommen werden können.


Also das wollte ich erstmal offen lassen, so gut es geht... Ich kann es zwar jetzt schon eingrenzen, wollte es aber erweiterbar halten, wenn möglich

- Die Obstacles könnten beispielsweise permanent unbeweglich sein (großer Felsbrocken), oder aber auch (zb eine Kiste) den Spieler stoppen, sich selbst aber 1 Feld weiterbewegen. Oder ein Schrank, der umkippen kann. Oder eine Tür, die verschlossen ist, durch einen Trigger aber geöffnet wird(Obstacle wird dann durch den Trigger entfernt)

- Trigger könnten Lichtschalter sein, die das Level "verändern" oder aber auch Flammen (Spieler stirbt) oder eine Grube (Spieler stirbt) oder einfach eine Druckplatte, also ein weiterer Schalter.

- Die WorldObjects wären friendly und hostile NPCs. Dabei können diese unterschiedlich auf Dinge reagieren und ihre eigene Logik haben. Manche gucken starr nach vorn, manche bewegen sich, wenn man ihnen zu nahe kommt.

Zur Namenswahl: häufig wird auch "Mob" (für Movable Object) für Objekte verwendet, die sich nicht am Grid orientieren (und nicht statisch sind). Sollten Obstacles auch mal nicht statisch sein, könnte es vielleicht sinnvoll sein, keine Unterscheidung zwischen Obstacles und WorldObjects vorzunehmen. Trigger können auch nur solange getrennt betrachtet werden, wie es immer Bereiche sind, in die man reinläuft, um etwas auszulösen. Allerdings ist auch hier eine Abgrenzung schwierig, weil es mal bspw. bewegliche Objekte geben kann, die intern wie Trigger gehandhabt werden müssen (bspw. ein Hase der gefangen werden soll).


Nein, solche komplexen Dinge werden, so sehe ich es zumindest jetzt, nicht vorkommen. Der Spieler kann nur entlang einer Achse sliden und trifft dort eben auf ein Obstacle (bleibt stehen), auf einen Trigger (löst etwas aus) auf beides (Lichtschalter an einer Wand) oder auf einen NPC, der dann etwas tut. Kommt der Spieler neben einem NPC zum stehen, hat sich also nicht direkt auf ihn zubewegt, wird auch eine Aktion des NPCs ausgelöst.

Sacaldur

Community-Fossil

Beiträge: 2 326

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

4

08.10.2019, 10:02

Welches Ziel verfolgst du damit, die Level in Dateien abzulegen? Ich frage, weil es Vor- und Nachteile mit sich bringt. Sofern du die Vorteile nicht wirklich brauchst, solltest du aufgrund der Nachteile vielleicht doch lieber dazu übergehen, die Level in Szenen zu definieren, da du dort mehr Freiheiten hast und nicht in solche Probleme rennst, wie "wie handhabe ich Häuser?"


Eigentlich ist der einzige Grund Bequemlichkeit, da es wahrscheinlich ca. 100 Level geben könnte. Außerdem muss der Erschaffer des Levels dann nicht mühsam alles per Hand reinziehen und kann über die Datei schneller Änderungen vornehmen.

Am bequemsten wäre es, wenn der Erschaffer (also du) ein Tool hat, welches ihn bei der Erstellung unterstützt. Das kann nun entweder Unity sein, oder Unity mit ein wenig Editor-Scripting, oder Tiled mit passendem Exporter, oder ein ganz eigenes Tool. In jedem Fall wäre es wesentlich komfortabler, als eine Textdatei anpassen zu müssen. Die paar Objekte zu definieren oder anzupassen dürfte kein so großes Problem darstellen, aber wenn man dann erstmal Umgebungen mit der Größe 100x100 oder mehr hat, muss man dennoch den Bodentypen für alle Felder definieren, was bei Textdateien eher mühselig wäre.


Insgesamt solltest du berücksichtigen, dass das Schreiben von Tools oder anderen Element drum herum um das eigentliche Spiel durchaus interessant sein und eine entsprechende Herausforderung darstellen kann, was man aber konkret brauchen wird, wird man erst während der Umsetzung des Spiels herausfinden. Ich habe das Gefühl, dass du zu viel offen halten willst, weil du noch nicht weißt, was dir vielleicht in den Sinn kommen könnte, statt genau dort weiterzumachen und dir zu überlegen, was du genau brauchen wirst.
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

5

08.10.2019, 19:46

Ich kenne mich da zwar nicht so gut aus aber beschreibe trotzdem mal wie ich das mal gemacht habe.

Ich hatte zum Beispiel 10 verschiedene Boden Tiles, 10 Dekoobjekte und 5 Spiellogikobjekte.
Jedes hat eine unique ID bekommen.

Anschließend habe ich für jedes Feld die einzelnen IDs gespeichert.

map[0,0] = "101,205,302";
map[0,1] = "101,204,301";

Also hat Kachel 0,0 den Boden mit der ID 101, darauf steht das Dekoobjekt mit der ID 205 (ein Baum) und hat einen Checkpoint (Spiellogikobjekt mit ID 302).
100-199 Boden, 200-299 Deko, 300-399 Logik.

Eventuell kann man für die einzelnen Objekt noch eine zusätzliche Ausrichtung oder Verschiebung angeben.
Zuerst hatte ich die kompletten Objekte gespeichert und das Savefile wurde mehrere MB groß, hinterher waren es nur noch wenige KB.

Was meint ihr dazu? Ist dieser Ansatz sinnvoll, gut? Was kann man besser/anders machen?

Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 695

Wohnort: Gießen

  • Private Nachricht senden

6

08.10.2019, 20:07

Ich habe das Gefühl, dass du zu viel offen halten willst, weil du noch nicht weißt, was dir vielleicht in den Sinn kommen könnte, statt genau dort weiterzumachen und dir zu überlegen, was du genau brauchen wirst.


Ja. Wahrscheinlich schon. Ich muss das Ganze mal etwas eingrenzen.

@Raubhamster

Ja, so in etwa war auch mein Gedanke. Ich habe dann aber von Zahlen abgesehen, weil ich diese dann ja auch wieder mappen müsste. Daher wollte ich einfach den Pfad zum Asset angeben... Da gibt es dann auch wieder Vor- und Nachteile

Werbeanzeige