//~ [HideInInspector] public int totalUnitCount=0; //~ [HideInInspector] public bool spawned=false; public SubWave Clone(){ SubWave subWave=new SubWave(); subWave.unit=unit; subWave.count=count; subWave.interval=interval; subWave.delay=delay; subWave.path=path; return subWave; }
public SubWave Clone(){ SubWave subWave=new SubWave(); subWave.unit=unit; subWave.count=count; subWave.interval=interval; subWave.delay=delay; subWave.path=path; subWave.overrideHP=overrideHP; subWave.overrideShield=overrideShield; subWave.overrideMoveSpd=overrideMoveSpd; subWave.overrideLifeCost=overrideLifeCost; subWave.overrideScoreCost=overrideScoreCost; //subWave.overrideValue=overrideValue; subWave.overrideValueMin=new List<int>(overrideValueMin); subWave.overrideValueMax=new List<int>(overrideValueMax); return subWave; }
IEnumerator SpawnSubWave(SubWave subWave, Wave parentWave) { yield return new WaitForSeconds(subWave.delay); PathTD path=defaultPath; if(subWave.path!=null) path=subWave.path; Vector3 pos=path.GetSpawnPoint().position; Quaternion rot=path.GetSpawnPoint().rotation; int spawnCount=0; while(spawnCount<subWave.count){ GameObject obj=ObjectPoolManager.Spawn(subWave.unit, pos, rot); //GameObject obj=(GameObject)Instantiate(subWave.unit, pos, rot); UnitCreep unit=obj.GetComponent<UnitCreep>(); if(subWave.overrideHP>0) unit.defaultHP=subWave.overrideHP; if(subWave.overrideShield>0) unit.defaultShield=subWave.overrideShield; if(subWave.overrideMoveSpd>0) unit.moveSpeed=subWave.overrideMoveSpd; unit.Init(path, totalSpawnCount, parentWave.waveID); totalSpawnCount+=1; activeUnitCount+=1; parentWave.activeUnitCount+=1; spawnCount+=1; if(spawnCount==subWave.count) break; yield return new WaitForSeconds(subWave.interval); } parentWave.subWaveSpawnedCount+=1; if(parentWave.subWaveSpawnedCount==parentWave.subWaveList.Count){ parentWave.spawned=true; spawning=false; Debug.Log("wave "+(parentWave.waveID+1)+" has done spawning"); yield return new WaitForSeconds(0.5f); if(currentWaveID<=waveList.Count-2){ //for UI to show spawn button again if(spawnMode==_SpawnMode.Continous && allowSkip && onEnableSpawnE!=null) onEnableSpawnE(); if(spawnMode==_SpawnMode.WaveCleared && allowSkip && onEnableSpawnE!=null) onEnableSpawnE(); } } }
public Wave Generate(int waveID) { if(pathList.Count==0){ Debug.Log("no path at all"); return null; } Wave wave=new Wave(); wave.waveID=waveID; waveID+=1; int _subWaveCount=Mathf.Max(1, (int)subWaveCount.GetValueAtWave(waveID)); int totalUnitCount=(int)unitCount.GetValueAtWave(waveID); _subWaveCount=Mathf.Min(totalUnitCount, _subWaveCount); //filter thru all the units, only use the one that meets the wave requirement (>minWave) List<ProceduralUnitSetting> availableUnitList=new List<ProceduralUnitSetting>(); int nearestAvailableID=0; float currentNearestValue=Mathf.Infinity; for(int i=0; i<unitSettingList.Count; i++){ if(unitSettingList[i].minWave<=waveID) availableUnitList.Add(unitSettingList[i]); //while we are at it, check which unit has the lowest wave requirement, just in case if(availableUnitList.Count==0 && unitSettingList[i].minWave<currentNearestValue){ currentNearestValue=unitSettingList[i].minWave; nearestAvailableID=i; } } //if no unit available, simply uses the one with lowest requirement if(availableUnitList.Count==0) availableUnitList.Add(unitSettingList[nearestAvailableID]); //we are going to just iterate thru the pathlist and assign them to each subwave. //So here we introduce an offset so it doesnt always start from the first path in the list int startingPathID=Random.Range(0, pathList.Count); for(int i=0; i<_subWaveCount; i++){ SubWave subWave=new SubWave(); int unitID=Random.Range(0, availableUnitList.Count); ProceduralUnitSetting unitSetting=availableUnitList[unitID]; subWave.unit=unitSetting.unit.gameObject; subWave.overrideHP=unitSetting.HP.GetValueAtWave(waveID); subWave.overrideShield=unitSetting.shield.GetValueAtWave(waveID); subWave.overrideMoveSpd=unitSetting.speed.GetValueAtWave(waveID); //limit the minimum interval to 0.25f subWave.interval=Mathf.Max(0.25f, unitSetting.interval.GetValueAtWave(waveID)); //iterate through the path, randomly skip one int pathID=startingPathID+(Random.Range(0f, 1f)>0.75f ? 1 : 0); while(pathID>=pathList.Count) pathID-=pathList.Count; subWave.path=pathList[pathID]; subWave.delay=i*Random.Range(2f, 3f); wave.subWaveList.Add(subWave); } //fill up the unit count int remainingUnitCount=totalUnitCount; while(remainingUnitCount>0){ for(int i=0; i<_subWaveCount; i++){ if(wave.subWaveList[i].count==0){ wave.subWaveList[i].count=1; remainingUnitCount-=1; } else{ int rand=Random.Range(0, 3); rand=Mathf.Min(rand, remainingUnitCount); wave.subWaveList[i].count+=rand; remainingUnitCount-=rand; } } } wave.duration=wave.CalculateSpawnDuration(); //get the slowest moving unit and the longest path so we know which subwave is going to take the longest to finish float longestDuration=0; for(int i=0; i<_subWaveCount; i++){ float pathDist=wave.subWaveList[i].path.GetPathDistance(); float moveSpeed=wave.subWaveList[i].overrideMoveSpd; float duration=pathDist/moveSpeed; if(duration>longestDuration) longestDuration=duration; } //add the longest to the existing duration wave.duration+=longestDuration*Random.Range(0.5f, 0.8f); for(int i=0; i<rscSettingList.Count; i++){ wave.rscGainList.Add((int)rscSettingList[i].GetValueAtWave(waveID)); } return wave; }
void OnGUI() { if(window==null) Init(); if(instance==null){ EditorGUI.LabelField(new Rect(5, 5, 350, 18), "No SpawnManager in current scene"); GetSpawnManager(); return; } if(creepList.Count!=creepNameList.Length) ResetCreepNameList(); if(instance.spawnLimit==SpawnManager._SpawnLimit.Finite && !instance.procedurallyGenerateWave){ if(GUI.Button(new Rect(window.position.width-130, 5, 125, 25), configureAutoGen ? "Wave List" : "Configuration")){ configureAutoGen=!configureAutoGen; } if(!configureAutoGen){ GUI.color=new Color(0, 1, 1, 1); cont=new GUIContent("Auto Generate", "Procedurally generate all the waves\nCAUTION: overwirte all existing wave!"); if(GUI.Button(new Rect(window.position.width-130, 35, 125, 25), cont)){ for(int i=0; i<instance.waveList.Count; i++) instance.waveList[i]=instance.waveGenerator.Generate(i); } GUI.color=Color.white; } } if(GUI.Button(new Rect(window.position.width-130, 90, 125, 25), "Creep Editor")){ UnitCreepEditorWindow.Init(); } float startX=5; float startY=5; int spawnMode=(int)instance.spawnMode; cont=new GUIContent("Spawn Mode:", "Spawn mode in this level"); EditorGUI.LabelField(new Rect(startX, startY, width, height), cont); cont=new GUIContent("", ""); contList=new GUIContent[spawnModeLabel.Length]; for(int i=0; i<contList.Length; i++) contList[i]=new GUIContent(spawnModeLabel[i], spawnModeTooltip[i]); spawnMode = EditorGUI.Popup(new Rect(startX+spaceX, startY, width, 15), cont, spawnMode, contList); instance.spawnMode=(SpawnManager._SpawnMode)spawnMode; if(instance.spawnMode!=SpawnManager._SpawnMode.Round){ cont=new GUIContent("Allow Skip:", "Allow player to skip ahead and spawn the next wave"); EditorGUI.LabelField(new Rect(startX+spaceX+width+20, startY, width, height), cont); instance.allowSkip=GUI.Toggle(new Rect(startX+spaceX+width+90, startY, 15, 15), instance.allowSkip, ""); } int spawnLimit=(int)instance.spawnLimit; cont=new GUIContent("Spawn Count:", "Spawn count in this level. Infinite (endless mode) must use procedural wave generation"); EditorGUI.LabelField(new Rect(startX, startY+=spaceY, width, height), cont); cont=new GUIContent("", ""); contList=new GUIContent[spawnLimitLabel.Length]; for(int i=0; i<contList.Length; i++) contList[i]=new GUIContent(spawnLimitLabel[i], spawnLimitTooltip[i]); spawnLimit = EditorGUI.Popup(new Rect(startX+spaceX, startY, width, 15), cont, spawnLimit, contList); instance.spawnLimit=(SpawnManager._SpawnLimit)spawnLimit; cont=new GUIContent("Auto Start: ", "Check to have the spawning start on a fixed timer. Rather than waiting for player initiation"); EditorGUI.LabelField(new Rect(startX, startY+=spaceY, width+50, height), cont); instance.autoStart=EditorGUI.Toggle(new Rect(startX+spaceX, startY, width, height), instance.autoStart); if(instance.autoStart){ cont=new GUIContent("Timer: ", "The duration to wait in second before the spawning start"); EditorGUI.LabelField(new Rect(startX+spaceX+30, startY, width+50, height), cont); instance.autoStartDelay=EditorGUI.FloatField(new Rect(startX+spaceX+70, startY, width-70, height), instance.autoStartDelay); } if(instance.spawnLimit==SpawnManager._SpawnLimit.Finite){ cont=new GUIContent("Auto Generate", "Check to have the SpawnManager automatically generate the wave in runtime as opposed to using preset data"); EditorGUI.LabelField(new Rect(startX, startY+=spaceY, width+50, height), cont); instance.procedurallyGenerateWave=EditorGUI.Toggle(new Rect(startX+spaceX, startY, width, height), instance.procedurallyGenerateWave); cont=new GUIContent("Default Path:", "The primary path to be used. Every creep will follow this path unless an alternate path is specified in a sub-wave"); EditorGUI.LabelField(new Rect(startX, startY+=spaceY, width, height), cont); instance.defaultPath=(PathTD)EditorGUI.ObjectField(new Rect(startX+spaceX, startY, width, 15), instance.defaultPath, typeof(PathTD), true); cont=new GUIContent("Waves Size: "+instance.waveList.Count, "Number of waves in the level"); EditorGUI.LabelField(new Rect(startX, startY+=spaceY, width, 15), cont); if(GUI.Button(new Rect(startX+spaceX, startY-1, 40, 15), "-1")){ if(instance.waveList.Count>1){ instance.waveList.RemoveAt(instance.waveList.Count-1); waveFoldList.RemoveAt(waveFoldList.Count-1); } } if(GUI.Button(new Rect(startX+spaceX+50, startY-1, 40, 15), "+1")){ if(instance.waveList.Count>0) instance.waveList.Add(instance.waveList[instance.waveList.Count-1].Clone()); else{ Wave wave=new Wave(); SubWave subWave=new SubWave(); wave.subWaveList.Add(subWave); List<Rsc> rscList=EditorDBManager.GetRscList(); wave.rscGainList=new List<int>(); for(int i=0; i<rscList.Count; i++) wave.rscGainList.Add(0); instance.waveList.Add(wave); } waveFoldList.Add(true); } } else configureAutoGen=false; if(instance.spawnLimit==SpawnManager._SpawnLimit.Infinite || configureAutoGen){ EditorGUI.LabelField(new Rect(startX, startY+30, 400, height), "Procedural Wave Generation Parameters"); startY+=10; } startY+=35; float waveConfigStartY=startY; Rect visibleRect=new Rect(startX, startY, window.position.width-10, window.position.height-startY-5); Rect contentRect=new Rect(startX, startY, contentWidth-25, contentHeight); contentWidth=0; GUI.color=new Color(.8f, .8f, .8f, 1f); GUI.Box(visibleRect, ""); GUI.color=Color.white; scrollPos = GUI.BeginScrollView(visibleRect, scrollPos, contentRect); startX+=5; startY+=10; float cachedX=startX; Vector2 v2=Vector2.zero; if(instance.spawnLimit==SpawnManager._SpawnLimit.Infinite || configureAutoGen || instance.procedurallyGenerateWave){ v2=WaveGeneratorSetting(startX+5, startY); } else{ v2=WaveConfigurator(startX, startY); } startX=cachedX; startY=v2.y; GUI.EndScrollView(); contentHeight=startY-waveConfigStartY; if(GUI.changed) EditorUtility.SetDirty(instance); }