In CosPlay, particle effects animation is defined by the following classes:
Particle effects animation is based on the concept of a pixel-based particle and particle emitter. Particle emitter emits particles. Each particle and its emitter have a fully programmable behavior. The key characteristic of particle effect animation is the randomness over the large number of individual elements that you can easily model and implement using fully programmable particles and emitters.
This type of animation is ideal for use cases when animation based on predefined set of key frames is impractical or hard to implement. For example, particle effects animation is used for explosion simulation, continues fire or cloud animations, atmospheric events like rain or snow, "pixie dust" effects, etc.
Let's see how particle effects can be used. In our example we will create a short-time explosion animation - something we could use in our games.
Particle defines a single-pixel element (a-la mini-sprite) that has its own lifecycle and gets updated on each frame update. Particle emitter is a components that is responsible for creating particles. And particle sprite ties all that together into single renderable component. Particle sprite can have one or more particle emitters and each emitter can create multiple particles.
Here's the source code for a particle that participates in a circular explosion pattern:
// Defines the radius of explosion in terms of the particle age. val MAX_AGE = 15 class KaboomParticle(initX: Int, initY: Int, dx: Float, dy: Float) extends CPParticle: private var x = initX.toFloat private var y = initY.toFloat // Linear color gradient, slowly dimming. private val cf = CPCurve.colorGradient(CPRand.rand(COLORS), C_GRAY1, MAX_AGE) // X-curve for slowing down the speed of particle as it moves away from the center. private val dxf = CPCurve.lagrangePoly(Seq( x -> 1f, x + (dx * MAX_AGE) / 4 -> 0.5f, x + dx * MAX_AGE -> 0.3f )) // Y-curve for slowing down the speed of particle as it moves away from the center. private val dyf = CPCurve.lagrangePoly(Seq( y -> 1f, y + (dy * MAX_AGE) / 4 -> 0.4f, y + dy * MAX_AGE -> 0.2f )) private var age = 0 override def update(ctx: CPSceneObjectContext): Unit = age += 1 // Curve X and Y-coordinates changes. x += dx * dxf(x) y += dy * dyf(y) override def getX: Int = x.round override def getY: Int = y.round override val getZ: Int = 1 override def getPixel: CPPixel = CPRand.randSymbol()&cf() override def isAlive: Boolean = age < MAX_AGE
KaboomParticleis a class that implements CPParticle trait and takes initial XY-coordinate and initial direction.
Particle emitter is a user-defined components that is responsible for creating particles.
Particle Emitter Is An Asset
Just like other assets such as CPFont, CPImage, CPShader, CPAnimation or CPVideo they are not managed or governed by the CosPlay game engine unlike scenes and scene object, that are managed and governed by the game engine. Assets are typically created outside the game loop and managed by the developer, they can be freely shared between scenes or scene objects as any other standard Scala objects.
Here's the source code for a particle emitter that creates a circular explosion pattern:
val x = ... val y = ... val emitter = new CPParticleEmitter(): // Number of particles this emitter will emit on each update. private final val GEN_SIZE = 20 private var age = 0 override def reset(): Unit = age = 0 override def emit(ctx: CPBaseContext): Iterable[CPParticle] = if !isPaused && age < MAX_AGE then age += 1 // Emit particles in 360 degree circle. for (_ <- 0 to GEN_SIZE) yield KaboomParticle(x, y, (CPRand.randFloat() - 0.5f) * 3.5f, (CPRand.randFloat() - 0.5f) * 2f, ) else Seq.empty
emit(ctx)(line 9) is called on each frame update by the particle sprite.
emit(ctx)produces a collection of particles that would start their lifecycle on this frame update.
GEN_SIZEon the line 6).
As a reminder, a particle defines a single-pixel element (a-la mini-sprite) that has its own lifecycle and gets updated on each frame update. Particle emitter is a components that is responsible for creating particles. And particle sprite ties all that together into single renderable scene object. Particle sprite can have one or more particle emitters and each emitter can create multiple particles.
Particle effect sprite can be created in just ons line:
val kaboomSpr = CPParticleSprite("kaboom", Seq(emitter))
To make it a bit more interesting we will also add a sound effect to our explosion animation. We'll use callbacks provided by the CPParticlerSprite to accomplish that:
val kaboomSpr = CPParticleSprite("kaboom", Seq(emitter)) val boomSnd = CPSound(src = "sounds/examples/boom.wav") kaboomSpr.setOnStart(Option(_ => boomSnd.playOnce())) kaboomSpr.setOnEnd(Option(_ => boomSnd.stop(1000)))
When put all together here is the result animation you are going to get (see built-in Particle Example for the full source code):
CosPlay comes with the following built-in prefab particles:
These prefab particles are used in various games that are shipped with CosPlay.