Untitled
unknown
csharp
2 years ago
40 kB
1
Indexable
Never
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 } }