add cellular automata generator
This commit is contained in:
131
addons/ca_level_generator/CaGenerator.cs
Normal file
131
addons/ca_level_generator/CaGenerator.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
public static class CaGenerator
|
||||
{
|
||||
public static bool[,] Generate(CaGeneratorSettings s)
|
||||
{
|
||||
var rng = new Random(s.Seed);
|
||||
return s.Mode switch
|
||||
{
|
||||
CaMode.Cave => GenerateCave(s, rng),
|
||||
CaMode.Platform => GeneratePlatform(s, rng),
|
||||
CaMode.Terrain => GenerateTerrain(s, rng),
|
||||
_ => GenerateCave(s, rng),
|
||||
};
|
||||
}
|
||||
|
||||
public static bool[,] Smooth(bool[,] grid) => SmoothPass(grid, 5);
|
||||
|
||||
// ── Cave ──────────────────────────────────────────────────────────────
|
||||
private static bool[,] GenerateCave(CaGeneratorSettings s, Random rng)
|
||||
{
|
||||
var grid = RandomFill(s.Width, s.Height, s.FillDensity, rng);
|
||||
if (s.BorderWalls) EnforceBorder(grid);
|
||||
for (int i = 0; i < s.SmoothingPasses; i++)
|
||||
{
|
||||
grid = SmoothPass(grid, 5);
|
||||
if (s.BorderWalls) EnforceBorder(grid);
|
||||
}
|
||||
return grid;
|
||||
}
|
||||
|
||||
// ── Platform ──────────────────────────────────────────────────────────
|
||||
private static bool[,] GeneratePlatform(CaGeneratorSettings s, Random rng)
|
||||
{
|
||||
int w = s.Width, h = s.Height;
|
||||
var grid = new bool[w, h];
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
grid[x, h - 1] = true;
|
||||
grid[x, h - 2] = true;
|
||||
|
||||
for (int y = 0; y < h - 2; y++)
|
||||
{
|
||||
// Density linearly increases from 10% at top to 60% at bottom,
|
||||
// scaled by user's FillDensity relative to default 0.48.
|
||||
float t = (float)y / (h - 3);
|
||||
float rowDensity = (0.1f + t * 0.5f) * (s.FillDensity / 0.48f);
|
||||
grid[x, y] = rng.NextDouble() < rowDensity;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < s.SmoothingPasses; i++)
|
||||
{
|
||||
// Threshold 4 (not 5): horizontal platform groups survive, isolated
|
||||
// vertical pixels collapse into flat platforms.
|
||||
grid = SmoothPass(grid, 4);
|
||||
for (int x = 0; x < w; x++) { grid[x, h - 1] = true; grid[x, h - 2] = true; }
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
// ── Terrain ───────────────────────────────────────────────────────────
|
||||
private static bool[,] GenerateTerrain(CaGeneratorSettings s, Random rng)
|
||||
{
|
||||
int w = s.Width, h = s.Height;
|
||||
var grid = new bool[w, h];
|
||||
|
||||
// Start terrain surface at ~60% from bottom (40% from top)
|
||||
int surfaceRow = (int)(h * 0.4f);
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
int delta = rng.Next(-2, 3);
|
||||
surfaceRow = Math.Clamp(surfaceRow + delta, h / 6, h - 2);
|
||||
|
||||
for (int y = surfaceRow; y < h; y++)
|
||||
grid[x, y] = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < s.SmoothingPasses; i++)
|
||||
grid = SmoothPass(grid, 5);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
// ── Shared helpers ────────────────────────────────────────────────
|
||||
private static bool[,] RandomFill(int w, int h, float density, Random rng)
|
||||
{
|
||||
var grid = new bool[w, h];
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
grid[x, y] = rng.NextDouble() < density;
|
||||
return grid;
|
||||
}
|
||||
|
||||
private static bool[,] SmoothPass(bool[,] grid, int threshold)
|
||||
{
|
||||
int w = grid.GetLength(0), h = grid.GetLength(1);
|
||||
var next = new bool[w, h];
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
next[x, y] = CountSolidNeighbors(grid, x, y) >= threshold;
|
||||
return next;
|
||||
}
|
||||
|
||||
private static int CountSolidNeighbors(bool[,] grid, int cx, int cy)
|
||||
{
|
||||
int w = grid.GetLength(0), h = grid.GetLength(1), count = 0;
|
||||
for (int dx = -1; dx <= 1; dx++)
|
||||
for (int dy = -1; dy <= 1; dy++)
|
||||
{
|
||||
if (dx == 0 && dy == 0) continue;
|
||||
int nx = cx + dx, ny = cy + dy;
|
||||
// Out-of-bounds counts as solid (closes cave edges naturally)
|
||||
if (nx < 0 || nx >= w || ny < 0 || ny >= h) count++;
|
||||
else if (grid[nx, ny]) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static void EnforceBorder(bool[,] grid)
|
||||
{
|
||||
int w = grid.GetLength(0), h = grid.GetLength(1);
|
||||
for (int x = 0; x < w; x++) { grid[x, 0] = true; grid[x, h - 1] = true; }
|
||||
for (int y = 0; y < h; y++) { grid[0, y] = true; grid[w - 1, y] = true; }
|
||||
}
|
||||
}
|
||||
1
addons/ca_level_generator/CaGenerator.cs.uid
Normal file
1
addons/ca_level_generator/CaGenerator.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://exr10b7nmkgn
|
||||
23
addons/ca_level_generator/CaGeneratorSettings.cs
Normal file
23
addons/ca_level_generator/CaGeneratorSettings.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
public enum CaMode { Cave, Platform, Terrain }
|
||||
|
||||
public class CaGeneratorSettings
|
||||
{
|
||||
public CaMode Mode { get; set; } = CaMode.Cave;
|
||||
public int Width { get; set; } = 40;
|
||||
public int Height { get; set; } = 22;
|
||||
public Vector2I Offset { get; set; } = Vector2I.Zero;
|
||||
public float FillDensity { get; set; } = 0.48f;
|
||||
public int SmoothingPasses { get; set; } = 4;
|
||||
public bool BorderWalls { get; set; } = true;
|
||||
public int Seed { get; set; } = 12345;
|
||||
// TerrainSet == -1 → raw tile mode
|
||||
public int TerrainSet { get; set; } = 0;
|
||||
public int Terrain { get; set; } = 0;
|
||||
// Used only when TerrainSet == -1
|
||||
public int SourceId { get; set; } = 0;
|
||||
public Vector2I AtlasCoords { get; set; } = Vector2I.Zero;
|
||||
}
|
||||
1
addons/ca_level_generator/CaGeneratorSettings.cs.uid
Normal file
1
addons/ca_level_generator/CaGeneratorSettings.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://isnscgr1thvc
|
||||
79
addons/ca_level_generator/CaGeneratorTestRunner.cs
Normal file
79
addons/ca_level_generator/CaGeneratorTestRunner.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
#if TOOLS
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
[Tool]
|
||||
public partial class CaGeneratorTestRunner : Node
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
int pass = 0, fail = 0;
|
||||
|
||||
void Assert(bool cond, string msg)
|
||||
{
|
||||
if (cond) { GD.Print($" PASS: {msg}"); pass++; }
|
||||
else { GD.PrintErr($" FAIL: {msg}"); fail++; }
|
||||
}
|
||||
|
||||
GD.Print("=== CaGenerator Tests ===");
|
||||
|
||||
// Grid dimensions
|
||||
var s = new CaGeneratorSettings { Width = 20, Height = 15, SmoothingPasses = 0, Seed = 42 };
|
||||
var g = CaGenerator.Generate(s);
|
||||
Assert(g.GetLength(0) == 20, "Width == 20");
|
||||
Assert(g.GetLength(1) == 15, "Height == 15");
|
||||
|
||||
// Determinism
|
||||
var g2 = CaGenerator.Generate(s);
|
||||
bool det = true;
|
||||
for (int x = 0; x < 20 && det; x++)
|
||||
for (int y = 0; y < 15 && det; y++)
|
||||
if (g[x, y] != g2[x, y]) det = false;
|
||||
Assert(det, "Same seed → same output");
|
||||
|
||||
// Different seeds → different output
|
||||
var s2 = new CaGeneratorSettings { Width = 20, Height = 15, SmoothingPasses = 0, Seed = 99 };
|
||||
var g3 = CaGenerator.Generate(s2);
|
||||
bool diff = false;
|
||||
for (int x = 0; x < 20 && !diff; x++)
|
||||
for (int y = 0; y < 15 && !diff; y++)
|
||||
if (g[x, y] != g3[x, y]) diff = true;
|
||||
Assert(diff, "Different seeds → different output");
|
||||
|
||||
// Cave border walls
|
||||
var sb = new CaGeneratorSettings { Width = 20, Height = 15, BorderWalls = true, SmoothingPasses = 0, Seed = 42 };
|
||||
var gb = CaGenerator.Generate(sb);
|
||||
bool border = true;
|
||||
for (int x = 0; x < 20; x++) if (!gb[x, 0] || !gb[x, 14]) { border = false; break; }
|
||||
for (int y = 0; y < 15; y++) if (!gb[0, y] || !gb[19, y]) { border = false; break; }
|
||||
Assert(border, "Cave: border cells all solid");
|
||||
|
||||
// Platform floor
|
||||
var sp = new CaGeneratorSettings { Mode = CaMode.Platform, Width = 20, Height = 15, SmoothingPasses = 0, Seed = 42 };
|
||||
var gp = CaGenerator.Generate(sp);
|
||||
bool floor = true;
|
||||
for (int x = 0; x < 20; x++) if (!gp[x, 14] || !gp[x, 13]) { floor = false; break; }
|
||||
Assert(floor, "Platform: bottom 2 rows solid");
|
||||
|
||||
// Platform: top row not all solid (mostly empty at top)
|
||||
int topSolid = 0;
|
||||
for (int x = 0; x < 20; x++) if (gp[x, 0]) topSolid++;
|
||||
Assert(topSolid < 15, "Platform: top row mostly empty");
|
||||
|
||||
// Terrain: bottom always solid
|
||||
var st = new CaGeneratorSettings { Mode = CaMode.Terrain, Width = 20, Height = 15, SmoothingPasses = 0, Seed = 42 };
|
||||
var gt = CaGenerator.Generate(st);
|
||||
bool terrBottom = true;
|
||||
for (int x = 0; x < 20; x++) if (!gt[x, 14]) { terrBottom = false; break; }
|
||||
Assert(terrBottom, "Terrain: bottom row always solid");
|
||||
|
||||
// Smooth: output same dimensions
|
||||
var smoothed = CaGenerator.Smooth(g);
|
||||
Assert(smoothed.GetLength(0) == 20, "Smooth: width preserved");
|
||||
Assert(smoothed.GetLength(1) == 15, "Smooth: height preserved");
|
||||
|
||||
GD.Print($"=== Results: {pass} passed, {fail} failed ===");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
1
addons/ca_level_generator/CaGeneratorTestRunner.cs.uid
Normal file
1
addons/ca_level_generator/CaGeneratorTestRunner.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://6y4snwf31boh
|
||||
360
addons/ca_level_generator/CaLevelGeneratorDock.cs
Normal file
360
addons/ca_level_generator/CaLevelGeneratorDock.cs
Normal file
@@ -0,0 +1,360 @@
|
||||
#if TOOLS
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
[Tool]
|
||||
public partial class CaLevelGeneratorDock : Control
|
||||
{
|
||||
public CaLevelGeneratorPlugin Plugin { get; set; }
|
||||
|
||||
// Controls referenced in Task 8 wiring
|
||||
private OptionButton _layerDropdown;
|
||||
private OptionButton _terrainDropdown;
|
||||
private HBoxContainer _rawTileRow;
|
||||
private SpinBox _sourceIdSpin;
|
||||
private SpinBox _atlasXSpin;
|
||||
private SpinBox _atlasYSpin;
|
||||
private Button _caveBtn;
|
||||
private Button _platformBtn;
|
||||
private Button _terrainBtn;
|
||||
private SpinBox _widthSpin;
|
||||
private SpinBox _heightSpin;
|
||||
private SpinBox _offsetXSpin;
|
||||
private SpinBox _offsetYSpin;
|
||||
private HSlider _densitySlider;
|
||||
private Label _densityLabel;
|
||||
private HSlider _smoothPassSlider;
|
||||
private Label _smoothPassLabel;
|
||||
private CheckBox _borderCheck;
|
||||
private SpinBox _seedSpin;
|
||||
private Button _genBtn;
|
||||
private Button _smoothBtn;
|
||||
private Button _clearBtn;
|
||||
|
||||
private CaMode _mode = CaMode.Cave;
|
||||
|
||||
private System.Collections.Generic.List<TileMapLayer> _layers = new();
|
||||
private TileMapLayer _selectedLayer;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
CustomMinimumSize = new Vector2(200, 0);
|
||||
var scroll = new ScrollContainer();
|
||||
scroll.SetAnchorsAndOffsetsPreset(LayoutPreset.FullRect);
|
||||
scroll.SizeFlagsVertical = SizeFlags.ExpandFill;
|
||||
AddChild(scroll);
|
||||
|
||||
var vbox = new VBoxContainer();
|
||||
vbox.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
scroll.AddChild(vbox);
|
||||
|
||||
// Target Layer
|
||||
vbox.AddChild(new Label { Text = "Target Layer" });
|
||||
_layerDropdown = new OptionButton();
|
||||
_layerDropdown.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
vbox.AddChild(_layerDropdown);
|
||||
|
||||
// Terrain
|
||||
vbox.AddChild(new Label { Text = "Terrain" });
|
||||
_terrainDropdown = new OptionButton();
|
||||
_terrainDropdown.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
vbox.AddChild(_terrainDropdown);
|
||||
|
||||
// Raw tile row (hidden when terrain is available)
|
||||
_rawTileRow = new HBoxContainer();
|
||||
_rawTileRow.Visible = false;
|
||||
_rawTileRow.AddChild(new Label { Text = "Src" });
|
||||
_sourceIdSpin = new SpinBox { MinValue = 0, MaxValue = 99, Value = 0 };
|
||||
_rawTileRow.AddChild(_sourceIdSpin);
|
||||
_rawTileRow.AddChild(new Label { Text = "X" });
|
||||
_atlasXSpin = new SpinBox { MinValue = 0, MaxValue = 99, Value = 0 };
|
||||
_rawTileRow.AddChild(_atlasXSpin);
|
||||
_rawTileRow.AddChild(new Label { Text = "Y" });
|
||||
_atlasYSpin = new SpinBox { MinValue = 0, MaxValue = 99, Value = 0 };
|
||||
_rawTileRow.AddChild(_atlasYSpin);
|
||||
vbox.AddChild(_rawTileRow);
|
||||
|
||||
// Mode toggle
|
||||
vbox.AddChild(new Label { Text = "Mode" });
|
||||
var modeRow = new HBoxContainer();
|
||||
modeRow.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
_caveBtn = MakeModeButton("Cave", () => SetMode(CaMode.Cave));
|
||||
_platformBtn = MakeModeButton("Platform", () => SetMode(CaMode.Platform));
|
||||
_terrainBtn = MakeModeButton("Terrain", () => SetMode(CaMode.Terrain));
|
||||
_caveBtn.ButtonPressed = true;
|
||||
modeRow.AddChild(_caveBtn);
|
||||
modeRow.AddChild(_platformBtn);
|
||||
modeRow.AddChild(_terrainBtn);
|
||||
vbox.AddChild(modeRow);
|
||||
|
||||
vbox.AddChild(new HSeparator());
|
||||
|
||||
// Width / Height
|
||||
var dimRow = new HBoxContainer();
|
||||
dimRow.AddChild(MakeSpinColumn("Width", out _widthSpin, 5, 500, 40));
|
||||
dimRow.AddChild(MakeSpinColumn("Height", out _heightSpin, 5, 500, 22));
|
||||
vbox.AddChild(dimRow);
|
||||
|
||||
// Offset X / Y
|
||||
var offRow = new HBoxContainer();
|
||||
offRow.AddChild(MakeSpinColumn("Offset X", out _offsetXSpin, -9999, 9999, 0));
|
||||
offRow.AddChild(MakeSpinColumn("Offset Y", out _offsetYSpin, -9999, 9999, 0));
|
||||
vbox.AddChild(offRow);
|
||||
|
||||
// Fill Density
|
||||
var densHeader = new HBoxContainer();
|
||||
densHeader.AddChild(new Label { Text = "Fill Density", SizeFlagsHorizontal = SizeFlags.ExpandFill });
|
||||
_densityLabel = new Label { Text = "48%" };
|
||||
densHeader.AddChild(_densityLabel);
|
||||
vbox.AddChild(densHeader);
|
||||
_densitySlider = new HSlider { MinValue = 0, MaxValue = 100, Value = 48, Step = 1 };
|
||||
_densitySlider.ValueChanged += v => _densityLabel.Text = $"{(int)v}%";
|
||||
vbox.AddChild(_densitySlider);
|
||||
|
||||
// Smoothing Passes
|
||||
var smoothHeader = new HBoxContainer();
|
||||
smoothHeader.AddChild(new Label { Text = "Smoothing Passes", SizeFlagsHorizontal = SizeFlags.ExpandFill });
|
||||
_smoothPassLabel = new Label { Text = "4" };
|
||||
smoothHeader.AddChild(_smoothPassLabel);
|
||||
vbox.AddChild(smoothHeader);
|
||||
_smoothPassSlider = new HSlider { MinValue = 0, MaxValue = 10, Value = 4, Step = 1 };
|
||||
_smoothPassSlider.ValueChanged += v => _smoothPassLabel.Text = $"{(int)v}";
|
||||
vbox.AddChild(_smoothPassSlider);
|
||||
|
||||
// Border walls
|
||||
_borderCheck = new CheckBox { Text = "Solid border walls", ButtonPressed = true };
|
||||
vbox.AddChild(_borderCheck);
|
||||
|
||||
// Seed
|
||||
vbox.AddChild(new Label { Text = "Seed" });
|
||||
var seedRow = new HBoxContainer();
|
||||
_seedSpin = new SpinBox { MinValue = 0, MaxValue = int.MaxValue, Value = 12345,
|
||||
AllowGreater = true, SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
var randBtn = new Button { Text = "🎲" };
|
||||
randBtn.Pressed += () => _seedSpin.Value = GD.Randi();
|
||||
seedRow.AddChild(_seedSpin);
|
||||
seedRow.AddChild(randBtn);
|
||||
vbox.AddChild(seedRow);
|
||||
|
||||
vbox.AddChild(new HSeparator());
|
||||
|
||||
// Action buttons
|
||||
_genBtn = new Button { Text = "▶ Generate", SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
vbox.AddChild(_genBtn);
|
||||
|
||||
var actionRow = new HBoxContainer();
|
||||
actionRow.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
_smoothBtn = new Button { Text = "✦ Smooth", SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
_clearBtn = new Button { Text = "✕ Clear", SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
actionRow.AddChild(_smoothBtn);
|
||||
actionRow.AddChild(_clearBtn);
|
||||
vbox.AddChild(actionRow);
|
||||
|
||||
_layerDropdown.ItemSelected += OnLayerSelected;
|
||||
_terrainDropdown.ItemSelected += _ => SaveSettings();
|
||||
_genBtn.Pressed += OnGenerate;
|
||||
_smoothBtn.Pressed += OnSmooth;
|
||||
_clearBtn.Pressed += OnClear;
|
||||
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
public void OnSceneChanged(Node sceneRoot)
|
||||
{
|
||||
ScanLayers(sceneRoot);
|
||||
RestoreLastLayer(sceneRoot?.SceneFilePath ?? "");
|
||||
}
|
||||
|
||||
private void SetMode(CaMode mode)
|
||||
{
|
||||
_mode = mode;
|
||||
_caveBtn.ButtonPressed = mode == CaMode.Cave;
|
||||
_platformBtn.ButtonPressed = mode == CaMode.Platform;
|
||||
_terrainBtn.ButtonPressed = mode == CaMode.Terrain;
|
||||
}
|
||||
|
||||
private static Button MakeModeButton(string text, System.Action onPressed)
|
||||
{
|
||||
var btn = new Button { Text = text, ToggleMode = true,
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
btn.Pressed += onPressed;
|
||||
return btn;
|
||||
}
|
||||
|
||||
private static Control MakeSpinColumn(string label, out SpinBox spin,
|
||||
double min, double max, double value)
|
||||
{
|
||||
var col = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
col.AddChild(new Label { Text = label });
|
||||
spin = new SpinBox { MinValue = min, MaxValue = max, Value = value,
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill };
|
||||
col.AddChild(spin);
|
||||
return col;
|
||||
}
|
||||
|
||||
private void ScanLayers(Node root)
|
||||
{
|
||||
_layers.Clear();
|
||||
_layerDropdown.Clear();
|
||||
if (root == null) return;
|
||||
CollectLayers(root);
|
||||
foreach (var layer in _layers)
|
||||
_layerDropdown.AddItem(layer.Name);
|
||||
if (_layers.Count > 0) OnLayerSelected(0);
|
||||
}
|
||||
|
||||
private void CollectLayers(Node node)
|
||||
{
|
||||
if (node is TileMapLayer layer) _layers.Add(layer);
|
||||
foreach (Node child in node.GetChildren()) CollectLayers(child);
|
||||
}
|
||||
|
||||
private void OnLayerSelected(long index)
|
||||
{
|
||||
if (index < 0 || index >= _layers.Count) return;
|
||||
_selectedLayer = _layers[(int)index];
|
||||
PopulateTerrainDropdown(_selectedLayer);
|
||||
|
||||
var sceneRoot = EditorInterface.Singleton.GetEditedSceneRoot();
|
||||
if (sceneRoot != null)
|
||||
{
|
||||
var key = $"ca_generator/last_layer_{sceneRoot.SceneFilePath}";
|
||||
EditorInterface.Singleton.GetEditorSettings()
|
||||
.SetSetting(key, _selectedLayer.GetPath().ToString());
|
||||
}
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
private void RestoreLastLayer(string sceneFilePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sceneFilePath) || _layers.Count == 0) return;
|
||||
var key = $"ca_generator/last_layer_{sceneFilePath}";
|
||||
var es = EditorInterface.Singleton.GetEditorSettings();
|
||||
if (!es.HasSetting(key)) return;
|
||||
var path = es.GetSetting(key).AsString();
|
||||
for (int i = 0; i < _layers.Count; i++)
|
||||
{
|
||||
if (_layers[i].GetPath().ToString() == path)
|
||||
{
|
||||
_layerDropdown.Select(i);
|
||||
OnLayerSelected(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateTerrainDropdown(TileMapLayer layer)
|
||||
{
|
||||
_terrainDropdown.Clear();
|
||||
var tileSet = layer.TileSet;
|
||||
bool hasTerrains = false;
|
||||
|
||||
if (tileSet != null)
|
||||
{
|
||||
for (int ts = 0; ts < tileSet.GetTerrainSetsCount(); ts++)
|
||||
{
|
||||
for (int t = 0; t < tileSet.GetTerrainsCount(ts); t++)
|
||||
{
|
||||
_terrainDropdown.AddItem(tileSet.GetTerrainName(ts, t));
|
||||
_terrainDropdown.SetItemMetadata(
|
||||
_terrainDropdown.ItemCount - 1,
|
||||
Variant.From((ts << 16) | t));
|
||||
hasTerrains = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_terrainDropdown.Visible = hasTerrains;
|
||||
_rawTileRow.Visible = !hasTerrains;
|
||||
}
|
||||
|
||||
private CaGeneratorSettings BuildSettings()
|
||||
{
|
||||
int terrainSet = -1, terrain = 0;
|
||||
if (_terrainDropdown.Visible && _terrainDropdown.ItemCount > 0)
|
||||
{
|
||||
int packed = _terrainDropdown.GetSelectedMetadata().AsInt32();
|
||||
terrainSet = packed >> 16;
|
||||
terrain = packed & 0xFFFF;
|
||||
}
|
||||
|
||||
return new CaGeneratorSettings
|
||||
{
|
||||
Mode = _mode,
|
||||
Width = (int)_widthSpin.Value,
|
||||
Height = (int)_heightSpin.Value,
|
||||
Offset = new Vector2I((int)_offsetXSpin.Value, (int)_offsetYSpin.Value),
|
||||
FillDensity = (float)_densitySlider.Value / 100f,
|
||||
SmoothingPasses = (int)_smoothPassSlider.Value,
|
||||
BorderWalls = _borderCheck.ButtonPressed,
|
||||
Seed = (int)_seedSpin.Value,
|
||||
TerrainSet = terrainSet,
|
||||
Terrain = terrain,
|
||||
SourceId = (int)_sourceIdSpin.Value,
|
||||
AtlasCoords = new Vector2I((int)_atlasXSpin.Value, (int)_atlasYSpin.Value),
|
||||
};
|
||||
}
|
||||
|
||||
private void OnGenerate()
|
||||
{
|
||||
if (_selectedLayer == null) return;
|
||||
var settings = BuildSettings();
|
||||
var grid = CaGenerator.Generate(settings);
|
||||
TilemapPainter.Paint(_selectedLayer, grid, settings, Plugin.UndoRedo);
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
private void OnSmooth()
|
||||
{
|
||||
if (_selectedLayer == null) return;
|
||||
TilemapPainter.Smooth(_selectedLayer, BuildSettings(), Plugin.UndoRedo);
|
||||
}
|
||||
|
||||
private void OnClear()
|
||||
{
|
||||
if (_selectedLayer == null) return;
|
||||
TilemapPainter.Clear(_selectedLayer, BuildSettings(), Plugin.UndoRedo);
|
||||
}
|
||||
|
||||
private void SaveSettings()
|
||||
{
|
||||
var es = EditorInterface.Singleton.GetEditorSettings();
|
||||
es.SetSetting("ca_generator/mode", (int)_mode);
|
||||
es.SetSetting("ca_generator/width", (int)_widthSpin.Value);
|
||||
es.SetSetting("ca_generator/height", (int)_heightSpin.Value);
|
||||
es.SetSetting("ca_generator/offset_x", (int)_offsetXSpin.Value);
|
||||
es.SetSetting("ca_generator/offset_y", (int)_offsetYSpin.Value);
|
||||
es.SetSetting("ca_generator/fill_density", _densitySlider.Value);
|
||||
es.SetSetting("ca_generator/smoothing_passes", (int)_smoothPassSlider.Value);
|
||||
es.SetSetting("ca_generator/border_walls", _borderCheck.ButtonPressed);
|
||||
es.SetSetting("ca_generator/seed", (int)_seedSpin.Value);
|
||||
es.SetSetting("ca_generator/source_id", (int)_sourceIdSpin.Value);
|
||||
es.SetSetting("ca_generator/atlas_x", (int)_atlasXSpin.Value);
|
||||
es.SetSetting("ca_generator/atlas_y", (int)_atlasYSpin.Value);
|
||||
}
|
||||
|
||||
private void LoadSettings()
|
||||
{
|
||||
var es = EditorInterface.Singleton.GetEditorSettings();
|
||||
if (es == null) return;
|
||||
|
||||
SetMode((CaMode)(es.HasSetting("ca_generator/mode") ? es.GetSetting("ca_generator/mode").AsInt32() : 0));
|
||||
_widthSpin.Value = es.HasSetting("ca_generator/width") ? es.GetSetting("ca_generator/width").AsDouble() : 40.0;
|
||||
_heightSpin.Value = es.HasSetting("ca_generator/height") ? es.GetSetting("ca_generator/height").AsDouble() : 22.0;
|
||||
_offsetXSpin.Value = es.HasSetting("ca_generator/offset_x") ? es.GetSetting("ca_generator/offset_x").AsDouble() : 0.0;
|
||||
_offsetYSpin.Value = es.HasSetting("ca_generator/offset_y") ? es.GetSetting("ca_generator/offset_y").AsDouble() : 0.0;
|
||||
_densitySlider.Value = es.HasSetting("ca_generator/fill_density") ? es.GetSetting("ca_generator/fill_density").AsDouble() : 48.0;
|
||||
_smoothPassSlider.Value = es.HasSetting("ca_generator/smoothing_passes") ? es.GetSetting("ca_generator/smoothing_passes").AsDouble() : 4.0;
|
||||
_borderCheck.ButtonPressed = es.HasSetting("ca_generator/border_walls") ? es.GetSetting("ca_generator/border_walls").AsBool() : true;
|
||||
_seedSpin.Value = es.HasSetting("ca_generator/seed") ? es.GetSetting("ca_generator/seed").AsDouble() : 12345.0;
|
||||
|
||||
_sourceIdSpin.Value = es.HasSetting("ca_generator/source_id") ? es.GetSetting("ca_generator/source_id").AsDouble() : 0.0;
|
||||
_atlasXSpin.Value = es.HasSetting("ca_generator/atlas_x") ? es.GetSetting("ca_generator/atlas_x").AsDouble() : 0.0;
|
||||
_atlasYSpin.Value = es.HasSetting("ca_generator/atlas_y") ? es.GetSetting("ca_generator/atlas_y").AsDouble() : 0.0;
|
||||
|
||||
_densityLabel.Text = $"{(int)_densitySlider.Value}%";
|
||||
_smoothPassLabel.Text = $"{(int)_smoothPassSlider.Value}";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
1
addons/ca_level_generator/CaLevelGeneratorDock.cs.uid
Normal file
1
addons/ca_level_generator/CaLevelGeneratorDock.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dnuvfv3rgyywd
|
||||
33
addons/ca_level_generator/CaLevelGeneratorPlugin.cs
Normal file
33
addons/ca_level_generator/CaLevelGeneratorPlugin.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
#if TOOLS
|
||||
using Godot;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
[Tool]
|
||||
public partial class CaLevelGeneratorPlugin : EditorPlugin
|
||||
{
|
||||
private CaLevelGeneratorDock _dock;
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
_dock = new CaLevelGeneratorDock { Plugin = this };
|
||||
AddControlToDock(DockSlot.RightUl, _dock);
|
||||
SceneChanged += OnSceneChanged;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
SceneChanged -= OnSceneChanged;
|
||||
RemoveControlFromDocks(_dock);
|
||||
_dock.QueueFree();
|
||||
_dock = null;
|
||||
}
|
||||
|
||||
private void OnSceneChanged(Node sceneRoot)
|
||||
{
|
||||
_dock?.OnSceneChanged(sceneRoot);
|
||||
}
|
||||
|
||||
public EditorUndoRedoManager UndoRedo => GetUndoRedo();
|
||||
}
|
||||
#endif
|
||||
1
addons/ca_level_generator/CaLevelGeneratorPlugin.cs.uid
Normal file
1
addons/ca_level_generator/CaLevelGeneratorPlugin.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cojnhxpcgepi2
|
||||
100
addons/ca_level_generator/TilemapPainter.cs
Normal file
100
addons/ca_level_generator/TilemapPainter.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
#if TOOLS
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Mr.BrickAdventures.Tools.CaLevelGenerator;
|
||||
|
||||
public static class TilemapPainter
|
||||
{
|
||||
public static void Paint(
|
||||
TileMapLayer layer,
|
||||
bool[,] grid,
|
||||
CaGeneratorSettings settings,
|
||||
EditorUndoRedoManager undoRedo)
|
||||
{
|
||||
var before = layer.TileMapData;
|
||||
ApplyGrid(layer, grid, settings);
|
||||
var after = layer.TileMapData;
|
||||
RegisterUndo(layer, before, after, undoRedo, "CA Generate");
|
||||
}
|
||||
|
||||
public static void Smooth(
|
||||
TileMapLayer layer,
|
||||
CaGeneratorSettings settings,
|
||||
EditorUndoRedoManager undoRedo)
|
||||
{
|
||||
var grid = ReadGrid(layer, settings.Offset, new Vector2I(settings.Width, settings.Height));
|
||||
grid = CaGenerator.Smooth(grid);
|
||||
var before = layer.TileMapData;
|
||||
ApplyGrid(layer, grid, settings);
|
||||
var after = layer.TileMapData;
|
||||
RegisterUndo(layer, before, after, undoRedo, "CA Smooth");
|
||||
}
|
||||
|
||||
public static void Clear(
|
||||
TileMapLayer layer,
|
||||
CaGeneratorSettings settings,
|
||||
EditorUndoRedoManager undoRedo)
|
||||
{
|
||||
var before = layer.TileMapData;
|
||||
for (int x = 0; x < settings.Width; x++)
|
||||
for (int y = 0; y < settings.Height; y++)
|
||||
layer.EraseCell(settings.Offset + new Vector2I(x, y));
|
||||
var after = layer.TileMapData;
|
||||
RegisterUndo(layer, before, after, undoRedo, "CA Clear");
|
||||
}
|
||||
|
||||
private static bool[,] ReadGrid(TileMapLayer layer, Vector2I offset, Vector2I size)
|
||||
{
|
||||
var grid = new bool[size.X, size.Y];
|
||||
for (int x = 0; x < size.X; x++)
|
||||
for (int y = 0; y < size.Y; y++)
|
||||
grid[x, y] = layer.GetCellSourceId(offset + new Vector2I(x, y)) != -1;
|
||||
return grid;
|
||||
}
|
||||
|
||||
private static void ApplyGrid(TileMapLayer layer, bool[,] grid, CaGeneratorSettings settings)
|
||||
{
|
||||
int w = grid.GetLength(0), h = grid.GetLength(1);
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
layer.EraseCell(settings.Offset + new Vector2I(x, y));
|
||||
|
||||
if (settings.TerrainSet >= 0)
|
||||
{
|
||||
var solidCells = new Array<Vector2I>();
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
if (grid[x, y])
|
||||
solidCells.Add(settings.Offset + new Vector2I(x, y));
|
||||
|
||||
if (solidCells.Count > 0)
|
||||
layer.SetCellsTerrainConnect(solidCells, settings.TerrainSet, settings.Terrain);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
if (grid[x, y])
|
||||
layer.SetCell(
|
||||
settings.Offset + new Vector2I(x, y),
|
||||
settings.SourceId,
|
||||
settings.AtlasCoords);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterUndo(
|
||||
TileMapLayer layer,
|
||||
byte[] before,
|
||||
byte[] after,
|
||||
EditorUndoRedoManager undoRedo,
|
||||
string actionName)
|
||||
{
|
||||
undoRedo.CreateAction(actionName);
|
||||
undoRedo.AddUndoProperty(layer, "tile_map_data", before);
|
||||
undoRedo.AddDoProperty(layer, "tile_map_data", after);
|
||||
undoRedo.CommitAction(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
1
addons/ca_level_generator/TilemapPainter.cs.uid
Normal file
1
addons/ca_level_generator/TilemapPainter.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://y55l4iw35tih
|
||||
6
addons/ca_level_generator/ca_generator_tests.tscn
Normal file
6
addons/ca_level_generator/ca_generator_tests.tscn
Normal file
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://test_ca_generator"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/ca_level_generator/CaGeneratorTestRunner.cs" id="1_catest"]
|
||||
|
||||
[node name="CaGeneratorTestRunner" type="Node"]
|
||||
script = ExtResource("1_catest")
|
||||
6
addons/ca_level_generator/plugin.cfg
Normal file
6
addons/ca_level_generator/plugin.cfg
Normal file
@@ -0,0 +1,6 @@
|
||||
[plugin]
|
||||
name="CA Level Generator"
|
||||
description="Cellular automata level blockout generator"
|
||||
author="Mr. Brick Adventures"
|
||||
version="1.0"
|
||||
script="CaLevelGeneratorPlugin.cs"
|
||||
@@ -88,7 +88,7 @@ movie_writer/fps=24
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/dialogue_manager/plugin.cfg", "res://addons/limbo_console/plugin.cfg", "res://addons/phantom_camera/plugin.cfg")
|
||||
enabled=PackedStringArray("res://addons/ca_level_generator/plugin.cfg", "res://addons/dialogue_manager/plugin.cfg", "res://addons/limbo_console/plugin.cfg", "res://addons/phantom_camera/plugin.cfg")
|
||||
|
||||
[file_customization]
|
||||
|
||||
|
||||
@@ -54,12 +54,14 @@ texture = ExtResource("5_q7rhw")
|
||||
18:0/0 = 0
|
||||
18:0/0/terrain_set = 0
|
||||
18:0/0/terrain = 2
|
||||
18:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
18:0/0/terrains_peering_bit/right_side = 2
|
||||
18:0/0/terrains_peering_bit/bottom_right_corner = 2
|
||||
18:0/0/terrains_peering_bit/bottom_side = 2
|
||||
19:0/0 = 0
|
||||
19:0/0/terrain_set = 0
|
||||
19:0/0/terrain = 2
|
||||
19:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
19:0/0/terrains_peering_bit/right_side = 2
|
||||
19:0/0/terrains_peering_bit/bottom_right_corner = 2
|
||||
19:0/0/terrains_peering_bit/bottom_side = 2
|
||||
@@ -68,22 +70,26 @@ texture = ExtResource("5_q7rhw")
|
||||
20:0/0 = 0
|
||||
20:0/0/terrain_set = 0
|
||||
20:0/0/terrain = 2
|
||||
20:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
20:0/0/terrains_peering_bit/bottom_side = 2
|
||||
20:0/0/terrains_peering_bit/bottom_left_corner = 2
|
||||
20:0/0/terrains_peering_bit/left_side = 2
|
||||
23:0/0 = 0
|
||||
23:0/0/terrain_set = 0
|
||||
23:0/0/terrain = 2
|
||||
23:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
23:0/0/terrains_peering_bit/right_side = 2
|
||||
23:0/0/terrains_peering_bit/bottom_side = 2
|
||||
24:0/0 = 0
|
||||
24:0/0/terrain_set = 0
|
||||
24:0/0/terrain = 2
|
||||
24:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
24:0/0/terrains_peering_bit/right_side = 2
|
||||
24:0/0/terrains_peering_bit/left_side = 2
|
||||
25:0/0 = 0
|
||||
25:0/0/terrain_set = 0
|
||||
25:0/0/terrain = 2
|
||||
25:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
25:0/0/terrains_peering_bit/bottom_side = 2
|
||||
25:0/0/terrains_peering_bit/left_side = 2
|
||||
30:0/0 = 0
|
||||
@@ -181,12 +187,14 @@ texture = ExtResource("5_q7rhw")
|
||||
17:1/0 = 0
|
||||
17:1/0/terrain_set = 0
|
||||
17:1/0/terrain = 2
|
||||
17:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
17:1/0/terrains_peering_bit/right_side = 2
|
||||
17:1/0/terrains_peering_bit/bottom_right_corner = 2
|
||||
17:1/0/terrains_peering_bit/bottom_side = 2
|
||||
18:1/0 = 0
|
||||
18:1/0/terrain_set = 0
|
||||
18:1/0/terrain = 2
|
||||
18:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
18:1/0/terrains_peering_bit/right_side = 2
|
||||
18:1/0/terrains_peering_bit/bottom_right_corner = 2
|
||||
18:1/0/terrains_peering_bit/bottom_side = 2
|
||||
@@ -195,9 +203,11 @@ texture = ExtResource("5_q7rhw")
|
||||
18:1/0/terrains_peering_bit/top_side = 2
|
||||
18:1/0/terrains_peering_bit/top_right_corner = 2
|
||||
19:1/0 = 0
|
||||
19:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
20:1/0 = 0
|
||||
20:1/0/terrain_set = 0
|
||||
20:1/0/terrain = 2
|
||||
20:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
20:1/0/terrains_peering_bit/right_side = 2
|
||||
20:1/0/terrains_peering_bit/bottom_right_corner = 2
|
||||
20:1/0/terrains_peering_bit/bottom_side = 2
|
||||
@@ -208,32 +218,38 @@ texture = ExtResource("5_q7rhw")
|
||||
21:1/0 = 0
|
||||
21:1/0/terrain_set = 0
|
||||
21:1/0/terrain = 2
|
||||
21:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
21:1/0/terrains_peering_bit/bottom_side = 2
|
||||
21:1/0/terrains_peering_bit/bottom_left_corner = 2
|
||||
21:1/0/terrains_peering_bit/left_side = 2
|
||||
22:1/0 = 0
|
||||
22:1/0/terrain_set = 0
|
||||
22:1/0/terrain = 2
|
||||
22:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
22:1/0/terrains_peering_bit/right_side = 2
|
||||
22:1/0/terrains_peering_bit/bottom_side = 2
|
||||
23:1/0 = 0
|
||||
23:1/0/terrain_set = 0
|
||||
23:1/0/terrain = 2
|
||||
23:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
23:1/0/terrains_peering_bit/left_side = 2
|
||||
23:1/0/terrains_peering_bit/top_side = 2
|
||||
25:1/0 = 0
|
||||
25:1/0/terrain_set = 0
|
||||
25:1/0/terrain = 2
|
||||
25:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
25:1/0/terrains_peering_bit/right_side = 2
|
||||
25:1/0/terrains_peering_bit/top_side = 2
|
||||
26:1/0 = 0
|
||||
26:1/0/terrain_set = 0
|
||||
26:1/0/terrain = 2
|
||||
26:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
26:1/0/terrains_peering_bit/bottom_side = 2
|
||||
26:1/0/terrains_peering_bit/left_side = 2
|
||||
28:1/0 = 0
|
||||
28:1/0/terrain_set = 0
|
||||
28:1/0/terrain = 2
|
||||
28:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
28:1/0/terrains_peering_bit/bottom_side = 2
|
||||
30:1/0 = 0
|
||||
31:1/0 = 0
|
||||
@@ -335,15 +351,18 @@ texture = ExtResource("5_q7rhw")
|
||||
17:2/0 = 0
|
||||
17:2/0/terrain_set = 0
|
||||
17:2/0/terrain = 2
|
||||
17:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
17:2/0/terrains_peering_bit/right_side = 2
|
||||
17:2/0/terrains_peering_bit/bottom_right_corner = 2
|
||||
17:2/0/terrains_peering_bit/bottom_side = 2
|
||||
17:2/0/terrains_peering_bit/top_side = 2
|
||||
17:2/0/terrains_peering_bit/top_right_corner = 2
|
||||
18:2/0 = 0
|
||||
18:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
19:2/0 = 0
|
||||
19:2/0/terrain_set = 0
|
||||
19:2/0/terrain = 2
|
||||
19:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
19:2/0/terrains_peering_bit/right_side = 2
|
||||
19:2/0/terrains_peering_bit/bottom_right_corner = 2
|
||||
19:2/0/terrains_peering_bit/bottom_side = 2
|
||||
@@ -353,9 +372,11 @@ texture = ExtResource("5_q7rhw")
|
||||
19:2/0/terrains_peering_bit/top_side = 2
|
||||
19:2/0/terrains_peering_bit/top_right_corner = 2
|
||||
20:2/0 = 0
|
||||
20:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
21:2/0 = 0
|
||||
21:2/0/terrain_set = 0
|
||||
21:2/0/terrain = 2
|
||||
21:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
21:2/0/terrains_peering_bit/bottom_side = 2
|
||||
21:2/0/terrains_peering_bit/bottom_left_corner = 2
|
||||
21:2/0/terrains_peering_bit/left_side = 2
|
||||
@@ -364,16 +385,19 @@ texture = ExtResource("5_q7rhw")
|
||||
22:2/0 = 0
|
||||
22:2/0/terrain_set = 0
|
||||
22:2/0/terrain = 2
|
||||
22:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
22:2/0/terrains_peering_bit/bottom_side = 2
|
||||
22:2/0/terrains_peering_bit/top_side = 2
|
||||
26:2/0 = 0
|
||||
26:2/0/terrain_set = 0
|
||||
26:2/0/terrain = 2
|
||||
26:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
26:2/0/terrains_peering_bit/bottom_side = 2
|
||||
26:2/0/terrains_peering_bit/top_side = 2
|
||||
28:2/0 = 0
|
||||
28:2/0/terrain_set = 0
|
||||
28:2/0/terrain = 2
|
||||
28:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
28:2/0/terrains_peering_bit/bottom_side = 2
|
||||
28:2/0/terrains_peering_bit/top_side = 2
|
||||
33:2/0 = 0
|
||||
@@ -471,12 +495,14 @@ texture = ExtResource("5_q7rhw")
|
||||
17:3/0 = 0
|
||||
17:3/0/terrain_set = 0
|
||||
17:3/0/terrain = 2
|
||||
17:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
17:3/0/terrains_peering_bit/right_side = 2
|
||||
17:3/0/terrains_peering_bit/top_side = 2
|
||||
17:3/0/terrains_peering_bit/top_right_corner = 2
|
||||
18:3/0 = 0
|
||||
18:3/0/terrain_set = 0
|
||||
18:3/0/terrain = 2
|
||||
18:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
18:3/0/terrains_peering_bit/right_side = 2
|
||||
18:3/0/terrains_peering_bit/bottom_right_corner = 2
|
||||
18:3/0/terrains_peering_bit/bottom_side = 2
|
||||
@@ -485,9 +511,11 @@ texture = ExtResource("5_q7rhw")
|
||||
18:3/0/terrains_peering_bit/top_side = 2
|
||||
18:3/0/terrains_peering_bit/top_right_corner = 2
|
||||
19:3/0 = 0
|
||||
19:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
20:3/0 = 0
|
||||
20:3/0/terrain_set = 0
|
||||
20:3/0/terrain = 2
|
||||
20:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
20:3/0/terrains_peering_bit/right_side = 2
|
||||
20:3/0/terrains_peering_bit/bottom_side = 2
|
||||
20:3/0/terrains_peering_bit/bottom_left_corner = 2
|
||||
@@ -498,32 +526,38 @@ texture = ExtResource("5_q7rhw")
|
||||
21:3/0 = 0
|
||||
21:3/0/terrain_set = 0
|
||||
21:3/0/terrain = 2
|
||||
21:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
21:3/0/terrains_peering_bit/left_side = 2
|
||||
21:3/0/terrains_peering_bit/top_left_corner = 2
|
||||
21:3/0/terrains_peering_bit/top_side = 2
|
||||
22:3/0 = 0
|
||||
22:3/0/terrain_set = 0
|
||||
22:3/0/terrain = 2
|
||||
22:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
22:3/0/terrains_peering_bit/right_side = 2
|
||||
22:3/0/terrains_peering_bit/top_side = 2
|
||||
23:3/0 = 0
|
||||
23:3/0/terrain_set = 0
|
||||
23:3/0/terrain = 2
|
||||
23:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
23:3/0/terrains_peering_bit/bottom_side = 2
|
||||
23:3/0/terrains_peering_bit/left_side = 2
|
||||
25:3/0 = 0
|
||||
25:3/0/terrain_set = 0
|
||||
25:3/0/terrain = 2
|
||||
25:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
25:3/0/terrains_peering_bit/right_side = 2
|
||||
25:3/0/terrains_peering_bit/bottom_side = 2
|
||||
26:3/0 = 0
|
||||
26:3/0/terrain_set = 0
|
||||
26:3/0/terrain = 2
|
||||
26:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
26:3/0/terrains_peering_bit/left_side = 2
|
||||
26:3/0/terrains_peering_bit/top_side = 2
|
||||
28:3/0 = 0
|
||||
28:3/0/terrain_set = 0
|
||||
28:3/0/terrain = 2
|
||||
28:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
28:3/0/terrains_peering_bit/top_side = 2
|
||||
30:3/0 = 0
|
||||
31:3/0 = 0
|
||||
@@ -603,12 +637,14 @@ texture = ExtResource("5_q7rhw")
|
||||
18:4/0 = 0
|
||||
18:4/0/terrain_set = 0
|
||||
18:4/0/terrain = 2
|
||||
18:4/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
18:4/0/terrains_peering_bit/right_side = 2
|
||||
18:4/0/terrains_peering_bit/top_side = 2
|
||||
18:4/0/terrains_peering_bit/top_right_corner = 2
|
||||
19:4/0 = 0
|
||||
19:4/0/terrain_set = 0
|
||||
19:4/0/terrain = 2
|
||||
19:4/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
19:4/0/terrains_peering_bit/right_side = 2
|
||||
19:4/0/terrains_peering_bit/left_side = 2
|
||||
19:4/0/terrains_peering_bit/top_left_corner = 2
|
||||
@@ -617,22 +653,26 @@ texture = ExtResource("5_q7rhw")
|
||||
20:4/0 = 0
|
||||
20:4/0/terrain_set = 0
|
||||
20:4/0/terrain = 2
|
||||
20:4/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
20:4/0/terrains_peering_bit/left_side = 2
|
||||
20:4/0/terrains_peering_bit/top_left_corner = 2
|
||||
20:4/0/terrains_peering_bit/top_side = 2
|
||||
23:4/0 = 0
|
||||
23:4/0/terrain_set = 0
|
||||
23:4/0/terrain = 2
|
||||
23:4/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
23:4/0/terrains_peering_bit/right_side = 2
|
||||
23:4/0/terrains_peering_bit/top_side = 2
|
||||
24:4/0 = 0
|
||||
24:4/0/terrain_set = 0
|
||||
24:4/0/terrain = 2
|
||||
24:4/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
24:4/0/terrains_peering_bit/right_side = 2
|
||||
24:4/0/terrains_peering_bit/left_side = 2
|
||||
25:4/0 = 0
|
||||
25:4/0/terrain_set = 0
|
||||
25:4/0/terrain = 2
|
||||
25:4/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
25:4/0/terrains_peering_bit/left_side = 2
|
||||
25:4/0/terrains_peering_bit/top_side = 2
|
||||
30:4/0 = 0
|
||||
@@ -682,6 +722,7 @@ texture = ExtResource("5_q7rhw")
|
||||
28:5/0 = 0
|
||||
28:5/0/terrain_set = 0
|
||||
28:5/0/terrain = 2
|
||||
28:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
28:5/0/terrains_peering_bit/bottom_side = 2
|
||||
30:5/0 = 0
|
||||
31:5/0 = 0
|
||||
@@ -717,30 +758,40 @@ texture = ExtResource("5_q7rhw")
|
||||
15:6/0 = 0
|
||||
16:6/0 = 0
|
||||
17:6/0 = 0
|
||||
17:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
18:6/0 = 0
|
||||
18:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
19:6/0 = 0
|
||||
19:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
20:6/0 = 0
|
||||
20:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
21:6/0 = 0
|
||||
21:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
23:6/0 = 0
|
||||
23:6/0/terrain_set = 0
|
||||
23:6/0/terrain = 2
|
||||
23:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
23:6/0/terrains_peering_bit/right_side = 2
|
||||
24:6/0 = 0
|
||||
24:6/0/terrain_set = 0
|
||||
24:6/0/terrain = 2
|
||||
24:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
24:6/0/terrains_peering_bit/right_side = 2
|
||||
24:6/0/terrains_peering_bit/left_side = 2
|
||||
25:6/0 = 0
|
||||
25:6/0/terrain_set = 0
|
||||
25:6/0/terrain = 2
|
||||
25:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
25:6/0/terrains_peering_bit/left_side = 2
|
||||
27:6/0 = 0
|
||||
27:6/0/terrain_set = 0
|
||||
27:6/0/terrain = 2
|
||||
27:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
27:6/0/terrains_peering_bit/right_side = 2
|
||||
28:6/0 = 0
|
||||
28:6/0/terrain_set = 0
|
||||
28:6/0/terrain = 2
|
||||
28:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
28:6/0/terrains_peering_bit/bottom_side = 2
|
||||
28:6/0/terrains_peering_bit/left_side = 2
|
||||
28:6/0/terrains_peering_bit/top_side = 2
|
||||
@@ -786,12 +837,15 @@ texture = ExtResource("5_q7rhw")
|
||||
15:7/0 = 0
|
||||
16:7/0 = 0
|
||||
17:7/0 = 0
|
||||
17:7/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
18:7/0 = 0
|
||||
20:7/0 = 0
|
||||
21:7/0 = 0
|
||||
21:7/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
28:7/0 = 0
|
||||
28:7/0/terrain_set = 0
|
||||
28:7/0/terrain = 2
|
||||
28:7/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
28:7/0/terrains_peering_bit/top_side = 2
|
||||
30:7/0 = 0
|
||||
31:7/0 = 0
|
||||
@@ -825,6 +879,7 @@ texture = ExtResource("5_q7rhw")
|
||||
24:8/0 = 0
|
||||
24:8/0/terrain_set = 0
|
||||
24:8/0/terrain = 2
|
||||
24:8/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
24:8/0/terrains_peering_bit/bottom_side = 2
|
||||
30:8/0 = 0
|
||||
31:8/0 = 0
|
||||
@@ -855,26 +910,32 @@ texture = ExtResource("5_q7rhw")
|
||||
15:9/0 = 0
|
||||
16:9/0 = 0
|
||||
17:9/0 = 0
|
||||
17:9/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
18:9/0 = 0
|
||||
20:9/0 = 0
|
||||
21:9/0 = 0
|
||||
21:9/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
23:9/0 = 0
|
||||
23:9/0/terrain_set = 0
|
||||
23:9/0/terrain = 2
|
||||
23:9/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
23:9/0/terrains_peering_bit/right_side = 2
|
||||
24:9/0 = 0
|
||||
24:9/0/terrain_set = 0
|
||||
24:9/0/terrain = 2
|
||||
24:9/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
24:9/0/terrains_peering_bit/right_side = 2
|
||||
24:9/0/terrains_peering_bit/left_side = 2
|
||||
24:9/0/terrains_peering_bit/top_side = 2
|
||||
25:9/0 = 0
|
||||
25:9/0/terrain_set = 0
|
||||
25:9/0/terrain = 2
|
||||
25:9/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
25:9/0/terrains_peering_bit/left_side = 2
|
||||
27:9/0 = 0
|
||||
27:9/0/terrain_set = 0
|
||||
27:9/0/terrain = 2
|
||||
27:9/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
27:9/0/terrains_peering_bit/bottom_side = 2
|
||||
29:9/0 = 0
|
||||
30:9/0 = 0
|
||||
@@ -914,19 +975,26 @@ texture = ExtResource("5_q7rhw")
|
||||
15:10/0 = 0
|
||||
16:10/0 = 0
|
||||
17:10/0 = 0
|
||||
17:10/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
18:10/0 = 0
|
||||
18:10/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
19:10/0 = 0
|
||||
19:10/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
20:10/0 = 0
|
||||
20:10/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
21:10/0 = 0
|
||||
21:10/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
27:10/0 = 0
|
||||
27:10/0/terrain_set = 0
|
||||
27:10/0/terrain = 2
|
||||
27:10/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
27:10/0/terrains_peering_bit/right_side = 2
|
||||
27:10/0/terrains_peering_bit/bottom_side = 2
|
||||
27:10/0/terrains_peering_bit/top_side = 2
|
||||
28:10/0 = 0
|
||||
28:10/0/terrain_set = 0
|
||||
28:10/0/terrain = 2
|
||||
28:10/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
28:10/0/terrains_peering_bit/left_side = 2
|
||||
31:10/0 = 0
|
||||
32:10/0 = 0
|
||||
@@ -1021,20 +1089,24 @@ texture = ExtResource("5_q7rhw")
|
||||
23:11/0 = 0
|
||||
23:11/0/terrain_set = 0
|
||||
23:11/0/terrain = 2
|
||||
23:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
23:11/0/terrains_peering_bit/right_side = 2
|
||||
24:11/0 = 0
|
||||
24:11/0/terrain_set = 0
|
||||
24:11/0/terrain = 2
|
||||
24:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
24:11/0/terrains_peering_bit/right_side = 2
|
||||
24:11/0/terrains_peering_bit/bottom_side = 2
|
||||
24:11/0/terrains_peering_bit/left_side = 2
|
||||
25:11/0 = 0
|
||||
25:11/0/terrain_set = 0
|
||||
25:11/0/terrain = 2
|
||||
25:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
25:11/0/terrains_peering_bit/left_side = 2
|
||||
27:11/0 = 0
|
||||
27:11/0/terrain_set = 0
|
||||
27:11/0/terrain = 2
|
||||
27:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
27:11/0/terrains_peering_bit/top_side = 2
|
||||
29:11/0 = 0
|
||||
30:11/0 = 0
|
||||
@@ -1137,6 +1209,7 @@ texture = ExtResource("5_q7rhw")
|
||||
24:12/0 = 0
|
||||
24:12/0/terrain_set = 0
|
||||
24:12/0/terrain = 2
|
||||
24:12/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||
24:12/0/terrains_peering_bit/top_side = 2
|
||||
29:12/0 = 0
|
||||
30:12/0 = 0
|
||||
|
||||
119
scenes/level_forest_1.tscn
Normal file
119
scenes/level_forest_1.tscn
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user