Last active
July 18, 2018 05:17
-
-
Save juliomarcos/e69f103b8a1fb3bbd9eb5c0fd1cbade6 to your computer and use it in GitHub Desktop.
Weighted Enemy Picker / Unity.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.Events; | |
using System.Linq; | |
public enum WaveType { | |
Annihilation, | |
Timed, | |
} | |
[Serializable] | |
public class EnemySpawn { | |
public GameObject prefab; | |
[Range(1, 10)] | |
public int frequency = 1; | |
} | |
[Serializable] | |
public class Wave { | |
public WaveType waveType; | |
public float timeToNextSpawn; | |
public EnemySpawn[] enemies; | |
private EnemyPicker picker; | |
public void Init() { | |
picker = new EnemyPicker(enemies); | |
} | |
public GameObject PickEnemy() { | |
return picker.WeightedPick(); | |
} | |
} | |
class EnemyPicker { | |
private EnemySpawn[] enemies; | |
private int[] weights; | |
private int cumulativeSum; | |
public EnemyPicker(EnemySpawn[] enemies) { | |
this.enemies = enemies; | |
InitWeightsVector(); | |
} | |
public GameObject WeightedPick() { | |
if (enemies.Length == 1) return enemies.First().prefab; | |
int r = UnityEngine.Random.Range(1, cumulativeSum+1); | |
for(int i=0,j=0;;j++) | |
{ | |
i += weights[j]; | |
if (i >= r) return enemies[j].prefab; | |
} | |
} | |
private void InitWeightsVector() | |
{ | |
weights = new int[enemies.Length]; | |
for (int i = 0; i < enemies.Length; i++) | |
{ | |
EnemySpawn enemySpawn = enemies[i]; | |
cumulativeSum += enemySpawn.frequency; | |
weights[i] = cumulativeSum; | |
} | |
} | |
} | |
public class WaveSpawner : MonoBehaviour | |
{ | |
public Transform[] positions; | |
public Wave[] waves; | |
public UnityEvent onEndAllWaves; | |
private int waveIndex; | |
private Transform parent; | |
public void Start() { | |
parent = positions.First().transform; | |
foreach (var wave in waves) { wave.Init(); } | |
SpawnCurrentWave(); | |
StartCoroutine(WaitAndMayAdvanceWave()); | |
} | |
private IEnumerator WaitAndMayAdvanceWave() { | |
yield return new WaitForSeconds(waves[waveIndex].timeToNextSpawn); | |
waveIndex = waveIndex + 1; | |
if (waveIndex == waves.Length) { | |
onEndAllWaves.Invoke(); | |
} else { | |
SpawnCurrentWave(); | |
StartCoroutine(WaitAndMayAdvanceWave()); | |
} | |
} | |
private void SpawnCurrentWave() | |
{ | |
var wave = waves[waveIndex]; | |
for (int i = 0; i < positions.Length; i++) | |
{ | |
var enemyPrefab = wave.PickEnemy(); | |
var transform = positions[i]; | |
var go = Instantiate(enemyPrefab, transform.position, transform.rotation); | |
go.transform.SetParent(parent, true); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.TestTools; | |
using NUnit.Framework; | |
using System.Collections; | |
public class NewTestScript { | |
[Test] | |
public void single_enemy_picker_works() { | |
var refObj = new GameObject(); | |
EnemySpawn es = new EnemySpawn(refObj, 1); | |
EnemySpawn[] enemies = new EnemySpawn[] { | |
es | |
}; | |
EnemyPicker ep = new EnemyPicker(enemies); | |
var result = ep.WeightedPick(); | |
Assert.AreEqual(refObj, result); | |
} | |
public class BiasedEnemyPicker : EnemyPicker { | |
public BiasedEnemyPicker(EnemySpawn[] enemies) : base(enemies) { | |
} | |
protected override int RandomPickWeight() { | |
return cumulativeSum / 2; | |
} | |
} | |
[Test] | |
public void two_enemies_picker_works() { | |
var refObj1 = new GameObject(); | |
var refObj2 = new GameObject(); | |
EnemySpawn es1 = new EnemySpawn(refObj1, 1); | |
EnemySpawn es2 = new EnemySpawn(refObj2, 3); | |
EnemySpawn[] enemies = new EnemySpawn[] { | |
es1, | |
es2 | |
}; | |
EnemyPicker ep = new BiasedEnemyPicker(enemies); | |
var result = ep.WeightedPick(); | |
Assert.AreEqual(refObj2, result); | |
} | |
// // A UnityTest behaves like a coroutine in PlayMode | |
// // and allows you to yield null to skip a frame in EditMode | |
// [UnityTest] | |
// public IEnumerator NewTestScriptWithEnumeratorPasses() { | |
// // Use the Assert class to test conditions. | |
// // yield to skip a frame | |
// yield return null; | |
// } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment