1308 lines
45 KiB
C#
Raw Normal View History

2024-02-20 18:39:12 +08:00
using HPJ.Simulation.Enums;
using HPJ.Simulation.Pathing;
using System;
using System.Collections.Generic;
using System.Linq;
namespace HPJ.Simulation.Map
{
/// <summary>
/// The set of maps (base and redundant) that represent a specific area
/// </summary>
[Serializable]
public class MapSet
{
/// <summary>
/// The Settings for this Map Set
/// </summary>
public MapSetSettings SetSettings = new MapSetSettings();
/// <summary>
/// The Instance ID to distinguish each map set apart
/// </summary>
public int InstanceID;
/// <summary>
/// Shows if this Map Set is initialized or not
/// </summary>
public bool Initialized { get; protected set; }
/// <summary>
/// The Base map that comes with each Map Set
/// </summary>
public Map BaseMap { get; protected set; }
/// <summary>
/// The Redundant Maps that help are used to help reduce queue times for each Navigation Agent
/// </summary>
public Map[] RedundantMaps { get; protected set; }
/// <summary>
/// The List of Bridges that connect to this Map Set
/// </summary>
public List<MapBridge> MapBridges { get; set; }
/// <summary>
/// The List of Seams that connect to this Map Set
/// </summary>
public List<MapSeam> MapSeams { get; set; }
/// <summary>
/// The Callback to links back up to Unity. Cannot use Debug.Log() in the simulation side of the navigation
/// </summary>
public Action<string, SimulationDebugLog> DebugLogCallback;
/// <summary>
/// The List of Key points around the border of the Map Set
/// </summary>
public List<IntVector3> KeyBorderPositions { get; set; }
/// <summary>
/// Bottom Left Corner of the Map
/// </summary>
public IntVector3 BottomLeftPosition { get; set; }
/// <summary>
/// Left Center Position of the Map
/// </summary>
public IntVector3 LeftPosition { get; set; }
/// <summary>
/// Bottom Center Position of the Map
/// </summary>
public IntVector3 BottomPosition { get; set; }
/// <summary>
/// Bottom Right Corner of the Map
/// </summary>
public IntVector3 BottomRightPosition { get; set; }
/// <summary>
/// Top Right Corner of the Map
/// </summary>
public IntVector3 TopRightPosition { get; set; }
/// <summary>
/// Right Center Position of the Map
/// </summary>
public IntVector3 RightPosition { get; set; }
/// <summary>
/// Top Center Position of the Map
/// </summary>
public IntVector3 TopPosition { get; set; }
/// <summary>
/// Top Left Corner of the Map
/// </summary>
public IntVector3 TopLeftPosition { get; set; }
/// <summary>
/// Middle Position of the Map Position of the Map
/// </summary>
public IntVector3 MiddlePosition { get; set; }
public MapSet()
{
MapBridges = new List<MapBridge>();
MapSeams = new List<MapSeam>();
OutgoingClaims = new Dictionary<IntVector2, TileOwnershipClaim>();
}
/// <summary>
/// Initilizes the Map Set
/// </summary>
/// <param name="Parrelism"></param>
/// <param name="Redundancy"></param>
/// <param name="CreateAgentMap"></param>
/// <param name="debugLogCallback"></param>
public void Initialize(int Parrelism, int Redundancy, bool CreateAgentMap, Action<string, SimulationDebugLog> debugLogCallback)
{
try
{
DebugLogCallback = debugLogCallback;
Redundancy++;
RedundantMaps = new Map[Redundancy];
for (int i = 0; i < Redundancy; i++)
{
Map NewMap = new Map(SetSettings.MapSettings, $"{SetSettings.Name} - Map ({i})", Parrelism, CreateAgentMap);
NewMap.Initialize(debugLogCallback);
RedundantMaps[i] = NewMap;
}
BaseMap = RedundantMaps[0];
// Initialize Pathfinding
if (AStar.Instance == null)
{
AStar.Instance = new AStar();
}
if (JumpPointSearch.Instance == null)
{
JumpPointSearch.Instance = new JumpPointSearch();
}
KeyBorderPositions = new List<IntVector3>();
IntVector3 WorldTileMax = new IntVector3();
WorldTileMax.x = SetSettings.MapSettings.TileSize * SetSettings.MapSettings.MapWidth;
WorldTileMax.y = 0;
WorldTileMax.z = SetSettings.MapSettings.TileSize * SetSettings.MapSettings.MapHeight;
BottomLeftPosition = SetSettings.MapSettings.Offset;
KeyBorderPositions.Add(BottomLeftPosition);
BottomPosition = SetSettings.MapSettings.Offset + WorldTileMax.xVector() / 2;
KeyBorderPositions.Add(BottomPosition);
BottomRightPosition = SetSettings.MapSettings.Offset + WorldTileMax.xVector();
KeyBorderPositions.Add(BottomRightPosition);
LeftPosition = SetSettings.MapSettings.Offset + WorldTileMax.zVector() / 2;
KeyBorderPositions.Add(LeftPosition);
MiddlePosition = SetSettings.MapSettings.Offset + WorldTileMax.xzVector() / 2;
KeyBorderPositions.Add(MiddlePosition);
RightPosition = SetSettings.MapSettings.Offset + WorldTileMax.xVector() + WorldTileMax.zVector() / 2;
KeyBorderPositions.Add(RightPosition);
TopLeftPosition = SetSettings.MapSettings.Offset + WorldTileMax.zVector();
KeyBorderPositions.Add(TopLeftPosition);
TopPosition = SetSettings.MapSettings.Offset + WorldTileMax.xVector() / 2 + WorldTileMax.zVector();
KeyBorderPositions.Add(TopPosition);
TopRightPosition = SetSettings.MapSettings.Offset + WorldTileMax.xzVector();
KeyBorderPositions.Add(TopRightPosition);
Initialized = true;
}
catch (Exception ex)
{
debugLogCallback?.Invoke($"{ex.Message}: {ex.StackTrace}", SimulationDebugLog.Error);
}
}
public void OnDestroy()
{
for (int i = 0; i < RedundantMaps.Length; i++)
{
RedundantMaps[i].OnDestroy();
}
}
/// <summary>
/// Logs the debugs occured in the simulation
/// </summary>
/// <param name="Log"></param>
public void Log(string Log)
{
DebugLogCallback?.Invoke(Log, SimulationDebugLog.Log);
}
/// <summary>
/// Logs the warning occured in the simulation
/// </summary>
/// <param name="Log"></param>
public void LogWarning(string Log)
{
DebugLogCallback?.Invoke(Log, SimulationDebugLog.Warning);
}
/// <summary>
/// Logs the errors occured in the simulation
/// </summary>
/// <param name="Log"></param>
public void LogError(string Log)
{
DebugLogCallback?.Invoke(Log, SimulationDebugLog.Error);
}
#region Pathfinding
private int _redundantMapCounter = -1;
/// <summary>
/// The Call a navigation job sends to the map to be calculated
/// </summary>
/// <param name="Job"></param>
public void SetDestination(NavigationJob Job)
{
_redundantMapCounter++;
if (_redundantMapCounter >= RedundantMaps.Length)
{
_redundantMapCounter = 0;
}
if (RedundantMaps.Length == 0)
{
LogWarning("Warning, No Maps to cast 'Set Destination On'");
return;
}
RedundantMaps[_redundantMapCounter].AddNavigationJob(Job);
}
/// <summary>
/// Checks to see if this job is compatible with this map set. For example a job that has its start in another map is not compatible with this map set
/// </summary>
/// <param name="job"></param>
/// <returns></returns>
public bool JobCompatible(NavigationJob job)
{
if (BaseMap == null)
{
LogError($"Map {SetSettings.Name} Close Range is Null");
return false;
}
return BaseMap.JobCompatible(job);
}
/// <summary>
/// Whether this index is out of range of the map
/// </summary>
/// <param name="newTilePosition"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public bool OutOfRange(IntVector2 newTilePosition)
{
if (newTilePosition.x < 0 || newTilePosition.y < 0)
{
return true;
}
if (newTilePosition.x >= SetSettings.MapSettings.MapWidth || newTilePosition.y >= SetSettings.MapSettings.MapHeight)
{
return true;
}
return false;
}
#endregion
#region Map Changes
/// <summary>
/// The Call that changes the tiles on each map in the Map Set
/// </summary>
/// <param name="MapJob"></param>
public void ChangeMap(ChangeMapJob MapJob)
{
foreach (Map map in RedundantMaps)
{
map.AddMapChange(MapJob);
}
}
/// <summary>
/// A dictionary to keep track of the outgoing claims
/// </summary>
public Dictionary<IntVector2, TileOwnershipClaim> OutgoingClaims { get; protected set; }
/// <summary>
/// Requests to claim a tile
/// </summary>
/// <param name="Tile"></param>
/// <param name="AgentID"></param>
/// <returns></returns>
public bool AttemptClaim(IntVector2 Tile, ushort AgentID)
{
if (BaseMap.AgentOwnershipMap.Tiles[Tile.x, Tile.y] != 0)
{
return false;
}
if (OutgoingClaims.ContainsKey(Tile))
{
return false;
}
TileOwnershipClaim NewClaim = new TileOwnershipClaim(AgentID, Tile);
OutgoingClaims.Add(Tile, NewClaim);
Claim(NewClaim);
return true;
}
/// <summary>
/// Disowns a claim to a tile
/// </summary>
/// <param name="Tile"></param>
/// <param name="AgentID"></param>
/// <returns></returns>
public bool DisownClaim(IntVector2 Tile, ushort AgentID)
{
if (BaseMap.AgentOwnershipMap.Tiles[Tile.x, Tile.y] != AgentID)
{
return false;
}
DisownTileOwnership NewClaim = new DisownTileOwnership(AgentID, Tile);
foreach (Map map in RedundantMaps)
{
map.AddDisownmentClaim(NewClaim);
}
return true;
}
/// <summary>
/// Clears the list of claims
/// </summary>
public void ClearClaims()
{
OutgoingClaims.Clear();
}
/// <summary>
/// Adds a agent tile request claim for this map set
/// </summary>
/// <param name="Claim"></param>
protected void Claim(TileOwnershipClaim Claim)
{
foreach (Map map in RedundantMaps)
{
map.AddClaim(Claim);
}
}
#endregion
#region Helpers
/// <summary>
/// This Changed the DATA the Default data and makes all the tiles to the default tile type (TileTypes.Standard)
/// </summary>
public void CleanMapTiles()
{
SetSettings.MapSettings.MapInfo.CleanMap();
}
/// <summary>
/// The Closest point on the map to the reach point
/// </summary>
/// <param name="reachPoint"></param>
/// <returns></returns>
public IntVector3 GetClosestPoint(IntVector3 reachPoint)
{
IntVector3 ClosestPoint = new IntVector3();
IntVector2 TileIndex = GetMapTileIndex(reachPoint);
ClosestPoint.y = reachPoint.y;
if (TileIndex.x < SetSettings.MapSettings.Offset.x)
{
ClosestPoint.x = SetSettings.MapSettings.Offset.x;
}
else if (TileIndex.x >= SetSettings.MapSettings.Offset.x + SetSettings.MapSettings.MapWidth)
{
ClosestPoint.x = SetSettings.MapSettings.Offset.x + SetSettings.MapSettings.MapWidth * SetSettings.MapSettings.TileSize - 1;
}
else
{
ClosestPoint.x = reachPoint.x;
}
if (TileIndex.y < SetSettings.MapSettings.Offset.z)
{
ClosestPoint.z = SetSettings.MapSettings.Offset.z;
}
else if (TileIndex.y >= SetSettings.MapSettings.Offset.z + SetSettings.MapSettings.MapHeight)
{
ClosestPoint.z = SetSettings.MapSettings.Offset.z + SetSettings.MapSettings.MapHeight * SetSettings.MapSettings.TileSize - 1;
}
else
{
ClosestPoint.z = reachPoint.z;
}
return ClosestPoint;
}
/// <summary>
/// The Closest valid point to the reach point
/// </summary>
/// <param name="ClosestPoint"></param>
/// <param name="ValidTypes"></param>
/// <returns></returns>
public IntVector3 GetClosestValidPoint(IntVector3 ClosestPoint, TileTypes[] ValidTypes)
{
IntVector2 TileIndex = GetMapTileIndex(ClosestPoint);
int Radius = 1;
while (Radius <= 50)
{
for(int x = -Radius; x <= Radius; x++)
{
IntVector2 NewTileIndex = TileIndex + new IntVector2(x, Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
NewTileIndex = TileIndex + new IntVector2(x, -Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
}
for (int y = -Radius; y <= Radius; y++)
{
IntVector2 NewTileIndex = TileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
NewTileIndex = TileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
}
Radius++;
}
return ClosestPoint;
}
/// <summary>
/// The Closest valid point to the reach point
/// </summary>
/// <param name="ClosestPoint"></param>
/// <param name="ValidTypes"></param>
/// <returns></returns>
public IntVector3 GetClosestValidPoint(IntVector3 ClosestPoint, List<TileTypes> ValidTypes)
{
IntVector2 TileIndex = GetMapTileIndex(ClosestPoint);
int Radius = 1;
while (Radius <= 50)
{
for (int x = -Radius; x <= Radius; x++)
{
IntVector2 NewTileIndex = TileIndex + new IntVector2(x, Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
NewTileIndex = TileIndex + new IntVector2(x, -Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
}
for (int y = -Radius; y <= Radius; y++)
{
IntVector2 NewTileIndex = TileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
NewTileIndex = TileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
}
Radius++;
}
return ClosestPoint;
}
/// <summary>
/// The Closest valid point to the current tile index
/// </summary>
/// <param name="ClosestPoint"></param>
/// <param name="ValidTypes"></param>
/// <returns></returns>
public IntVector3 GetClosestValidPoint(IntVector2 CurrentTileIndex, TileTypes[] ValidTypes)
{
int Radius = 1;
while (Radius <= 50)
{
for (int x = -Radius; x <= Radius; x++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(x, Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
NewTileIndex = CurrentTileIndex + new IntVector2(x, -Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
}
for (int y = -Radius; y <= Radius; y++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
NewTileIndex = CurrentTileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
}
Radius++;
}
return GetWorldTileIndex(CurrentTileIndex);
}
/// <summary>
/// The Closest valid point to the current tile index
/// </summary>
/// <param name="ClosestPoint"></param>
/// <param name="ValidTypes"></param>
/// <returns></returns>
public IntVector3 GetClosestValidPoint(IntVector2 CurrentTileIndex, List<TileTypes> ValidTypes)
{
int Radius = 1;
while (Radius <= 50)
{
for (int x = -Radius; x <= Radius; x++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(x, Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
NewTileIndex = CurrentTileIndex + new IntVector2(x, -Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
}
for (int y = -Radius; y <= Radius; y++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
NewTileIndex = CurrentTileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return GetWorldTileIndex(NewTileIndex);
}
}
Radius++;
}
return GetWorldTileIndex(CurrentTileIndex);
}
/// <summary>
/// The Closest valid tile index to the current tile index
/// </summary>
/// <param name="ClosestPoint"></param>
/// <param name="ValidTypes"></param>
/// <returns></returns>
public IntVector2 GetClosestValidIndex(IntVector2 CurrentTileIndex, TileTypes[] ValidTypes)
{
int Radius = 1;
while (Radius <= 50)
{
for (int x = -Radius; x <= Radius; x++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(x, Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(x, -Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
}
for (int y = -Radius; y <= Radius; y++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
}
Radius++;
}
return CurrentTileIndex;
}
/// <summary>
/// The Closest valid tile index to the current tile index
/// </summary>
/// <param name="CurrentTileIndex"></param>
/// <param name="ValidTypes"></param>
/// <returns></returns>
public IntVector2 GetClosestValidIndex(IntVector2 CurrentTileIndex, List<TileTypes> ValidTypes)
{
int Radius = 1;
while (Radius <= 50)
{
for (int x = 0; x <= Radius; x++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(x, Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(x, -Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-x, Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-x, -Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
}
for (int y = 0; y <= Radius; y++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(Radius, -y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-Radius, -y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
}
Radius++;
}
return CurrentTileIndex;
}
/// <summary>
/// The Closest valid tile index to the current tile index
/// </summary>
/// <param name="CurrentTileIndex"></param>
/// <param name="ValidTypes"></param>
/// <param name="SimAgentID"></param>
/// <returns></returns>
public IntVector2 GetClosestValidIndex(IntVector2 CurrentTileIndex, List<TileTypes> ValidTypes, ushort SimAgentID)
{
int Radius = 1;
if (BaseMap.AgentAvoidence)
{
while (Radius <= 50)
{
for (int x = 0; x <= Radius; x++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(x, Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)) && BaseMap.AgentOwnershipMap.ValidTileForAgent(SimAgentID, NewTileIndex.x, NewTileIndex.y))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(x, -Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)) && BaseMap.AgentOwnershipMap.ValidTileForAgent(SimAgentID, NewTileIndex.x, NewTileIndex.y))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-x, Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)) && BaseMap.AgentOwnershipMap.ValidTileForAgent(SimAgentID, NewTileIndex.x, NewTileIndex.y))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-x, -Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)) && BaseMap.AgentOwnershipMap.ValidTileForAgent(SimAgentID, NewTileIndex.x, NewTileIndex.y))
{
return NewTileIndex;
}
}
for (int y = 0; y <= Radius; y++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)) && BaseMap.AgentOwnershipMap.ValidTileForAgent(SimAgentID, NewTileIndex.x, NewTileIndex.y))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)) && BaseMap.AgentOwnershipMap.ValidTileForAgent(SimAgentID, NewTileIndex.x, NewTileIndex.y))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(Radius, -y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)) && BaseMap.AgentOwnershipMap.ValidTileForAgent(SimAgentID, NewTileIndex.x, NewTileIndex.y))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-Radius, -y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)) && BaseMap.AgentOwnershipMap.ValidTileForAgent(SimAgentID, NewTileIndex.x, NewTileIndex.y))
{
return NewTileIndex;
}
}
Radius++;
}
}
else
{
while (Radius <= 50)
{
for (int x = 0; x <= Radius; x++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(x, Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(x, -Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-x, Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-x, -Radius);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
}
for (int y = 0; y <= Radius; y++)
{
IntVector2 NewTileIndex = CurrentTileIndex + new IntVector2(Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-Radius, y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(Radius, -y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
NewTileIndex = CurrentTileIndex + new IntVector2(-Radius, -y);
if (ValidTypes.Contains(GetTileType(NewTileIndex)))
{
return NewTileIndex;
}
}
Radius++;
}
}
return CurrentTileIndex;
}
/// <summary>
/// Gets the world tile index relative to the tile index of the map set
/// </summary>
/// <param name="newTileIndex"></param>
/// <param name="GetTileCenter"></param>
/// <returns></returns>
public IntVector3 GetWorldTileIndex(IntVector2 newTileIndex, bool GetTileCenter = true)
{
IntVector3 WorldTilePosition = new IntVector3();
WorldTilePosition.x = SetSettings.MapSettings.Offset.x + newTileIndex.x * SetSettings.MapSettings.TileSize;
WorldTilePosition.y = SetSettings.MapSettings.Offset.y;
WorldTilePosition.z = SetSettings.MapSettings.Offset.z + newTileIndex.y * SetSettings.MapSettings.TileSize;
if (GetTileCenter)
{
WorldTilePosition.x += SetSettings.MapSettings.TileSize / 2;
WorldTilePosition.z += SetSettings.MapSettings.TileSize / 2;
}
return WorldTilePosition;
}
/// <summary>
/// Gets the world tile index relative to the tile index of the map set
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="GetTileCenter"></param>
/// <returns></returns>
public IntVector3 GetWorldTileIndex(int x, int y, bool GetTileCenter = true)
{
IntVector3 WorldTilePosition = new IntVector3();
WorldTilePosition.x = SetSettings.MapSettings.Offset.x + x * SetSettings.MapSettings.TileSize;
WorldTilePosition.y = SetSettings.MapSettings.Offset.y;
WorldTilePosition.z = SetSettings.MapSettings.Offset.z + y * SetSettings.MapSettings.TileSize;
if (GetTileCenter)
{
WorldTilePosition.x += SetSettings.MapSettings.TileSize / 2;
WorldTilePosition.z += SetSettings.MapSettings.TileSize / 2;
}
return WorldTilePosition;
}
/// <summary>
/// This gets you the Tile Index of the Default Map
/// </summary>
/// <param name="WorldPosition"></param>
/// <returns></returns>
public IntVector2 GetMapTileIndex(IntVector3 WorldTileIndexPosition)
{
// Offset the Position
IntVector2 TileIndex = new IntVector2();
TileIndex.x = (int)Math.Floor((WorldTileIndexPosition.x - SetSettings.MapSettings.Offset.x) / (float)SetSettings.MapSettings.TileSize);
TileIndex.y = (int)Math.Floor((WorldTileIndexPosition.z - SetSettings.MapSettings.Offset.z) / (float)SetSettings.MapSettings.TileSize);
return TileIndex;
}
/// <summary>
/// Checks to see if this point is on the Map
/// </summary>
/// <param name="hitTileIndexPosition"></param>
/// <returns></returns>
public bool PointInMap(IntVector3 hitTileIndexPosition)
{
if (hitTileIndexPosition.x < SetSettings.MapSettings.Offset.x || hitTileIndexPosition.z < SetSettings.MapSettings.Offset.z)
{
return false;
}
if (hitTileIndexPosition.x >= SetSettings.MapSettings.Offset.x + SetSettings.MapSettings.MapWidth * SetSettings.MapSettings.TileSize || hitTileIndexPosition.z >= SetSettings.MapSettings.Offset.z + SetSettings.MapSettings.MapHeight * SetSettings.MapSettings.TileSize)
{
return false;
}
return true;
}
/// <summary>
/// Checks to see if this point is on the Map
/// </summary>
/// <param name="hitTileIndexPosition"></param>
/// <returns></returns>
public bool PointInMap(IntVector2 TileIndex)
{
if (TileIndex.x < 0 || TileIndex.y < 0)
{
return false;
}
if (TileIndex.x >= SetSettings.MapSettings.MapWidth || TileIndex.y >= SetSettings.MapSettings.MapHeight)
{
return false;
}
return true;
}
/// <summary>
/// This Changed the DATA the Default data, the maps that are generated on awake are not effected by this
/// </summary>
/// <param name="WorldPosition"></param>
/// <param name="NewType"></param>
public void ChangeDefaultTileType(IntVector3 WorldTileIndexPosition, TileTypes NewType, int Radius, PainterTypes painterType)
{
IntVector2 TileIndex = GetMapTileIndex(WorldTileIndexPosition);
if (painterType == PainterTypes.Square)
{
for (int x = -Radius; x <= Radius; x++)
{
for (int y = -Radius; y <= Radius; y++)
{
if (GetDefaultTileType(TileIndex.x + x, TileIndex.y + y) == TileTypes.OutOfBounds)
{
continue;
}
SetSettings.MapSettings.MapInfo.SavedTiles[TileIndex.x + x, TileIndex.y + y] = (byte)NewType;
}
}
}
else
{
for (int x = -Radius; x <= Radius; x++)
{
for (int y = -Radius; y <= Radius; y++)
{
if (GetDefaultTileType(TileIndex.x + x, TileIndex.y + y) == TileTypes.OutOfBounds)
{
continue;
}
if (x * x + y * y > Radius * Radius)
{
continue;
}
SetSettings.MapSettings.MapInfo.SavedTiles[TileIndex.x + x, TileIndex.y + y] = (byte)NewType;
}
}
}
}
/// <summary>
/// This Changed the DATA the Default data, the maps that are generated on awake are not effected by this
/// </summary>
/// <param name="WorldPosition"></param>
/// <param name="NewType"></param>
public void ChangeDefaultTileType(int x, int y, TileTypes NewType)
{
if (GetDefaultTileType(x, y) == TileTypes.OutOfBounds)
{
return;
}
SetSettings.MapSettings.MapInfo.SavedTiles[x, y] = (byte)NewType;
}
/// <summary>
/// This gets you the Tile Type at a Index from the Default Map
/// </summary>
/// <param name="TileIndex"></param>
/// <returns></returns>
public TileTypes GetDefaultTileType(IntVector2 TileIndex)
{
if (TileIndex.x < 0 || TileIndex.y < 0 || TileIndex.x >= SetSettings.MapSettings.MapWidth || TileIndex.y >= SetSettings.MapSettings.MapHeight)
{
return TileTypes.OutOfBounds;
}
return (TileTypes)SetSettings.MapSettings.MapInfo.SavedTiles[TileIndex.x, TileIndex.y];
}
/// <summary>
/// This gets you the Tile Type at a Index from the Default Map
/// </summary>
/// <param name="TileIndex"></param>
/// <returns></returns>
public TileTypes GetDefaultTileType(int x, int y)
{
if (x < 0 || y < 0 || x >= SetSettings.MapSettings.MapWidth || y >= SetSettings.MapSettings.MapHeight)
{
return TileTypes.OutOfBounds;
}
return (TileTypes)SetSettings.MapSettings.MapInfo.SavedTiles[x, y];
}
/// <summary>
/// This gets you the Tile Type at a Index from the Map
/// </summary>
/// <param name="TileIndex"></param>
/// <returns></returns>
public TileTypes GetTileType(IntVector2 TileIndex)
{
if (TileIndex.x < 0 || TileIndex.y < 0 || TileIndex.x >= SetSettings.MapSettings.MapWidth || TileIndex.y >= SetSettings.MapSettings.MapHeight)
{
return TileTypes.OutOfBounds;
}
if (BaseMap == null)
{
return TileTypes.OutOfBounds;
}
return BaseMap.GetTileType(TileIndex);
}
/// <summary>
/// This gets you the Tile Type at a World Position Index from the Map
/// </summary>
/// <param name="TileIndex"></param>
/// <returns></returns>
public TileTypes GetTileType(IntVector3 worldTileIndex)
{
IntVector2 MapIndex = GetMapTileIndex(worldTileIndex);
return GetTileType(MapIndex);
}
/// <summary>
/// This gets you the Tile Type at a Index from the Default Map
/// </summary>
/// <param name="TileIndex"></param>
/// <returns></returns>
public TileTypes GetTileType(int x, int y)
{
if (x < 0 || y < 0 || x >= SetSettings.MapSettings.MapWidth || y >= SetSettings.MapSettings.MapHeight)
{
return TileTypes.OutOfBounds;
}
return BaseMap.GetTileType(x, y);
}
/// <summary>
/// Adds the bridge if this bridge is connected to this Map
/// </summary>
/// <param name="bridge"></param>
public void AddBridge(MapBridge bridge)
{
if (RedundantMaps != null)
{
foreach (Map map in RedundantMaps)
{
if (!map.Bridges.Contains(bridge))
{
map.Bridges.Add(bridge);
}
}
}
if (!MapBridges.Contains(bridge))
{
MapBridges.Add(bridge);
}
}
/// <summary>
/// Adds the seam if this seam is connected to this Map
/// </summary>
/// <param name="bridge"></param>
public void AddSeam(MapSeam seam)
{
if (RedundantMaps != null)
{
foreach (Map map in RedundantMaps)
{
if (!map.Seams.Contains(seam))
{
map.Seams.Add(seam);
}
}
}
if (!MapSeams.Contains(seam))
{
MapSeams.Add(seam);
}
}
/// <summary>
/// Clears the Maps and the Bridges connected to this Map
/// </summary>
public void ClearMaps()
{
if (RedundantMaps != null)
{
foreach(Map map in RedundantMaps)
{
map.Bridges.Clear();
map.Seams.Clear();
}
}
MapBridges.Clear();
}
/// <summary>
/// Finds the closest bridge that connects the destination Map
/// </summary>
/// <param name="nextMap"></param>
/// <param name="start"></param>
/// <returns></returns>
public MapBridge GetClosestBridge(MapSet nextMap, IntVector3 start)
{
MapBridge ClosestBridge = null;
int ClosestScore = int.MaxValue;
// Check for direct bridges first
foreach (MapBridge Bridge in MapBridges)
{
if (!Bridge.ValidBridge)
{
continue;
}
if (Bridge.CanWalkInDirection(this, nextMap))
{
IntVector3 BridgePoint = Bridge.GetPoint(this);
int Distance = IntVector3.DistanceSquared(BridgePoint, start);
if (Distance < ClosestScore)
{
ClosestBridge = Bridge;
ClosestScore = Distance;
}
}
}
return ClosestBridge;
}
/// <summary>
/// Finds the closest seam that connects the destination Map
/// </summary>
/// <param name="nextMap"></param>
/// <param name="start"></param>
/// <returns></returns>
public MapSeam GetClosestSeam(MapSet nextMap, IntVector3 start)
{
MapSeam ClosestSeam = null;
int ClosestScore = int.MaxValue;
// Check for direct bridges first
foreach (MapSeam Seam in MapSeams)
{
if (!Seam.ValidSeam)
{
continue;
}
if (Seam.DirectConnects(this, nextMap))
{
IntVector3 BridgePoint = Seam.GetPoint(this, start);
int Distance = IntVector3.DistanceSquared(BridgePoint, start);
if (Distance < ClosestScore)
{
ClosestSeam = Seam;
ClosestScore = Distance;
}
}
}
return ClosestSeam;
}
/// <summary>
/// Gets the closest Map Tile Index based on a tile index relative to this Map
/// </summary>
/// <param name="tileIndex"></param>
/// <returns></returns>
public IntVector2 GetClosestMapTileIndex(IntVector2 tileIndex)
{
if (tileIndex.x < 0)
{
tileIndex.x = 0;
}
else if (tileIndex.x >= SetSettings.MapSettings.MapWidth)
{
tileIndex.x = SetSettings.MapSettings.MapWidth - 1;
}
if (tileIndex.y < 0)
{
tileIndex.y = 0;
}
else if (tileIndex.y >= SetSettings.MapSettings.MapHeight)
{
tileIndex.y = SetSettings.MapSettings.MapHeight - 1;
}
return tileIndex;
}
/// <summary>
/// Gets the closest Map Tile Index based on a tile index relative to this Map
/// </summary>
/// <param name="worldIndex"></param>
/// <returns></returns>
public IntVector2 GetClosestMapTileIndex(IntVector3 worldIndex)
{
IntVector2 tileIndex = GetMapTileIndex(worldIndex);
return GetClosestMapTileIndex(tileIndex);
}
#endregion
}
/// <summary>
/// The settings of the Map Set
/// </summary>
[Serializable]
public class MapSetSettings
{
/// <summary>
/// The Name of the Map
/// </summary>
public string Name;
/// <summary>
/// The Settings for each Map on the Map Set
/// </summary>
public MapSettings MapSettings = new MapSettings();
public MapSetSettings()
{
Name = "No Name";
}
}
}