Hi. Question and solution may be very simple but not understand. I have done several projects where are collectables and when certain amount collected level will end. Now i am making shooter project where need to kill certain amount of enemies and then level finished. I have tried some tuturial but not working, solution may be very easy, some ennemy count which reduced after every destroy, but if someone have simple solution i appreciate
Counting each kill is still the best, simplest and most efficient solution.
Counting an integer seems to be breakable at many levels (if an enemy is not spawned, you won’t be able to finish the wave, if an enemy dies twice because of another bug etc…).
What I would do is add each enemy in an array and remove enemies from the array when they die. When the array is empty, you fire off the “end level” logic.
I know what you mean. But the solution really depends on the game. You would still need to implement several checks in both cases, for example, was the enemy correctly spawned?
The way he describes the level passage trigger is x kill => next level. What if you have 1000 enemies, but you only need to kill 10? Keeping track of 1000 elements seems overkill (yeah, I know, I’m exaggerating a little bit).
Anyway, do you mean an array or a set? I haven’t checked the costs of large collections in UE4 yet.
It really depends on how simple or complex your setup is. However, there is one method you can use which is quite solid. I’m sure it could be done in an easier way, but I believe it should be fairly efficient in terms of performance, and at the same time is easy to modify later on if you find out you want to add additional functionality. The setup I show here assumes no waves, and that you want to end the game as soon as all enemies are dead. Do note that if you want to make it compatible with multiplayer you may need to do some minor changes, but since I have never worked with multiplayer I will leave that part up to you to find out.
By doing it this way, you don’t add any code to the tick events of any actors, which should help out on performance. In truth, unless you have large amounts of enemies with complex code you would likely not notice this difference in performance, but it is always good practice to keep things optimized. I will admit that I am still rather inexperienced, so someone might be able to optimize this even further.
Anyways, this is how I would do it.
The Game Mode
Create a new game mode and make sure that it applies to the levels you want to use it on. If your project already has a custom game mode, you may add this code to it rather than create a new one.
In this game mode, create an integer variable to keep track of enemies left on the map. In my example, I’ve called it “Enemies Left”.
Also create a new custom event (or function… either is fine and essentially works the same way) inside your game mode. This event will be triggered every time an enemy dies, and takes care of chaning the count of enemies left, and checking if the level should be ended. I called it “One Enemy Killed”.
Add code to the new event that does the following:
Subtracts 1 from the “Enemies Left” variable.
Next, check if we’ve reached 0 enemies with a “Enemies Left” <= 0. We could have made it just an equal node, but the using a less than or equal node makes sure that it treats negative numbers as 0, just in case something goes wrong and we end up with negative numbers. If there are still enemies left, we do nothing. If we have reached 0, then we go to the next step.
Branch off from true in the branch and add the code you use to end your level. I have left this open as that differs from game to game
Here is how the game mode looks in my example:
Next we need to add some code to the blueprint for your enemy. We’ll have to add to the enemies left counter when an enemy spawns, and make sure to tell the game mode when the enemy dies.
On Begin Play event, get the current game mode, and cast it to your Custom Game Mode. The short version is that casting it will make verify that the game mode is in fact our new, custom game mode, and tells the game that it should use variables only available to our new game mode. Not every game mode has an “Enemies Left” variable, so this just makes sure it works correctly. Add this code to the Begin Play event:
From the “As [name of your new game mode]” output, drag out and get our “Enemies Left” variable. Add 1 to this.
Again, drag out an “Enemies Left” variable, but this time we need to set it. Use the result from our addition in the last step as the new value for the set mode. Now the game mode should correctly register an enemy when it spawns on the map.
We also need an event that triggers when a unit is killed. If you don’t have an event for this already, you can either create a custom event, or add it do the event that handles damage on your enemy (in which case, make sure the code only triggers when enemy is dead). I am not showing how to actually handle that damage as that is, again, something that varies quite a lot from game to game. Add the following code to the event that runs when killed:
Once again, get the game mode, and cast it to your Custom Game Mode.
Drag out from the “As [name of your new game mode]”, but this time you want to run the event/function we created inside the game mode. In my example, I called it “One Enemy Killed”.
Here is how my Enemy example looks:
There you go. To summarize: When an enemy spawns, it tells the game mode to add 1 to “Enemies Left”. When an enemy is killed, it notifies game mode that it has died. Game mode subtracts 1 from “Enemies Left” then checks if there are enemies left. If there are no enemies left, it ends the level.
You can as mentioned add other functionality fairly easily if you want to. I won’t go into too much details here as I don’t know what other functionality you might need, but to take a very quick example: If, rather than killing everyone, each level just requires you to kill a certain amount, instead of having each enemy add 1 to enemies left when spawning, you could make each level hold a variable that states how many enemies need to be killed and copy that value into “enemies left” variable when the game starts.
Hope this helps you out!
Thanks for help. I am making simple third person shooter. different levels and each level is let say 30-50 enemies which need to shoot/kill. And when all killed level completed. Each level same enemy amount and i also made calculator to hud that how many enemies need to be killed
You’re welcome! If you always need to kill absolutely every enemy on a level then the blueprint code I supplied should work just fine as-is.
2c: I strongly advise taking the Array option (Array Add / Remove), over keeping an Integer count etc…
Why? There are always some rare circumstances where references to enemies can become invalid.
There’s always ‘Enemy didn’t spawn’ because obstacle was in the way (rare case of player blocking).
Weapon imparts damage to AI that shouldn’t have been affected… AI falls off map and Kill-Z kicks in…
Plus, you’re structuring your code better for later on, when you add anything from minimaps to saving.
one stupid question more, i have done collectables counter to hud earlier, but how i can get this enemies left to mine hud, i mean counter that how many enemies left? do i need to in hud to add node cast to gamemode or cast to enemy, tried many choices but not good results
Use the same “beginplay” event from your enemies to cast to your HUD and add to a counter. Use your “On killed” event to subtract from the counter or vice versa whichever way you want to go.
Here’s one more solution that is very simple and hopefully avoids most of the issues of having enemies not spawning correctly or invalid references:
- Add a specific tag to all enemies - call it ‘Enemy’
- Create an actor blueprint and call it BP_CheckEnemies
- Inside this blueprint create a custom event and call it EventCheckEnemiesLeft.
- Call this custom event on your Begin Play Node
- EventCheckEnemiesLeft creates a timer (looping) of slow frequency that does a Get All Actors with Tag. Use tag ‘Enemy.’ From this array drag and type “get” and Get. From here drag 'Is Valid" (boolean). And from here drag ‘NOT’ and connect this to a branch.
- If this condition is TRUE, trigger another custom event that ends the level
Essentially you are checking for all actors in your level with tag ‘Enemy’ every X seconds (I would make it 1 or 2 seconds to keep it performant). If the array comes back empty (get is Invalid) then there are no more enemies in your level and you can end it.
Can you please show this in blueprint? That will a great help. Thanks in Advance