Shader is a piece of user-defined code that is executed on each frame pass for each scene object that has one or more shaders attached to it. Shader is defined by the CPShader trait:
getShaders()
method.Animation in CosPlay
In CosPlay there are different ways one could implement animated scene objects. In the end, all of these approaches deliver the same result but each individual technique is tailor-made for a specific animation type:
Shader is a piece of user-defined code that is executed on each frame for each scene object that has one or more shaders attached to it. There are types of animations that simply don't fit any other type of animation. The typical example of shader-based animation is the various lighting effect: flash-lite, sun shadows, transitions, highlighting, etc. These types of animation simply cannot be reasonably implemented using sprites, or particles, or canvas drawing. In such cases, shaders provide simple and effective contract to implement this behavior. Note also that If the shader is stateless it can be added to multiple scene objects to provide its effect.
Shader Is An Asset
Just like other assets such as CPFont, CPImage, CPParticleEmitter, 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.
Shader is any class or object that implements CPShader trait. Let's develop a flashlight effect shader that can be programmatically toggled on and off. When turned on it should produce the effect similar to this (screenshot is taken from Shader Example):
Here's full code for this type of shader:
object FlashLightShader extends CPShader: private final val RADIUS = 8 private var on = false // Method to programmatically turn the effect on and off. def toggle(): Unit = on = !on // Called on each frame update. override def render(ctx: CPSceneObjectContext, objRect: CPRect, inCamera: Boolean): Unit = if on then val canv = ctx.getCanvas val cx = objRect.centerX val cy = objRect.centerY val effRect = CPRect(cx - RADIUS * 2, cy - RADIUS, RADIUS * 4, RADIUS * 2) effRect.loop((x, y) => { if canv.isValid(x, y) then // Account for character with/height ratio to make a proper circle... val dx = (cx - x).abs.toFloat / 1.85 val dy = (cy - y).abs.toFloat val r = Math.sqrt(dx * dx + dy * dy).toFloat if r <= RADIUS then // Flashlight is a circular effect. val zpx = canv.getZPixel(x, y) val px = zpx.px val newFg = px.fg.lighter(0.8f * (1.0f - r / RADIUS)) canv.drawPixel(px.withFg(newFg), x, y, zpx.z) })
NOTES:
render(...)
(line 9).toggle()
on line 6 provides a way to turn on and off this effect from the outside of this shader, e.g. based on keyboard event.Once shader is created it can be attached to any scene object. For example, in the code below we create a simple image sprite with our shader attached to it. On Space press the flashlight effect toggles on and off:
val bulbImg = ... val bulbSpr = new CPImageSprite("bulb", 10, 10, 1, bulbImg, false, Seq(FlashLightShader)): override def update(ctx: CPSceneObjectContext): Unit = super.update(ctx) ctx.getKbEvent match case Some(evt) => if evt.key == KEY_SPACE then FlashLightShader.toggle() case None => ()
CosPlay comes with number of built-in prefab shaders:
These prefab shaders are used in various games that are shipped with CosPlay.