summaryrefslogtreecommitdiff
path: root/scripts/Map/MapDivision.cs
blob: e50b3319269477490487273f495e734cec366cfe (plain)
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
using Godot;

namespace TheLegendOfGustav.Map;

/// <summary>
/// Classe utilizada pelo gerador de mapas.
/// Uma divisão é uma região retangular de espaço que pode
/// conter dentro de si duas regiões menores *ou* uma sala.
/// Uma divisão é uma árvore binária que possui espaço para salas em suas folhas.
/// </summary>
public partial class MapDivision : RefCounted
{
	public MapDivision(Vector2I position, Vector2I size)
	{
		Position = position;
		Size = size;
	}

	public MapDivision(Vector2I position, int width, int height)
	{
		Position = position;
		Size = new(width, height);
	}

	public MapDivision(int x, int y, int width, int height)
	{
		Position = new(x, y);
		Size = new(width, height);
	}

	/// <summary>
	/// Região retangular da divisão.
	/// </summary>
	public Vector2I Position { get; set; }
	public Vector2I Size { get; set; }

	public Vector2I Center
	{
		get => new(Position.X + Size.X / 2, Position.Y + Size.Y / 2);
	}

	/// <summary>
	/// Filhos da árvore
	/// </summary>
	public MapDivision Left { get; private set; }
	public MapDivision Right { get; private set; }

	/// <summary>
	/// Se a divisão atual for uma folha.
	/// As folhas representam salas.
	/// </summary>
	public bool IsLeaf
	{
		get => Left == null && Right == null;
	}

	/// <summary>
	/// É conveniente ter acesso à todas as folhas da árvore.
	/// </summary>
	/// <returns>Lista com todas as folhas da árvore.</returns>
	public Godot.Collections.Array<MapDivision> GetLeaves()
	{
		if (IsLeaf)
		{
			Godot.Collections.Array<MapDivision> list = [];
			list.Add(this);
			return list;
		}
		return Left.GetLeaves() + Right.GetLeaves();
	}

	/// <summary>
	/// Algoritmo para gerar as divisões.
	/// O mapa começa com uma única divisão que oculpa sua extensão completa.
	/// Depois disso, ela se dividirá recursivamente n vezes.
	/// As divisões nas folhas representam espaços onde pode gerar uma sala.
	/// </summary>
	/// <param name="iterations">Número de iterações</param>
	/// <param name="rng">Gerador de números</param>
	public void Split(int iterations, RandomNumberGenerator rng)
	{
		float SplitRatio = rng.RandfRange(0.35f, 0.65f);
		bool horizontalSplit = Size.X <= Size.Y;

		// Eu defini um limite mínimo de 4 de altura e 4 de largura para divisões.

		if (horizontalSplit)
		{
			int leftHeight = (int)(Size.Y * SplitRatio);
			if (leftHeight > 4 && Size.Y - leftHeight > 4)
			{
				Left = new MapDivision(Position, Size.X, leftHeight);
				Right = new MapDivision(Position.X, Position.Y + leftHeight, Size.X, Size.Y - leftHeight);
			}
		}
		else
		{
			int leftWidth = (int)(Size.Y * SplitRatio);

			if (leftWidth > 4 && Size.Y - leftWidth > 4)
			{
				Left = new MapDivision(Position, leftWidth, Size.Y);
				Right = new MapDivision(Position.X + leftWidth, Position.Y, Size.X - leftWidth, Size.Y);
			}
		}

		if (iterations > 1)
		{
			Left?.Split(iterations - 1, rng);
			Right?.Split(iterations - 1, rng);
		}
	}
}