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

1

11.06.2016, 17:54

Prozedurale Levelgenerierung

Hallo,
ich möchte für einen Online-2D-Dungeoncrawler in Javascript eine "Klasse" schreiben
die selbst einzelne Dungeons erstellt. Ich habe auch soweit Code geschrieben der so
einigermaßen funktoniert... :S Räume, sowie Wände werden erstellt, aber sobald es
daran geht die einzelnen Wege zu generieren braucht das Programm eine Ewigkeit!
Und ich frage mich wo ist das Problem?

chaosgamer

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
function Dungeon() {
    this.data = [];
    this.dungeonSize = { x: null, y: null };
    this.dungeonRoom = null;
}

Dungeon.prototype = new Game();

Dungeon.prototype.tiles = 8; // => The size of the only tile.
Dungeon.prototype.minDungeonSize = { x: 35, y: 21 };
Dungeon.prototype.roomSize = { min: 6, max: 13 };
Dungeon.prototype.roomQuantity = { min : 7, max: null };

// "<" = room || "+" = waypoint || ">" = way || ":" = nothing || ";" = wall

// => (dX,dY) >> Dungeonsize
Dungeon.prototype.createNewDungeon = function(dX,dY,rQ) {
    this.dungeonSize.x = dX + this.minDungeonSize.x;
    this.dungeonSize.y = dY + this.minDungeonSize.y;
    this.roomQuantity.max = rQ + this.roomQuantity.min;

    this.data = new Array(this.dungeonSize.y);
    
    for (var i = 0; i < this.data.length; i++) {
        this.data[i] = new Array(this.dungeonSize.x);
        for (var b = 0; b < this.data[i].length; b++) { 
            this.data[i][b] = ":";
            if((i % 2 == 0) && (b % 2 == 0)) this.data[i][b] = "+";
        }
    }
    this.createTheRoom();
    this.createTheWall();
    this.createTheMaze();
    this.createTheWall();
};

Dungeon.prototype.createTheRoom = function() {
    this.dungeonRoom = new Array(Math.floor((Math.random() * (this.roomQuantity.max - this.roomQuantity.min)) + this.roomQuantity.min));
    
    for(var i = 0; i < this.dungeonRoom.length; i++) {
        this.dungeonRoom[i] =   {   xSize: this.randomSize(),
                                    ySize: this.randomSize(),
                                    xPos:  this.randomPosition(this.dungeonSize.x),
                                    yPos:  this.randomPosition(this.dungeonSize.y)
                                };
        for(var a = this.dungeonRoom[i].yPos; a < (this.dungeonRoom[i].yPos + this.dungeonRoom[i].ySize); a++) {
            for(var b = this.dungeonRoom[i].xPos; b < (this.dungeonRoom[i].xPos + this.dungeonRoom[i].xSize); b++) {
                if(this.data[a][b] == ":" || this.data[a][b] == "+") this.data[a][b] = "<";
            } 
        }
    }
};

Dungeon.prototype.randomPosition = function(value) {
    var finalValue;
    do {
        finalValue = Math.floor(Math.random() * (value - 3));
        if(finalValue % 2 == 0) break;
    } while(true);

    return finalValue;
};

Dungeon.prototype.randomSize = function() {
    var finalValue;
    do {
        finalValue = Math.floor((Math.random() * (this.roomSize.max - this.roomSize.min)) + this.roomSize.min);
        if(!(finalValue % 2 == 0)) break;
    } while(true);

    return finalValue;
};

