Skip to content

Commit f5ec6d9

Browse files
committed
mapgen working
1 parent 9db2872 commit f5ec6d9

4 files changed

Lines changed: 240 additions & 12 deletions

File tree

assets/images/autotiles.png

609 Bytes
Loading

assets/images/floor.png

1.83 KB
Loading

source/GameMap.hx

Lines changed: 237 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@ package;
22

33
import flixel.FlxG;
44
import flixel.addons.tile.FlxCaveGenerator;
5+
import flixel.group.FlxGroup;
56
import flixel.tile.FlxBaseTilemap.FlxTilemapAutoTiling;
67
import flixel.tile.FlxTilemap;
78

8-
class GameMap extends FlxTilemap
9+
class GameMap extends FlxGroup
910
{
1011
public var walkableTiles:Array<Int> = [];
1112
public var roomsInfo:Array<RoomInfo> = [];
1213

14+
public var floorMap:FlxTilemap;
15+
public var wallsMap:FlxTilemap;
16+
1317
public function new()
1418
{
1519
super();
@@ -153,28 +157,31 @@ class GameMap extends FlxTilemap
153157
{
154158
if (leaf.left != null || leaf.right != null)
155159
continue;
156-
var margin = 2;
160+
// increase margin so rooms stay away from partition edges
161+
var margin = 3;
157162
var maxRW = Math.max(3, leaf.w - margin * 2);
158163
var maxRH = Math.max(3, leaf.h - margin * 2);
159164
if (maxRW < 3 || maxRH < 3)
160165
continue;
161166

162-
var rW = Math.max(3, maxRW - Std.int(FlxG.random.float() * Std.int(maxRW * 0.12)));
163-
var rH = Math.max(3, maxRH - Std.int(FlxG.random.float() * Std.int(maxRH * 0.12)));
167+
// increase room fraction so rooms are larger (65% - 90% of partition)
168+
var rW = Std.int(Math.max(3, maxRW * (0.65 + FlxG.random.float() * 0.25)));
169+
var rH = Std.int(Math.max(3, maxRH * (0.65 + FlxG.random.float() * 0.25)));
164170
var rx = leaf.x + margin + Std.int(FlxG.random.float() * Math.max(0, leaf.w - rW - margin * 2));
165171
var ry = leaf.y + margin + Std.int(FlxG.random.float() * Math.max(0, leaf.h - rH - margin * 2));
166172

167173
var cx = rx + Std.int(rW / 2);
168174
var cy = ry + Std.int(rH / 2);
169175

170-
var circles = 5 + Std.int(FlxG.random.float() * 8); // 5..12
176+
// more circles and slightly larger radii for richer blobs
177+
var circles = 6 + Std.int(FlxG.random.float() * 7); // 6..12
171178
for (c in 0...circles)
172179
{
173180
var angle = FlxG.random.float() * Math.PI * 2;
174-
var edgeBias = 0.35 + FlxG.random.float() * 0.65;
181+
var edgeBias = 0.35 + FlxG.random.float() * 0.55; // push toward edge moderately
175182
var ox = cx + Std.int((rW / 2) * Math.cos(angle) * edgeBias) + Std.int((FlxG.random.float() - 0.5) * 4);
176183
var oy = cy + Std.int((rH / 2) * Math.sin(angle) * edgeBias) + Std.int((FlxG.random.float() - 0.5) * 4);
177-
var maxRad = Math.max(2, Std.int(Math.min(rW, rH) * (0.20 + FlxG.random.float() * 0.55)));
184+
var maxRad = Math.max(2, Std.int(Math.min(rW, rH) * (0.18 + FlxG.random.float() * 0.50))); // larger circles
178185

179186
var minx:Int = Std.int(Math.max(1, ox - maxRad - 1));
180187
var maxx:Int = Std.int(Math.min(totalW - 2, ox + maxRad + 1));
@@ -285,7 +292,7 @@ class GameMap extends FlxTilemap
285292
carveCrooked(x1, y1, mxi, myi, width, depth + 1);
286293
carveCrooked(mxi, myi, x2, y2, width, depth + 1);
287294

288-
if (FlxG.random.float() < 0.18 && depth < 4)
295+
if (FlxG.random.float() < 0.35 && depth < 6)
289296
{
290297
var bx = Std.int(mxi + (FlxG.random.float() - 0.5) * dist * 0.5);
291298
var by = Std.int(myi + (FlxG.random.float() - 0.5) * dist * 0.5);
@@ -301,11 +308,23 @@ class GameMap extends FlxTilemap
301308
return;
302309
if (node.left != null && node.right != null)
303310
{
304-
var a = node.left.roomCenter;
305-
var b = node.right.roomCenter;
311+
// find nearest room center in left subtree and right subtree
312+
function findCenter(n:Dynamic):Dynamic
313+
{
314+
if (n == null)
315+
return null;
316+
if (n.roomCenter != null)
317+
return n.roomCenter;
318+
var l:Dynamic = findCenter(n.left);
319+
if (l != null)
320+
return l;
321+
return findCenter(n.right);
322+
}
323+
var a = findCenter(node.left);
324+
var b = findCenter(node.right);
306325
if (a != null && b != null)
307326
{
308-
var w = Std.int(3 + Std.int(FlxG.random.float() * 9));
327+
var w = Std.int(3 + Std.int(FlxG.random.float() * 6));
309328
carveCrooked(a.x, a.y, b.x, b.y, w, 0);
310329
}
311330
}
@@ -359,14 +378,220 @@ class GameMap extends FlxTilemap
359378
M[y][totalW - 1] = 1;
360379
}
361380

381+
// --- Remove orphan (disconnected) floor regions, keeping the largest connected area ---
382+
// Build component id grid initialized to -1
383+
var comp:Array<Array<Int>> = [];
384+
for (yy in 0...totalH)
385+
{
386+
var crow:Array<Int> = [];
387+
for (xx in 0...totalW)
388+
crow.push(-1);
389+
comp.push(crow);
390+
}
391+
392+
var comps:Array<Array<Dynamic>> = [];
393+
var cid:Int = 0;
394+
for (yy in 0...totalH)
395+
{
396+
for (xx in 0...totalW)
397+
{
398+
if (M[yy][xx] != 0 || comp[yy][xx] != -1)
399+
continue;
400+
// flood-fill / BFS stack
401+
var stack:Array<Dynamic> = [];
402+
stack.push({x: xx, y: yy});
403+
comp[yy][xx] = cid;
404+
var list:Array<Dynamic> = [];
405+
while (stack.length > 0)
406+
{
407+
var cur = stack.pop();
408+
list.push(cur);
409+
var dxs:Array<Int> = [-1, 1, 0, 0];
410+
var dys:Array<Int> = [0, 0, -1, 1];
411+
for (k in 0...4)
412+
{
413+
var nx:Int = cur.x + dxs[k];
414+
var ny:Int = cur.y + dys[k];
415+
if (nx < 0 || ny < 0 || nx >= totalW || ny >= totalH)
416+
continue;
417+
if (M[ny][nx] == 0 && comp[ny][nx] == -1)
418+
{
419+
comp[ny][nx] = cid;
420+
stack.push({x: nx, y: ny});
421+
}
422+
}
423+
}
424+
comps.push(list);
425+
cid++;
426+
}
427+
}
428+
429+
// find largest component
430+
var keepId:Int = -1;
431+
var bestSize:Int = -1;
432+
for (i in 0...comps.length)
433+
{
434+
if (comps[i].length > bestSize)
435+
{
436+
bestSize = comps[i].length;
437+
keepId = i;
438+
}
439+
}
440+
441+
// fill (turn to wall) any component that is not the main one
442+
for (i in 0...comps.length)
443+
{
444+
if (i == keepId)
445+
continue;
446+
for (t in comps[i])
447+
M[t.y][t.x] = 1;
448+
}
449+
450+
// Recompute each room's tile list based on final map (roomsInfo built earlier may be stale)
451+
for (r in 0...roomsInfo.length)
452+
{
453+
var room:RoomInfo = roomsInfo[r];
454+
var rx:Int = Std.int(room.bbox.x);
455+
var ry:Int = Std.int(room.bbox.y);
456+
var rw:Int = Std.int(room.bbox.w);
457+
var rh:Int = Std.int(room.bbox.h);
458+
var by0:Int = Std.int(Math.max(0, ry - 1));
459+
var by1:Int = Std.int(Math.min(totalH, ry + rh + 1));
460+
var bx0:Int = Std.int(Math.max(0, rx - 1));
461+
var bx1:Int = Std.int(Math.min(totalW, rx + rw + 1));
462+
var newTiles:Array<Dynamic> = [];
463+
for (yy in by0...by1)
464+
for (xx in bx0...bx1)
465+
if (M[yy][xx] == 0)
466+
newTiles.push({x: xx, y: yy});
467+
room.tiles = newTiles;
468+
room.area = newTiles.length;
469+
}
470+
471+
// rebuild global walkable list
362472
walkableTiles = [];
363473
for (yy in 0...totalH)
364474
for (xx in 0...totalW)
365475
if (M[yy][xx] == 0)
366476
walkableTiles.push(yy * totalW + xx);
367477

368478
var csv:String = FlxCaveGenerator.convertMatrixToString(M);
369-
this.loadMapFromCSV(csv, "assets/images/autotiles.png", TILE_SIZE, TILE_SIZE, FlxTilemapAutoTiling.AUTO);
479+
// create floor tilemap (full-extent mockup) and add it below walls
480+
var floorCsv:String = generateFloorCSV(totalW, totalH);
481+
floorMap = new FlxTilemap();
482+
// use OFF autotiling for the simple floor tileset (4 tiles in floor.png)
483+
floorMap.loadMapFromCSV(floorCsv, "assets/images/floor.png", TILE_SIZE, TILE_SIZE, FlxTilemapAutoTiling.OFF);
484+
this.add(floorMap);
485+
486+
// create walls tilemap and add on top of floor
487+
wallsMap = new FlxTilemap();
488+
wallsMap.loadMapFromCSV(csv, "assets/images/autotiles.png", TILE_SIZE, TILE_SIZE, FlxTilemapAutoTiling.FULL);
489+
this.add(wallsMap);
490+
}
491+
492+
// --- helper: generate a floor CSV using multi-octave value-noise (Perlin-like) ---
493+
private function generateFloorCSV(w:Int, h:Int):String
494+
{
495+
// simple value-noise: grid of random values sampled with bilinear interpolation
496+
497+
// sample with multiple octaves (tuned for more coherence)
498+
var octaves = 4;
499+
var persistence = 0.62; // stronger low-frequency contribution
500+
var lacunarity = 1.7; // slower frequency increase -> bigger features
501+
var baseFreq:Float = 0.6; // start at a lower base frequency for larger patches
502+
503+
var maxAmp:Float = 0.0;
504+
for (o in 0...octaves)
505+
maxAmp += Math.pow(persistence, o);
506+
507+
// first build a float grid of values
508+
var vals:Array<Array<Float>> = [];
509+
for (j in 0...h)
510+
{
511+
var crow:Array<Float> = [];
512+
for (i in 0...w)
513+
crow.push(0.0);
514+
vals.push(crow);
515+
}
516+
517+
for (j in 0...h)
518+
{
519+
for (i in 0...w)
520+
{
521+
var amplitude:Float = 1.0;
522+
var freq:Float = baseFreq;
523+
var val:Float = 0.0;
524+
for (o in 0...octaves)
525+
{
526+
var sx:Float = i / Math.max(1, w) * freq;
527+
var sy:Float = j / Math.max(1, h) * freq;
528+
var ix:Int = Std.int(Math.floor(sx));
529+
var iy:Int = Std.int(Math.floor(sy));
530+
var fx:Float = sx - ix;
531+
var fy:Float = sy - iy;
532+
// four corner values (value noise)
533+
var v00:Float = FlxG.random.float();
534+
var v10:Float = FlxG.random.float();
535+
var v01:Float = FlxG.random.float();
536+
var v11:Float = FlxG.random.float();
537+
// bilinear interpolation
538+
var a:Float = v00 * (1 - fx) + v10 * fx;
539+
var b:Float = v01 * (1 - fx) + v11 * fx;
540+
var s:Float = a * (1 - fy) + b * fy;
541+
val += s * amplitude;
542+
amplitude *= persistence;
543+
freq *= lacunarity;
544+
}
545+
vals[j][i] = val / maxAmp;
546+
}
547+
}
548+
549+
// apply a couple of light smoothing passes (3x3 box blur) to increase coherence
550+
for (p in 0...2)
551+
{
552+
var buf:Array<Array<Float>> = [];
553+
for (y in 0...h)
554+
{
555+
var brow:Array<Float> = [];
556+
for (x in 0...w)
557+
{
558+
var sum:Float = 0.0;
559+
var cnt:Int = 0;
560+
for (oy in -1...2)
561+
for (ox in -1...2)
562+
{
563+
var nx:Int = x + ox;
564+
var ny:Int = y + oy;
565+
if (nx < 0 || ny < 0 || nx >= w || ny >= h)
566+
continue;
567+
sum += vals[ny][nx];
568+
cnt++;
569+
}
570+
brow.push(sum / Math.max(1, cnt));
571+
}
572+
buf.push(brow);
573+
}
574+
vals = buf;
575+
}
576+
577+
// quantize to 0..3 and build CSV
578+
var rows:Array<String> = [];
579+
for (j in 0...h)
580+
{
581+
var cols:Array<String> = [];
582+
for (i in 0...w)
583+
{
584+
var v:Float = vals[j][i];
585+
var idx = Std.int(Math.floor(v * 4));
586+
if (idx < 0)
587+
idx = 0;
588+
if (idx > 3)
589+
idx = 3;
590+
cols.push(Std.string(idx));
591+
}
592+
rows.push(cols.join(","));
593+
}
594+
return rows.join("\n");
370595
}
371596
}
372597

source/PlayState.hx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package;
22

33
import flixel.FlxG;
44
import flixel.FlxState;
5+
import flixel.tile.FlxBaseTilemap.FlxTilemapAutoTiling;
6+
import flixel.tile.FlxTilemap;
57

68
class PlayState extends FlxState
79
{
@@ -10,6 +12,7 @@ class PlayState extends FlxState
1012
override public function create():Void
1113
{
1214
super.create();
15+
// GameMap now produces both floor and walls layers
1316
tilemap = new GameMap();
1417
tilemap.generate();
1518
add(tilemap);

0 commit comments

Comments
 (0)