7. Animation & Visual Effects
# 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.