Making a Game - Adding Engine Particle Effects - EP13

by

Video Tutorial

Aims of this Tutorial

  • Create an engine particle effect in Godot.
  • Place these particle effects around the spaceships.
  • Programmatically control the particle effects based on what thrusters would be firing assuming Newtonian mechanics (roughly).

Creating a Particle Effect

First off, we want multiple instances of this effect, so, to make life easy for ourselves, lets create a new scene and pick 'Particles' as the node. If you are using GLES 2, you will need to use 'CPU Particles' which will not get the benefit of GPU acceleration. Now, you will not notice any particles yet. That is because we need both a particle mesh and particle shader.

For the particle mesh, I picked a cube, but you can pick a mesh that you like. You should note that meshes with higher complexity will be more taxing on your computer and you will not be able to use as many particles in your effect. You also need to add a shader to your mesh. I went with a simple emission shader with a nice blue colour.

Now you need to add a particle shader to your particle node. This is where the magic happens, as we can set the behaviour of the particles. I gave my particles some randomized lifetime, initial velocity in a cone centered around the x axis, and slight damping. You should also increase your particle count to create more of a stream of particles. I went with a point like emission so the particles comes out of the spike on my engines, but you can pick a volume for the particles to come out of, which could work will with a different engine design.

Placing the Particle Effects

Now we need to instantiate, duplicate, scale, rotate and translate the scene to line up with all the engines. I highly recommend that you use a naming scheme that helps you identify what each thruster does. This will come in handy in the next section where we program them.

Programming the Thrusters

We need to write a function that will update the thrusters visuals based on the current linear and rotational thrust vectors. Since we used the naming scheme for placing the thrusters, we can simply read what each thruster is supposed to do. We also want to turn off the particle effects if we don't need them to save on computing power. Here is some sample code for one of the thrusters:

func update_engine_particles(linear_thrust : Vector3, rotational_thrust : Vector3) -> void:
    var engine_particles : Particles = $"EngineParticleContainer/S-X,R-Y"
	if linear_thrust.x < 0 or rotational_thrust.y > 0:
		engine_particles.emitting = true
		engine_particles.scale = Vector3.ONE * (max(-linear_thrust.x / MAX_LIN_THRUST, 0)+max(rotational_thrust.y / MAX_ROT_THRUST, 0)) * 0.005
	else:
		engine_particles.emitting = false

Once you have done this for all your particle effects, we also need a function to turn off the particle effects when we are not running the plan. This is also done easily by looping through an array of all particle effects:

func disable_all_engine_particles() -> void:
	var engine_particles = [
		$"EngineParticleContainer/S-X,R+Y",
		$"EngineParticleContainer/S+X,R-Y",
		$"EngineParticleContainer/S-X,R-Y",
		$"EngineParticleContainer/S+X,R+Y",
		$"EngineParticleContainer/S-Y,R+Z,R+X",
		$"EngineParticleContainer/S-Y,R-Z,R+X",
		$"EngineParticleContainer/S-Y,R-Z,R-X",
		$"EngineParticleContainer/S-Y,R+Z,R-X",
		$"EngineParticleContainer/S+Y,R-Z,R+X",
		$"EngineParticleContainer/S+Y,R+Z,R+X",
		$"EngineParticleContainer/S+Y,R-Z,R-X",
		$"EngineParticleContainer/S+Y,R+Z,R-X",
		$EngineParticleContainer/SZ,
		$EngineParticleContainer/SZ2
	]
	for ep in engine_particles:
		ep.emitting = false

Now we simply need to call these functions in the physics update loop, and we should have the thrusters working for both local and remote clients!