“Slime Project”

(Developed Early 2021)

Solo Project

Engine: Unreal Engine 4

Development Time: 58 hours*

*rough estimate due to pivot (see below)

Music is “Sun-Kissed Skin” by Arulo

 
 
Description

Slime Project was initially inspired by Dungeon Slime, a game currently being developed by Brian May. In the development of Slime Project, I explored mechanics and systems in support of a broad theme (in this case, "being a slime"), and created an external system to provide more context and purpose.

Initially an exercise in level design, I grew increasingly interested in the mechanical possibilities. As this was a personal project, I saw no reason I shouldn’t shift focus. And with the pivot towards systems design and the user experience, everything came together. I took the level I had made and created a much smaller-scale area inspired by it to stage my systems in a believable and holistic environment. From there, it was just a matter of taking my most promising systems and bringing them to the finish line.


Expand each section to read more about it.

 
 
Movement Design
 
Basic Movement
Slime going through and over fences

Slime going through and over fences

When I first saw Dungeon Slime, I was fascinated by the way the slime squeezed through a fence, revealing itself as a living clump of individual parts. In speaking with him, Brian pointed me towards the plugin used to make the procedural mesh and talked about the basics of his slime's movement, which I then adjusted to better fit Slime Project's goals.

The slime itself is made of 64 spheres controlled by a Sphere Manager, and each sphere also has its own code for individual adjustments. The Manager applies force to each sphere based on that sphere’s location, the location of the player capsule, directional input, and the current player state, creating a consistency of form and properly conveying what's going on. Individual spheres will also constrain their velocity and relative locations in situations like jumping, and will temporarily disable their collision if they’re too far from the player. I also experimented with shaping the bottom of the slime with an invisible "platform" of instanced spheres that only collide with the slime at certain times.

Invisible spheres shapes the slime’s jump

Invisible spheres shape the slime’s jump

It was important to me that I facilitate verticality in the slime's movement. Whereas Dungeon Slime approached this from the point of stealthily climbing around exterior surfaces, Slime Project had no need for restricting the player path in that way. As such, Slime Project added variable-strength jumping, mantling, coyote time, and attach points. And because it's always fun to go fast, there's a run button (called “surge” for thematic reasons).

Jumping uses a basic physics impulse on the player, but the real magic comes from the visuals. A meter centered on the slime shows the current jump strength so you don’t have to wonder how long you need to hold the button. The jump has a variable strength to let you reach both high and low ledges with ease. The camera also pulls back and up while jumping to give the best possible view of landing spots.

The slime itself flattens out while holding the jump button to show you’re preparing for something while emphasizing the slime’s springiness. This shape is achieved by adjusting the target location of spheres above a certain relative height. Sphere adjustments like this are incredibly useful for fine-tuning the slime’s shape, as seen with surging.


Slime_Surge_cropped_500x376.gif

Surging

Surging is the slime's version of running. On top of the increased speed, I knew it would be important to have a visual difference while surging. Since I can't rely on the conveyance of the basic "running" animation, I looked to what makes fluids look fast, taking inspiration from swirling currents. I first added a general rotational force applied at all times, so the slime is always swirling around a bit. Then by slightly relaxing the force pulling them in, the spheres swing around in larger arcs like an eddy or whirlpool. I also extended the distance the spheres can be from you, making it look like the slime takes larger "steps".


The player capsule teleports while mantling, and the slime follows

The player capsule teleports while mantling, and the slime follows

Mantling and Coyote Time

Mantling, the ability to grab onto a surface your jump barely misses, is a staple in a lot of modern 3D games because it helps you do what you want. Its lesser-known cousin Coyote Time is where you can jump in the split second after walking off a platform. Both were no-brainer inclusions to help smooth the player experience.

Coyote time was straightforward to implement, but mantling took a bit more work. To achieve it, a series of traces is done in front of you while coming down from a jump, checking for a valid landing spot within a certain vertical distance. It checks above a certain relative height to avoid "mantling" below the slime. Upon finding a valid location, the player capsule is teleported to it and the spheres simply follow as usual, creating a fluid visual.


Attach Points

There are two main types of attach points: solo and spline-based, and entering either shape changes the player state. Solo attach points act like hand-holds for the slime, letting you cling to their locations. If an attach point has an associated spline, however, you're pulled to a location on the spline instead, and can move along the spline in either direction. When you no longer overlap any attach points, the player state returns to normal.

Solo and spline-based attach points

