using Godot; using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Reflection.Metadata.Ecma335; public partial class Map : TileMapLayer { public PackedScene _mapCellScene = GD.Load("res://map_cell.tscn"); public int _minX, _maxX, _minY, _maxY, _mainSource = 0; public string _isSolidString = "is_solid", _dispositionString = "disposition"; public Vector2 _cellSize, _sizeInPixels, _sizeInCells; public AStarGrid2D _astar = new(); public Dictionary _cells = new(), _leftmostColumn = new(), _rightmostColumn = new(), _topRow = new(), _bottomRow = new(); public int _firstOpenRow { get { for (int i = 0; i < _maxY; i++) { if (!IsRowFull(i)) { return i; } } return -1; } } public int _lastOpenRow { get { for (int i = _maxY; i > _minY; i--) { if (!IsRowFull(i)) { return i; } } return -1; } } public int _firstOpenColumn { get { for (int i = 0; i < _maxX; i++) { if (!IsColumnnFull(i)) { return i; } } return -1; } } public int _lastOpenColumn { get { for (int i = _maxX; i > _minX; i--) { if (!IsColumnnFull(i)) { return i; } } return -1; } } public override void _Ready() { base._Ready(); List usedCells = [.. GetUsedCells()]; _cellSize = TileSet.TileSize; for (int i = 0; i < usedCells.Count; i++) { MapCell newMapCell = _mapCellScene.Instantiate(); Vector2I usedCell = usedCells[i]; newMapCell._address = usedCell; newMapCell.GlobalPosition = GetCellPositionFromAddress(newMapCell._address); newMapCell._occupant = null; _cells[usedCell] = newMapCell; AddChild(newMapCell); } _minX = _cells.Min(c => c.Value._address.X); _maxX = _cells.Max(c => c.Value._address.X); _minY = _cells.Min(c => c.Value._address.Y); _maxY = _cells.Max(c => c.Value._address.Y); _leftmostColumn = _cells.Where(c => c.Value._address.X == _minX).ToDictionary(); _rightmostColumn = _cells.Where(c => c.Value._address.X == _maxX).ToDictionary(); _topRow = _cells.Where(c => c.Value._address.Y == _minY).ToDictionary(); _bottomRow = _cells.Where(c => c.Value._address.Y == _maxY).ToDictionary(); _sizeInCells = new Vector2(_topRow.Count, _leftmostColumn.Count); _sizeInPixels = _sizeInCells * _cellSize; SetupAstar(); } public Vector2I GetAddressFromPosition(Vector2 POSITION) { if (POSITION.X < GlobalPosition.X || POSITION.Y < GlobalPosition.Y) { return new Vector2I(-1,-1); } else if (POSITION.X > (GlobalPosition + (new Vector2(_maxX, _maxY) * _cellSize)).X || POSITION.Y > (GlobalPosition + (new Vector2(_maxX, _maxY) * _cellSize)).Y) { return new Vector2I(-1,-1); } return new Vector2I((int)Math.Floor(POSITION.X / _cellSize.X), (int)Math.Floor(POSITION.Y / _cellSize.Y)); } public Vector2 GetCellPosition(MapCell CELL) { return CELL.GlobalPosition; } public Vector2 GetCellPositionFromAddress(Vector2I CELL_ADDRESS) { return GlobalPosition + CELL_ADDRESS * _cellSize + _cellSize / 2; } public MapCellOccupant GetOccupant(Vector2I CELL_TO_CHECK) { return _cells[CELL_TO_CHECK]._occupant; } public bool HasOccupant(Vector2I CELL_TO_CHECK) { return GetOccupant(CELL_TO_CHECK) != null; } public bool IsCellSolid(Vector2I CELL_TO_CHECK) { bool hasOccupant = HasOccupant(CELL_TO_CHECK); bool isSolid = (bool)GetCellTileData(CELL_TO_CHECK).GetCustomData(_isSolidString); return hasOccupant || isSolid; } public bool IsColumnnFull(int COLUMN_TO_CHECK) { List rowCells = [.. _cells.Where(c => c.Value._address.X == COLUMN_TO_CHECK).ToDictionary().Keys]; return rowCells.All(_astar.IsPointSolid); } public bool IsRowFull(int ROW_TO_CHECK) { List rowCells = [.. _cells.Where(c => c.Value._address.Y == ROW_TO_CHECK).ToDictionary().Keys]; return rowCells.All(_astar.IsPointSolid); } public void SetCellPeg(MapCell CELL, Peg PEG) { if (PEG != null) { if (PEG._address != -Vector2I.One) { CELL._occupant = null; SetCellSolid(_cells[PEG._address]); } PEG._address = CELL._address; } CELL._occupant = PEG; SetCellSolid(CELL); } public void SetCellSolid(MapCell CELL) { _astar.SetPointSolid(CELL._address, IsCellSolid(CELL._address)); // _astar.SetPointWeightScale(ADDRESS, IsCellSolid(ADDRESS) ? 1000 : 1); } public void SetupAstar() { _astar.Region = new Rect2I(_minX, _minY, _topRow.Count, _leftmostColumn.Count); _astar.CellSize = _cellSize; _astar.DefaultComputeHeuristic = AStarGrid2D.Heuristic.Manhattan; _astar.DiagonalMode = AStarGrid2D.DiagonalModeEnum.Never; _astar.Update(); for (int i = 0; i < _cells.Count; i++) { _astar.SetPointWeightScale(_cells.ElementAt(i).Value._address, Math.Abs(_cells.ElementAt(i).Value._address.Y * 2)); } EvaluateSolidCells(); } public List GetPath(Vector2I FROM, Vector2I TO, bool INCLUDE_FROM = false, bool PARTIAL = false) { _astar.SetPointSolid(FROM, false); List pathTaken = [.. _astar.GetIdPath(FROM, TO, PARTIAL)]; _astar.SetPointSolid(FROM, true); if (!INCLUDE_FROM) { pathTaken.Remove(FROM); } return pathTaken; } public void EvaluateSolidCells() { for (int i = 0; i < _cells.Count; i++) { SetCellSolid(_cells.ElementAt(i).Value); } } }