From 3d35e125bac6aca342d3b35140e0ee28eb97d29e Mon Sep 17 00:00:00 2001 From: Lucas Coelho <58010418+LucasVinicius314@users.noreply.github.com> Date: Thu, 27 Oct 2022 13:58:23 -0300 Subject: [PATCH] Spawn de inimigos segmentado por dificuldade, sistema de spawn mais completo --- Assets/Prefabs/Canvas.prefab | 164 +++++++++++++++++++- Assets/Scenes/MainScene.unity | 85 +++++++++- Assets/Scripts/GameManagerScript.cs | 88 +++-------- Assets/Scripts/Models/EnemySpawnSettings.cs | 11 +- Assets/Scripts/PlayerScript.cs | 2 + Assets/Scripts/RoomScript.cs | 79 ++++++++++ Assets/Scripts/StatsScript.cs | 10 ++ 7 files changed, 360 insertions(+), 79 deletions(-) diff --git a/Assets/Prefabs/Canvas.prefab b/Assets/Prefabs/Canvas.prefab index 6d845e6..c07f291 100644 --- a/Assets/Prefabs/Canvas.prefab +++ b/Assets/Prefabs/Canvas.prefab @@ -3557,6 +3557,86 @@ MonoBehaviour: m_VerticalOverflow: 0 m_LineSpacing: 1 m_Text: Dano +--- !u!1 &5786165326313048569 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9129343121021219635} + - component: {fileID: 3850002207610289737} + - component: {fileID: 6943966996809970594} + m_Layer: 0 + m_Name: Difficulty + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9129343121021219635 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5786165326313048569} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6541826974359309613} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3850002207610289737 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5786165326313048569} + m_CullTransparentMesh: 1 +--- !u!114 &6943966996809970594 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5786165326313048569} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 12800000, guid: 0e446559229638f448d0706b0656bbe0, type: 3} + m_FontSize: 12 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 0 --- !u!1 &5941958435114552132 GameObject: m_ObjectHideFlags: 0 @@ -3670,6 +3750,86 @@ RectTransform: m_AnchoredPosition: {x: -5, y: 0} m_SizeDelta: {x: -20, y: 0} m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &6624794674392374493 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 846873939859871888} + - component: {fileID: 2762014832840752568} + - component: {fileID: 4684092489768213349} + m_Layer: 0 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &846873939859871888 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6624794674392374493} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6541826974359309613} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2762014832840752568 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6624794674392374493} + m_CullTransparentMesh: 1 +--- !u!114 &4684092489768213349 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6624794674392374493} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 12800000, guid: 0e446559229638f448d0706b0656bbe0, type: 3} + m_FontSize: 12 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Dificuldade atual --- !u!1 &7334273576904498236 GameObject: m_ObjectHideFlags: 0 @@ -3940,13 +4100,15 @@ RectTransform: - {fileID: 7463554454055162917} - {fileID: 7482012678611493145} - {fileID: 4213524155332047350} + - {fileID: 846873939859871888} + - {fileID: 9129343121021219635} m_Father: {fileID: 2932101239374365858} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} m_AnchoredPosition: {x: 80, y: -200} - m_SizeDelta: {x: 180, y: 180} + m_SizeDelta: {x: 180, y: 240} m_Pivot: {x: 0, y: 1} --- !u!222 &8980498674201781340 CanvasRenderer: diff --git a/Assets/Scenes/MainScene.unity b/Assets/Scenes/MainScene.unity index e2ca601..f8c1de6 100644 --- a/Assets/Scenes/MainScene.unity +++ b/Assets/Scenes/MainScene.unity @@ -700,22 +700,45 @@ MonoBehaviour: - {fileID: 4026393600238520495, guid: 4f847d9983c9b47469670e627d94626e, type: 3} enemySpawnSettings: isEnemySpawnEnabled: 1 + difficultyIndexWeight: 1 + difficultyCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: -0.017335435 + value: 0.99400204 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 16.033 + value: 10.165251 + inSlope: 0.54586494 + outSlope: 0.54586494 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.15172148 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 spawnBatchSize: 2 - spawnInterval: 10 - maxEnemiesAlive: 5 + bossPrefab: {fileID: 2422363816341469345, guid: d1a345f2a0f822246a75854118660aab, type: 3} enemyPrefabs: - {fileID: 2422363816341469345, guid: 878f06b5ada303f47b84bdd84f0d4917, type: 3} - {fileID: 2422363816341469345, guid: d8fc18198181de64a9748ac34ed8bbd3, type: 3} - - {fileID: 2422363816341469345, guid: d1a345f2a0f822246a75854118660aab, type: 3} enemyDropSettings: enableDrops: 1 enemyDrops: - prefab: {fileID: 3578579234224482949, guid: 69c28c34c6fbeeb4b91ecb764913c032, type: 3} chance: 0.11 - prefab: {fileID: 4227791301383778845, guid: e5b6e2820f4646d44bf2868c20e6048e, type: 3} - chance: 0.071 + chance: 0.25 - prefab: {fileID: 6724353180413059161, guid: f1a5ddd8653b52941b34911e403e9c05, type: 3} - chance: 0.069 + chance: 0.24 isNavMeshBaked: 0 currentRoom: {fileID: 0} --- !u!114 &1524951598 @@ -1089,6 +1112,10 @@ PrefabInstance: propertyPath: m_Mesh value: objectReference: {fileID: 764316535} + - target: {fileID: 4026393600420885624, guid: b9519a0483ddad14d827540255bc2c9f, type: 3} + propertyPath: m_VersionIndex + value: 5318 + objectReference: {fileID: 0} - target: {fileID: 4026393600420885628, guid: b9519a0483ddad14d827540255bc2c9f, type: 3} propertyPath: m_Mesh value: @@ -1305,6 +1332,30 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 846873939859871888, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 846873939859871888, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 846873939859871888, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 846873939859871888, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 846873939859871888, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 846873939859871888, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} - target: {fileID: 887981261800075050, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -1945,6 +1996,30 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 9129343121021219635, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9129343121021219635, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9129343121021219635, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9129343121021219635, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9129343121021219635, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9129343121021219635, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} - target: {fileID: 9148812110294212001, guid: 3b586217a958dcd42976ca69ca9e3ed3, type: 3} propertyPath: m_AnchorMax.y value: 0 diff --git a/Assets/Scripts/GameManagerScript.cs b/Assets/Scripts/GameManagerScript.cs index 9aa2b1f..05981cd 100644 --- a/Assets/Scripts/GameManagerScript.cs +++ b/Assets/Scripts/GameManagerScript.cs @@ -26,6 +26,7 @@ public class GameManagerScript : MonoBehaviour MinimapScript? minimapScript; RoomNetwork roomNetwork = new RoomNetwork(); List enemies = new List(); + HashSet visitedRooms = new HashSet(); // State. MenuState menuState = MenuState.closed; @@ -36,6 +37,7 @@ public class GameManagerScript : MonoBehaviour // Getters de state. public MenuState GetMenuState => menuState; public ControlState GetControlState => controlState; + public List GetEnemies => enemies; // Getters de tipo primitivo. public string GetTargetControlScheme => controlState == ControlState.keyboard @@ -52,6 +54,23 @@ public class GameManagerScript : MonoBehaviour public EnemySpawnSettings GetEnemySpawnSettings => enemySpawnSettings; public EnemyDropSettings GetEnemyDropSettings => enemyDropSettings; + public void AttemptEnemySpawn() + { + // TODO: Terminar spawn do boss + + if (currentRoom == null || visitedRooms.Contains(currentRoom)) + { + return; + } + + visitedRooms.Add(currentRoom); + + if (enemySpawnSettings.isEnemySpawnEnabled) + { + currentRoom.GetComponent()?.SpawnEnemies(); + } + } + public void BakeNavMesh() { GetComponent().BuildNavMesh(); @@ -131,70 +150,6 @@ public void KillEnemy(GameObject enemy) Destroy(enemy); } - System.Collections.IEnumerator SpawnLoop() - { - while (true) - { - if (enemySpawnSettings.isEnemySpawnEnabled && - enemies.Count < enemySpawnSettings.maxEnemiesAlive) - { - for (int i = 0; i < enemySpawnSettings.spawnBatchSize; i++) - { - var prefab = enemySpawnSettings.GetRandomEnemyPrefab(); - - var tries = 0; - - while (true) - { - tries++; - - // Sistema de segurança para não cair em loop. - if (tries > 10) - { - break; - } - - var vector2 = Random.insideUnitCircle * 10f; - - var position = new Vector3(x: vector2.x, y: 4f, z: vector2.y); - - RaycastHit hit; - if ( - !Physics.Raycast( - position, - Vector3.down, - out hit, - 10f, - Layers.geometryMask - ) - ) - { - continue; - } - - // Não deixar o inimigo spawnar em cima de paredes. - if (hit.point.y > 1f) - { - continue; - } - - var enemy = Instantiate( - prefab, - hit.point, - Quaternion.identity - ); - - enemies.Add(enemy); - - break; - } - } - } - - yield return new WaitForSeconds(enemySpawnSettings.spawnInterval); - } - } - void Awake() { instance = this; @@ -215,11 +170,6 @@ void OnGUI() GUI.Label(new Rect(100, 36, 100, 20), $"Enemies alive: {enemies.Count}"); } - void Start() - { - StartCoroutine(SpawnLoop()); - } - void Update() { #if UNITY_EDITOR diff --git a/Assets/Scripts/Models/EnemySpawnSettings.cs b/Assets/Scripts/Models/EnemySpawnSettings.cs index 225dcf5..9a5f663 100644 --- a/Assets/Scripts/Models/EnemySpawnSettings.cs +++ b/Assets/Scripts/Models/EnemySpawnSettings.cs @@ -6,14 +6,17 @@ [System.Serializable] public class EnemySpawnSettings { + [Header("General spawn settings")] public bool isEnemySpawnEnabled; + [Min(0f)] + public float difficultyIndexWeight = 1f; + public AnimationCurve difficultyCurve = default!; + + [Header("Room spawn settings")] [Min(1)] public int spawnBatchSize; - [Min(1f)] - public float spawnInterval; - [Min(1)] - public int maxEnemiesAlive = 5; + public GameObject bossPrefab = default!; public List enemyPrefabs = default!; public GameObject GetRandomEnemyPrefab() diff --git a/Assets/Scripts/PlayerScript.cs b/Assets/Scripts/PlayerScript.cs index 1941170..f585d6e 100644 --- a/Assets/Scripts/PlayerScript.cs +++ b/Assets/Scripts/PlayerScript.cs @@ -80,6 +80,8 @@ public void CalculatePath(bool isFirstRender) // Atualiza a sala atual. manager.currentRoom = parent.gameObject; + manager.AttemptEnemySpawn(); + // Verifica se faz sentido procurar um caminho. if (manager.currentRoom != null && network.bossRoom != null) { diff --git a/Assets/Scripts/RoomScript.cs b/Assets/Scripts/RoomScript.cs index d337064..93cf493 100644 --- a/Assets/Scripts/RoomScript.cs +++ b/Assets/Scripts/RoomScript.cs @@ -10,6 +10,7 @@ public class RoomScript : MonoBehaviour [SerializeField] Vector3 dimensions; + public float difficultyIndex = 0f; public RoomType roomType; public Vector3 GetDimensions => dimensions; @@ -227,6 +228,84 @@ bool IsRoomPlacementAvailable(Vector3 checkArea, Transform origin) ); } + public void SpawnEnemies() + { + var manager = GameManagerScript.instance; + var settings = manager.GetEnemySpawnSettings; + + var batchSize = + settings.spawnBatchSize * + settings.difficultyIndexWeight * + settings.difficultyCurve.Evaluate(difficultyIndex / 20); + + StatsScript.instance.UpdateDifficulty(difficultyIndex); + + Debug.Log( + $"Current room difficulty: {difficultyIndex}: {batchSize} enemies." + ); + + for (int i = 0; i < batchSize; i++) + { + var prefab = settings.GetRandomEnemyPrefab(); + + var tries = 0; + + while (true) + { + tries++; + + // Sistema de segurança para não cair em loop. + if (tries > 10) + { + break; + } + + var vector2 = Random.insideUnitCircle * 10f; + + var position = new Vector3( + x: vector2.x + transform.position.x, + y: 4f, + z: vector2.y + transform.position.z + ); + + RaycastHit hit; + if ( + !Physics.Raycast( + position, + Vector3.down, + out hit, + 10f, + Layers.geometryMask + ) + ) + { + continue; + } + + // Não deixar o inimigo spawnar em cima de paredes. + if (hit.point.y > 1f) + { + continue; + } + + var enemy = Instantiate( + prefab, + hit.point, + Quaternion.identity + ); + + manager.GetEnemies.Add(enemy); + + break; + } + } + } + + void Awake() + { + difficultyIndex = transform.position.magnitude; + } + void Start() { if (isRoot) diff --git a/Assets/Scripts/StatsScript.cs b/Assets/Scripts/StatsScript.cs index c8e0571..be7e68e 100644 --- a/Assets/Scripts/StatsScript.cs +++ b/Assets/Scripts/StatsScript.cs @@ -8,9 +8,18 @@ public class StatsScript : MonoBehaviour Text? damageText; Text? movementSpeedText; Text? attackRangeText; + Text? difficultyText; public static StatsScript instance = default!; + public void UpdateDifficulty(float difficulty) + { + if (difficultyText != null) + { + difficultyText.text = difficulty.ToString("0.00"); + } + } + public void UpdateStats(PlayerBuffs buffs) { if (damageText != null) @@ -42,5 +51,6 @@ void Awake() damageText = transform.Find("Damage").GetComponent(); movementSpeedText = transform.Find("MovementSpeed").GetComponent(); attackRangeText = transform.Find("AttackRange").GetComponent(); + difficultyText = transform.Find("Difficulty").GetComponent(); } }