The Odessa Tree
A game by Overscoped
The Odessa Tree is a third-person puzzle platformer, made with Unreal Engine, by team Overscoped, a group of senior year students at Drexel University. I was a programmer on the team. This page details a Material Function and a UI prompt system which I designed. For more information, please check out our official website using the link above.
Dithering Effect on Foliage
Due to the overgrown nature of the vegetation in game world, there are many overhangs of ivy leavies throughout the map. These overhanging ivies can sometimes get in the way of the third-person camera, obstructing player’s view on the character.
To solve this issue, I made a Material Function that takes into account the fragments that fall in between the character and the camera. I then added it to the ivy’s materials, which will apply a fading dithering effect using the Opacity Mask.
The Material Function will create a circular, dithering mask, which can be applied to the Opacity Mask on a material that is Masked for its Blend Mode. The circular mask masks out 100% at the center of the screen and its effect gradually decreases further away from the screen center.
This Material Function uses a Material Parameter Collection that holds the data of camera distance as well as other data that are germane to this Material Function. Camera distance is the distance between the camera and the character, which is useful in determining which fragments of foliage are to be masked out.
The Material Parameter Collection has a number of parameters that can affect how the dithering effect appears. One of them is the distance between the character and the camera, which continues to be updated at run time.
The “Distance” Scalar Parameter is set by the
”Update Camera Distance” in another utility class on the player character that is called every 0.1 second using a looping Timer.
Prompt Trigger Box
As with other games, The Odessa Tree utilizes trigger boxes that show prompts/hints when the player enters them. A challenge with having three characters is that the prompt for an interaction with a mechanic may need to be different for some or all characters.
As shown above, there is a trigger box placed around a white cube, which is just a reference point. When a character enters the box, a specific prompt shows up, depending which character is entering it.
I designed the prompt system such that the game designer can choose one or more characters to show a specific prompt to. The interface is a drop-down menu as you can see here.
The Trigger For variable is an enum that is marked as a bitmask. This allows for the ability to multi-select. Here is the implementation of enum in C++:
And, for example, here is how this enum can be declared as a member in a struct:
When it comes to checking if a character is one of the character types that the game designer specifies for triggering a prompt, a simple AND operation will do the trick. Here is a function that checks if Vessel (the target to search for) is in Collection:
If a trigger box is too small, it is easy for the player to walk past it. For the player to see that prompt again, they will have to walk back into the box. And that assumes the player notices there is a prompt. If they don’t, and the information is important, such as how to use an ability, this can pose a problem for the gameplay experience.
To counter that, I provided an option on the trigger box that a prompt can stay on the screen even if the player exits the box. The prompt can only be removed from the screen if a certain action is performed. Its use cases can be found across the tutorial area where the designer carefully curated the information presented to the player.
This does introduce another problem. Let’s say a player triggers a prompt that does not go away until they hit the right trigger. And, without doing so, the player enters another trigger box that also shows a prompt. Suddenly, there are two prompt UI widgets fighting for screen space.
A workaround of this is to make sure the screen is clear before displaying a prompt on it. I drew inspiration from the concept of critical section in concurrent programming. However, in this case, I used Unreal’s Subsystem to achieve the same effect.
One of the checks a prompt trigger box needs to go through before displaying the prompt, is to see if there is already a prompt on the screen. It does so by querying the Dialouge Subsystem, as you can see below. If there is, this prompt will not display.
Upon displaying or removing itself from the screen, a prompt box will register to Dialogue Subsystem. The idea is to pass the reference to a widget to the subsystem. Here is a simplied code snippet:
To see complete code samples, please visit the repo.