Creating a Simple Afterimage Effect For Your Sprite in Unity

Justen Chong
7 min readJun 4, 2021

Goal: Create an afterimage in order to allow the player to follow high speed movement/accent the movement of an entity

Before we get started, I want to point a very important distinction for creating VFX for Games rather than Film. For games, the proper term is technically Realtime VFX rather than just simply calling them VFX. This is because the VFX for a game have to run in realtime and possibly be dynamic in order to match what’s happening in the game world. For example, a laser beam may have to bend or reflect differently depending on what angle it hits a surface, or the trail behind on a magical projectile has to change colour and size based on the element and the speed it’s travelling, etc.

Having your effects be dynamic and change to match the game world’s logic as it changes in realtime is the key distinction between the two. In film, you have the raw footage already and the raw footage won’t change unless they decide to reshoot so your effects don’t have to know how to react to what’s happening in the film world. You can just tell it what to do.
Also, Special Effects and Visual Effects are not the same thing in film. Special Effects are done on site while Visual Effects are done in post.

With that being said here is how I created the afterimage effect for my Boss Enemy.

First let’s layout the pros and cons of this technique:

Pros:
+ Very quick and simple to implement
+ Some components are easily adjustable because it uses the particle system
+ No need to instantiate anything so it’s very efficient

Cons:
- Only works if character is not animated because the afterimage effect uses a static sprite. Getting an afterimage effect like Vergil from Devil May Cry 5 or Noctis from FFXV is more difficult. I’ll save that for another article
- Does require a script in order to sync the rotation

Now that we’ve broken down the pros and cons, just like with programming we have to breakdown the behaviour of the effect step by step. You’ll find that Realtime VFX and programming often go hand in hand so it’s good to think of them in the same fashion that you would approach programming:

  1. Create the particle
  2. Spawn particle ONLY as the character moves
  3. Change the particle’s colour to communicate that it is an afterimage
  4. Spawn on top of the character’s position and do not move
  5. Sync the rotation of the particle with the character when it spawns
  6. Polish the effect to make it apply the feeling we need

Steps 2, 3, and 4 can be done within the particle system very easily. However, Step 5 will require a script as the default particle system does not have any dynamic fields built in.

Step 1 is very straightforward. We can simply create a new material and slap our sprite onto it as the main texture. Make sure that the sprite you’re using is a file type that supports transparency like PNG and has a transparent background. Then make sure you select a particle shader (in my case, URP/Particles/Unlit) and set the “Surface Type” to Transparent.

(NOTE: If you don’t set the shader as a particle then settings adjusted in the particle system’s modules will not apply properly)

Then set the material in the Renderer at the bottom of the particle system

For Step 2, the property we’re looking for is “Rate Over Distance” which is found under the “Emission” module which is located underneath the Main Module.

This will spawn the entered number of particles as the particle system moves. This also means that moving it’s parent object will cause the particle system to produce particles. I don’t know the exact calculation so it’s best to enter a number and try it out.

You can try it out easily by selecting it in your hierarchy, clicking “Play” on the little submenu that shows up in your scene view and then moving it around the scene.

If your character has a Rigidbody like mine does then make sure you set the Emitter Velocity property in the Main module accordingly. I’m moving my character via transform so it’s set to Transform, but if you’re moving it via Rigidbody then make sure it’s set to Rigidbody.

For Step 3, the property we’re looking for is “Start Color” which in found in the “Main” module which is located above the Emission module

I adjusted the Alpha so that it shadows the main object better and adjusted the colour in order to prevent the player from mistaking it as a clone of the actual character. This way it looks like an afterimage

For Step 4, we first need to change the “Simulation Space” property in the Main module to World. This essentially spawns the particle into the world with no parent. So whatever behaviour is programmed into it will be carried out from where ever is spawns. Local essentially parents each particle to the particle system.

Since we already have the Main module open we can make sure that the particles don’t move by setting the “Start Speed” to 0.

Now that the particles don’t move and they will not follow the particle system after spawning we need to make sure that they spawn on the same position of the player instead somewhere nearby. To do this, we have to go to the “Shape” module which is located under Emission and adjust the “Shape” property. By default, the Shape(Property) is set to Sphere.

We can just set the radius to zero and then Unity will set it to the smallest acceptable value automatically.

Now instead of spawning somewhere randomly in a radius around the player, particles will now spawn at the player’s position because the radius of the sphere is effectively zero.

For Step 5, we’re going to need a script. We want the Z rotation of each particle to match the Z rotation of the character every frame. So our method looks like this.

Where “parSys” is a ParticleSystem defined globally at the top of the script.

parSys.main means we’re getting the “Main” module of the particle system and var is a variable declaration you can use if you’re too lazy to specifically define your data type. Line 154 is what changes the start rotation of the particle to match the character’s Z axis every frame. Just make sure you put the method in Update().

Finally, Step 6 will take a lot of patience in order to get the effect to look just right so try your best to stay focused. I’ll go through this bit very quickly because this is more specific to my tastes, but has a lot of room for customization.

  • I wanted the afterimages to disappear quickly so that they wouldn’t take up screen space for too long so I adjusted the “Start Lifetime” in the Main module to 0.5 seconds.
  • I wanted the particles to fade out to make their disappearance less noticeable by the player. It can be very jarring when things suddenly appear or disappear. This can be done in the “Color Over Lifetime” module by adjusting the gradient

Wow! That was a long one! I honestly didn’t realize how long this was going to be until I started writing it! I certainly hope that any readers who made it this far learned a lot.

Thanks for reading and I hope that helps! ^_^b

--

--