You do realise that code is generally processed sequentially? Your third if statement (the second “else if”) can never ever be hit. Actually seeing your programs structure starts with properly aligning your if statement levels.
Just look at your top level if statements:
if (Time.time<15)
{
}
else if (Time.time>15)
{
}
else if (Time.time > 30)
{
}
Again the code is executed sequentially. So if time has a value of say 5. You first check if time is less than 15. Yes, that’s true so we enter the first if body and anything in the else chain is ignored.
Now imagine the value is 20. The first if statement is not true since 20 is not smaller than 15 so we skip to the else statement. Here we check if the value is greater than 15 which is true so we enter the body of the second block and any “else” following is ignored.
Now imagine the value is 3000. Of course the first statement will not be entered since 3000 is even larger. However the second statement is still true so we will enter that if statement body since 3000 is greater than 15.
So it’s absolutely impossible to ever enter the third block of code because all values will either fall into the first or second case. Well to be entirely correct there is a small exceptional case when time is exactly 15. In this case you will not enter the first one since 15 is not smaller than 15 so you skip to the next else if. You will not enter this one either since 15 is not larger than 15 either. So this is the only case where you actually check the 3rd if statement. However you will of course not enter that body since the if statement checks of time is greater than 30. Since you can only reach this point when the value is exactly 15 you will never enter that if body.
Your whole approach looks really weird. If those are your only 3 cases you can do this:
if (Time.time < 15)
{
}
else if (Time.time < 30)
{
}
else
{
}
This will split the code into the sections 0-15, 15-30, 30-infinity. Though it generally would make more sense to seperate your basic logic, which is always the same, from your configuration data for each phase / round / wave. Whenever you have similar code in several cases (2+) you should think about if you can actually extract the individual values out as data and use a unified logic.
For example if you want to jump to the next phase / wave every 15 seconds, you can simply do
int currentPhase = Mathf.FloorToInt(Time.time / 15);
“currentPhase” will be 0 during the time 0-15, will be 1 during the time 15-30, 2 during the time 30-45 and so on. Of course if you create phases or waves in an array you probably have a max wave. If you want to continue the logic but you want to just keep the last phase config, just clamp the currentPhase value
int phaseIndex = Mathf.Clamp(currentPhase, 0, phases.Length - 1);
This assumes you have an array called “phases” which might hold the relevant data for each phase.
If you want to have different times between phases (not always 15 seconds) you can use a different approach. However we don’t know what your needs are and Unity answers is not a place to discuss basic programming logic or structural design. If you need more help with this you should be more clear what your requirements are. For example a long time ago I created this extremely simple but powerful enemy wave spawner. It keeps the concrete spawning logic open. Since you want to have different spawn points to choose from for each wave / phase you want to include that in the wave logic. I just put that link here for reference. Create your own spawner that suits your needs.