Dungeon.prototype.createTheMaze = function() {
    var this_Stack = [];
    var between;
    var value;
    var course = [];

    do {
        var a = Math.floor(Math.floor(Math.random() * this.dungeonSize.y));
        var b = Math.floor(Math.floor(Math.random() * this.dungeonSize.x));

        if(this.data[a][b] == "+" && !(this.data[a][b + 2] == "<" || this.data[a][b - 2] == "<" || this.data[a + 2][b] == "<" || this.data[a - 2][b] == "<")) {
            if((a < 20 || a > (this.dungeonSize.y - 20)) && (b < 20 || b > (this.dungeonSize.x - 20))) {
                this.data[a][b] = ";";
                break;              
            }
        }   
    } while(true);


    for (var i = 0; i <= 100; i++) {
        if (this.data[a][b + 2] == "+" && !(this.data[a][b + 2] == "<") && !(this.data[a][b + 2] == ">")) course.push([a,b + 2]);
        if (this.data[a][b - 2] == "+" && !(this.data[a][b - 2] == "<") && !(this.data[a][b - 2] == ">")) course.push([a,b - 2]);
        if (this.data[a + 2][b] == "+" && !(this.data[a + 2][b] == "<") && !(this.data[a + 2][b] == ">")) course.push([a + 2,b]);
        if (this.data[a - 2][b] == "+" && !(this.data[a - 2][b] == "<") && !(this.data[a - 2][b] == ">")) course.push([a - 2,b]);

        if (course.length == 0) break;

        between = course[Math.floor((Math.random() * 4) - 1)]
        course = [];
        
        if (a < between[0]) {
            a = between[0];
            this.data[a][b] = this.data[a - 1][b] = ">";
        } else if (a > between[0]) {
            a = between[0];
            this.data[a][b] = this.data[a + 1][b] = ">";
        } else {

            if (b < between[1]) {
                b = between[1];
                this.data[a][b] = this.data[a][b - 1] = ">";
            } else {
                b = between[1];
                this.data[a][b] = this.data[a][b + 1] = ">";
            }

        }

        between = [];

        this_Stack.push([a,b]);

    }
};

Dungeon.prototype.createTheWall = function() {
    for(var i = 0; i < this.data.length; i++) {
        for(var a = 0; a < this.data[i].length; a++) {
            if((this.data[i][a] == ">" || this.data[i][a] == "<") && (this.data[i - 3][a] == ":" || this.data[i - 3][a] == "+") && !(this.data[i - 1] == ">")) {
                this.data[i - 1][a] = ";";
                this.data[i - 2][a] = ";";
                this.data[i - 3][a] = ":";
            }
        }
    }
};

2

11.06.2016, 18:42

Joa keine Ahnung. Was sagt denn Firebug?

MfG
Check

Zipfelpilz

unregistriert

3

12.06.2016, 07:12

Auffällig sind auf jeden Fall deine Endlosschleifen, aus denen du dich mit Zufallszahlen rauswürfelst. Wie wahrscheinlich ist der Eintritt der Bedingungen ab Zeile 84? Ein besserer Ansatz wäre es von einem Zufallspunkt eine Breitensuche nach einem geeigneten Feld durchzuführen. Noch vorhersagbarer wird es, wenn du die möglichen Startpunkte vorher in einer Liste speicherst und daraus einen auswählst.

Ähnliches gilt für die randomSize()-Funktion, die hat zwar eine einfachere Abbruchbedingung, trotzdem könntest du den gewürfelten Wert einfach nachkorrigieren, indem du den nächsten Wert nimmst, falls finalValue gerade ist. Dann brauchen diese Schleifen nie mehr als einen Durchlauf. Ob dein Problem daran liegt, weiß ich aber auch nicht - versuch es mal mit dem Debugger einzugrenzen, wie dir schon geraten wurde.

Die Bedingungen ab Zeile 94 haben auch noch Optimierungsbedarf.

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

4

12.06.2016, 10:05

Noch vorhersagbarer wird es, wenn du die möglichen Startpunkte vorher in einer Liste speicherst und daraus einen auswählst.
Das wäre meiner Meinung nach die bessere Vorgehensweise.

Ähnliches gilt für die randomSize()-Funktion, die hat zwar eine einfachere Abbruchbedingung, trotzdem könntest du den gewürfelten Wert einfach nachkorrigieren, [...]
Ein Nachkorrigieren ist noch nichtmal notwendig. Stattdessen könnte direkt ein gültiger Wert generiert werden: Math.floor(Math.random() * (max - min) * 0.5) * 2 + min (Man beachte, dass max dabei exklusiv ist.)

versuch es mal mit dem Debugger einzugrenzen, wie dir schon geraten wurde.
Ja.
Wenn der Code auf ein paar mehr Funktionen aufgeteilt wäre, dürfte der Profiler der jeweiligen Entwicklerwerkzeuge bereits einiges an Informationen liefern.

Die Bedingungen ab Zeile 94 haben auch noch Optimierungsbedarf.
Ja, zum Beispiel indem die Werte aus dem Array zwischengespeichert werden. Man könnte auch schauen, ob man dafür eine Funktion schreibt, da die Bedingungen und durchgeführten Aktionen bis auf die Indizes gleich sind.
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

Werbeanzeige