New Enemy Movement — Probability Explained

Objective: Implementing a new enemy movement
With today’s tutorial we’re going to use many things already in our hands with the aim of adding a little spice to enemy movement.
Till now, enemies fly down, respawn at top at a different position and fly down again. We can do better.
I decided to add an oscillatory movement (but it could have been literally anything) to the enemies. With a probability shot, this feature is turned on or off for each enemy and will remain so until it is destroyed by the player.
The oscillation movement will be the one of a harmonic oscillator: the position is proportional to the sine or cosine function of time.
So, at start, we define whether or not the enemy has to oscillate:
If you’re new to random generation and probability here is the explanation: Random.value
generates a random number between 0 and 1 (inclusive), so let’s say it’s 0.67
. If we want something to happen with a probability p < 1
simply we have to check if the extracted number is less than (or equal to) p
.
Let’s say p = 0.8
, so a high probability (80% chance), if our random number is less than that, the toss is a success. In our example, 0.67
is a success. It is easy to understand that every number in [0; 1] is less or equal to 1, so 1 represent certainty. For the same reason 0 represents impossibility. The greater the p value, the “more” there are numbers which are less than p.
In code, not only the random is used to check if the enemy has won the lottery of Oscillating Ville, but it is also stored as a “phase”. We’ll see.
Now, once the bool is set, it is used in Move()
method to make the enemy oscillate, or not.
This is the oscillation method. As you can see it is just another translate method that will combine with the fly-down one. What’s interesting is the amount of space we have to translate: the harmonic oscillator law.

A is the amplitude of the motion, half the span from one extreme to the other. The Greek letter ω is the angular frequency (2 times pi times the frequency). The Greek letter φ is the phase, representing the starting position of the oscillator.
That is why I stored the random number, multiplied by pi it would be the perfect phase, different for each oscillator so he won’t move the same (in phase).
Now, why I used Time.time
and not Time.deltaTime
? Let’s remember the differences:
- time is the time since the game has started
- deltaTime is the time since the previous frame
If we would use deltaTime, we would put in the oscillator law a value that resets to zero at each frame, namely at 60 fps deltaTime would go from 0 to 1/60 s and back to zero. In our case, the sine function for those time values is always growing and the enemy will simply slide right.
So the choice falls on time instead, it is an ever-growing value that would perfectly fit in the sine/cosine law.

And that’s it. You can see that amplitude and frequency are collected from the Level Manager, along with the probability: you can tweak the values for each level.
This is the result, using an amplitude of 0.01 and a frequency of 0.8.
