Hello! Welcome back to our JRPG engine-building journey.
In our last few lessons, we've assembled a powerful event system. We started with a basic interpreter, then integrated a dialogue manager that can handle complex, branching conversations by pausing the event flow. Today, we'll give that system eyes and legs. We're moving from static dialogue to dynamic, cinematic scenes.
This lesson directly addresses the learning outcome: Implement event commands for controlling character and camera movement to create simple cutscenes. We will expand our EventInterpreter's vocabulary with commands to move characters, pan the camera, and control timing, transforming our event system into a director's toolkit.
1. The Architecture of a Cutscene
Before we dive into specific commands, let's consider the high-level structure of a cutscene. In tools like RPG Maker, and in well-designed game engines, a cutscene isn't managed by the participating characters themselves. Instead, it's orchestrated by a single, dedicated "controlling event." This approach centralizes the logic, making scenes easier to create, debug, and maintain.
This controlling event typically follows a three-act structure: Setup, Execution, and Cleanup.
The official RPG Maker blog provides an excellent article, 'Cutscene Basics,' that outlines this professional workflow. It's a great primer on the architectural pattern we'll be adopting.
Please read the sections 'Starting Settings', 'Hidden Actors', and the final section describing the cleanup process (starting with 'Now that the cutscene is done...'). Focus on these key architectural ideas: The Controlling Event: Using a single autorun event to manage the entire scene. Player Handling: Why it's crucial to make the player character transparent and disable their collision (Through ON) at the start. Cutscene Actors: Using dedicated event objects for cutscene characters, activated by a 'cutscene' switch. Cleanup: The importance of reversing the setup steps (restoring the player, turning off switches) to return control cleanly.
This setup/cleanup pattern is fundamental. It ensures the game world is in a predictable state before the cutscene begins and is restored to a playable state after it ends, preventing a host of bugs.
2. Expanding the Event Command Library
Our goal is to translate the concepts from the article into commands for our EventInterpreter. Here are the primary tools we'll need, which are standard across most 2D RPG engines.
| RPG Maker Command | Our Engine's Command (Example) | Purpose |
|---|---|---|
| Set Move Route | moveCharacter | Defines a path and actions for a character to follow. |
| Scroll Map | scrollCamera | Pans the camera across the map. |
| Wait | wait | Pauses the event sequence for a set duration. |
| Change Screen Color Tone | fadeScreen | Fades the screen to/from a color (e.g., black). |
| Screen Shake/Flash | shakeScreen/flashScreen | Adds dramatic visual effects. |
Let's look at the two most important commands for choreography: moving characters and the camera.
3. Choreographing Characters: Set Move Route
The Set Move Route command is the heart of any cutscene. It's not just about moving from point A to B; it's a mini-script for a single character, containing a sequence of actions they perform.
In our data-driven system, a moveCharacter command would look something like this in JSON:
{
"type": "moveCharacter",
"target": "npc_guard",
"waitForCompletion": true,
"route": [
{ "type": "changeSpeed", "speed": 4 },
{ "type": "move", "direction": "up", "steps": 5 },
{ "type": "turn", "direction": "left" },
{ "type": "wait", "frames": 30 },
{ "type": "move", "direction": "left", "steps": 3 }
]
}
The EventInterpreter would find the npc_guard object and pass it the route array. The character's own update method would then be responsible for executing these steps sequentially.
The possibilities within a move route are extensive. You can change a character's speed, animation, transparency, and more.
RPG Maker MV Tutorial #19 - Movement Routing!
To get a full sense of what's possible within a move route, this tutorial from SomeRanDev provides a focused look at RPG Maker's 'Set Move Route' window. Notice how many different actions can be queued up.
Watch from 0:51 to 6:01. Don't worry about memorizing every command. Instead, focus on the categories of actions available: Movement & Turning: Basic directional steps, diagonal moves, turning in place. Character Properties: Changing speed, frequency, transparency (Transparent ON/OFF), and even the character's sprite image. State Control: The ability to turn switches on/off directly from a move route.
4. Directing the Camera: Scroll Map and Wait
A static camera can make a scene feel flat. Panning the camera is a simple but effective technique to direct the player's attention, reveal new information, or add a sense of scale. The scrollCamera command would instruct our camera object to smoothly interpolate its position to a new target over a set duration.
Just as important as movement is the deliberate use of pauses. The wait command is essential for pacing, allowing moments to land, giving the player time to absorb a visual, or synchronizing actions.
How To Make A Pokémon Game - Part 5: Event Commands
The 'How To Make A Pokémon Game' tutorial series by Thundaga has excellent, concise explanations for many event commands. Let's look at how it demonstrates camera scrolling and waiting.
Please watch these two short segments: Wait Command (16:52 - 18:06): Note the explanation that frames are the unit of time (typically 60 frames = 1 second). This is a standard convention. Scroll Map (47:25 - 49:20): Pay attention to the core parameters (direction, distance, speed) and the crucial advice to always scroll the camera back to its original focus to avoid breaking gameplay.
5. The Asynchronous Challenge: waitForCompletion
Here we encounter the same architectural consideration as with our dialogue system. Character and camera movements take time. The EventInterpreter cannot simply fire off a moveCharacter command and immediately proceed to the next line, or an NPC might start talking before they've finished walking into the room.
This is where the waitForCompletion flag comes in.
"waitForCompletion": true: TheEventInterpreterpauses. It delegates the movement task to the character/camera controller and waits for a callback or promise resolution before processing the next event command. In your front-end experience, this is the exact equivalent ofawait someAnimation()."waitForCompletion": false: TheEventInterpreterinitiates the movement but does not pause. It immediately continues to the next command. This is how you achieve simultaneous actions, like two characters walking towards each other at the same time. You would issue twomoveCharactercommands, both withwaitForCompletion: false, followed by a final command that does wait for both to finish (or a simplewaitcommand for the estimated duration).
The Cutscene Basics article you read earlier demonstrates this when Kasey and a dog run simultaneously. One Set Move Route is set without "Wait for Completion," while the second one has it checked, ensuring the event list pauses until the second character (Kasey) finishes her movement.
Test your understanding!
You want to create a short cutscene where two guards simultaneously walk away from a door to let the player pass. After they have both reached their final positions, a "door unlock" sound effect should play.
How would you structure the event commands using the waitForCompletion flag to achieve this?
Show answer
moveCharacter(Guard 1): SetwaitForCompletion: false. This starts Guard 1's movement but allows the interpreter to proceed immediately.moveCharacter(Guard 2): SetwaitForCompletion: true. This starts Guard 2's movement. Because it waits for completion, the interpreter will now pause until Guard 2 has finished their route.playSoundEffect("door_unlock"): This command will only be executed after the interpreter resumes, which happens once Guard 2 (and by extension, Guard 1 who started at the same time) has stopped moving.
6. Putting It All Together: A Sample Cutscene Script
Let's script a simple scene using our new commands to solidify the concepts.
Scenario: The player enters a town for the first time. An old man (named old_man_event) walks up to them, says a line of dialogue, and then the camera pans to show the town square before returning.
Here is what the event list in JSON might look like:
[
// --- SETUP ---
{ "type": "fadeScreen", "color": [0,0,0], "duration": 30, "to": "out" },
{ "type": "wait", "frames": 30 },
{ "type": "moveCharacter", "target": "player", "route": [{ "type": "transparent", "state": true }] },
{ "type": "setEventPosition", "target": "old_man_event", "x": 10, "y": 20 },
{ "type": "fadeScreen", "color": [0,0,0], "duration": 30, "to": "in" },
{ "type": "wait", "frames": 30 },
// --- EXECUTION ---
{
"type": "moveCharacter",
"target": "old_man_event",
"waitForCompletion": true,
"route": [
{ "type": "move", "direction": "up", "steps": 4 }
]
},
{ "type": "showDialogue", "dialogueId": "OldManWelcome" },
{ "type": "wait", "frames": 60 },
{
"type": "scrollCamera",
"direction": "right",
"distance": 8, // in tiles
"speed": 2,
"waitForCompletion": true
},
{ "type": "wait", "frames": 120 },
{
"type": "scrollCamera",
"direction": "left",
"distance": 8,
"speed": 2,
"waitForCompletion": true
},
// --- CLEANUP ---
{ "type": "fadeScreen", "color": [0,0,0], "duration": 30, "to": "out" },
{ "type": "wait", "frames": 30 },
{ "type": "moveCharacter", "target": "player", "route": [{ "type": "transparent", "state": false }] },
{ "type": "fadeScreen", "color": [0,0,0], "duration": 30, "to": "in" },
{ "type": "endEvent" }
]
This script demonstrates the full loop: hiding the player, choreographing an NPC, controlling the camera, showing dialogue, and cleanly returning control to the player.
Conclusion
You have now designed the core components for a robust cinematic event system. By adding commands for character and camera movement, and by understanding the critical role of timing and synchronization (wait, waitForCompletion), you can move beyond static conversations and begin to tell stories with action and direction.
Key Takeaways:
- Cutscenes are best managed by a single "controlling event" that handles setup, execution, and cleanup.
- The
moveCharacter(Set Move Route) command is a powerful tool for scripting detailed character actions, not just movement. - The
scrollCamera(Scroll Map) command directs the player's focus and adds a cinematic quality to scenes. - The
waitForCompletionflag is the key architectural pattern for handling asynchronous actions, allowing for both sequential and simultaneous movements. This is directly analogous toasync/awaitin modern JavaScript.
Preview of the next lesson:
We've built a system that can execute a pre-defined list of commands. But what if we want those commands to change based on the player's actions or story progress? In the next lesson, we will implement conditional event logic (IF/ELSE) based on game flags. This will allow our events to check the game's state (e.g., "Has the player found the key?") and react dynamically, making our game world feel truly responsive.
Can't find a good explanation? Sign up and we'll make it for you
Sign up