diff options
| author | Matheus <matheus.guedes.mg.m@gmail.com> | 2025-09-09 19:09:34 -0300 |
|---|---|---|
| committer | Matheus <matheus.guedes.mg.m@gmail.com> | 2025-09-09 19:09:34 -0300 |
| commit | c6bbb834f7758027c0df338f1520f34fad3befea (patch) | |
| tree | 1818cd23c24be16fbe19b16dd0a510874d440d83 /scripts/Map/FieldOfView.cs | |
| parent | f1b51bed52ffbd90b5b7cc8dcfc6f0484bbbeb3c (diff) | |
Organização
Diffstat (limited to 'scripts/Map/FieldOfView.cs')
| -rw-r--r-- | scripts/Map/FieldOfView.cs | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/scripts/Map/FieldOfView.cs b/scripts/Map/FieldOfView.cs new file mode 100644 index 0000000..40df320 --- /dev/null +++ b/scripts/Map/FieldOfView.cs @@ -0,0 +1,115 @@ +using Godot; + +namespace TheLegendOfGustav.Map; + +// Copiado e adaptado deste cara aqui: https://www.roguebasin.com/index.php?title=C%2B%2B_shadowcasting_implementation e deste também https://selinadev.github.io/08-rogueliketutorial-04/ + +// Eu não vou mentir, li como o algoritmo funciona, mas mesmo assim não entendi. + +public partial class FieldOfView : Node +{ + + private Godot.Collections.Array<Tile> fov = []; + + private static readonly int[,] multipliers = new int[4, 8]{ + {1, 0, 0, -1, -1, 0, 0, 1}, + {0, 1, -1, 0, 0, -1, 1, 0}, + {0, 1, 1, 0, 0, -1, -1, 0}, + {1, 0, 0, 1, -1, 0, 0, -1} + }; + private void CastLight(MapData data, Vector2I pos, int radius, int row, float startSlope, float endSlope, int xx, int xy, int yx, int yy) + { + if (startSlope < endSlope) + { + return; + } + + float nextStartSlope = startSlope; + for (int i = row; i <= radius; i++) + { + bool blocked = false; + for (int dx = -i, dy = -i; dx <= 0; dx++) + { + float lSlope = (float)((dx - 0.5) / (dy + 0.5)); + float rSlope = (float)((dx + 0.5) / (dy - 0.5)); + + if (startSlope < rSlope) + { + continue; + } + else if (endSlope > lSlope) + { + break; + } + + int sax = dx * xx + dy * xy; + int say = dx * yx + dy * yy; + + if ((sax < 0 && int.Abs(sax) > pos.X) || (say < 0 && int.Abs(say) > pos.Y)) + { + continue; + } + int ax = pos.X + sax; + int ay = pos.Y + say; + + if (ax >= data.Width || ay >= data.Height) + { + continue; + } + + Tile currentTile = data.GetTile(ax, ay); + int radius2 = radius * radius; + if ((dx * dx + dy * dy) < radius2) + { + currentTile.IsInView = true; + fov.Add(currentTile); + } + + if (blocked) + { + if (!currentTile.IsTransparent) + { + nextStartSlope = rSlope; + continue; + } + else + { + blocked = false; + startSlope = nextStartSlope; + } + } + else if (!currentTile.IsTransparent) + { + blocked = true; + nextStartSlope = rSlope; + CastLight(data, pos, radius, i + 1, startSlope, lSlope, xx, xy, yx, yy); + } + } + if (blocked) + { + break; + } + } + } + + private void ClearFOV() + { + foreach (Tile tile in fov) + { + tile.IsInView = false; + } + fov.Clear(); + } + + public void UpdateFOV(MapData data, Vector2I position, int radius) + { + ClearFOV(); + Tile start = data.GetTile(position); + start.IsInView = true; + fov.Add(start); + for (int i = 0; i < 8; i++) + { + CastLight(data, position, radius, 1, 1.0f, 0.0f, multipliers[0, i], multipliers[1, i], multipliers[2, i], multipliers[3, i]); + } + } +} |
