Scouts’ Odyssey (Unreal Engine 4)
(University Project, May 2023 - August 2023)
The trailer for Scouts’ Odyssey (created by Joy Kelly, an artist on the team).
Description
In the third semester of my masters course at Abertay University I took part in a client project for The Chinese Room, working in a multidisciplinary team to produce a game about characters telling stories with the environment changing around them. We created “Scouts’ Odyssey”, a relaxing puzzle game where scouts act out a story told by their scoutmaster and figure out all the details as they go, changing the environment around them as the story unfolds and puzzles are solved.
I was one of two programmers on this project, responsible for all the interaction logic in the game as well as handling 2D animations, creating materials with controls for playing back frame-based animations via C++ code. I also did some technical art work to create effects like an outline on the character when they appear behind geometry, planar mapping on scene props and a pulsing glow effect for interactable objects when the player gets close enough to them.
Project Components
Gameplay and Interaction Logic:
Interaction component structure:
Scouts’ Odyssey is a puzzle game based around interacting with the world and finding a way forward, so at the beginning of the project it was decided that an effective way to structure this logic in code would be to encapsulate it into a component - checking if an object can be interacted with is done by checking if it holds an interaction component. I created a C++ class which describes the base functionality of interactions:
OnInteractWithItem - Called by the player character and describes what happens when the player specifically interacts with an item.
DoTask - Called from dialogue trees and describes what items do during particular dialogue events.
This structure massively increased the development time of new interactions, with some taking as little as 30 minutes to implement!
UML diagram of the interact component, plus all the in-game interactions which inherit from it.
Character controller:
Since the puzzles and dialogue are the main aspects of the game and our target audience was players aged 8 and up, making a character controller which doesn’t get in the way of the player going or doing where and what they want was very important. I’m a fan of games with snappy controls like Hollow Knight and Celeste since they give the player a lot of control and freedom in solve problems during gameplay, so I used a similar approach and created a simple but responsive system in Scouts’ Odyssey.
Our playtesting sessions didn’t outline any issues from the player in interacting with the world or going to different places, so this approach worked well!
Simple character controller for responsive gameplay, so as not to detract from the puzzle aspect of the game.
Technical Art Work:
Outline effect:
As a way of helping the player better understand their place in the world while exploring, I created an outline effect that indicates the player’s position on-screen when they’re behind some other geometry.
This works by using a separate SceneCaptureComponent actor which matches the main camera’s location and rotation, renders only the player character into a render target, then uses Laplacian edge detection in a post processing pass on the scene’s custom depth/stencil buffer to produce an outline around the player, storing the edge detection results in the render target.
This is then composited onto the frame in another post process pass when the player’s depth in the custom depth/stencil texture is greater than Unreal’s scene depth texture, which indicates that the player is behind something and obscured from view. This effect also takes the animations into account so the player can see this detail in the silhouette, which is a nice plus!
An outline of the player’s sprite which appears when behind geometry, responding to the sprite animation’s current frame as well.
Glow Effect:
To indicate to the player what scene props and items can be interacted with and when they can do so, scene props use instances of a base material with controls for adjusting the strength of a pulsing emissive glow. Scene props and items can then enable or disable this glow effect when the player enters or exits a trigger volume, respectively.
Objects toggling their glow effect on and off when the player is within reach and able to interact with them.
Material Management:
On the project I took charge of managing a small library of base materials for different types of in-game objects and functionality. As well as the glow effect described above, there are base materials with features like use of a cardboard normal map to give the impression that the scene props are cut out of cardboard, 2D animation materials with C++-side controls for automatically displaying the appropriate sprite in a spritesheet, UI materials for looping through a given spritesheet, etc.
The list of base materials used in the game, as well as some of their instances.
2D Animation Playback Systems:
Spritesheet Material:
Building off of tech from a project I’d completed in the previous semester, I created a material for handling and playing back spritesheet animations. This makes extensive use of the flipbook node with additional parameters which allow for programmers to have full control over animation playback in C++/Blueprint logic. Moving the animation playback logic outside of the material was particularly useful for handling different types of animations, for example walking animations can be played with simple looping logic, “change item” animations can be played start-to-finish for the item being put away and played in reverse for the new item being equipped, even idle animations with sprites for the character blinking can be played back in a unique way to have the character blink in a realistic way.
The material node graph which plays back spritesheet animations.
Spritesheets for switching between the hammer and acorn items, authored by Igor Oliveira (top) and their use in-game (bottom). When switching items, the current items’s animation will be played front-to-back before switching to the new item’s animation, which is played front-to-back.
Texture Management:
This project made use of a lot of different spritesheets for the player character, AI actors, and any interaction effects like smoke clouds around items that disappear. To make handling all these spritesheets a much more streamlined process, I created a data asset template which holds animation metadata including the dimensions of the spritesheet, the number of empty frames in the spritesheet, the intended playback framerate of the animation and the specific frame that events should occur on (for synchronising things with animations like a tent being set up on the “hammer hit” frame, or an acorn flying into the air on the frame where said acorn leaves the player’s hand).
Using this template sped up the import process for animations sped up development time a lot - adding a new animation into the engine became a simple and quick process of importing the texture, setting up a data asset with the animation’s properties and plugging it into the player character class so that it would be played back during gameplay.
An excerpt of the player character actor’s animation list (left) and an example of a spritesheet animation data asset with additional animation metadata, for convenient handling in C++/Blueprint code (right).