David here again!
In Thimbleweed Park 1, there was a large puddle the actors walked through, and we saw splashing around their feet, and heard splashing for each step. I’m going to talk about how we did that by setting up room triggers and turning on a special animation layer in the actor’s animation file.
Triggers
In the Dinky engine, triggers are quadrilaterals on the screen, usually placed somewhere in the area where the actors are going to walk. When an actor enters a trigger, the triggerEnter() function is called, and when they exit the trigger, the triggerLeave() function is called.
Triggers are added using our room setup tool, Wimpy. We add a generic object, indicate it’s a trigger, and adjust the four corners of the quadrilateral to match the desired trigger area. More on this below.
Animation Layers
In my last blog post on animation, I mentioned we could have multiple layers for things like hats, heads and nose glasses. We also used layers for splashes.
In the above screenshot you can see all the layers that make up the basic Agent Ray animation, including one for eye blinks (the blink is made up of a few pixels which cover her eyes), eyes looking left or right, a collection of six heads that each have a different mouth shape (maybe we’ll go into lipsync in another blog), and near the bottom, you see the splash layer.
There’s also a layer near the bottom called _trigger. This has nothing to do with room triggers, but is a flag we can set to trigger a sound effect (footstep), or some other event we need synchronized with the animation.
The _floor layer is for reference only, and helps us align the actor to where the floor will be. I have it turned off in the above screen capture.
The splash animation is made up of three frames. We position the frames over the actor’s feet, timed to the moment the foot hits the ground (or water).
Here’s the splash animation of Agent Ray.
Trigger Code
Now that we have the animation working, here’s the code to turn on and off the splash layer on Agent Ray. splashTrigger is what I named the room trigger in Wimpy:
splashTrigger = {
function triggerEnter(actor) {
footstepsWater(actor)
}
function triggerLeave(actor) {
footstepsNormal(actor)
}
}
and elsewhere we have the actual footstep functions:
function footstepsNormal(actor) {
actor.footstep_sound = actor.footstep_save
actorShowLayer(actor, "splash", false)
}
function footstepsWater(actor) {
actor.footstep_sound = SOUNDID(footstep_water)
actorShowLayer(actor, "splash", true)
}
function footstepsGrass(actor) {
actor.footstep_sound = SOUNDID(footstep_grass)
actorShowLayer(actor, "splash", false)
}
Each actor has a default footstep, and we save that off in the footstep_save variable for each actor.
The actorShowLayer command turns on and off the specified layer.
I threw in another function above, footstepsGrass(), where I was testing out the sound of walking on grass and added another room trigger area over the grass outside the Nickel News.
Finally, we have a system function that is called when there’s a _trigger in the animation, as I described above. Again, this is a different kind of trigger from a room-defined trigger quadrilateral. For animation events, the _triggerEvent() function is called.
function _triggerEvent(actor, event) {
if (event == "@step") {
local sid = actor?.footstep_sound
if (sid) {
playSoundAt(sid, actor)
}
} else {
if (is_function(actor?.triggerEvent, 1)) {
actor.triggerEvent(event)
}
}
}
The event name in Aseprite for footstep _trigger events is @step. If there are other event names in the animation, the else portion of the code is run, but only if the specified actor has its own triggerEvent code. For example, the Sheriff from Thimbleweed Park 1 had an animation of flipping a coin, and this is the code that’s triggered when that event is detected in his animation:
function triggerEvent(sound) {
if (sound == "@coinFlip") playSoundAt(SOUNDID(coin_flip), sheriff)
}
Here’s what the splash animation looks and sounds like in the game. I don’t have a puddle here, but I’ve made the trigger quadrilaterals visible for you to see.
– David Fox

Comments:
Twice the work, but double the pride :-)
So how is the solution for TP2? Do you have a workflow already? Or will it be similar?
Can you use existing code or are the concepts vastly different? (Bet this would be another blog post itself)
Thanks, David!
The only thing I don’t get is, what’s in the _trigger frame number 5 in the Aseprite file? Is there really something? Or is just a check for you know where the trigger should start, and save that frame number in a variable in the code manually?
Really enjoining all the blogs! Thank you.
I'm definitely pulling code snippets from both Delores and RtMI as inspiration. This engine is an evolved version from those two games, so much of the code is similar, and when there's an engine function that Ron hasn't yet implemented, we talk about it and he either brings it over, or it goes on a wishlist for later.
So, concepts are nearly identical in terms of the way we code. The tools keep getting better, and we now have even more experience to draw upon.
I wish I could jump into all this and be part of developing a game like this.
Keep up the good work, you surely triggered me!
Also, I'm currently not cutting off the splash sound, so it can last longer than the character in the puddle. That's probably less of an issue. If we do use splashes in the game, I'll be sure to tune it better than this demo.
Animation layers were also in Return to Monkey Island too, right? I've wanted to know what that was; it gave the walk-n-talk scene near the end with Guybrush and Elaine life.
I don't think the water sprite should follow the character. If you step through it frame by frame, the splash stays attached to them for a couple of extra frames before the next animation frame and eventually disappearing. Since the splash happens in world space, the physics should behave that way too - once the water is in the air, it's on its own and the character's movement shouldn't carry it along.
It might be easier to picture if you imagine the character running through the puddle at high speed. A splash glued to them at that point would look really out of place. :)
I can imagine that having the splash live on the character rather than in the environment makes this tricky to keyframe, since the walk speed affects where the water should end up.
This is so interesting and yet raises so many follow up questions. 😅
Thanks for sharing!
If we use this in the new game, we'll adjust so it synchs better.
Add comment: