Game Design - Color Match 3

This will be the final update on this project for a while since I’ve achieved what I consider the “Minimum Viable Product.” All basic gameplay and animation is implemented with temporary assets. Functional multiplayer both against another player or against the AI is now possible. In the future, I may make adjustments, but the focus will shift towards art and lookdev. Below is a wrap up of this iteration’s technical development.

UE5 Terminology

Local Player Node - This creates another controllable player entity that can be setup with your custom controller and player classes. By default, this makes the game split screen, but that is a simple option change in the project settings.

AI Behavior Tree - The essential blueprint for linking together behavior of your AI. Various logic like Sequences, Selectors, and Simple Parallels determine the order and fail conditions of custom tasks.

Blackboard - Keeps track of all of the variables being used in the Behavior Tree. Can function as targets or booleans for decorators, to name some use cases.

AI Controller - The equivalent to the Player Controller for AI characters. Can manage behavior tree logic per task, switch behavior trees, change blackboard key values, etc.

NavMesh - A large collision box that projects onto surfaces that the AI is allowed to occupy. Adjust settings to determine what surfaces are covered, and with what rules.

NavMeshDefault - This holds more settings for the NavMesh. Features like generating NavLinks, or regenerating the Mesh all together during runtime.

NavLinks - AI Characters get lost when they leave the ground and the NavMesh. NavLinks can remedy this by letting them jump to another surface that is too high without ever technically exiting their allowed boundaries.

Basic Character and Animation

First order of business: get rid of these cubes. If I wanted to be able to showcase multiplayer, it would be really hard to tell what was going on without some kind of animation. I already knew long term I would like to have a humanoid character to be playable in this game, so having a running and jump animation would really push the readability for playtesting. I have a general idea of the character design, and I’ll make a post on that when its further along. For now, I essentially wanted to answer the question of “how many heads tall should the character be?” A game like Mario Party sits around the 2-4 head range, but that was a too little cartoony. 6-8 felt too mature and realistic, which also wasn’t the direction I was going.

Player Static Mesh

When I made a block model and test with a 5 head humanoid character, I was happy with the animations that I could make with it, and it was readable in game. The model that exists currently is a bunch of Maya primitive cubes merged together, and a solid color applied as a material to differentiate player slot.

Simple run animation

Scaling to Four Players

Once I started to get a sense of how Local Player and AI Controllers worked in Blueprints, it became clear to me that some shifting around of logic should be done. At the time, I had the menu enhanced input on the character class itself, when really those needed to be moved to the player controller so that things like pause functionality and menu control could override controlling the character blueprint. I decided to make a menu “character” so that if the player controller receives pause input, it possesses the menu and shuts out any players (and the game) from moving. This way multiple players couldn’t layer their pauses on top of each other, because the menu actor could only be possessed by one player at time.

Then I restructured spawning of actors and how that was implemented in the GameMode blueprint. Based on data about players and control types collected from the UI, the game mode spawns and assigns to arrays references of HumanCharacter, ComputerCharacter (both children of my custom BaseCharacter), PlayerController, and AIController. When players lose lives or game over, their associated classes are destroyed and zeroed in an array, so that the game continues with the remaining players and the arrays hold their length for logic loop reasons.

PSA: I could not get Local Player to work in UE 5.3, and various blog posts share a similar sentiment. It would not let me assign any control, keyboard or controller, to player 2 or beyond. After updating the whole project to UE 5.5, it started to work without changing to my blueprints, so I’m seeing this as a bug.

I changed the way that the result of the round is displayed. Before, a big “Correct” or “Incorrect” flashed on the center of the screen, but this won’t work with multiple characters in play. For now, I’ve put a cube above each character shaded green or red based on the result they got.

All players given a red block indicator since no one made it to the blue platform

Another feature makes it so that if the player runs off of the edge of the stage, they trigger a collision box that immediately destroys them and zeroes out their lives. The stakes just got higher! When a player wins, the game displays “(Color) Wins” in their color, making it clear who has the bragging rights.

AI Enemies

Designing AI players proves to be a fascinating exercise in reframing your thoughts on the game’s design. When I’m playing, a color comes up, I decide what I think is right, and I get on that platform. That train of thought is basically what needs to be converted to AI Behavior Tree action. Get them to pick a platform and get on top of it, hopefully adding some faux unpredictability to whether they are right or wrong.

I find Unreal Engine’s behavior tree to be very intuitive and straightforward. An endless string of “if this, then thats,” with a super obvious highlight display showing exactly where the tree is at any given time. For this basic build, I wanted to keep it simple. Choose a platform, move and jump to it, hope its right. Although this ended up being anything but simple…

For an AI to work in Unreal Engine, it needs a NavMesh. This is essentially a box that projects on to 3D surfaces a 2D map of places where the AI can receive instructions. There’s a medley of customization options, and the viewport preview can be finnicky and not up to date. With default settings it also doesn’t do all that well with movable platforms like I have, with the space in the air where they spawned being the only area that they could access. There is a setting to make the NavMesh update dynamically, so that saves us there.

The next issue is the jumping. While moving to an object is easy to implement and even a default task for the AI, jumping seems to override any other actions. From my best guess, the AI is jumping out of the NavMesh, so it stops moving towards its target. The closest I could find from others with a similar issue is when the player themselves jumps when being followed, so I suspect its the same in my situation. Unreal has a built in solution for this: NavLinks. Although for my purposes, I had to extend the class in C++.

Two NavLinks spawn and follow each platform, shown by the green arrows (function parameter can be adjusted for more)

NavLinks are meant to be static objects that exist in in your level. You place them, and then manually edit their start and end points to determine the path the AI is allowed to move between NavMesh surfaces. The problem in my case is obvious, I can’t manually place a NavLink when the surface at one end is constantly moving! Unfortunately, the relative end positions of the NavLink are not Blueprint accessible, but using the SetLinkData function of the NavLinkProxyClass, I can actually update in realtime the location of the NavLink so that one point is always centered on the platform, and the other is always on the ground. With these problems solved, the AI was functioning as well as a really bad player!

Final Thoughts

I have learned a lot about Unreal Engine and game design from this project. Whenever I have created assets in the past, I try to consider how the gameplay loop and technical systems can inform concepting and rigging to enhance player experience. It has been fun to be on the other side, planning and creating a game with basically no art assets, and seeing if I can still make something enjoyable. I have a few other projects I am wrapping up in the next couple weeks before I dive back into this, but I’m eager to see where I can take it in the future!

Thanks for reading!

Previous
Previous

Character - The Shrew

Next
Next

Game Design - Color Match Game 2