Tower Defense Tutorial – Brackeys – Ep. 16

February 16, 2019

Tower Defense Tutorial

Episode 16 – Slowing

Youtube – How to make a Tower Defense Game (E16 SLOWING) – Unity Tutorial

By: Brackeys
Ep. 16

This tutorial will clean up some of the Turret coding, as well as add a slowing effect to the Laser Beamer turret, as well as damage over time (DoT).

We added this line of code to apply the damage over time to enemies:

targetEnemy.TakeDamage(damageOverTime * Time.deltaTime);

This initially held the GetComponent() call to get the Enemy script component of the target, but this would be very expensive to do every frame. To remedy this, we created the targetEnemy variable which is assigned the GetComponent() value when we select a new target, so it only needs done once each time the laser starts hitting a target.

To clean up our Enemy script coding, we separated it out into two scripts: Enemy and Enemy Movement. Brackeys suggests it is a good practice to keep all of your enemy’s stats or values that you want to change about them in one script, and have the other script components reach out to that information when they need those values (i.e. speed, health, etc.).

To connect our new EnemyMovement script to the original Enemy script, we simply added an Enemy variable, enemy, and then GetComponent() on that at start. To further ensure they are connected (i.e. Future editors know to keep these together), we added a RequireComponent(typeof(Enemy)) above the class name.

We wanted the laser to slow the object a consistent amount. We did not want slows to stack from multiple lasers or increase over time in any way. This resulted in creating a startSpeed to go along with speed. Speed was set equal to startSpeed in the Start method of Enemy. This allows us to constantly set speed as a fraction of startSpeed, since startSpeed is never modified. This also meant we didn’t want to show speed in the inspector, but still needed to keep it public, so we added [HideInInspector] above it so it did not show.

This worked well to slow the enemy, but then it remained slow forever. We needed to reset the speed somehow. Their solution was to just reset the speed every frame in the Update that was moving the enemy (after the movement occurred). While this works, this seems like a lot of extra calculations that could be solved in a cleaner way.

Suggested cleaner solution to slow and movement being off by a frame: Have a list of debuffs that the enemy script goes through each frame to check what debuffs are currently on it, and then apply those to any actions it does.

In this case, we actually went into the Script Execution Order (Project Settings -> Script Execution Order). This allows you to drag in scripts to dictate what order they are processed in. The number value entered is the number of milliseconds between this script and the default time.

SUMMARY

  • Simplest way to do damage over time is to have a method dealing damage * time.deltaTime that is called in Update somehow
  • RequireComponent makes sure that any time you add this script to an object, it will also add the specified component as well. Good for making sure all the components needed for a certain script to reference are on a given object.
  • It is good practice to keep all of an object’s “stats” in one place, and have other functionality that references these stats separated out into other components/scripts. (i.e. Our enemy stats were kept in Enemy, but another script, EnemyMovement, was created which referenced Enemy for stats like speed and then applied that to all the functionality internally)
  • Use [HideInInspector] if you want a public variable but don’t want it shown in the inspector
  • You can use the Script Execution Order to dictate what order scripts are run