|
Post by Andy on Nov 21, 2014 19:20:03 GMT
I'm having problems wiring my code up to Core Gamekit. My game has a single Unity scene, and I want to create waves on-the-fly based on a configuration file. So, if they're on game level 1, I would create "wave 1" and so on. The data reader would create the new wave and set values like delay and number of enemies to spawn.
I have a single enemy spawner.
I'm having problems wiring my code to Core Gamekit. Some things I tried (I don't have the code in front of me):
1) InsertLevel and InsertWave combined with FindWave(): the InsertLevel and InsertWave methods check a list (List<WaveSettings). That list is empty (debugger) so FindWave returns null.
2) I looked at LevelSettings to see if I could get a handle to the list of levels or waves. It was not exposed (that I could tell). It seems like that information is only exposed in the syncro scripts.
3) I thought about building all of the possible levels/waves in the Core Gamekit interface. Then, I'd use DeleteLevel (DeleteWave?) to drop out all of the levels and waves I wasn't using on that particular game level. I didn't have time to try this idea. And, I'd prefer to be able to build a Wave on the fly instead of deleting the 100+ waves I'm not using on a particular game level.
4) I looked through the API and the forum for things like AddWave() and AddLevel().
Does that make sense? Is it supported? Do you have a suggestion or sample code?
---
Second question:
I create a PoolBoss with all of the prefabs (30+). Because I have a single scene, I don't want to pre-load all of the prefabs since most of them will not be used on a particular game level. I set the minimum quantity of the PoolItems to 0. In my code, I grab the PoolBoss and then programmatically change the preload quantity for the few prefabs used in the particular game level.
I wired it together but I haven't tested the concept because I haven't solved the level question above. I'm wondering it this will work like I hope (i.e. that after I run my script, the PoolBoss will not spawn prefabs with quantity 0 but will spawn prefabs with quantity >0).
Thanks in advance
|
|
|
Post by Andy on Nov 21, 2014 23:16:25 GMT
I was thinking about my problem. I realized that I can look at the code attached to the "Add" button on the custom editor. I'll check tonight to see if that helps answer my question.
|
|
|
Post by DarkTonic Dev on Nov 21, 2014 23:49:50 GMT
It's not supported to change the waves dynamically. However you could set up all the possible waves and start at certain wave numbers with the Custom Start Wave functionality, based on your own custom logic. Level and Wave info is in LevelSettings.cs. The per-Spawner "wave info" of what to spawn during a wave is in the Spawners.
Also, you can use World Variables for number of things to spawn and delay and anything else. That way, if you set the World Variable on a previous Scene (main menu scene maybe), all that dynamic stuff would happen when the main game scene loads. You can also skip certain waves based on World Variable values...
Pool Boss only works properly if it creates all the clones on Awake, which is before you can do any of that dynamic stuff, unless you were to go into Script Execution Order and make your script run before Pool Boss I guess. Again, not a supported scenario. However...I don't think you should be worried about a pool with 30 prefabs. That's not really a lot. We have a couple games with hundreds of prefabs in Pool Boss and it's fine.
|
|
|
Post by Andy on Nov 22, 2014 0:28:32 GMT
Thanks for the advice.
I'll look into 1) setting up all of my waves in the interface and 2) calling the appropriate wave programmatically. Your advice will save me spending hours trying something that wouldn't work anyway!
In regards to the Pool Boss, I'll also adjust it like you suggested. I'll set each PoolItem to a minimum of at least one item. I have two follow-up questions on this if you have a second (just because I'm curious):
1) If I programmatically change the PoolItem's minimum size later, does that change the Pool Boss? For example, if I switch the minimum size from 1 to 5, does the Pool Boss adjust accordingly and spawn the new prefabs? Or does it only spawn on awake/start/enable?
2) (Assuming #1 is yes) If I programmatically change the PoolItem's minimum size to 0, does Pool Boss destroy the prefabs?
I'll also experiment with the script execution order. I'll post back with the results.
I love Master Audio, by the way.
|
|
|
Post by DarkTonic Dev on Nov 22, 2014 0:50:57 GMT
#1, minimum of pool item - you mean "Preload Qty" right? If so, that value is only used when Pool Boss runs its Awake event and sets up all the despawned clones for pooling. So changing the value after Pool Boss does Awake won't do anything. Creating more at runtime would cause a performance hiccup (see note below).
#2, nope, that also does nothing. Destroying the prefabs would cause a performance hiccup (see note below).
Side note: if you only create 1 of each item, and you need more later, they will be Instantiated at the time you need them, which can cause performance hiccups. That's not really the ideal way to use pooling and kind of defeats at least half the purpose of using it. In our games, we set the Preload Qty to the most of each item we will ever need. It does cause a couple seconds of pause at the beginning of a Scene, but after that everything is super smooth.
However, if you were to change the Preload Qty programmatically before Pool Boss ran Awake, that could be good.
|
|
|
Post by Andy on Nov 23, 2014 15:56:21 GMT
I got both scenarios to work. Based on your suggestions, I did a little research on Unity lifecycle to see whether Awake() is triggered before a script/Game Object is enabled. It's triggered after the script is enabled. So, the trick to getting this to work is to turn off parts of the Level Wave Settings framework, set them up, and then enable them.
Steps:
*) setup Level Wave Settings. For example, I setup my Pool Boss prefabs (min quantity 0), created PrefabPools, and two spawners (Hero and Enemy). I also created a "Create hero" wave (1, 1) and a dummy wave (2, 1). *) disable the Level Settings script, Pool Boss Game Object, and the Enemy spawner Wave Syncro Prefab Spawner script. *) write a controlling script. Mine is called WaveSettings and it's attached to the Level Wave Settings Game Object. *) write a public Load(YourLevelData) method to wire everything together.
The one thing I didn't get working was a way to create a new level in Wave Syncro. I'll append the sample code below (called CreateWave). Everything looks right when I start the Unity scene, but the spawner does not spawn the prefabs. Instead, I had to create a dummy wave and reset its values in my code. So, that's bonus-point-time for anyone who can get it to work!
Anyway, I like this technique. It allows me to define everything on the fly and still use the neat features of your kit (spawners with random offsets, killable triggers and prefab substitution(?)).
I'm going to append some sample code below. Sorry if the formatting is off. This should help get people started.
/// <summary> /// Load the waves and pools. /// </summary> /// <param name="level">The level setup information</param> public void Load(LevelData level) { if (this.alreadyLoaded) { Debug.Log("WaveSettings already loaded. Skipping Load()"); } else { this.alreadyLoaded = true;
this.currentLevel = level; this.ActivateMonsters(level); this.AdjustWaves(level, 1);
this.poolBoss.SetActive(true); this.enemySpawner.enabled = true; this.levelSettingsScript.enabled = true; this.transform.parent.gameObject.SetActive(true); } }
/// <summary> /// Examine the level setup data and make sure /// the pool has activated the appropriate /// GameObjects (monsters). /// </summary> /// <param name="level">Level setup information</param> private void ActivateMonsters(LevelData level) { Dictionary<string, WavePrefabPool> pools = this.GetPrefabPools();
foreach (WaveData wave in level.Waves) { foreach (SubWaveData subwave in wave.SubWaves) { if (pools.ContainsKey(subwave.Pool)) { Debug.Log("WaveSettings will attempt to set minimum quantity for items in pool:" + subwave.Pool); this.ActivateInPoolBoss(pools[subwave.Pool]); } else { Debug.LogWarning("WaveSettings failed to find a pool named " + subwave.Pool); } } } }
/// <summary> /// Set the number of instances to spawn in the pool boss. I /// have turned them to 0 when the level starts so /// that they don't spawn objects that I'm not going to use in the scene. /// This method resets the initial quantity. /// </summary> /// <param name="pool">The prefab pool</param> private void ActivateInPoolBoss(WavePrefabPool pool) { foreach (WavePrefabPoolItem poolItem in pool.poolItems) { foreach (PoolBossItem bossItem in this.poolBossScript.poolItems) { if (poolItem.prefabToSpawn == bossItem.prefabTransform) { bossItem.instancesToPreload = PreloadQuantity; break; } }
Debug.Log("WaveSettings activated pool prefab:" + poolItem.prefabToSpawn.name); } }
/// <summary> /// Get the pools /// </summary> /// <returns>A hash of pools indexed by name</returns> private Dictionary<string, WavePrefabPool> GetPrefabPools() { Dictionary<string, WavePrefabPool> pools = new Dictionary<string, WavePrefabPool>();
WavePrefabPool[] allPools = FindObjectsOfType<WavePrefabPool>(); if (allPools == null || allPools.Length == 0) { Debug.LogWarning("WaveSettings could not find any WavePrefabPool items"); } else { foreach (WavePrefabPool onePool in allPools) { pools.Add(onePool.name, onePool); } } return pools; }
/// <summary> /// Used to create waves on the fly /// </summary> /// <remarks> /// This method doesn't work currently. The resulting <see cref="LevelSettings"/> and /// <see cref="WaveSyncroPrefabSpawner"/> Gane Objects /// look fine, but the new waves don't launch for some reason. Use the /// AdjustWaves() method instead /// </remarks> /// <param name="level">Level setup information</param> private void CreateWaves(LevelData level) { if (this.enemySpawner != null && this.levelSettingsScript != null) { int spawnLevelNumber = 1; foreach (WaveData wave in level.Waves) { int spawnWaveNumber = 0; foreach (SubWaveData subwave in wave.SubWaves) { LevelSpecifics newLevel = new LevelSpecifics(); LevelWave newWave = new LevelWave(); newLevel.WaveSettings.Add(newWave); newWave.waveName = level.Name; newWave.WaveDuration = 1000; this.levelSettingsScript.LevelTimes.Add(newLevel);
WaveSpecifics waveSpecifics = new WaveSpecifics(); waveSpecifics.SpawnLevelNumber = spawnLevelNumber; waveSpecifics.SpawnWaveNumber = spawnWaveNumber; waveSpecifics.MaxToSpwn = new KillerInt(subwave.Count); waveSpecifics.MinToSpwn = new KillerInt(subwave.Count); waveSpecifics.spawnSource = WaveSpecifics.SpawnOrigin.PrefabPool; waveSpecifics.prefabPoolName = subwave.Pool; waveSpecifics.TimeToSpawnEntireWave = new KillerFloat(subwave.TimeToSpawn); waveSpecifics.WaveDelaySec = new KillerFloat(subwave.Delay); this.enemySpawner.waveSpecs.Add(waveSpecifics);
spawnWaveNumber++; }
spawnLevelNumber++; } } }
/// <summary> /// Used to overwrite the current settings in the dummy waves /// with this game level's waves. /// </summary> /// <remarks> /// You must setup the appropriate waves in the Level Settings /// interface in order to overwrite them. For example, if you're /// adjusting level 2/wave 1, it needs to be created already. /// </remarks> /// <param name="level">Level setup information</param> /// <param name="levelOffset">Used to offset the level number (i.e. do /// not overwrite the "launch hero" level 1 information</param> private void AdjustWaves(LevelData level, int levelOffset) { if (this.enemySpawner != null && this.levelSettingsScript != null) { int spawnLevelNumber = levelOffset; foreach (WaveData wave in level.Waves) { int spawnWaveNumber = 0; foreach (SubWaveData subwave in wave.SubWaves) { WaveSpecifics waveSpecifics = this.enemySpawner.waveSpecs[0]; waveSpecifics.MaxToSpwn = new KillerInt(subwave.Count); waveSpecifics.MinToSpwn = new KillerInt(subwave.Count); waveSpecifics.TimeToSpawnEntireWave = new KillerFloat(subwave.TimeToSpawn); waveSpecifics.WaveDelaySec = new KillerFloat(subwave.Delay);
spawnWaveNumber++; }
spawnLevelNumber++; } } }
/// <summary> /// Write error messages back if the objects that we need to be /// inactive are actually active. /// </summary> /// <param name="parent">The parent object of this script.</param> private void CheckForActiveObjects() { if (this.levelSettingsScript.enabled) { Debug.LogWarning("WaveSettings: Level Wave Setting script should be inactive in order to load new Pool Boss and Wave settings"); }
if (this.poolBoss.activeInHierarchy) { Debug.LogWarning("WaveSettings: Pool Boss should be inactive so we can set PoolItem quantities"); }
if (this.enemySpawner.enabled) { Debug.LogWarning("WaveSettings: Enemy spawner should be inactive so we can create new waves"); } }
|
|
|
Post by DarkTonic Dev on Nov 23, 2014 19:55:40 GMT
That's cool. I fixed your code formatting with the "C" Code icon  That's cool. Although I think you may be wrong about the life cycle thing. The information I has says that the order of events is: Awake, Enable and then Start.  It's a bit old, but I don't think it has changed. If you have different information, please share it 
|
|
|
Post by Andy on Nov 23, 2014 20:21:44 GMT
|
|
|
Post by DarkTonic Dev on Nov 23, 2014 21:09:16 GMT
Yeah, that's correct. It could be confusing because enabling the object and OnEnable are similarly named. I was just saying that OnEnable will fire before Awake once you do "make active" the Game object. And neither will run until you do if it's inactive.
I'm not sure why CreateWave didn't work, you will need to debug I guess.
|
|
dtu
New Member
Posts: 1
Posts: 1
|
Post by dtu on Dec 15, 2014 17:59:20 GMT
I just wanted to chime in on this being a sought after feature, because I was now coming to the board looking exactly for this functionality. The reason is that I am spawning letters from words, and in a multilingual setup it would make little sense to prefab all waves/words for several different languages if this could be done programatically using just a wordlist.
Just saying - I hope this feature will come.
If there was an optional early loader for a settings script - that script could come with examples of how to setup everything from pools to waves?
|
|
|
Post by DarkTonic Dev on Dec 16, 2014 0:29:05 GMT
I just wanted to chime in on this being a sought after feature, because I was now coming to the board looking exactly for this functionality. The reason is that I am spawning letters from words, and in a multilingual setup it would make little sense to prefab all waves/words for several different languages if this could be done programatically using just a wordlist. Just saying - I hope this feature will come. If there was an optional early loader for a settings script - that script could come with examples of how to setup everything from pools to waves? You can go ahead and request some kind of feature like this on the roadmap thread in this forum (stickied also). I believe you're only the 2nd person asking for this out of over 1,500 users. So it would definitely go to last position on the roadmap. Thank you.
|
|