7. Animation & Visual Effects

Defold Platformer Framework
# 7. Animation & Visual Effects In this section, we'll explore how to enhance your platformer with animations and visual effects to make your game more dynamic and engaging. ## Character Animations ### Setting Up Animation Groups Defold uses animation groups to organize different animation sequences. For your platformer character, you'll typically need animations for: - Idle - Running - Jumping - Falling - Attack/Action ```mermaid graph TD A[Character Sprite] --> B[Idle Animation] A --> C[Running Animation] A --> D[Jumping Animation] A --> E[Falling Animation] A --> F[Attack Animation] ``` ### Animation Component Setup In your character.go file, ensure you have an animation component properly configured: ```lua -- In character.script function init(self) -- Get animation component reference self.anim = msg.url(".", "sprite", "animate") -- Set default animation msg.post(self.anim, "play_animation", {id = hash("idle")}) end ``` ### Transitioning Between Animations Trigger animations based on character state: ```lua function update(self, dt) -- Determine current state if self.grounded then if math.abs(self.velocity.x) > 10 then msg.post(self.anim, "play_animation", {id = hash("run")}) else msg.post(self.anim, "play_animation", {id = hash("idle")}) end else if self.velocity.y > 0 then msg.post(self.anim, "play_animation", {id = hash("jump")}) else msg.post(self.anim, "play_animation", {id = hash("fall")}) end end end ``` ## Particle Effects Particle effects can add significant visual appeal to your platformer. ### Common Particle Effects - Dust when landing/running - Sparkles for collectibles - Impact effects for attacks - Environmental particles (rain, snow, leaves) ### Creating a Dust Effect 1. Create a particle effect file (.particlefx) 2. Configure it with appropriate textures and parameters 3. Trigger it at the right moments: ```lua -- In character.script function on_message(self, message_id, message, sender) if message_id == hash("contact_point_response") and message.group == hash("ground") then if not self.was_grounded then -- Spawn landing dust effect factory.create("#dust_factory", self.position, nil, {}, 1) end self.was_grounded = true end end ``` ## Screen Effects ### Camera Shake Add impact to jumps, landings, and attacks with camera shake: ```lua function shake_camera(self, intensity, duration) -- Store original camera position local cam_pos = go.get_position("camera") -- Shake for duration local t = 0 while t < duration do local offset_x = math.random(-intensity, intensity) local offset_y = math.random(-intensity, intensity) go.set_position(cam_pos + vmath.vector3(offset_x, offset_y, 0), "camera") t = t + dt coroutine.yield() end -- Reset camera position go.set_position(cam_pos, "camera") end ``` ### Screen Flash For impacts or special events: ```lua function flash_screen(self, color, duration) -- Create a full-screen quad local flash = factory.create("#flash_factory") -- Set color with full alpha go.set("#flash", "color", vmath.vector4(color.x, color.y, color.z, 1)) -- Fade out go.animate("#flash", "color.w", go.PLAYBACK_ONCE_FORWARD, 0, go.EASING_LINEAR, duration, 0, function() go.delete(flash) end) end ``` ## Juice and Polish "Juice" refers to small visual and feedback elements that make interactions feel satisfying. ### Squash and Stretch Apply scale animations when landing or jumping: ```lua function jump(self) -- Vertical stretch when jumping go.animate(".", "scale", go.PLAYBACK_ONCE_FORWARD, vmath.vector3(0.8, 1.2, 1), go.EASING_OUTQUAD, 0.2) -- Apply jump force self.velocity.y = JUMP_POWER end function land(self) -- Horizontal squash when landing go.animate(".", "scale", go.PLAYBACK_ONCE_FORWARD, vmath.vector3(1.2, 0.8, 1), go.EASING_OUTQUAD, 0.2, function() go.animate(".", "scale", go.PLAYBACK_ONCE_FORWARD, vmath.vector3(1, 1, 1), go.EASING_OUTQUAD, 0.2) end) end ``` ### Collectible Animations Make collectibles more appealing with simple animations: ```lua -- In collectible.script function init(self) -- Gentle floating motion go.animate(".", "position.y", go.PLAYBACK_LOOP_PINGPONG, go.get_position().y + 10, go.EASING_INOUTSINE, 1.5) -- Continuous rotation go.animate(".", "euler.z", go.PLAYBACK_LOOP_FORWARD, 360, go.EASING_LINEAR, 3) end ``` ## Performance Considerations When adding visual effects, keep performance in mind: 1. Limit the number of simultaneous particle effects 2. Use object pooling for frequently spawned effects 3. Disable off-screen effects 4. Profile your game regularly to identify performance bottlenecks ```lua -- Object pooling example for dust effects function init(self) self.dust_pool = {} for i = 1, 10 do local dust = factory.create("#dust_factory") go.set_scale(vmath.vector3(0, 0, 0), dust) table.insert(self.dust_pool, dust) end end function spawn_dust(self, position) if #self.dust_pool > 0 then local dust = table.remove(self.dust_pool) go.set_position(position, dust) go.set_scale(vmath.vector3(1, 1, 1), dust) -- Return to pool after effect finishes timer.delay(1.0, false, function() go.set_scale(vmath.vector3(0, 0, 0), dust) table.insert(self.dust_pool, dust) end) end end ``` ## Math-Based Effects Some advanced visual effects utilize mathematical functions for organic movement: ### Sine Wave Motion For floating or oscillating objects: $$y(t) = A \sin(2\pi f t + \phi) + y_0$$ Where: - $A$ is the amplitude - $f$ is the frequency - $\phi$ is the phase offset - $y_0$ is the base position ```lua function update(self, dt) self.time = self.time + dt local new_y = self.base_y + 5 * math.sin(2 * math.pi * 0.5 * self.time) go.set_position(vmath.vector3(self.position.x, new_y, self.position.z)) end ``` By implementing these animation and visual effect techniques, you'll create a more dynamic and polished platformer that provides satisfying feedback to players.