using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Gameplay.Character;
using GridScene.ECS;
using GridScene.ECS.Non_Entitas;
using GridScene.ECS.Systems;
using GridScene.Events;
using Id;
using Modules.Character;
using Modules.Database;
using Modules.Event;
using Modules.Level;
using Modules.UI;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Jobs;
using UnityEngine.ResourceManagement.AsyncOperations;
using Random = UnityEngine.Random;
namespace GridScene
{
public class GridManager : MonoBehaviour
{
#region Structs
[BurstCompile]
private readonly struct MoveEnemyGameObjectsJob : IJobParallelForTransform
{
[ReadOnly] private readonly NativeArray<float2> _positions;
[ReadOnly] private readonly NativeArray<float2> _forwardDirections;
public MoveEnemyGameObjectsJob
(
NativeArray<float2> positions,
NativeArray<float2> forwardDirections
)
{
_positions = positions;
_forwardDirections = forwardDirections;
}
public void Execute(int index, TransformAccess transform)
{
transform.position = new Vector3(_positions[index].x, transform.position.y, _positions[index].y);
if (MoveEnemiesSystem.Magnitude(_forwardDirections[index]) > math.EPSILON)
{
transform.rotation = Quaternion.LookRotation
(
math.normalize
(
new Vector3
(
_forwardDirections[index].x,
0.0f,
_forwardDirections[index].y
)
),
Vector3.up
);
}
}
}
#endregion Structs
#region DataClasses
public class TileInfo
{
#region MemberVars
private readonly int _x;
private readonly int _y;
private readonly bool _isObstacle;
private readonly int _scale;
private readonly bool _isChild;
private readonly int2[] _children;
private uint _enemyId;
#endregion MemberVars
#region Properties
public int X => _x;
public int Y => _y;
public bool IsObstacle => _isObstacle;
public uint EnemyId
{
get => _enemyId;
set => _enemyId = value;
}
public int Scale => _scale;
public bool IsChild => _isChild;
public int2[] Children => _children;
#endregion Properties
#region Constructors
public TileInfo(int x, int y, bool isObstacle = false)
{
_x = x;
_y = y;
_isObstacle = isObstacle;
_enemyId = uint.MaxValue;
_scale = 1;
_isChild = false;
_children = null;
BaseEvent<FreeTileIncrementEvent>.Raise(new FreeTileIncrementEvent(!_isObstacle));
}
public TileInfo
(
int x,
int y,
uint enemyId,
int scale = 1,
bool isChild = false,
int2[] children = null
)
{
_x = x;
_y = y;
_isObstacle = false;
_enemyId = enemyId;
_scale = scale;
_isChild = isChild;
_children = children;
BaseEvent<FreeTileIncrementEvent>.Raise(new FreeTileIncrementEvent(false));
}
#endregion Constructors
}
#endregion DataClasses
#region MemberVars
private static GridManager _instance;
private CharacterModel _characterModel;
private TileInfo[,] _tileInfos;
private Dictionary<uint, EnemyUnitId> _enemyById;
private int _freeTileCount;
private bool _freeTileCountChanged;
private TileInfo[] _freeTiles;
private Dictionary<int2, GameEntity> _enemyGridPositions;
private Transform _playerTransform;
private IReadOnlyDictionary<EnemyId, EnemyDefinition> _enemyDatabase;
private Dictionary<string, AsyncOperationHandle<GameObject>> _asyncOperationHandles =
new Dictionary<string, AsyncOperationHandle<GameObject>>();
private TransformAccessArray _transformAccessArray;
private JobHandle _moveEnemyGameObjectsJobHandle;
private IUIModule _uiModule;
#if CHEATS_ACTIVE
private GridCheats _cheats;
private string[,] _chunkNames;
#endif
private NativeArray<Entity> _enemyEntities;
private Dictionary<int2, int2[]> _parentToChildren;
private Dictionary<uint, Entity> _enemyIdToEntity;
private EntityManager _entityManager;
private Dictionary<uint, int2> _enemyIdToGridPosition;
[SerializeField] private CharacterId _characterId;
[SerializeField] private CameraController _cameraController;
[SerializeField] private EnemyController _enemyController;
[SerializeField] private int _gridWidth = 1000;
[SerializeField] private int _gridHeight = 1000;
[SerializeField] private GPUIHordeManager _gpuiHordeManager = null;
#region Temporary
[SerializeField] private bool _placeEnemiesRandomly = false;
[SerializeField] private int _numRandomEnemies = 25000;
[SerializeField] private int _numRandomHeavyEnemies = 50;
[SerializeField] private bool _useGPUI = false;
#endregion Temportary
#endregion MemberVars
#region Properties
public static GridManager Instance => _instance;
public Transform PlayerTransform => _playerTransform;
public Dictionary<int2, GameEntity> EnemyGridPositions => _enemyGridPositions;
#if CHEATS_ACTIVE
public bool IsDebugHitZoneEnabled => _cheats.IsDebugHitZoneEnabled;
#endif
#endregion Properties
#region MonoBehaviorCallbacks
private void Awake()
{
_instance = this;
_uiModule = GameEngine.Module<IUIModule>();
_uiModule.ShowView(typeof(HudScreen));
BaseEvent<FreeTileIncrementEvent>.Register(OnFreeTileIncrement);
BaseEvent<MoveEnemyGridPositionEvent>.Register(OnMoveEnemyGridPosition);
BaseEvent<EnemiesKilledEvent>.Register(OnEnemiesKilled);
_freeTileCount = 0;
_enemyById = new Dictionary<uint, EnemyUnitId>();
_freeTileCountChanged = false;
_enemyDatabase = GameEngine.Module<IDatabaseModule>().Database<EnemyDatabase>().Dictionary;
_parentToChildren = new Dictionary<int2, int2[]>();
_enemyIdToEntity = new Dictionary<uint, Entity>();
_entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
_enemyIdToGridPosition = new Dictionary<uint, int2>();
_enemyGridPositions = new Dictionary<int2, GameEntity>();
for (int iY = 0; iY < _gridHeight; iY++)
{
for (int iX = 0; iX < _gridWidth; iX++)
{
_enemyGridPositions.Add(new int2(iX, iY), null);
}
}
#if CHEATS_ACTIVE
_cheats = new GridCheats();
#endif
StartCoroutine(LoadAssets());
}
#if CHEATS_ACTIVE
private void Update()
{
DisplayPlayerPosition();
}
#endif
private void OnDestroy()
{
#if CHEATS_ACTIVE
_cheats.Dispose();
#endif
if (_characterModel != null)
{
_characterModel.StatHandler.OnCharacterDied -= OnCharacterDied;
_characterModel.DestroyGameplayInstance();
}
foreach (var asyncOperation in _asyncOperationHandles)
{
if (asyncOperation.Value.IsValid())
{
Addressables.Release(asyncOperation.Value);
}
}
_instance = null;
_asyncOperationHandles.Clear();
_transformAccessArray.Dispose();
_enemyEntities.Dispose();
BaseEvent<FreeTileIncrementEvent>.Unregister(OnFreeTileIncrement);
BaseEvent<MoveEnemyGridPositionEvent>.Unregister(OnMoveEnemyGridPosition);
BaseEvent<EnemiesKilledEvent>.Unregister(OnEnemiesKilled);
}
#endregion MonoBehaviorCallbacks
#region OtherCallbacks
private void OnEnemiesKilled(EnemiesKilledEvent eventData)
{
_moveEnemyGameObjectsJobHandle.Complete();
NativeArray<Entity> remainingEntities =
new NativeArray<Entity>(_enemyEntities.Length - eventData.Killed.Count, Allocator.TempJob);
for (int iKilled = 0; iKilled < eventData.Killed.Count; iKilled++)
{
if (_useGPUI)
{
int iRemaining = 0;
for (int iEntity = 0; iEntity < _enemyEntities.Length; iEntity++)
{
if (_enemyIdToEntity.ContainsKey(eventData.Killed[iKilled]))
{
_entityManager.DestroyEntity(_enemyIdToEntity[eventData.Killed[iKilled]]);
_enemyIdToEntity.Remove(eventData.Killed[iKilled]);
}
else
{
remainingEntities[iRemaining] = _enemyEntities[iEntity];
iRemaining++;
}
}
}
else
{
List<int> toRemove = new List<int>();
for (int iTransform = 0; iTransform < _transformAccessArray.length; iTransform++)
{
if (_transformAccessArray[iTransform] == _enemyById[eventData.Killed[iKilled]].transform)
{
toRemove.Add(iTransform);
}
if (toRemove.Count == eventData.Killed.Count)
{
break;
}
}
for (int iRemove = 0; iRemove < toRemove.Count; iRemove++)
{
GameObject go = _transformAccessArray[toRemove[iRemove]].gameObject;
_transformAccessArray.RemoveAtSwapBack(toRemove[iRemove]);
Destroy(go);
}
}
}
for (int iKilled = 0; iKilled < eventData.Killed.Count; iKilled++)
{
DestroyEnemyGridData(eventData.Killed[iKilled]);
}
if (_useGPUI)
{
_enemyEntities.Dispose();
_enemyEntities = remainingEntities;
}
else
{
remainingEntities.Dispose();
}
}
private void OnFreeTileIncrement(FreeTileIncrementEvent eventData)
{
_freeTileCount += eventData.Increased ? 1 : -1;
if (_freeTileCount < 0)
{
_freeTileCount = 0;
}
if (!_freeTileCountChanged)
{
_freeTileCountChanged = true;
}
}
private void OnMoveEnemyGridPosition(MoveEnemyGridPositionEvent eventData)
{
TileInfo enemy = _tileInfos[eventData.PreviousPosition.x, eventData.PreviousPosition.y];
int scale = enemy.Scale;
bool hasChildren = enemy.Children != null;
if (hasChildren)
{
for (int iChild = 0; iChild < enemy.Children.Length; iChild++)
{
_tileInfos[enemy.Children[iChild].x, enemy.Children[iChild].y] = new TileInfo
(
enemy.Children[iChild].x,
enemy.Children[iChild].y
);
}
}
_tileInfos[enemy.X, enemy.Y] =
new TileInfo(eventData.PreviousPosition.x, eventData.PreviousPosition.y);
int2[] newChildren = hasChildren ? new int2[scale * scale - 1] : null;
_tileInfos[eventData.NewPosition.x, eventData.NewPosition.y] = new TileInfo
(
eventData.NewPosition.x,
eventData.NewPosition.y,
eventData.EnemyId,
scale,
false,
newChildren
);
if (!_enemyIdToGridPosition.ContainsKey(eventData.EnemyId))
{
_enemyIdToGridPosition.Add(eventData.EnemyId, eventData.NewPosition);
}
else
{
_enemyIdToGridPosition[eventData.EnemyId] = eventData.NewPosition;
}
if (!hasChildren)
{
return;
}
int iChildren = 0;
for (int iChildY = eventData.NewPosition.y; iChildY < eventData.NewPosition.y + scale; iChildY++)
{
for (int iChildX = eventData.NewPosition.x; iChildX < eventData.NewPosition.x + scale; iChildX++)
{
if (iChildX == eventData.NewPosition.x && iChildY == eventData.NewPosition.y)
{
continue;
}
_tileInfos[iChildX, iChildY] = new TileInfo
(
iChildX,
iChildY,
eventData.EnemyId,
scale,
true
);
newChildren[iChildren] = new int2(iChildX, iChildY);
iChildren++;
}
}
if (_parentToChildren.ContainsKey(eventData.PreviousPosition))
{
_parentToChildren.Remove(eventData.PreviousPosition);
}
if (!_parentToChildren.ContainsKey(eventData.NewPosition))
{
_parentToChildren.Add(eventData.NewPosition, newChildren);
}
else
{
_parentToChildren[eventData.NewPosition] = newChildren;
}
}
#endregion OtherCallbacks
#region Methods
private void DestroyEnemyGridData(uint id)
{
int2 gridPos = _enemyIdToGridPosition[id];
TileInfo tileInfo = _tileInfos[gridPos.x, gridPos.y];
if (tileInfo.Children != null)
{
for (int iChild = 0; iChild < tileInfo.Children.Length; iChild++)
{
_tileInfos[tileInfo.Children[iChild].x, tileInfo.Children[iChild].y] =
new TileInfo(tileInfo.Children[iChild].x, tileInfo.Children[iChild].y);
}
}
_tileInfos[gridPos.x, gridPos.y] = new TileInfo(gridPos.x, gridPos.y);
if (_parentToChildren.ContainsKey(_enemyIdToGridPosition[id]))
{
_parentToChildren.Remove(_enemyIdToGridPosition[id]);
}
_enemyIdToGridPosition.Remove(id);
_enemyById.Remove(id);
for (int iY = 0; iY < _gridHeight; iY++)
{
for (int iX = 0; iX < _gridWidth; iX++)
{
if (_tileInfos[iX, iY] == null)
{
continue;
}
if (_tileInfos[iX, iY].EnemyId != id)
{
continue;
}
_tileInfos[iX, iY] = new TileInfo(iX, iY);
}
}
}
private IEnumerator LoadAssets()
{
yield return CreateGrid();
InitTiles();
yield return LoadCharacterVisual();
_enemyController.Init();
}
private IEnumerator CreateGrid()
{
_tileInfos = new TileInfo[_gridWidth, _gridHeight];
int widthGenerated = 0;
int heightGenerated = 0;
BiomeDefinition biomeDefinition = GameEngine.Module<ILevelModule>().GetCurrentBiome();
List<ChunkGenerationData> chunkGenerationDatas = new List<ChunkGenerationData>();
foreach (var biomeDefinitionChunk in biomeDefinition.Chunks)
{
AsyncOperationHandle<GameObject> asyncOperation = Addressables.LoadAssetAsync<GameObject>(biomeDefinitionChunk);
yield return asyncOperation;
ChunkData chunkData = asyncOperation.Result.GetComponent<ChunkData>();
chunkGenerationDatas.Add(new ChunkGenerationData(asyncOperation.Result.name, chunkData.StartingWeightSelection, chunkData.SelectionWeightLoss, chunkData.ChunkPosition));
_asyncOperationHandles.Add(asyncOperation.Result.name, asyncOperation);
}
List<List<ChunkGenerationData>> chunksByPosition = new List<List<ChunkGenerationData>>();
int chunkPositionCount = Enum.GetValues(typeof(EChunkPosition)).Length;
for (int i = 0; i < chunkPositionCount; i++)
{
chunksByPosition.Add(chunkGenerationDatas.Where(x => (int)x.ChunkPosition == i).ToList());
}
#if CHEATS_ACTIVE
int verticalChunkCount = _gridHeight / GridConfiguration.ChunkHeight;
int horizontalChunkCount = _gridWidth / GridConfiguration.ChunkWidth;
_chunkNames = new string[horizontalChunkCount,verticalChunkCount];
#endif
while (heightGenerated < _gridHeight)
{
while (widthGenerated < _gridWidth)
{
EChunkPosition chunkPosition = GetCurrentChunkPosition(heightGenerated, widthGenerated);
Debug.Log(chunksByPosition);
string randomChunk = GridConfiguration.SelectNextChunk(chunksByPosition[(int)chunkPosition]);
#if CHEATS_ACTIVE
_chunkNames[widthGenerated / GridConfiguration.ChunkWidth, heightGenerated / GridConfiguration.ChunkHeight] = randomChunk;
#endif
GameObject instantiatedChunk = Instantiate(_asyncOperationHandles[randomChunk].Result, new Vector3(widthGenerated, 0f, heightGenerated), Quaternion.identity, transform);
instantiatedChunk.transform.rotation = quaternion.identity;
ChunkData chunkData = instantiatedChunk.GetComponent<ChunkData>();
foreach (var chunkDataObstaclePosition in chunkData.ObstaclePositions)
{
_tileInfos[widthGenerated + chunkDataObstaclePosition.x, heightGenerated + chunkDataObstaclePosition.y] =
new TileInfo(widthGenerated + chunkDataObstaclePosition.x, heightGenerated + chunkDataObstaclePosition.y, true);
}
widthGenerated += GridConfiguration.ChunkWidth;
}
heightGenerated += GridConfiguration.ChunkHeight;
widthGenerated = 0;
}
}
private EChunkPosition GetCurrentChunkPosition(int heightGenerated, int widthGenerated)
{
bool isBottom = heightGenerated == 0;
bool isTop = (heightGenerated + GridConfiguration.ChunkHeight) == _gridHeight;
bool isLeft = widthGenerated == 0;
bool isRight = (widthGenerated + GridConfiguration.ChunkWidth) == _gridWidth;
if (isBottom)
{
if (isLeft)
{
return EChunkPosition.BottomLeftCorner;
}
return isRight ? EChunkPosition.BottomRightCorner : EChunkPosition.Bottom;
}
if (isTop)
{
if (isLeft)
{
return EChunkPosition.TopLeftCorner;
}
return isRight ? EChunkPosition.TopRightCorner : EChunkPosition.Top;
}
if (isLeft)
{
return EChunkPosition.Left;
}
return isRight ? EChunkPosition.Right : EChunkPosition.Center;
}
private IEnumerator LoadCharacterVisual()
{
ICharacterModule characterModule = GameEngine.Module<ICharacterModule>();
CharacterInstanceId characterInstanceId = characterModule.CreateCharacter(_characterId);
_characterModel = characterModule.GetCharacterModel(characterInstanceId);
yield return _characterModel.CreateGameplayInstance();
_playerTransform = _characterModel.VisualHandler.GetInstance().transform;
_characterModel.VisualHandler.GetController().Init(_cameraController.gameObject);
_cameraController.Initialize(_playerTransform);
_characterModel.StatHandler.OnCharacterDied += OnCharacterDied;
}
private void InitTiles()
{
for (int yTile = 0; yTile < _gridHeight; yTile++)
{
for (int xTile = 0; xTile < _gridWidth; xTile++)
{
if (_tileInfos[xTile, yTile] != null)
{
continue;
}
_tileInfos[xTile, yTile] = new TileInfo(xTile, yTile);
}
}
}
private bool IsFreeTile(int x, int y)
{
Vector3 playerPos = _playerTransform.position;
return !_tileInfos[x, y].IsObstacle &&
((int)playerPos.x != x || (int)playerPos.z != y) &&
_tileInfos[x, y].EnemyId == uint.MaxValue &&
!_tileInfos[x, y].IsChild;
}
private void GetAllFreeTiles(bool randomized = false, int scale = 1)
{
if (_freeTileCountChanged)
{
_freeTileCountChanged = false;
}
else
{
return;
}
List<TileInfo> freeTiles = new List<TileInfo>();
int freeTile = 0;
for (int iY = 0; iY < _gridHeight; iY++)
{
for (int iX = 0; iX < _gridWidth; iX++)
{
if (!IsFreeTile(iX, iY))
{
continue;
}
if (scale == 1)
{
freeTiles.Add(_tileInfos[iX, iY]);
freeTile++;
}
else
{
if (iX + scale - 1 > _gridWidth - 1)
{
continue;
}
if (iY + scale - 1 > _gridHeight - 1)
{
continue;
}
bool allTilesAvailable = true;
int2[] children = new int2[scale * scale - 1];
int iChild = 0;
int2 parent = new int2(iX, iY);
for (int iChildY = iY; iChildY < iY + scale; iChildY++)
{
for (int iChildX = iX; iChildX < iX + scale; iChildX++)
{
if (iChildX == iX && iChildY == iY)
{
continue;
}
if (!IsFreeTile(iChildX, iChildY))
{
iChildY = iY + scale;
allTilesAvailable = false;
break;
}
children[iChild] = new int2(iChildX, iChildY);
_tileInfos[iChildX, iChildY] =
new TileInfo(iChildX, iChildY, uint.MaxValue, scale, true);
iChild++;
}
}
if (!allTilesAvailable)
{
continue;
}
if (!_parentToChildren.ContainsKey(parent))
{
_parentToChildren.Add(parent, children);
}
else
{
_parentToChildren[parent] = children;
}
freeTiles.Add(_tileInfos[iX, iY]);
freeTile++;
}
}
}
_freeTiles = freeTiles.ToArray();
if (!randomized)
{
return;
}
TileInfo temp = null;
int index = 0;
for (int iTile = 0; iTile < _freeTiles.Length; iTile++)
{
index = Random.Range(0, _freeTiles.Length);
temp = _freeTiles[index];
_freeTiles[index] = _freeTiles[iTile];
_freeTiles[iTile] = temp;
}
}
public float2 CapPosition(float2 position)
{
if (position.x < 0.0f)
{
position.x = 0.0f;
}
else if (position.x > _gridWidth - 1)
{
position.x = (_gridWidth - 1) + (position.x - (float)Math.Floor(position.x));
}
if (position.y < 0.0f)
{
position.y = 0.0f;
}
else if (position.y > _gridHeight - 1)
{
position.y = (_gridHeight - 1) + (position.y - (float)Math.Floor(position.y));
}
return position;
}
public EnemyUnitId[] GetNextBatchOfEnemies()
{
if (!_placeEnemiesRandomly) //temporary
{
return null;
}
GetAllFreeTiles(true);
TileInfo tileInfo = null;
int length = _freeTiles.Length >= _numRandomEnemies ? _numRandomEnemies : _freeTiles.Length;
EnemyUnitId[] ids = new EnemyUnitId[length];
Transform enemy = null;
Vector3 enemyScale = Vector3.zero;
int iEnemy = 0;
_transformAccessArray = new TransformAccessArray(_numRandomEnemies + _numRandomHeavyEnemies);
_enemyEntities = new NativeArray<Entity>(_numRandomEnemies + _numRandomHeavyEnemies, Allocator.TempJob);
int iEntity = 0;
for (iEnemy = 0; iEnemy < length; iEnemy++)
{
tileInfo = _freeTiles[iEnemy];
EnemyId morlock = new EnemyId("Morloch"); //temporary
if (!_useGPUI) //temporary
{
enemy = Instantiate(_enemyDatabase[morlock].VisualPrefab).transform;
enemyScale = enemy.localScale;
enemy.position =
new Vector3(tileInfo.X + enemyScale.x * 0.5f, 0.0f, tileInfo.Y + enemyScale.z * 0.5f);
_transformAccessArray.Add(enemy);
ids[iEnemy] = enemy.gameObject.AddComponent<EnemyUnitId>();
}
else
{
enemyScale = _enemyDatabase[morlock].VisualPrefab.transform.localScale;
_enemyEntities[iEntity] = _gpuiHordeManager.SpawnEnemy
(
_enemyDatabase[morlock].GPUIType,
new Vector3(tileInfo.X + enemyScale.x * 0.5f, 0.0f, tileInfo.Y + enemyScale.z * 0.5f),
Quaternion.identity
);
iEntity++;
GameObject temp = new GameObject("temp");
ids[iEnemy] = temp.AddComponent<EnemyUnitId>();
temp.SetActive(false);
temp.transform.position =
new Vector3(tileInfo.X + enemyScale.x * 0.5f, 0.0f, tileInfo.Y + enemyScale.z * 0.5f);
}
ids[iEnemy].Id = EnemyController.NextEnemyId;
if (_useGPUI)
{
_enemyIdToEntity.Add(ids[iEnemy].Id, _enemyEntities[iEnemy]);
}
ids[iEnemy].EnemyId = morlock;
ids[iEnemy].RadiusSize = _enemyDatabase[morlock].VisualScale * 0.5f;
_enemyById.Add(ids[iEnemy].Id, ids[iEnemy]);
_tileInfos[tileInfo.X, tileInfo.Y] = new TileInfo(tileInfo.X, tileInfo.Y, ids[iEnemy].Id);
_enemyIdToGridPosition.Add(ids[iEnemy].Id, new int2(tileInfo.X, tileInfo.Y));
}
EnemyId heavyMorlock = new EnemyId("HeavyMorloch"); //temporary
GetAllFreeTiles(true, (int)_enemyDatabase[heavyMorlock].VisualScale);
length = (_freeTiles.Length >= _numRandomHeavyEnemies ? _numRandomHeavyEnemies : _freeTiles.Length);
EnemyUnitId[] idsHeavy = new EnemyUnitId[length];
for (iEnemy = 0; iEnemy < length; iEnemy++)
{
tileInfo = _freeTiles[iEnemy];
if (!_useGPUI)//temporary
{
enemy = Instantiate(_enemyDatabase[heavyMorlock].VisualPrefab).transform;
enemyScale = enemy.localScale;
enemy.position = new Vector3(tileInfo.X + enemyScale.x * 0.5f, 0.0f,
tileInfo.Y + enemyScale.z * 0.5f);
_transformAccessArray.Add(enemy);
idsHeavy[iEnemy] = enemy.gameObject.AddComponent<EnemyUnitId>();
}
else
{
enemyScale = _enemyDatabase[heavyMorlock].VisualPrefab.transform.localScale;
_enemyEntities[iEntity] = _gpuiHordeManager.SpawnEnemy
(
_enemyDatabase[heavyMorlock].GPUIType,
new Vector3(tileInfo.X + enemyScale.x * 0.5f, 0.0f, tileInfo.Y + enemyScale.z * 0.5f),
Quaternion.identity
);
iEntity++;
GameObject temp = new GameObject("temp");
idsHeavy[iEnemy] = temp.AddComponent<EnemyUnitId>();
temp.SetActive(false);
temp.transform.position =
new Vector3(tileInfo.X + enemyScale.x * 0.5f, 0.0f, tileInfo.Y + enemyScale.z * 0.5f);
}
idsHeavy[iEnemy].Id = EnemyController.NextEnemyId;
if (_useGPUI)
{
_enemyIdToEntity.Add(idsHeavy[iEnemy].Id, _enemyEntities[iEnemy]);
}
idsHeavy[iEnemy].EnemyId = heavyMorlock;
idsHeavy[iEnemy].RadiusSize = _enemyDatabase[heavyMorlock].VisualScale * 0.5f;
_enemyById.Add(idsHeavy[iEnemy].Id, idsHeavy[iEnemy]);
int2[] children = _parentToChildren[new int2(tileInfo.X, tileInfo.Y)];
tileInfo = new TileInfo
(
tileInfo.X,
tileInfo.Y,
idsHeavy[iEnemy].Id,
(int)_enemyDatabase[heavyMorlock].VisualPrefab.transform.localScale.x,
false,
children
);
_tileInfos[tileInfo.X, tileInfo.Y] = tileInfo;
_enemyIdToGridPosition.Add(idsHeavy[iEnemy].Id, new int2(tileInfo.X, tileInfo.Y));
for (int iChild = 0; iChild < children.Length; iChild++)
{
_tileInfos[children[iChild].x, children[iChild].y].EnemyId = tileInfo.EnemyId;
}
}
EnemyUnitId[] combined = new EnemyUnitId[length + ids.Length];
ids.CopyTo(combined, 0);
idsHeavy.CopyTo(combined, ids.Length);
return combined;
}
public EnemyUnitId GetEnemyUnitId(uint enemyId)
{
return _enemyById[enemyId];
}
public void MoveEnemies(NativeArray<float2> moved, NativeArray<float2> forwardDirections)
{
if (_useGPUI)
{
return;
}
_moveEnemyGameObjectsJobHandle.Complete();
MoveEnemyGameObjectsJob job = new MoveEnemyGameObjectsJob(moved, forwardDirections);
_moveEnemyGameObjectsJobHandle = job.Schedule(_transformAccessArray);
_moveEnemyGameObjectsJobHandle.Complete();
moved.Dispose();
forwardDirections.Dispose();
}
public TileInfo GetTileAt(int x, int y)
{
return x > -1 && y > -1 && x < _gridWidth && y < _gridHeight ? _tileInfos[x, y] : null;
}
public TileInfo[] GetTilesFromRadius(int x, int y, int offset, int minOffset = 0)
{
List<TileInfo> tileInfos = new List<TileInfo>();
int startingX = x - offset;
int endingX = x + offset;
int startingY = y - offset;
int endingY = y + offset;
TileInfo currentTile;
for (int posX = startingX; posX <= endingX; posX++)
{
for (int posY = startingY; posY <= endingY; posY++)
{
if (posY > y - minOffset && posY < y + minOffset && posX > x - minOffset && posX < x + minOffset)
{
continue;
}
currentTile = GetTileAt(posX, posY);
if (currentTile != null)
{
tileInfos.Add(currentTile);
}
}
}
return tileInfos.ToArray();
}
public TileInfo[] GetTilesFromTriangle(float2 origin, float2 forwardVector, float length, int offset)
{
List<TileInfo> tileInfos = new List<TileInfo>();
float2 perpendicularVector = new float2(-forwardVector.y, forwardVector.x) * 0.5f;
TileInfo currentTile;
for (int currentLength = -offset; currentLength <= length + offset; currentLength++)
{
float2 currentCenterPosition = origin + forwardVector * currentLength;
for (int currentWidth = 0; currentWidth <= currentLength + offset; currentWidth++)
{
float2 currentOffsetPosition = currentCenterPosition + perpendicularVector * currentWidth;
currentTile = GetTileAt((int)currentOffsetPosition.x, (int)currentOffsetPosition.y);
if (currentTile != null && !tileInfos.Contains(currentTile))
{
tileInfos.Add(currentTile);
}
currentOffsetPosition = currentCenterPosition - perpendicularVector * currentWidth;
currentTile = GetTileAt((int)currentOffsetPosition.x, (int)currentOffsetPosition.y);
if (currentTile != null && !tileInfos.Contains(currentTile))
{
tileInfos.Add(currentTile);
}
}
}
return tileInfos.ToArray();
}
public TileInfo[] GetTilesFromRay(float2 origin, float2 forwardVector, float length, float width, int offset)
{
List<TileInfo> tileInfos = new List<TileInfo>();
float2 perpendicularVector = new float2(-forwardVector.y, forwardVector.x) * 0.5f;
TileInfo currentTile;
for (int currentLength = -offset; currentLength <= length + offset; currentLength++)
{
float2 currentCenterPosition = origin + forwardVector * currentLength;
for (int currentWidth = 0; currentWidth <= width + offset; currentWidth++)
{
float2 currentOffsetPosition = currentCenterPosition + perpendicularVector * currentWidth;
currentTile = GetTileAt((int)currentOffsetPosition.x, (int)currentOffsetPosition.y);
if (currentTile != null && !tileInfos.Contains(currentTile))
{
tileInfos.Add(currentTile);
}
currentOffsetPosition = currentCenterPosition - perpendicularVector * currentWidth;
currentTile = GetTileAt((int)currentOffsetPosition.x, (int)currentOffsetPosition.y);
if (currentTile != null && !tileInfos.Contains(currentTile))
{
tileInfos.Add(currentTile);
}
}
}
return tileInfos.ToArray();
}
private void OnCharacterDied()
{
_uiModule.ShowView(typeof(GameOverPrompt), EViewLayer.Prompt);
BaseEvent<GamePausedEvent>.Raise(new GamePausedEvent(true));
}
#if CHEATS_ACTIVE
private void DisplayPlayerPosition()
{
if(!_cheats.IsDebugChunkInfoEnabled) return;
Vector3 playerPosition = _playerTransform.position;
string chunkName = _chunkNames[(int)playerPosition.x / GridConfiguration.ChunkWidth, (int)playerPosition.z / GridConfiguration.ChunkHeight];
string debugInfo =
$"{chunkName} Position {(int)playerPosition.x % GridConfiguration.ChunkWidth} - {(int)playerPosition.z % GridConfiguration.ChunkHeight}";
_uiModule.GetView<HudScreen>().UpdateDebugInfo(debugInfo);
}
#endif
#endregion Methods
}
}