mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-06-27 11:54:41 +00:00
1544 lines
52 KiB
C#
1544 lines
52 KiB
C#
using HPJ.Simulation.Enums;
|
|
using HPJ.Simulation.Pathing;
|
|
using HPJ.Simulation.Utilities;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace HPJ.Simulation.Map
|
|
{
|
|
/// <summary>
|
|
/// The Map that represents a area with square tiles
|
|
/// </summary>
|
|
public class Map
|
|
{
|
|
protected string _name;
|
|
/// <summary>
|
|
/// The Name of the Map
|
|
/// </summary>
|
|
public string Name { get { return _name; } }
|
|
|
|
protected byte[,] _tiles;
|
|
/// <summary>
|
|
/// A 2D Array of the tiles of the Map in bytes
|
|
/// </summary>
|
|
public byte[,] Tiles { get { return _tiles; } }
|
|
|
|
public MapSettings _settings;
|
|
/// <summary>
|
|
/// The Map Settings
|
|
/// </summary>
|
|
public MapSettings Settings { get { return _settings; } }
|
|
|
|
/// <summary>
|
|
/// If the Map has been Initialized
|
|
/// </summary>
|
|
public bool Initialized { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// If the Map logic is currently running
|
|
/// </summary>
|
|
public bool Running { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// If the Map uses agent avoidence
|
|
/// </summary>
|
|
public bool AgentAvoidence { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// If the map is currently completing navigation job requests
|
|
/// </summary>
|
|
public bool CompletingNavigationJobs { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// If the map is currently completing navigation map change requests
|
|
/// </summary>
|
|
public bool CompletingMapChanges { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// If the map is currently completing tile ownership claims
|
|
/// </summary>
|
|
public bool CompletingClaims { get; protected set; }
|
|
/// <summary>
|
|
/// If the map is currently completing tile disownment claims
|
|
/// </summary>
|
|
public bool CompletingDisownment { get; protected set; }
|
|
|
|
protected Dictionary<string, BytePointMap> _pointMaps;
|
|
/// <summary>
|
|
/// The Byte point maps used by the JPS pathfinding for each valid tile types
|
|
/// </summary>
|
|
public Dictionary<string, BytePointMap> PointMaps { get { return _pointMaps; } }
|
|
|
|
public List<MapBridge> _bridges;
|
|
/// <summary>
|
|
/// A List of all the bridges connected to this Map
|
|
/// </summary>
|
|
public List<MapBridge> Bridges { get { return _bridges; } }
|
|
|
|
public List<MapSeam> _seams;
|
|
/// <summary>
|
|
/// A List of all the seams connected to this Map
|
|
/// </summary>
|
|
public List<MapSeam> Seams { get { return _seams; } }
|
|
|
|
/// <summary>
|
|
/// The map copy that keeps record of tile ownership by agent
|
|
/// </summary>
|
|
public AgentMap AgentOwnershipMap { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// The Parrallel options used by the map for the multithreading of each Unit that wants pathfinding
|
|
/// </summary>
|
|
protected ParallelOptions _parallelOptions;
|
|
|
|
public Map(MapSettings mapSettings, string MapName, int DegreeOfParallelism, bool CreateAgentMap)
|
|
{
|
|
_name = MapName;
|
|
_settings = mapSettings;
|
|
_bridges = new List<MapBridge>();
|
|
_requestedJobs = new List<NavigationJob>();
|
|
_requestedMapChanges = new List<ChangeMapJob>();
|
|
_agentClaimRequests = new List<TileOwnershipClaim>();
|
|
_agentDisownmentClaimRequests = new List<DisownTileOwnership>();
|
|
_savedPaths = new Dictionary<PathingInfo, NavigationPath>();
|
|
_needToBeUpdatedPaths = new List<NavigationPath>();
|
|
_parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = DegreeOfParallelism };
|
|
AgentAvoidence = CreateAgentMap;
|
|
|
|
if (CreateAgentMap)
|
|
{
|
|
AgentOwnershipMap = new AgentMap(this);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The Debug callback to Unity
|
|
/// </summary>
|
|
public Action<string, SimulationDebugLog> DebugLogCallback;
|
|
|
|
/// <summary>
|
|
/// Initialized the Map
|
|
/// </summary>
|
|
/// <param name="debugLogCallback"></param>
|
|
public void Initialize(Action<string, SimulationDebugLog> debugLogCallback)
|
|
{
|
|
DebugLogCallback = debugLogCallback;
|
|
Running = true;
|
|
|
|
try
|
|
{
|
|
_pointMaps = new Dictionary<string, BytePointMap>();
|
|
|
|
_settings.MapInfo.MakeSureSizeIsRight();
|
|
_tiles = new byte[_settings.MapWidth, _settings.MapHeight];
|
|
// Create Tiles
|
|
for (int x = 0; x < _settings.MapWidth; x++)
|
|
{
|
|
for (int y = 0; y < _settings.MapHeight; y++)
|
|
{
|
|
_tiles[x, y] = _settings.MapInfo.SavedTiles[x, y];
|
|
}
|
|
}
|
|
Initialized = true;
|
|
|
|
_pointMaps.Add(_settings.DefaultTraversaleTiles.TilesToString(), new BytePointMap(_tiles, _settings.DefaultTraversaleTiles, Settings.MapWidth, Settings.MapHeight, Settings.CornerCutting));
|
|
DebugLogCallback?.Invoke($"{_name} Map Initialized", SimulationDebugLog.Log);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log($"({_settings.MapWidth},{_settings.MapHeight}) vs ({_settings.MapInfo.Width},{_settings.MapInfo.Height}) vs ({_settings.MapInfo.SavedTiles.GetLength(0)},{_settings.MapInfo.SavedTiles.GetLength(1)}) -> {_settings.MapInfo.SavedTiles.Length}, P{_settings.MapInfo.SavedTiles.LongLength}, {_settings.MapInfo.SavedTiles.Rank}");
|
|
DebugLogCallback?.Invoke($"{ex.Message}: {ex.StackTrace}", SimulationDebugLog.Error);
|
|
}
|
|
}
|
|
|
|
public void OnDestroy()
|
|
{
|
|
Running = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Debug.Log
|
|
/// </summary>
|
|
/// <param name="Log"></param>
|
|
public void Log(string Log)
|
|
{
|
|
DebugLogCallback?.Invoke(Log, SimulationDebugLog.Log);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Debug.Warning
|
|
/// </summary>
|
|
/// <param name="Log"></param>
|
|
public void LogWarning(string Log)
|
|
{
|
|
DebugLogCallback?.Invoke(Log, SimulationDebugLog.Warning);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Debug.Error
|
|
/// </summary>
|
|
/// <param name="Log"></param>
|
|
public void LogError(string Log)
|
|
{
|
|
DebugLogCallback?.Invoke(Log, SimulationDebugLog.Error);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or Generates a Byte point map based on a set of traversable tiles types
|
|
/// </summary>
|
|
/// <param name="path"></param>
|
|
/// <returns></returns>
|
|
internal BytePointMap GetBytePointMap(NavigationPath path)
|
|
{
|
|
lock (_pointMaps)
|
|
{
|
|
if (!_pointMaps.ContainsKey(path.Info.TraversableTilesKey))
|
|
{
|
|
_pointMaps.Add(path.Info.TraversableTilesKey, new BytePointMap(_tiles, path.Info.TraversableTilesKey.StringToTilesArray(), Settings.MapWidth, Settings.MapHeight, Settings.CornerCutting));
|
|
}
|
|
}
|
|
|
|
return _pointMaps[path.Info.TraversableTilesKey];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the movement speed for a specific tile type on this Map
|
|
/// </summary>
|
|
/// <param name="TileType"></param>
|
|
/// <returns></returns>
|
|
internal byte GetTileSpeedData(TileTypes TileType)
|
|
{
|
|
for (int i = 0; i < Settings.TileData.Count; i++)
|
|
{
|
|
TileData Data = Settings.TileData[i];
|
|
if (Data.Type == TileType)
|
|
{
|
|
return Data.Speed;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A List of the Requested Navigation Jobs
|
|
/// </summary>
|
|
protected List<NavigationJob> _requestedJobs;
|
|
|
|
/// <summary>
|
|
/// A List of the Requested Map Changes
|
|
/// </summary>
|
|
protected List<ChangeMapJob> _requestedMapChanges;
|
|
|
|
/// <summary>
|
|
/// A List of the Requested Tile Ownership claims
|
|
/// </summary>
|
|
protected List<TileOwnershipClaim> _agentClaimRequests;
|
|
|
|
/// <summary>
|
|
/// A List of the Requested Tile Disownment claims
|
|
/// </summary>
|
|
protected List<DisownTileOwnership> _agentDisownmentClaimRequests;
|
|
|
|
/// <summary>
|
|
/// A List of all the saved paths that need to be updated because they were invalidated or are new
|
|
/// </summary>
|
|
protected List<NavigationPath> _needToBeUpdatedPaths;
|
|
|
|
/// <summary>
|
|
/// A Dictionary of all the saved paths on this Map
|
|
/// </summary>
|
|
protected Dictionary<PathingInfo, NavigationPath> _savedPaths;
|
|
|
|
/// <summary>
|
|
/// The Update function of the map each update tick
|
|
/// </summary>
|
|
public void Update()
|
|
{
|
|
try
|
|
{
|
|
if (!Initialized)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Update Claims
|
|
lock (_agentDisownmentClaimRequests)
|
|
{
|
|
if (_agentDisownmentClaimRequests.Count > 0)
|
|
{
|
|
CompletingDisownment = true;
|
|
for (int i = 0; i < _agentDisownmentClaimRequests.Count; i++)
|
|
{
|
|
Disown(_agentDisownmentClaimRequests[i]);
|
|
}
|
|
|
|
CompletingDisownment = false;
|
|
_agentDisownmentClaimRequests.Clear();
|
|
}
|
|
}
|
|
lock (_agentClaimRequests)
|
|
{
|
|
if (_agentClaimRequests.Count > 0)
|
|
{
|
|
CompletingClaims = true;
|
|
for (int i = 0; i < _agentClaimRequests.Count; i++)
|
|
{
|
|
Claim(_agentClaimRequests[i]);
|
|
}
|
|
|
|
CompletingClaims = false;
|
|
_agentClaimRequests.Clear();
|
|
}
|
|
}
|
|
|
|
// Update Map
|
|
lock (_requestedMapChanges)
|
|
{
|
|
if (_requestedMapChanges.Count > 0)
|
|
{
|
|
CompletingMapChanges = true;
|
|
for (int i = 0; i < _requestedMapChanges.Count; i++)
|
|
{
|
|
ChangeMap(_requestedMapChanges[i]);
|
|
}
|
|
|
|
CompletingMapChanges = false;
|
|
_requestedMapChanges.Clear();
|
|
}
|
|
}
|
|
|
|
|
|
// Complete Navigation Jobs
|
|
lock (_requestedJobs)
|
|
{
|
|
if (_requestedJobs.Count > 0)
|
|
{
|
|
CompletingNavigationJobs = true;
|
|
lock (_savedPaths)
|
|
{
|
|
if (AgentAvoidence)
|
|
{
|
|
// Find out the paths that need to be recalculated
|
|
for (int i = 0; i < _requestedJobs.Count; i++)
|
|
{
|
|
NavigationJob Job = _requestedJobs[i];
|
|
NavigationPath Path;
|
|
|
|
Path = new NavigationPath(Job.Info, this);
|
|
_needToBeUpdatedPaths.Add(Path);
|
|
Path.AgentID = Job.AgentID;
|
|
|
|
Job.SetNewCurrentPath(Path);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Find out the paths that need to be recalculated
|
|
for (int i = 0; i < _requestedJobs.Count; i++)
|
|
{
|
|
NavigationJob Job = _requestedJobs[i];
|
|
NavigationPath Path;
|
|
|
|
if (_savedPaths.ContainsKey(Job.Info))
|
|
{
|
|
Path = _savedPaths[Job.Info];
|
|
if (!Path.ValidPath || Job.RepathSavedPath)
|
|
{
|
|
Path.Path.Clear();
|
|
// In Case the Path is already being pathed
|
|
if (!_needToBeUpdatedPaths.Contains(Path))
|
|
{
|
|
_needToBeUpdatedPaths.Add(Path);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Path = new NavigationPath(Job.Info, this);
|
|
_savedPaths.Add(Job.Info, Path);
|
|
_needToBeUpdatedPaths.Add(Path);
|
|
}
|
|
|
|
Job.SetNewCurrentPath(Path);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Recalculate Path
|
|
Parallel.ForEach(_needToBeUpdatedPaths, _parallelOptions, CompletePathfind);
|
|
|
|
// Complete the pathfinding
|
|
//Parallel.ForEach(_requestedJobs, _parallelOptions, FinishPathfinding);
|
|
for(int i = _requestedJobs.Count - 1; i >= 0; i--)
|
|
{
|
|
_requestedJobs[i].PathfindingComplete();
|
|
}
|
|
|
|
_needToBeUpdatedPaths.Clear();
|
|
_requestedJobs.Clear();
|
|
CompletingNavigationJobs = false;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogError($"Map Error {ex.Message}: {ex.StackTrace}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A Check to see if the navigation job can be run on this map
|
|
/// </summary>
|
|
/// <param name="job"></param>
|
|
/// <returns></returns>
|
|
internal bool JobCompatible(NavigationJob job)
|
|
{
|
|
if (!job.TraverableTileTypes.Contains(GetTileType(job.Info.PointA)) || !job.TraverableTileTypes.Contains(GetTileType(job.Info.PointB)))
|
|
{
|
|
return false;
|
|
}
|
|
return PointInMap(job.Info.PointA) && PointInMap(job.Info.PointB);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks to see if this point is valid on this map
|
|
/// </summary>
|
|
/// <param name="WorldPosition"></param>
|
|
/// <returns></returns>
|
|
public bool PointInMap(IntVector3 WorldPosition)
|
|
{
|
|
return GetTileType(WorldPosition) != TileTypes.OutOfBounds;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks to see if this point is valid on this map
|
|
/// </summary>
|
|
/// <param name="WorldPosition"></param>
|
|
/// <returns></returns>
|
|
public bool PointInMap(IntVector2 TilePosition)
|
|
{
|
|
return GetTileType(TilePosition) != TileTypes.OutOfBounds;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a Map change Request for this map
|
|
/// </summary>
|
|
/// <param name="MapChange"></param>
|
|
public void AddMapChange(ChangeMapJob MapChange)
|
|
{
|
|
lock (_requestedMapChanges)
|
|
{
|
|
_requestedMapChanges.Add(MapChange);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a agent tile request claim for this map
|
|
/// </summary>
|
|
/// <param name="Claim"></param>
|
|
public void AddClaim(TileOwnershipClaim Claim)
|
|
{
|
|
lock (_agentClaimRequests)
|
|
{
|
|
_agentClaimRequests.Add(Claim);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a agent tile disownment claim for this map
|
|
/// </summary>
|
|
/// <param name="Claim"></param>
|
|
public void AddDisownmentClaim(DisownTileOwnership Claim)
|
|
{
|
|
lock (_agentDisownmentClaimRequests)
|
|
{
|
|
_agentDisownmentClaimRequests.Add(Claim);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Changes the map tiles based on the map change requests
|
|
/// </summary>
|
|
/// <param name="MapChange"></param>
|
|
protected void ChangeMap(ChangeMapJob MapChange)
|
|
{
|
|
for (int i = 0; i < MapChange.TilesToBeChanged.Count; i++)
|
|
{
|
|
(IntVector2, TileTypes) TileChange = MapChange.TilesToBeChanged[i];
|
|
SetTile(TileChange.Item1, TileChange.Item2);
|
|
|
|
foreach(BytePointMap ByteMap in _pointMaps.Values)
|
|
{
|
|
ByteMap.ChangeTile(TileChange.Item1, TileChange.Item2);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Agent claims a tile
|
|
/// </summary>
|
|
/// <param name="Claim"></param>
|
|
protected void Claim(TileOwnershipClaim Claim)
|
|
{
|
|
AgentOwnershipMap.ClaimTile(Claim.RequestTile, Claim.OwnerID);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Agent disowns a claims to a tile
|
|
/// </summary>
|
|
/// <param name="Claim"></param>
|
|
protected void Disown(DisownTileOwnership Claim)
|
|
{
|
|
AgentOwnershipMap.DisownTile(Claim.RequestTile, Claim.OwnerID);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the tile to the new type
|
|
/// </summary>
|
|
/// <param name="TilePosition"></param>
|
|
/// <param name="TypeChange"></param>
|
|
protected void SetTile(IntVector2 TilePosition, TileTypes TypeChange)
|
|
{
|
|
_tiles[TilePosition.x, TilePosition.y] = (byte)TypeChange;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the current tile type of this tile index
|
|
/// </summary>
|
|
/// <param name="WorldPosition"></param>
|
|
/// <returns></returns>
|
|
public TileTypes GetTileType(IntVector3 WorldPosition)
|
|
{
|
|
// Offset the Position
|
|
WorldPosition.x -= Settings.Offset.x;
|
|
WorldPosition.z -= Settings.Offset.y;
|
|
|
|
WorldPosition.x = (int)Math.Floor((float)WorldPosition.x / Settings.TileSize);
|
|
WorldPosition.z = (int)Math.Floor((float)WorldPosition.z / Settings.TileSize);
|
|
|
|
if (WorldPosition.x < 0 || WorldPosition.z < 0 || WorldPosition.x >= Settings.MapWidth || WorldPosition.z >= Settings.MapHeight)
|
|
{
|
|
return TileTypes.OutOfBounds;
|
|
}
|
|
|
|
return (TileTypes)Tiles[WorldPosition.x, WorldPosition.z];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the current tile type of this tile index
|
|
/// </summary>
|
|
/// <param name="TilePosition"></param>
|
|
/// <returns></returns>
|
|
public TileTypes GetTileType(IntVector2 TilePosition)
|
|
{
|
|
if (TilePosition.x < 0 || TilePosition.y < 0 || TilePosition.x >= Settings.MapWidth || TilePosition.y >= Settings.MapHeight)
|
|
{
|
|
return TileTypes.OutOfBounds;
|
|
}
|
|
|
|
return (TileTypes)Tiles[TilePosition.x, TilePosition.y];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the current tile type of this tile index
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <param name="y"></param>
|
|
/// <returns></returns>
|
|
public TileTypes GetTileType(int x, int y)
|
|
{
|
|
if (x < 0 || y < 0 || x >= Settings.MapWidth || y >= Settings.MapHeight)
|
|
{
|
|
return TileTypes.OutOfBounds;
|
|
}
|
|
|
|
return (TileTypes)Tiles[x, y];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the current tile index at this world position
|
|
/// </summary>
|
|
/// <param name="WorldTileIndexPosition"></param>
|
|
/// <returns></returns>
|
|
public IntVector2 GetTileIndexPosition(IntVector3 WorldTileIndexPosition)
|
|
{
|
|
// Offset the Position
|
|
IntVector2 TileIndex = new IntVector2();
|
|
TileIndex.x = (int)((WorldTileIndexPosition.x - _settings.Offset.x) / (float)_settings.TileSize);
|
|
TileIndex.y = (int)((WorldTileIndexPosition.z - _settings.Offset.z) / (float)_settings.TileSize);
|
|
|
|
return TileIndex;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a navigation Request to the Map
|
|
/// </summary>
|
|
/// <param name="Job"></param>
|
|
public void AddNavigationJob(NavigationJob Job)
|
|
{
|
|
lock (_requestedJobs)
|
|
{
|
|
Job.CurrentStep = PathfindingCalculationStep.Pathfinding;
|
|
_requestedJobs.Add(Job);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the Requested Path on the Map
|
|
/// </summary>
|
|
/// <param name="Path"></param>
|
|
protected void CompletePathfind(NavigationPath Path)
|
|
{
|
|
if (Path.Info.NavigationType == NavigationTypes.JumpPointSearch)
|
|
{
|
|
JumpPointSearch.Instance.CalculatePath(Path, Path.HostMap, out string Status, out bool Succeeded);
|
|
Path.PreviousStatus = Status;
|
|
Path.ValidPath = Succeeded;
|
|
}
|
|
else if (Path.Info.NavigationType == NavigationTypes.AStar)
|
|
{
|
|
AStar.Instance.CalculatePath(Path, Path.HostMap, out string Status, out bool Succeeded);
|
|
Path.PreviousStatus = Status;
|
|
Path.ValidPath = Succeeded;
|
|
}
|
|
else if (Path.Info.NavigationType == NavigationTypes.Free)
|
|
{
|
|
Path.Path.Clear();
|
|
Path.Path.Add(Path.Info.PointA);
|
|
Path.Path.Add(Path.Info.PointB);
|
|
Path.PreviousStatus = "Free Pathed";
|
|
Path.ValidPath = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Comples the Navigation Job Request
|
|
/// </summary>
|
|
/// <param name="Job"></param>
|
|
protected void FinishPathfinding(NavigationJob Job)
|
|
{
|
|
Job.PathfindingComplete();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The Map settings used to shape the Map
|
|
/// </summary>
|
|
[Serializable]
|
|
public class MapSettings
|
|
{
|
|
/// <summary>
|
|
/// The Size of the tile in centimeters not meters
|
|
/// </summary>
|
|
public int TileSize = 100; // In cm
|
|
|
|
/// <summary>
|
|
/// The Number of tiles in the x direction
|
|
/// </summary>
|
|
public int MapWidth = 100;
|
|
|
|
/// <summary>
|
|
/// The Number of tiles in the z direction
|
|
/// </summary>
|
|
public int MapHeight = 100;
|
|
|
|
/// <summary>
|
|
/// The Physical offset of the map in centimeters
|
|
/// </summary>
|
|
public IntVector3 Offset = new IntVector3(); // in cm
|
|
|
|
/// <summary>
|
|
/// If corner cutting is enabled in the pathfinding on this Map
|
|
/// </summary>
|
|
public bool CornerCutting = false;
|
|
|
|
/// <summary>
|
|
/// The Data for each tile on this Map
|
|
/// </summary>
|
|
public List<TileData> TileData = new List<TileData>();
|
|
|
|
/// The Data used to keep track of the map width and height
|
|
/// </summary>
|
|
public MapData MapInfo = new MapData();
|
|
|
|
/// <summary>
|
|
/// The Default traversable tiles for this Map
|
|
/// </summary>
|
|
public TileTypes[] DefaultTraversaleTiles = new TileTypes[2] { TileTypes.Standard, TileTypes.Free };
|
|
|
|
public MapSettings()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adjusts the Map Size in a specific direction
|
|
/// </summary>
|
|
/// <param name="TilesChanged"></param>
|
|
/// <param name="ExpansionSide"></param>
|
|
/// <param name="NewOffset"></param>
|
|
/// <param name="Translation"></param>
|
|
public void AdjustMap(int TilesChanged, MapExpansionSide ExpansionSide, int NewOffset, int Translation = 0)
|
|
{
|
|
if (TilesChanged == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ExpansionSide == MapExpansionSide.Left)
|
|
{
|
|
if (TilesChanged <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TilesChanged >= 100000)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Translation = MapWidth - TilesChanged;
|
|
MapWidth = TilesChanged;
|
|
Offset.x = NewOffset;
|
|
}
|
|
else if (ExpansionSide == MapExpansionSide.Right)
|
|
{
|
|
if (TilesChanged <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TilesChanged >= 100000)
|
|
{
|
|
return;
|
|
}
|
|
|
|
MapWidth = TilesChanged;
|
|
Offset.x = NewOffset;
|
|
}
|
|
else if (ExpansionSide == MapExpansionSide.Top)
|
|
{
|
|
if (TilesChanged <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TilesChanged >= 100000)
|
|
{
|
|
return;
|
|
}
|
|
|
|
MapHeight = TilesChanged;
|
|
Offset.z = NewOffset;
|
|
}
|
|
else if (ExpansionSide == MapExpansionSide.Bottom)
|
|
{
|
|
if (TilesChanged <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TilesChanged >= 100000)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Translation = MapHeight - TilesChanged;
|
|
MapHeight = TilesChanged;
|
|
Offset.z = NewOffset;
|
|
}
|
|
|
|
UpdateMapSize();
|
|
if (ExpansionSide == MapExpansionSide.Left)
|
|
{
|
|
MapInfo.TransalateValues(Translation, 0);
|
|
}
|
|
else if (ExpansionSide == MapExpansionSide.Right)
|
|
{
|
|
MapInfo.TransalateValues(Translation, 0);
|
|
}
|
|
else if (ExpansionSide == MapExpansionSide.Bottom)
|
|
{
|
|
MapInfo.TransalateValues(0, Translation);
|
|
}
|
|
else if (ExpansionSide == MapExpansionSide.Top)
|
|
{
|
|
MapInfo.TransalateValues(0, Translation);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the Map Size
|
|
/// </summary>
|
|
public void UpdateMapSize()
|
|
{
|
|
MapInfo.UpdateToMapSize(MapWidth, MapHeight);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A Set of points that the navigation can use to transfer a Agent from one map to another
|
|
/// </summary>
|
|
[Serializable]
|
|
public class MapBridge
|
|
{
|
|
/// <summary>
|
|
/// Map on Side A of the Bridge
|
|
/// </summary>
|
|
public MapSet MapA; /*{ get { return _mapA; } set { _mapA = value; } }*/
|
|
//protected MapSet _mapA;
|
|
|
|
/// <summary>
|
|
/// Map on Side B of the Bridge
|
|
/// </summary>
|
|
public MapSet MapB; /*{ get { return _mapB; } set { _mapB = value; } }*/
|
|
//protected MapSet _mapB;
|
|
|
|
/// <summary>
|
|
/// Which ways the bridge can be used
|
|
/// </summary>
|
|
public BridgeDirections WalkableDirections;
|
|
|
|
/// <summary>
|
|
/// All the points from Map A to Map B
|
|
/// </summary>
|
|
public List<IntVector3> MidPoints;
|
|
|
|
/// <summary>
|
|
/// If this map is a valid and can be used
|
|
/// </summary>
|
|
public bool ValidBridge = false;
|
|
|
|
public MapBridge(MapSet A, MapSet B, List<IntVector3> BridgePoints)
|
|
{
|
|
WalkableDirections = BridgeDirections.Both;
|
|
MapA = A;
|
|
MapB = B;
|
|
MidPoints = BridgePoints;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks to see this bridge connects two maps
|
|
/// </summary>
|
|
/// <param name="startingMap"></param>
|
|
/// <param name="endingMap"></param>
|
|
/// <returns></returns>
|
|
public bool DirectConnects(MapSet startingMap, MapSet endingMap)
|
|
{
|
|
if (startingMap.InstanceID == MapA.InstanceID)
|
|
{
|
|
if (endingMap.InstanceID == MapB.InstanceID)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else if (startingMap.InstanceID == MapB.InstanceID)
|
|
{
|
|
if (endingMap.InstanceID == MapA.InstanceID)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks to see if you can walk on the bridge in this direction. Starting Map to Ending Map
|
|
/// </summary>
|
|
/// <param name="startingMap"></param>
|
|
/// <param name="endingMap"></param>
|
|
/// <returns></returns>
|
|
public bool CanWalkInDirection(MapSet startingMap, MapSet endingMap)
|
|
{
|
|
// Make sure these maps are even connected
|
|
if (!DirectConnects(startingMap, endingMap))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (WalkableDirections == BridgeDirections.Both)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (startingMap.InstanceID == MapA.InstanceID)
|
|
{
|
|
if (endingMap.InstanceID == MapB.InstanceID)
|
|
{
|
|
return WalkableDirections == BridgeDirections.A_To_B;
|
|
}
|
|
}
|
|
else if (startingMap.InstanceID == MapB.InstanceID)
|
|
{
|
|
if (endingMap.InstanceID == MapA.InstanceID)
|
|
{
|
|
return WalkableDirections == BridgeDirections.B_To_A;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the starting point for a Map if that map connects to this Bridge
|
|
/// </summary>
|
|
/// <param name="startingMap"></param>
|
|
/// <returns></returns>
|
|
public IntVector3 GetPoint(MapSet startingMap)
|
|
{
|
|
if (startingMap.InstanceID == MapA.InstanceID)
|
|
{
|
|
return MidPoints[0];
|
|
}
|
|
else if (startingMap.InstanceID == MapB.InstanceID)
|
|
{
|
|
return MidPoints[MidPoints.Count - 1];
|
|
}
|
|
|
|
return new IntVector3();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the ending point for a Map if that map connects to this Bridge
|
|
/// </summary>
|
|
/// <param name="startingMap"></param>
|
|
/// <returns></returns>
|
|
public IntVector3 GetOpposingPoint(MapSet startingMap)
|
|
{
|
|
if (startingMap.InstanceID == MapA.InstanceID)
|
|
{
|
|
return MidPoints[MidPoints.Count - 1];
|
|
}
|
|
else if (startingMap.InstanceID == MapB.InstanceID)
|
|
{
|
|
return MidPoints[0];
|
|
}
|
|
|
|
return new IntVector3();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks to see if the given maps is on one side of the Bridge
|
|
/// </summary>
|
|
/// <param name="Map"></param>
|
|
/// <returns></returns>
|
|
public bool Contains(MapSet Map)
|
|
{
|
|
if (Map.InstanceID == MapA.InstanceID)
|
|
{
|
|
return true;
|
|
}
|
|
else if (Map.InstanceID == MapB.InstanceID)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the other Map if you know one side the bridge connects too
|
|
/// </summary>
|
|
/// <param name="Map"></param>
|
|
/// <returns></returns>
|
|
public MapSet Other(MapSet Map)
|
|
{
|
|
if (MapA.InstanceID == Map.InstanceID)
|
|
{
|
|
return MapB;
|
|
}
|
|
else if (MapB.InstanceID == Map.InstanceID)
|
|
{
|
|
return MapA;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public void RefreshWithNew(MapSet Map)
|
|
{
|
|
if (MapA.InstanceID == Map.InstanceID)
|
|
{
|
|
MapA = Map;
|
|
}
|
|
else if (MapB.InstanceID == Map.InstanceID)
|
|
{
|
|
MapB = Map;
|
|
}
|
|
}
|
|
|
|
public void Verify()
|
|
{
|
|
ValidBridge = MapA != null && MapB != null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A Set of points that the navigation can use to transfer a Agent from one map to another
|
|
/// </summary>
|
|
[Serializable]
|
|
public class MapSeam
|
|
{
|
|
/// <summary>
|
|
/// Map on Side A of the Bridge
|
|
/// </summary>
|
|
public MapSet MapA;
|
|
|
|
/// <summary>
|
|
/// The connection side for Map A
|
|
/// </summary>
|
|
public SeamConnectionSide MapA_ConectionSide;
|
|
/// <summary>
|
|
/// The Map A Starting Tile Index
|
|
/// </summary>
|
|
public IntVector2 MapA_StartingTileIndex;
|
|
/// <summary>
|
|
/// The Map A Ending Tile Index
|
|
/// </summary>
|
|
public IntVector2 MapA_EndingTileIndex;
|
|
|
|
/// <summary>
|
|
/// Map on Side B of the Bridge
|
|
/// </summary>
|
|
public MapSet MapB;
|
|
|
|
/// <summary>
|
|
/// The connection side for Map A
|
|
/// </summary>
|
|
public SeamConnectionSide MapB_ConectionSide;
|
|
/// <summary>
|
|
/// The Map B Starting Tile Index
|
|
/// </summary>
|
|
public IntVector2 MapB_StartingTileIndex;
|
|
/// <summary>
|
|
/// The Map B Ending Tile Index
|
|
/// </summary>
|
|
public IntVector2 MapB_EndingTileIndex;
|
|
|
|
/// <summary>
|
|
/// If this map is a valid and can be used
|
|
/// </summary>
|
|
public bool ValidSeam = false;
|
|
|
|
public MapSeam(MapSet A, MapSet B, SeamConnectionSide mapA_ConectionSide, SeamConnectionSide mapB_ConectionSide)
|
|
{
|
|
MapA = A;
|
|
MapB = B;
|
|
MapA_ConectionSide = mapA_ConectionSide;
|
|
MapB_ConectionSide = mapB_ConectionSide;
|
|
|
|
if (mapA_ConectionSide == SeamConnectionSide.South)
|
|
{
|
|
MapA_StartingTileIndex = IntVector2.Zero;
|
|
MapA_EndingTileIndex = new IntVector2(A.SetSettings.MapSettings.MapWidth - 1, 0);
|
|
}
|
|
else if (mapA_ConectionSide == SeamConnectionSide.North)
|
|
{
|
|
MapA_StartingTileIndex = new IntVector2(0, A.SetSettings.MapSettings.MapHeight - 1);
|
|
MapA_EndingTileIndex = new IntVector2(A.SetSettings.MapSettings.MapWidth - 1, A.SetSettings.MapSettings.MapHeight - 1);
|
|
}
|
|
else if (mapA_ConectionSide == SeamConnectionSide.West)
|
|
{
|
|
MapA_StartingTileIndex = IntVector2.Zero;
|
|
MapA_EndingTileIndex = new IntVector2(0, A.SetSettings.MapSettings.MapHeight - 1);
|
|
}
|
|
else if (mapA_ConectionSide == SeamConnectionSide.East)
|
|
{
|
|
MapA_StartingTileIndex = new IntVector2(A.SetSettings.MapSettings.MapWidth - 1, 0);
|
|
MapA_EndingTileIndex = new IntVector2(A.SetSettings.MapSettings.MapWidth - 1, A.SetSettings.MapSettings.MapHeight - 1);
|
|
}
|
|
|
|
if (mapB_ConectionSide == SeamConnectionSide.South)
|
|
{
|
|
MapB_StartingTileIndex = IntVector2.Zero;
|
|
MapB_EndingTileIndex = new IntVector2(B.SetSettings.MapSettings.MapWidth - 1, 0);
|
|
}
|
|
else if (mapB_ConectionSide == SeamConnectionSide.North)
|
|
{
|
|
MapB_StartingTileIndex = new IntVector2(0, B.SetSettings.MapSettings.MapHeight - 1);
|
|
MapB_EndingTileIndex = new IntVector2(B.SetSettings.MapSettings.MapWidth - 1, B.SetSettings.MapSettings.MapHeight - 1);
|
|
}
|
|
else if (mapB_ConectionSide == SeamConnectionSide.West)
|
|
{
|
|
MapB_StartingTileIndex = IntVector2.Zero;
|
|
MapB_EndingTileIndex = new IntVector2(0, B.SetSettings.MapSettings.MapHeight - 1);
|
|
}
|
|
else if (mapB_ConectionSide == SeamConnectionSide.East)
|
|
{
|
|
MapB_StartingTileIndex = new IntVector2(B.SetSettings.MapSettings.MapWidth - 1, 0);
|
|
MapB_EndingTileIndex = new IntVector2(B.SetSettings.MapSettings.MapWidth - 1, B.SetSettings.MapSettings.MapHeight - 1);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks to see this bridge connects two maps
|
|
/// </summary>
|
|
/// <param name="startingMap"></param>
|
|
/// <param name="endingMap"></param>
|
|
/// <returns></returns>
|
|
public bool DirectConnects(MapSet startingMap, MapSet endingMap)
|
|
{
|
|
if (startingMap.InstanceID == MapA.InstanceID)
|
|
{
|
|
if (endingMap.InstanceID == MapB.InstanceID)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else if (startingMap.InstanceID == MapB.InstanceID)
|
|
{
|
|
if (endingMap.InstanceID == MapA.InstanceID)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks to see if the given maps is on one side of the Bridge
|
|
/// </summary>
|
|
/// <param name="Map"></param>
|
|
/// <returns></returns>
|
|
public bool Contains(MapSet Map)
|
|
{
|
|
if (Map.InstanceID == MapA.InstanceID)
|
|
{
|
|
return true;
|
|
}
|
|
else if (Map.InstanceID == MapB.InstanceID)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the other Map if you know one side the bridge connects too
|
|
/// </summary>
|
|
/// <param name="Map"></param>
|
|
/// <returns></returns>
|
|
public MapSet Other(MapSet Map)
|
|
{
|
|
if (MapA.InstanceID == Map.InstanceID)
|
|
{
|
|
return MapB;
|
|
}
|
|
else if (MapB.InstanceID == Map.InstanceID)
|
|
{
|
|
return MapA;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public void RefreshWithNew(MapSet Map)
|
|
{
|
|
if (MapA.InstanceID == Map.InstanceID)
|
|
{
|
|
MapA = Map;
|
|
}
|
|
else if (MapB.InstanceID == Map.InstanceID)
|
|
{
|
|
MapB = Map;
|
|
}
|
|
}
|
|
|
|
public void Verify()
|
|
{
|
|
ValidSeam = MapA != null && MapB != null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the closest valid point for the starting map to the seam
|
|
/// </summary>
|
|
/// <param name="startingMap"></param>
|
|
/// <param name="start"></param>
|
|
/// <returns></returns>
|
|
public IntVector3 GetPoint(MapSet startingMap, IntVector3 start)
|
|
{
|
|
IntVector2 StartIndex = startingMap.GetClosestMapTileIndex(start);
|
|
|
|
if (startingMap == MapA)
|
|
{
|
|
if (MapA_ConectionSide == SeamConnectionSide.North)
|
|
{
|
|
StartIndex.y = startingMap.SetSettings.MapSettings.MapHeight - 1;
|
|
}
|
|
else if (MapA_ConectionSide == SeamConnectionSide.South)
|
|
{
|
|
StartIndex.y = 0;
|
|
}
|
|
else if (MapA_ConectionSide == SeamConnectionSide.West)
|
|
{
|
|
StartIndex.x = startingMap.SetSettings.MapSettings.MapWidth - 1;
|
|
}
|
|
else if (MapA_ConectionSide == SeamConnectionSide.East)
|
|
{
|
|
StartIndex.x = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (MapB_ConectionSide == SeamConnectionSide.North)
|
|
{
|
|
StartIndex.y = startingMap.SetSettings.MapSettings.MapHeight - 1;
|
|
}
|
|
else if (MapB_ConectionSide == SeamConnectionSide.South)
|
|
{
|
|
StartIndex.y = 0;
|
|
}
|
|
else if (MapB_ConectionSide == SeamConnectionSide.West)
|
|
{
|
|
StartIndex.x = startingMap.SetSettings.MapSettings.MapWidth - 1;
|
|
}
|
|
else if (MapB_ConectionSide == SeamConnectionSide.East)
|
|
{
|
|
StartIndex.x = 0;
|
|
}
|
|
}
|
|
|
|
return startingMap.GetWorldTileIndex(StartIndex);
|
|
}
|
|
|
|
public IntVector3 GetOppositePoint(MapSet startingMap, IntVector3 start)
|
|
{
|
|
IntVector3 StartingPoint = GetPoint(startingMap, start);
|
|
|
|
// Iterative Method - Would like to remove when calculative method is fixed
|
|
MapSet EndingMap = Other(startingMap);
|
|
if (EndingMap == MapA)
|
|
{
|
|
int ClosestScore = int.MaxValue;
|
|
IntVector2 ClosestEndTileIndex = new IntVector2();
|
|
for (int x = 0; x <= MapA_StartingTileIndex.x; x++ )
|
|
{
|
|
for (int y = 0; y <= MapA_EndingTileIndex.y; y++)
|
|
{
|
|
int NewScore = IntVector3.Displacement(StartingPoint, EndingMap.GetWorldTileIndex(x, y));
|
|
if (NewScore < ClosestScore)
|
|
{
|
|
ClosestScore = NewScore;
|
|
ClosestEndTileIndex = new IntVector2(x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
return EndingMap.GetWorldTileIndex(ClosestEndTileIndex);
|
|
}
|
|
else if (EndingMap == MapB)
|
|
{
|
|
int ClosestScore = int.MaxValue;
|
|
IntVector2 ClosestEndTileIndex = new IntVector2();
|
|
for (int x = 0; x <= MapB_StartingTileIndex.x; x++)
|
|
{
|
|
for (int y = 0; y <= MapB_EndingTileIndex.y; y++)
|
|
{
|
|
int NewScore = IntVector3.Displacement(StartingPoint, EndingMap.GetWorldTileIndex(x, y));
|
|
if (NewScore < ClosestScore)
|
|
{
|
|
ClosestScore = NewScore;
|
|
ClosestEndTileIndex = new IntVector2(x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
return EndingMap.GetWorldTileIndex(ClosestEndTileIndex);
|
|
}
|
|
|
|
// Caluclation Method - Needs Work somehwere
|
|
IntVector2 StartIndex = startingMap.GetClosestMapTileIndex(StartingPoint);
|
|
int startingMapLength;
|
|
int endingMapLength;
|
|
double startingMapRatio;
|
|
if (startingMap == MapA)
|
|
{
|
|
if (MapA_ConectionSide == SeamConnectionSide.South || MapA_ConectionSide == SeamConnectionSide.North)
|
|
{
|
|
startingMapLength = MapA.SetSettings.MapSettings.MapWidth;
|
|
startingMapRatio = (double)StartIndex.x / startingMapLength;
|
|
}
|
|
else
|
|
{
|
|
startingMapLength = MapA.SetSettings.MapSettings.MapHeight;
|
|
startingMapRatio = (double)StartIndex.y / startingMapLength;
|
|
}
|
|
|
|
if (MapB_ConectionSide == SeamConnectionSide.South || MapB_ConectionSide == SeamConnectionSide.North)
|
|
{
|
|
endingMapLength = MapB.SetSettings.MapSettings.MapWidth;
|
|
}
|
|
else
|
|
{
|
|
endingMapLength = MapB.SetSettings.MapSettings.MapHeight;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (MapB_ConectionSide == SeamConnectionSide.South || MapB_ConectionSide == SeamConnectionSide.North)
|
|
{
|
|
startingMapLength = MapB.SetSettings.MapSettings.MapWidth;
|
|
startingMapRatio = (double)StartIndex.x / startingMapLength;
|
|
}
|
|
else
|
|
{
|
|
startingMapLength = MapB.SetSettings.MapSettings.MapHeight;
|
|
startingMapRatio = (double)StartIndex.y / startingMapLength;
|
|
}
|
|
|
|
if (MapA_ConectionSide == SeamConnectionSide.South || MapA_ConectionSide == SeamConnectionSide.North)
|
|
{
|
|
endingMapLength = MapA.SetSettings.MapSettings.MapWidth;
|
|
}
|
|
else
|
|
{
|
|
endingMapLength = MapA.SetSettings.MapSettings.MapHeight;
|
|
}
|
|
}
|
|
|
|
double mapLengthRatio = (double)endingMapLength / startingMapLength;
|
|
|
|
int mapEndFinalPoint = (int)System.Math.Round(mapLengthRatio * startingMapRatio * endingMapLength);
|
|
IntVector2 EndingPoint;
|
|
MapSet endingMap;
|
|
if (startingMap == MapA)
|
|
{
|
|
endingMap = MapB;
|
|
if (MapB_ConectionSide == SeamConnectionSide.South)
|
|
{
|
|
EndingPoint = new IntVector2(mapEndFinalPoint, 0);
|
|
}
|
|
else if (MapB_ConectionSide == SeamConnectionSide.North)
|
|
{
|
|
EndingPoint = new IntVector2(mapEndFinalPoint, MapB.SetSettings.MapSettings.MapHeight - 1);
|
|
}
|
|
else if (MapB_ConectionSide == SeamConnectionSide.West)
|
|
{
|
|
EndingPoint = new IntVector2(MapB.SetSettings.MapSettings.MapWidth - 1, mapEndFinalPoint);
|
|
}
|
|
else
|
|
{
|
|
EndingPoint = new IntVector2(0, mapEndFinalPoint);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
endingMap = MapA;
|
|
if (MapA_ConectionSide == SeamConnectionSide.South)
|
|
{
|
|
EndingPoint = new IntVector2(mapEndFinalPoint, 0);
|
|
}
|
|
else if (MapA_ConectionSide == SeamConnectionSide.North)
|
|
{
|
|
EndingPoint = new IntVector2(mapEndFinalPoint, MapA.SetSettings.MapSettings.MapHeight - 1);
|
|
}
|
|
else if (MapA_ConectionSide == SeamConnectionSide.West)
|
|
{
|
|
EndingPoint = new IntVector2(MapA.SetSettings.MapSettings.MapWidth - 1, mapEndFinalPoint);
|
|
}
|
|
else
|
|
{
|
|
EndingPoint = new IntVector2(0, mapEndFinalPoint);
|
|
}
|
|
}
|
|
|
|
return endingMap.GetWorldTileIndex(EndingPoint);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tile Size Data for the Map, used to save default tiles to the Map
|
|
/// </summary>
|
|
[System.Serializable]
|
|
public class MapData
|
|
{
|
|
public byte[,] SavedTiles = new byte[100, 100];
|
|
public int Width = 100;
|
|
public int Height = 100;
|
|
|
|
public MapData()
|
|
{
|
|
}
|
|
|
|
public bool MakeSureSizeIsRight()
|
|
{
|
|
if (Width != SavedTiles.GetLength(0) || Height != SavedTiles.GetLength(1))
|
|
{
|
|
try
|
|
{
|
|
byte[,] PreviousTiles = SavedTiles;
|
|
int PreviousWidth = SavedTiles.GetLength(0);
|
|
int PreviousHeight = SavedTiles.GetLength(1);
|
|
SavedTiles = new byte[Width, Height];
|
|
for (int x = 0; x < Width; x++)
|
|
{
|
|
for (int y = 0; y < Height; y++)
|
|
{
|
|
if (x < PreviousWidth && y < PreviousHeight)
|
|
{
|
|
SavedTiles[x, y] = PreviousTiles[x, y];
|
|
}
|
|
else
|
|
{
|
|
SavedTiles[x, y] = (byte)TileTypes.Standard;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
throw new Exception($"{e.Message} \n {e.StackTrace} \n ----------------------------------------- \n {Width} vs {SavedTiles.GetLength(0)} & {Height} vs {SavedTiles.GetLength(1)}");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the size of the Data
|
|
/// </summary>
|
|
/// <param name="mapWidth"></param>
|
|
/// <param name="mapHeight"></param>
|
|
public void UpdateToMapSize(int mapWidth, int mapHeight)
|
|
{
|
|
if (mapWidth == Width && mapHeight == Height)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
byte[,] PreviousTiles = SavedTiles;
|
|
SavedTiles = new byte[mapWidth, mapHeight];
|
|
int PreviousWidth = Width;
|
|
int PreviousHeight = Height;
|
|
Width = mapWidth;
|
|
Height = mapHeight;
|
|
for (int x = 0; x < mapWidth; x++)
|
|
{
|
|
for (int y = 0; y < mapHeight; y++)
|
|
{
|
|
if (x < PreviousWidth && y < PreviousHeight)
|
|
{
|
|
SavedTiles[x, y] = PreviousTiles[x, y];
|
|
}
|
|
else
|
|
{
|
|
SavedTiles[x, y] = (byte)TileTypes.Standard;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Moves the values of the tiles
|
|
/// </summary>
|
|
/// <param name="HorizontalTranslation"></param>
|
|
/// <param name="VerticalTranslation"></param>
|
|
public void TransalateValues(int HorizontalTranslation, int VerticalTranslation)
|
|
{
|
|
if (HorizontalTranslation == 0 && VerticalTranslation == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
byte[,] NewTiles = new byte[Width, Height];
|
|
for (int x = 0; x < Width; x++)
|
|
{
|
|
for (int y = 0; y < Height; y++)
|
|
{
|
|
int TranslatedX = x + HorizontalTranslation;
|
|
int TranslatedY = y + VerticalTranslation;
|
|
if (TranslatedX < 0 || TranslatedY < 0 || TranslatedX >= Width || TranslatedY >= Height)
|
|
{
|
|
NewTiles[x, y] = (byte)TileTypes.Standard;
|
|
}
|
|
else
|
|
{
|
|
NewTiles[x, y] = SavedTiles[TranslatedX, TranslatedY];
|
|
}
|
|
}
|
|
}
|
|
SavedTiles = NewTiles;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears the map of all tile types and turns them into standard tiles
|
|
/// </summary>
|
|
public void CleanMap()
|
|
{
|
|
for (int x = 0; x < Width; x++)
|
|
{
|
|
for (int y = 0; y < Height; y++)
|
|
{
|
|
SavedTiles[x, y] = (byte)TileTypes.Standard;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The Data that tells the speed multiplier for a given tile type
|
|
/// </summary>
|
|
[System.Serializable]
|
|
public class TileData
|
|
{
|
|
public TileTypes Type;
|
|
public byte Speed;
|
|
|
|
public TileData()
|
|
{
|
|
Type = TileTypes.Standard;
|
|
Speed = 100; // 100 = 100% Speed
|
|
}
|
|
|
|
public TileData(TileTypes tileType, byte speedMult)
|
|
{
|
|
Type = tileType;
|
|
Speed = speedMult;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used to keep track of a obstacles tiles and its state in the obstacle
|
|
/// </summary>
|
|
[Serializable]
|
|
public struct ObstacleData
|
|
{
|
|
public IntVector3 TileIndexKey;
|
|
public ObstacleValidationStates ValidationState;
|
|
|
|
public ObstacleData(IntVector3 Index)
|
|
{
|
|
TileIndexKey = Index;
|
|
ValidationState = ObstacleValidationStates.Added;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Means this tile is no longer valid and will need to be checked if it still belongs on this obstacle
|
|
/// </summary>
|
|
public void UnValidate()
|
|
{
|
|
ValidationState = ObstacleValidationStates.Invalidated;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates the tile, it belongs on this obstacle
|
|
/// </summary>
|
|
public void Validate()
|
|
{
|
|
ValidationState = ObstacleValidationStates.Validated;
|
|
}
|
|
}
|
|
}
|