Solo and spline-based attach points

Like mantling, attach points work by teleporting the player capsule on the initial collision. While mantling on a wall, the walls help shape the spheres' movement. Since attach points don't necessarily have that, the spheres move in a single unnatural and unsatisfying clump. To remedy this, spheres are made to "wait" when you hit an attach point, and are put into a list in order of distance from your new location. Then a handful of the closest waiting spheres are pulled towards you, and this continues for about a second until every sphere has stopped waiting. This creates a visual of the slime pulling itself towards the attach point.

Climbing with a player handle

Climbing with a player handle

Slime Project also has a pseudo-attach-point in the player handle. The player handle is basically a mobile solo attach point used for climbing an associated wall, using a 3D volume to determine where the handle can go. If it would leave the volume, it lets go of the slime. Whereas spline-based attach points allow movement along a 3D line, player handles facilitate non-linear movement in a space.

The player handle is my first foray into a wall-climbing mechanic. I'd love to explore the mechanic more in the future, particularly with a method that doesn’t involve external volumes.


 
 
 
Requests & Tracking
 
Requests

The original idea for Slime Project revolved around sneaking through tight spaces, grabbing loot, and figuring out how to get it back to your treasure trove. When I changed direction from level design, I cut out the majority of the puzzle aspect of the project as the mechanics weren't fully developed yet and I couldn't work on it forever. I'd love to return to this project in the future and work on puzzle design.

Today, Slime Project's gameplay sees you finding people with requests and bringing items to fulfill them. Some of those requests are straightforward enough: "Find three apples" or "Find a scroll and two candles", but not all items are equal.

Request_Comparison.jpg

For most items, requests will show what they look like. You might grab a bundle of wheat right from the field, off a table in the market, or inside someone's home, and they're all equally valid to turn in. But then there are unique items that exist only in singular instances, like a rare cliff fruit, or a particularly beautiful vase. Seeing a one-of-a-kind item’s picture isn't all that helpful for finding it, so instead you get a picture of an area near it as a hint.

The difficulty of finding an non-unique item can be adjusted based on their placement in the world, their relative location to the requester, and the amount requested. For unique items, it can be tuned based on landmarks in the hint picture as well as the difficulty of grabbing the item once it's found.

Hint_Comparison.png

When I first implemented the hint pictures using snapshots from scene capture cameras, the resulting images were squished, as I was forcing them into square boxes for the UI. As I can't change the proportions of the scene capture itself, I had to get creative. The ideal solution would work in runtime so I wouldn't have to take, crop, and import a screenshot each time. My research led me to a thread on dynamically cropping spritesheets; a perfect place to start. While I could have stopped there, I wanted to make a material function I could re-use in future projects, so it had to be usable regardless of the input texture's dimensions.

The current iteration of the function specifically crops to a square, so I had to mathematically define the size and placement of that square. I used four-vectors to cut down on the amount of nodes, with the first two components relating to the horizontal aspect, and the other two for cropping the top and bottom. The final material is very lightweight for use with dynamic material instances.

click to expand


Tracking

As in any game with multiple concurrent gameplay tasks, Slime Project lets you check your active requests. Each request is detailed in the pause menu, and you can track them one at a time, either from there or by pressing the Track button while close to a request. When a request is tracked, the Tracker UI expands to show its requirements, and pressing the Track button again collapses the UI to show only the images. This way, you always have the info you need at your fingertips without cluttering the screen.

Track_FromMenuAndWorld.gif
Slime_TrackUnique_cropped_500x278.gif

Given an open world and a multitude of requests, it's expected that a player might forget where to turn in a given request. In addition, you can't take objects through spaces that are too small for them, so you might lose something unique by squeezing through a gate. To address both, directional arrows pop up when the Tracker is expanded.

With the Tracker expanded, you'll be given an arrow over the slime that points back towards the requester. If the tracked request asks for a unique item that you've found but have since dropped, a small arrow pointing to it comes up in a circle around the slime. The system keeps track of whether a unique item has been found, regardless of the associated request's status. That means it works even if you found the item and dropped it before discovering the request.


 
 
 
Inventory
 
Inventory
Slime_Carousel_cropped_500x300.gif

So you don’t have to choose between opening the pause menu or discerning what’s inside the slime, I added the “carousel” to the top-right corner. The carousel shows a maximum of five inventory slots at a time, but lets the player scroll through everything for quick reference. The five slots shown are the defined as the current slot in the center, the next two slots to the right, and the prior two slots to the left (the count loops such that if the first inventory slot is in the center, the two left slots will show the final two items).

