diff --git a/Assets/Prefabs/Enemy_Normalo_1.prefab b/Assets/Prefabs/Enemy_Normalo_1.prefab new file mode 100644 index 0000000..f5cb1f1 --- /dev/null +++ b/Assets/Prefabs/Enemy_Normalo_1.prefab @@ -0,0 +1,156 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &963950361395072142 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2624890028258028658} + - component: {fileID: 4917318433241158522} + m_Layer: 0 + m_Name: Visual + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2624890028258028658 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963950361395072142} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 0.1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7507418902231499228} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!212 &4917318433241158522 +SpriteRenderer: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963950361395072142} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_Sprite: {fileID: -1147401495359466748, guid: bf9e1b36ade7f184c9f2bb5ff43766d8, type: 3} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 5.5200005, y: 4.7900004} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_SpriteSortPoint: 0 +--- !u!1 &3945524959569760868 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7507418902231499228} + - component: {fileID: 1432882644105522118} + - component: {fileID: 6605916074464269859} + m_Layer: 0 + m_Name: Enemy_Normalo_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7507418902231499228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3945524959569760868} + serializedVersion: 2 + 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: + - {fileID: 2624890028258028658} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1432882644105522118 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3945524959569760868} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 544fe3d5f687b6b4bbe68d79ffb11bd8, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Enemy + moveSpeed: 0.5 + targetReachedDistance: 0.1 +--- !u!114 &6605916074464269859 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3945524959569760868} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bea87a19f3a99294c9d065a24307484c, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::CharacterRotation + visual: {fileID: 2624890028258028658} + rotationSpeed: 540 + spriteForward: 0 diff --git a/Assets/Prefabs/Enemy_Normalo_1.prefab.meta b/Assets/Prefabs/Enemy_Normalo_1.prefab.meta new file mode 100644 index 0000000..64a713d --- /dev/null +++ b/Assets/Prefabs/Enemy_Normalo_1.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c790a7c672d8c0444b96deb42e30a12e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Enemy_Normalo_2.prefab b/Assets/Prefabs/Enemy_Normalo_2.prefab new file mode 100644 index 0000000..f043dc2 --- /dev/null +++ b/Assets/Prefabs/Enemy_Normalo_2.prefab @@ -0,0 +1,156 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1615185670323454042 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5225492181148914658} + - component: {fileID: 3695634402165062136} + - component: {fileID: 8865324250001949725} + m_Layer: 0 + m_Name: Enemy_Normalo_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5225492181148914658 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1615185670323454042} + serializedVersion: 2 + 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: + - {fileID: 344071642872381004} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3695634402165062136 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1615185670323454042} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 544fe3d5f687b6b4bbe68d79ffb11bd8, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Enemy + moveSpeed: 0.5 + targetReachedDistance: 0.1 +--- !u!114 &8865324250001949725 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1615185670323454042} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bea87a19f3a99294c9d065a24307484c, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::CharacterRotation + visual: {fileID: 344071642872381004} + rotationSpeed: 540 + spriteForward: 0 +--- !u!1 &3299937292263202480 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 344071642872381004} + - component: {fileID: 7248204723082772804} + m_Layer: 0 + m_Name: Visual + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &344071642872381004 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3299937292263202480} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 0.1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 5225492181148914658} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!212 &7248204723082772804 +SpriteRenderer: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3299937292263202480} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_Sprite: {fileID: 8414478535512612329, guid: bf9e1b36ade7f184c9f2bb5ff43766d8, type: 3} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 5.5200005, y: 4.7900004} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_SpriteSortPoint: 0 diff --git a/Assets/Prefabs/Enemy_Normalo_2.prefab.meta b/Assets/Prefabs/Enemy_Normalo_2.prefab.meta new file mode 100644 index 0000000..5a50e05 --- /dev/null +++ b/Assets/Prefabs/Enemy_Normalo_2.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d3be444575f6f5e47a1e7c90c7980c37 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Ingame.unity b/Assets/Scenes/Ingame.unity index a18e8ae..d3d1c2c 100644 --- a/Assets/Scenes/Ingame.unity +++ b/Assets/Scenes/Ingame.unity @@ -406,10 +406,25 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: eed070947de809f4d9fd7c87e1d9b1c3, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::EnemySpawner - enemyPrefab: {fileID: 3165014998622512207, guid: 0207a46e09507294d8f11a13eb2fa830, type: 3} + enemyTypes: + - prefabVariants: + - {fileID: 3945524959569760868, guid: c790a7c672d8c0444b96deb42e30a12e, type: 3} + - {fileID: 1615185670323454042, guid: d3be444575f6f5e47a1e7c90c7980c37, type: 3} + spawnChance: 10 + danger: 1 + enemyDifficulty: 3 spawnPoint: {fileID: 611220645} - minSpawnDelay: 0.5 - maxSpawnDelay: 2 + raiseRate: 0.1 + difficultyRaise: 0 + difficulty: 0 + startDelay: 3 + minBreak: 4 + maxBreak: 7 + spawnDelay: 0.5 + minGroupBreak: 1 + maxGroupBreak: 2 + minGroup: 2 + maxGroup: 7 --- !u!4 &611220645 Transform: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/Enemy.cs b/Assets/Scripts/Enemy.cs index 3abce4b..52c49ad 100644 --- a/Assets/Scripts/Enemy.cs +++ b/Assets/Scripts/Enemy.cs @@ -4,7 +4,7 @@ public class Enemy : MonoBehaviour, IMovementDirection { [Header("Movement")] [SerializeField] - private float moveSpeed = 2f; + private float moveSpeed = 0.5f; [SerializeField] private float targetReachedDistance = 0.1f; diff --git a/Assets/Scripts/EnemySpawner.cs b/Assets/Scripts/EnemySpawner.cs index e1d336b..e8ee80b 100644 --- a/Assets/Scripts/EnemySpawner.cs +++ b/Assets/Scripts/EnemySpawner.cs @@ -1,34 +1,57 @@ using System.Collections; +using System.Collections.Generic; using UnityEngine; public class EnemySpawner : MonoBehaviour { - [Header("Enemy")] - [SerializeField] - private GameObject enemyPrefab; + [System.Serializable] + public class EnemyTypeData + { + [Header("Enemy Prefabs")] + public List prefabVariants = new List(); - [Header("Spawn")] - [SerializeField] - private Transform spawnPoint; + [Header("Spawn Selection")] + [Min(0)] + public int spawnChance = 10; - [SerializeField] - private float minSpawnDelay = 0.5f; + public float danger = 0f; - [SerializeField] - private float maxSpawnDelay = 2f; + [Min(0)] + public int enemyDifficulty = 1; + } + + [Header("Enemy Types")] + public List enemyTypes = new List(); + + [Header("Spawn Point")] + public Transform spawnPoint; + + [Header("Difficulty")] + public float raiseRate = 0.1f; + public float difficultyRaise = 0f; + public float difficulty = 0f; + + [Header("Initial Spawn")] + public float startDelay = 5f; + + [Header("Failed Spawn Break")] + public float minBreak = 3f; + public float maxBreak = 7f; + + [Header("Group Spawn")] + public float spawnDelay = 0.5f; + public float minGroupBreak = 2f; + public float maxGroupBreak = 5f; + + public int minGroup = 2; + public int maxGroup = 5; + + private float tempDifficulty; + private bool hasSpawnedGroupThisCycle = false; + private bool pauseDifficultyGrowth = false; private void Start() { - if (enemyPrefab == null) - { - Debug.LogError( - "EnemySpawner: Kein Enemy-Prefab zugewiesen!", - this - ); - - return; - } - if (spawnPoint == null) { Debug.LogError( @@ -36,33 +59,362 @@ public class EnemySpawner : MonoBehaviour this ); + enabled = false; + return; + } + + if (!HasUsableEnemyType()) + { + Debug.LogError( + "EnemySpawner: Keine gültigen Gegnertypen vorhanden!", + this + ); + + enabled = false; return; } StartCoroutine(SpawnLoop()); } + private void Update() + { + // Freischaltschwelle wächst immer weiter. + difficultyRaise += raiseRate * Time.deltaTime; + + // Budget wächst nur, wenn es nicht pausiert ist. + if (!pauseDifficultyGrowth) + { + difficulty += difficultyRaise * Time.deltaTime; + } + Debug.Log("DifficultyRaise: " + difficultyRaise + " und Difficulty: " + difficulty); + } + private IEnumerator SpawnLoop() { + // Einmalige Wartezeit beim Spielstart. + yield return new WaitForSeconds( + Mathf.Max(0f, startDelay) + ); + while (true) { - float delay = UnityEngine.Random.Range( - minSpawnDelay, - maxSpawnDelay + // Neuer Zyklus beginnt. + hasSpawnedGroupThisCycle = false; + + while (true) + { + List group; + float resultingDifficulty; + + bool groupCanSpawn = TryBuildGroup( + out group, + out resultingDifficulty + ); + + // Keine gültige Gruppe möglich: + // Der aktuelle Zyklus endet. + if (!groupCanSpawn) + { + pauseDifficultyGrowth = false; + break; + } + + // Nur zwischen Gruppen desselben Zyklus warten. + if (hasSpawnedGroupThisCycle) + { + pauseDifficultyGrowth = true; + + yield return new WaitForSeconds( + GetRandomDelay(minGroupBreak, maxGroupBreak) + ); + } + + // Budget während des tatsächlichen Gruppenspawns + // ebenfalls einfrieren. + pauseDifficultyGrowth = true; + + for (int i = 0; i < group.Count; i++) + { + SpawnEnemy(group[i]); + + if (i < group.Count - 1) + { + yield return new WaitForSeconds( + Mathf.Max(0f, spawnDelay) + ); + } + } + + difficulty = resultingDifficulty; + + // Ab jetzt darf eine weitere Gruppe in diesem + // Zyklus erst nach einer GroupBreak spawnen. + hasSpawnedGroupThisCycle = true; + + // Budget nach dem Gruppenspawn wieder freigeben. + pauseDifficultyGrowth = false; + } + + // Zyklus beendet: normale Pause, während der das + // Budget weiterwachsen darf. + pauseDifficultyGrowth = false; + + yield return new WaitForSeconds( + GetRandomDelay(minBreak, maxBreak) ); - - yield return new WaitForSeconds(delay); - - SpawnEnemy(); } } - private void SpawnEnemy() + private bool TryBuildGroup( + out List group, + out float resultingDifficulty) { - Instantiate( - enemyPrefab, + group = new List(); + resultingDifficulty = difficulty; + + // Nur freigeschaltete Gegnertypen berücksichtigen. + // Die Budgetkosten werden hier noch NICHT gefiltert. + List availableEnemies = + GetAvailableEnemies(); + + if (availableEnemies.Count == 0) + { + return false; + } + + int targetGroupSize = Random.Range( + minGroup, + maxGroup + 1 + ); + + tempDifficulty = difficulty; + + for (int i = 0; i < targetGroupSize; i++) + { + // Auswahl ausschließlich anhand von spawnChance. + EnemyTypeData selectedEnemy = + ChooseWeightedEnemy(availableEnemies); + + if (selectedEnemy == null) + { + return false; + } + + // Kosten des ausgewählten Gegners abziehen. + tempDifficulty -= selectedEnemy.enemyDifficulty; + + if (tempDifficulty < 0f) + { + // D2: Die bisherigen Gegner reichen bereits + // für die Mindestgruppengröße. + if (group.Count >= minGroup) + { + // Die Kosten des abgelehnten Gegners + // wieder hinzurechnen. + resultingDifficulty = + tempDifficulty + + selectedEnemy.enemyDifficulty; + + return true; + } + + // D3: Mindestgruppengröße nicht erreicht. + // Nichts spawnen und Budget nicht verändern. + return false; + } + + // Der Gegner passt ins Budget und wird vorgemerkt. + group.Add(selectedEnemy); + } + + // D1: Die gewünschte Gruppengröße wurde erreicht. + resultingDifficulty = tempDifficulty; + + return true; + } + + private List GetAvailableEnemies() + { + List available = + new List(); + + foreach (EnemyTypeData enemy in enemyTypes) + { + if (enemy == null) + { + continue; + } + + if (enemy.danger > difficultyRaise) + { + continue; + } + + if (enemy.spawnChance <= 0) + { + continue; + } + + if (enemy.enemyDifficulty < 0) + { + continue; + } + + if (enemy.prefabVariants == null || + enemy.prefabVariants.Count == 0) + { + continue; + } + + bool hasValidPrefab = false; + + foreach (GameObject prefab in enemy.prefabVariants) + { + if (prefab != null) + { + hasValidPrefab = true; + break; + } + } + + if (hasValidPrefab) + { + available.Add(enemy); + } + } + + return available; + } + + private EnemyTypeData ChooseWeightedEnemy( + List availableEnemies) + { + int totalWeight = 0; + + foreach (EnemyTypeData enemy in availableEnemies) + { + totalWeight += enemy.spawnChance; + } + + if (totalWeight <= 0) + { + return null; + } + + int roll = Random.Range(1, totalWeight + 1); + int cumulativeWeight = 0; + + foreach (EnemyTypeData enemy in availableEnemies) + { + cumulativeWeight += enemy.spawnChance; + + if (roll <= cumulativeWeight) + { + return enemy; + } + } + + return null; + } + + private void SpawnEnemy(EnemyTypeData enemy) + { + List validPrefabs = new List(); + + foreach (GameObject prefab in enemy.prefabVariants) + { + if (prefab != null) + { + validPrefabs.Add(prefab); + } + } + + if (validPrefabs.Count == 0) + { + Debug.LogError( + "EnemySpawner: Keine gültige Prefabvariante vorhanden!", + this + ); + + return; + } + + // Zufällige Prefabvariante wählen. + int prefabIndex = Random.Range(0, validPrefabs.Count); + GameObject selectedPrefab = validPrefabs[prefabIndex]; + + GameObject spawnedEnemy = Instantiate( + selectedPrefab, spawnPoint.position, spawnPoint.rotation ); + + // Das Sprite hat eine 50-prozentige Chance, + // vertikal gespiegelt zu werden. + SpriteRenderer spriteRenderer = + spawnedEnemy.GetComponentInChildren(); + + if (spriteRenderer != null) + { + spriteRenderer.flipX = Random.value < 0.5f; + } } -} + + private bool HasUsableEnemyType() + { + return GetAvailableEnemies().Count > 0 || + HasAnyConfiguredEnemy(); + } + + private bool HasAnyConfiguredEnemy() + { + foreach (EnemyTypeData enemy in enemyTypes) + { + if (enemy == null || enemy.spawnChance <= 0) + { + continue; + } + + if (enemy.prefabVariants == null) + { + continue; + } + + foreach (GameObject prefab in enemy.prefabVariants) + { + if (prefab != null) + { + return true; + } + } + } + + return false; + } + + private float GetRandomDelay(float min, float max) + { + min = Mathf.Max(0f, min); + max = Mathf.Max(0f, max); + + if (max < min) + { + float temp = min; + min = max; + max = temp; + } + + return Random.Range(min, max); + } + + private void OnValidate() + { + raiseRate = Mathf.Max(0f, raiseRate); + startDelay = Mathf.Max(0f, startDelay); + spawnDelay = Mathf.Max(0f, spawnDelay); + + minGroup = Mathf.Max(1, minGroup); + maxGroup = Mathf.Max(minGroup, maxGroup); + } +} \ No newline at end of file diff --git a/Assets/Scripts/OLD_EnemySpawner.cs b/Assets/Scripts/OLD_EnemySpawner.cs new file mode 100644 index 0000000..716aa13 --- /dev/null +++ b/Assets/Scripts/OLD_EnemySpawner.cs @@ -0,0 +1,68 @@ +using System.Collections; +using UnityEngine; + +public class OLD_EnemySpawner : MonoBehaviour +{ + [Header("Enemy")] + [SerializeField] + private GameObject enemyPrefab; + + [Header("Spawn")] + [SerializeField] + private Transform spawnPoint; + + [SerializeField] + private float minSpawnDelay = 0.5f; + + [SerializeField] + private float maxSpawnDelay = 2f; + + private void Start() + { + if (enemyPrefab == null) + { + Debug.LogError( + "EnemySpawner: Kein Enemy-Prefab zugewiesen!", + this + ); + + return; + } + + if (spawnPoint == null) + { + Debug.LogError( + "EnemySpawner: Kein SpawnPoint zugewiesen!", + this + ); + + return; + } + + StartCoroutine(SpawnLoop()); + } + + private IEnumerator SpawnLoop() + { + while (true) + { + float delay = UnityEngine.Random.Range( + minSpawnDelay, + maxSpawnDelay + ); + + yield return new WaitForSeconds(delay); + + SpawnEnemy(); + } + } + + private void SpawnEnemy() + { + Instantiate( + enemyPrefab, + spawnPoint.position, + spawnPoint.rotation + ); + } +} diff --git a/Assets/Scripts/OLD_EnemySpawner.cs.meta b/Assets/Scripts/OLD_EnemySpawner.cs.meta new file mode 100644 index 0000000..58f83f6 --- /dev/null +++ b/Assets/Scripts/OLD_EnemySpawner.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f8b6d72d4e53e5d4cb31ba8ec6903a94 \ No newline at end of file diff --git a/Assets/Sprites.meta b/Assets/Sprites.meta new file mode 100644 index 0000000..a3f8b0f --- /dev/null +++ b/Assets/Sprites.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7a79100defbbf2841b6a260f042b6539 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Sprites/Enemies.png b/Assets/Sprites/Enemies.png new file mode 100644 index 0000000..0916253 Binary files /dev/null and b/Assets/Sprites/Enemies.png differ diff --git a/Assets/Sprites/Enemies.png.meta b/Assets/Sprites/Enemies.png.meta new file mode 100644 index 0000000..cbc7510 --- /dev/null +++ b/Assets/Sprites/Enemies.png.meta @@ -0,0 +1,403 @@ +fileFormatVersion: 2 +guid: bf9e1b36ade7f184c9f2bb5ff43766d8 +TextureImporter: + internalIDToNameTable: + - first: + 213: 2192450021786810173 + second: Enemies_0 + - first: + 213: -7537196482120660328 + second: Enemies_1 + - first: + 213: -860468679390908754 + second: Enemies_2 + - first: + 213: -7945901444079236628 + second: Enemies_3 + - first: + 213: -8421458170528590454 + second: Enemies_4 + - first: + 213: -1147401495359466748 + second: Enemies_5 + - first: + 213: 8414478535512612329 + second: Enemies_6 + - first: + 213: 3714015224569861163 + second: Enemies_7 + - first: + 213: -7844560889915226194 + second: Enemies_8 + - first: + 213: 4326287474489854147 + second: Enemies_9 + - first: + 213: 7877921557971618100 + second: Enemies_10 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 0 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 2 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: Enemies_0 + rect: + serializedVersion: 2 + x: 50 + y: 2815 + width: 17 + height: 17 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: d377660cda52d6e10800000000000000 + internalID: 2192450021786810173 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: Enemies_1 + rect: + serializedVersion: 2 + x: 74 + y: 2570 + width: 434 + height: 377 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 89acfd8bbbf766790800000000000000 + internalID: -7537196482120660328 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: Enemies_2 + rect: + serializedVersion: 2 + x: 785 + y: 2821 + width: 17 + height: 17 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: eae2e888b400f04f0800000000000000 + internalID: -860468679390908754 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: Enemies_3 + rect: + serializedVersion: 2 + x: 816 + y: 2567 + width: 399 + height: 407 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: ce9c46d5cbc7ab190800000000000000 + internalID: -7945901444079236628 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: Enemies_4 + rect: + serializedVersion: 2 + x: 2502 + y: 2763 + width: 41 + height: 107 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: a8515d6a968f02b80800000000000000 + internalID: -8421458170528590454 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: Enemies_5 + rect: + serializedVersion: 2 + x: 1438 + y: 2047 + width: 552 + height: 479 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 403d85e4b6c9310f0800000000000000 + internalID: -1147401495359466748 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: Enemies_6 + rect: + serializedVersion: 2 + x: 2192 + y: 2043 + width: 552 + height: 497 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 9edd06f65ab36c470800000000000000 + internalID: 8414478535512612329 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: Enemies_7 + rect: + serializedVersion: 2 + x: 70 + y: 1294 + width: 854 + height: 455 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: b2411e64b25da8330800000000000000 + internalID: 3714015224569861163 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: Enemies_8 + rect: + serializedVersion: 2 + x: 1356 + y: 1291 + width: 879 + height: 499 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: ea74ea1de65822390800000000000000 + internalID: -7844560889915226194 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: Enemies_9 + rect: + serializedVersion: 2 + x: 532 + y: 173 + width: 893 + height: 761 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 3c88031598f0a0c30800000000000000 + internalID: 4326287474489854147 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: Enemies_10 + rect: + serializedVersion: 2 + x: 1853 + y: 127 + width: 893 + height: 761 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 4394a4ffaeff35d60800000000000000 + internalID: 7877921557971618100 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + Enemies_0: 2192450021786810173 + Enemies_1: -7537196482120660328 + Enemies_10: 7877921557971618100 + Enemies_2: -860468679390908754 + Enemies_3: -7945901444079236628 + Enemies_4: -8421458170528590454 + Enemies_5: -1147401495359466748 + Enemies_6: 8414478535512612329 + Enemies_7: 3714015224569861163 + Enemies_8: -7844560889915226194 + Enemies_9: 4326287474489854147 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TowerdefenseInput.inputactions b/Assets/TowerdefenseInput.inputactions new file mode 100644 index 0000000..5cea94c --- /dev/null +++ b/Assets/TowerdefenseInput.inputactions @@ -0,0 +1,35 @@ +{ + "version": 1, + "name": "TowerdefenseInput", + "maps": [ + { + "name": "Player", + "id": "c99febab-6f3d-4948-ba79-b59537219da5", + "actions": [ + { + "name": "Click", + "type": "Button", + "id": "8433dee6-1018-4487-bfee-30d68a54fc5a", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "", + "id": "43e6b486-791d-4cac-aa62-48779e6b6bb6", + "path": "/leftButton", + "interactions": "", + "processors": "", + "groups": "", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + } + ] + } + ], + "controlSchemes": [] +} \ No newline at end of file diff --git a/Assets/TowerdefenseInput.inputactions.meta b/Assets/TowerdefenseInput.inputactions.meta new file mode 100644 index 0000000..6481b94 --- /dev/null +++ b/Assets/TowerdefenseInput.inputactions.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 52f8fc4522f76b44eba1f2985d511848 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3} + generateWrapperCode: 0 + wrapperCodePath: + wrapperClassName: + wrapperCodeNamespace: