@@ -2,14 +2,18 @@ package;
22
33import flixel .FlxG ;
44import flixel .addons .tile .FlxCaveGenerator ;
5+ import flixel .group .FlxGroup ;
56import flixel .tile .FlxBaseTilemap .FlxTilemapAutoTiling ;
67import 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
0 commit comments