Particle Effects

From Tales of Maj'Eyal
Revision as of 04:24, 19 July 2013 by Castler (Talk | contribs) (Created page with "Particle effects can be used to add pizzazz to your game. There are two parts to adding particles: invoking the particles from your main Lua code and actually defining them. ...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Particle effects can be used to add pizzazz to your game. There are two parts to adding particles: invoking the particles from your main Lua code and actually defining them. We'll cover invoking particle effects first, since it's considerably simpler, and you'll want to be able to invoke your new effects to test them out and tune their parameters.

Invoking Particles

Assuming your particle effect is named "my_particle.lua" (see below, there are a few main options for invoking it. (Other alternatives also exist for more specialized circumstances.)

On the map

The Map.particleEmitter function can add a particle effect to the map. For example, if a talent should display an effect centered on the user, add the following code to your talent's action function:

   game.level.map:particleEmitter(self.x, self.y, 1, "my_particle")

Make sure that your particle effect limits how many particles it generates; otherwise, it can run forever.

On an entity

A long-lasting particle effect can be added to an entity with Entity.addParticles and removed with Entity.removeParticles. For example, to associate a particle effect with a status condition, add the following to the appropriate newEffect block in your timed_effects.lua:

   activate = function(self, eff)
       eff.particle = self:addParticles(Particles.new("my_particle", 1))
   end,
   deactivate = function(self, eff)
       self:removeParticles(eff.particle)
   end,

As a projectile

See ActorProject.

Testing your particle effects

Note that particle effects files are loaded every time they're invoked. This makes it very easy to test your particles: make up a talent that invokes the particles, give it no resource cost and no cooldown, and invoke it as much as you want as you tweak the particle parameters.

Defining Particles

To define a new particle effect, create a Lua file under your module's data/gfx/particles directory.

The ToME source code has a huge set of existing particle effects under game/modules/tome/data/gfx/particles, so you can look there to see how particular effects are implemented.

Basic concepts

Particle effects are processed at 30 frames per second (regardless of the T-Engine's actual frame rate).

A particle effect is a fragment of Lua code that returns the following:

  1. A table of parameters for each particle. This table can define parameters directly, or it can contain a generator function that returns a table of parameters each time it's invoked.
  2. An emitter function. This function is called every frame (i.e., 30 times a second). Its main job is to call self:ps:emit(N) (where N is the number of particles to generate for that frame) as appropriate.
  3. (Optional) A number giving the maximum number of particles that the system will handle for this particle effect. Setting this too high will slightly hurt performance.
  4. (Optional) A string giving an image filename (minus extension) to load and use in place of the standard dot or spherical image.
  5. (Optional) A boolean that can be set to cause the particle system to not be automatically deleted when no more particles exist. Use with care.

Under normal conditions, a particle system will be automatically deleted when no more particles exist. The emitter function often limits itself to only running a certain number of times to ensure that particle systems don't go on forever.

Some basic trigonometry may be helpful to convert between x, y coordinates and angles on a circle.

Parameters

Particle effect code can return a table of parameters directly for use with the T-Engine's simple generator, or it can return a generator function.

Simple generator

A table for use with the simple generator might look like this:

return {
    base = 1000,
        
    angle = { 0, 360 }, anglev = { 2000, 4000 }, anglea = { 200, 600 },
        
    life = { 5, 10 },
    size = { 3, 6 }, sizev = {0, 0}, sizea = {0, 0},
        
    r = {0, 0}, rv = {0, 0}, ra = {0, 0},
    g = {80, 200}, gv = {0, 10}, ga = {0, 0},
    b = {0, 0}, bv = {0, 0}, ba = {0, 0},
    a = {255, 255}, av = {0, 0}, aa = {0, 0},
}

Note that each value is given as a pair of numbers; these give the minimum and maximum values for the RNG to randomly generate each particle. Also note that colors (r, g, b, and a) range from 0 to 255. Only integers are permitted.

The simple generator is fairly restrictive; it's only really suitable for particles moving outwards from a central point.

Generator function

The same particle effect expressed as a generator function would look like this: (UNTESTED)

return { generator = function()
    return {
        trail = 0,

        life = rng.range(5, 10),
        size = rng.range(3, 6), sizev = 0, sizea = 0,

        x = 0, xv = 0, xa = 0,
        y = 0, yv = 0, ya = 0,
        dir = math.rad(rng.range(0, 360)), dirv = 0, dira = 0,
        vel = rng.range(2, 4), velv = rng.range(0.2, 0.6), vela = 0,

        r = 0, rv = 0, ra = 0,
        g = rng.range(80, 200)/255, gv = rng.range(0, 10)/255, ga = 0,
        b = 0, bv = 0, ba = 0,
        a = 1, av = 0, aa = 0
    }
end }

The generator function invokes the RNG itself and returns floating point numbers.

Parameter values

Several parameters have ...v and ...a values. These give velocity and acceleration for that value. Each frame, velocity is added to the base value, then acceleration is added to velocity (causing velocity to change for future frames). For example:

   r = 1, rv = -0.1, ra = 0
   g = 0, gv = 0, ga = 0,
   b = 0, bv = 0, ba = 0

starts out solid red and fades to black over 10 frames.

As another example:

   y = 0, yv = 0, ya = -0.4

creates a particle that is initially motionless but starts moving up faster and faster.

Details on values:

General settings
life Number of frames for which the particle will exist
size, sizev, sizea Size of the particle
Simple generator only
base All velocity and acceleration values are divided by this before being processed (since the default generator can't take fractional values directly).
angle, anglev, anglea Angle along which the particle should move, in degrees, and velocity and acceleration at which it should move along that angle. Generator functions can use dir and vel for a similar effect.
Generator function only
trail Used to draw trails from one particle to another
x, xv, xa x coordinate, relative to the center of the particle system
y, yv, ry y coordinate, relative to the center of the particle system
dir, dirv, dira Angle along which the particle should move, in radians. dirv and dira give the rate at which that angle should change.
vel, velv, vela Velocity to move along the angle given by dir, and the "velocity of velocity" (i.e., acceleration) and the "acceleration of velocity." Movement can be done via xv, xa, yv, ya or dir, vel (or both at the same time).
Color
r, rv, ra Red component
g, gv, ga Green component
b, bv, ba Blue component
a, av, aa Alpha component. 255 (for the simple generator) or 1 (for a generator function) means fully opaque, 0 means fully transparent.