To prevent you from simply grabbing everything you find and instantly completing every request, inventory space is limited. You start with three inventory slots, but that doesn't mean you can only hold three items. Items of the same type stack, so five apples take up a single slot. But not every request is going to ask for apples, so it's important to swap items you need for items you don't, and to keep track of where you put them.

You can drop items from the inventory while paused, or even while traversing the world. Items are dropped either one at a time, or by dropping everything in a given slot, determined by player input. Manually dropping something from the carousel always drops from the central slot.

CapacityTable.png

To hold more item types at a time, you of course need to increase your inventory capacity, and you do that by completing requests. Completed requests give you points, and specific point thresholds increase your capacity. Each request gives one point plus an additional one for each unique item in it. When a threshold is reached, your capacity increases, and the threshold is subtracted from your current point total. Thresholds and capacity levels are defined by a data table, and the values of its final row can be used to infinitely continue capacity increases.

 
Inventory.png
 

The inventory went through a lot of rewrites and iterations. Because items in the inventory still exist in the world, the first version tracked every held item. That worked well enough, but large inventories were really bad for the framerate. A later version kept track of the first item of a given type separately, using it as a sort of "master version" that would handle the stack. I had quite a bit of spaghetti-code to handle if that version got pulled out but other instances didn't, and of course, that had its own bugs. After a lot of fixes and optimization, I realized I had trimmed it down to only pulling the class from the master version; all I had to do was move that code into an item manager, and that would handle everything.

Now, grabbing a fish simply tells the game you're holding a fish, and that fish_7 is being held. Pick up another one, and all that's changed is now you're holding fish_7 and fish_4. And if both of those fish are somehow pulled out of the slime, the manager script knows you're not holding any fish and adjusts everything accordingly.

It should be noted, my implentation works because it doesn't matter which instance of an item you're dropping. If that weren't the case for whatever reason, you would need to track them more specifically. While that wouldn't work well for Slime Project's current gameplay, I believe it would be ideal for a puzzle game where you're juggling items in a very small inventory (maybe five items maximum), so the player has an easy time visually identifying everything they have.


 
 
 
UI & Flow
 
Screen Layout
AllMenus_800x450.gif

While Slime Project isn’t the most complex thing in existence, there’s a handful of interconnected details you want access to while playing: what to look out for, how many of them you need vs how many you have, and if your inventory has room. The tracker takes care of most of that, while triggered text pop-ups relay information about inventory capacity.

UI_AllThree.png

Base UI (always visible)

click to expand

I keep everything vertically stacked on the right to keep the slime and the majority of the screen visible. And as explained above, the tracker can be collapsed to only show the absolute minimum needed information. With the carousel tucked into the upper-right corner, the UI should never impede gameplay.

When you pause the game, the pause menu takes up the remaining portion of the screen, keeping the carousel and tracker in view. I saw no reason to hide the tracker while paused, and the pause menu doesn’t need the entire screen anyway. It also keeps the UI feeling clean, with everything neatly in its own section.

Inventory
click to expand

The pause menu keeps the inventory and requests separate, unlike the sidebar, so I can convey as much relevant information as possible. For the inventory, that means all of its contents as well as capacity. For requests, that means giving all of the information the tracker conveys, but for every ongoing request. There’s also a tab for completed requests so you get to see everything you’ve done up until now.

 
 

Requests - Ongoing

click to expand

Requests - Complete

click to expand

 
 

Screen Flow

Screen Flow

click to expand


 
 
 
Looking Back

What Went Well

  • Created flexible and easy-to-use movement abilities with modular aspects (see: attach points).

  • Developed easily-extendable systems for items and requests.

  • Iterating on wireframes and screen flow from the beginning helped me create UI that's responsive, readable, and conveys desired information.

  • I learned a lot about using Unreal's UMG UI tool, both visually and with code.

  • Pivoting didn't negatively affect scheduling or speed of progress.

What Went Wrong

  • It took a long time to dial in on the final inventory implementation.

  • I delayed the pivot for a while because I was unnecessarily wary about changing course.

What I Learned (Improvements)

  • I should plan earlier on for structs and manager/controller scripts, so nothing needs to be consolidated later.

  • While interesting and leading to neat moments, I should be more cautious in the future about using a lot of physics forces on/around the player. In addition to frame-rate issues, it's fairly likely to create bugs.