top of page

CrunchTime

CrunchTime is a psychological horror game where the player must feed a monstrous entity by processing the remains of former workers into "meatloaves" using the industrial conveyor system available to them. 

​

I focused on developing the game's mechanical systems and environmental interactions, building most core gameplay features outside of the player's character controls and pawn. The project was developed in Unreal Engine 5.4.4 using primarily Blueprint Visual Scripting.

Conveyor Belt System
 

Video of a meatloaf/meatbiscuit on the conveyor belt moving

I designed a modular conveyor belt system that moves objects smoothly across from Point A to Point B using splines and a custom parent actor class called PickUp Actor:​

​

  1. PickUp Parent Actor Class - Inherited by all items that were needed to be moved along the conveyor belt from Point A to Point B. This actor contains a float variable (o to 1) called "alpha" that is constantly updated of their location along the spline.

  2. Spline Conveyor Blueprint - Is placed in-level on top of the conveyor belt mesh to be used as a guide as to where objects (that inherit from the PickUp Class) must go from Point A to Point B. It uses a collision box located at starting spline point to detect overlapping PickUp actors. The spline uses a timeline to adjust how the actors transition along it. This is so that when the actors need to pause and resume at certain points along the spline, the spline actor can just check the PickUp actor's alpha value and apply it to the spline's timeline so the PickUp actors would resume from its last location along the spline instead of starting from the beginning of the spline.

  3. Movement Timeline - Uses a timeline to smoothly drive each actor along the spline's path.

  4. Collision Control - All actors on the belt have their collision disabled to prevent player interaction with it which is then restored when the actor reaches the end of the spline.

  5. Pause/Resume - When travelling along the spline, the alpha of each PickUp actor's timeline was saved so when a malfunction occurred that required the conveyor belt to stop and the resume, the actors will continue along the path from their current location rather than the beginning of the spline.

Challenges

During the implementation of this mechanic, I had experienced PickUp actors not resuming from their current, still position when a conveyor belt malfunction is fixed. The idea was to have these actors stop randomly and resume along the conveyor belt spline after the belt is "fixed"; Instead of resuming from their current position, they would just not move. This was an issue as this affected playability; This bug would prevent players from being able to use the actors to progress further in the game.

image.png

Image of the original code that got all PickUp actors in the level and checked if they were within a distance threshold. And if so, a function (Mal) is called which resumes their movement. 

Originally, I was getting all PickUp actors in the level and checking if they were in a certain distance near the conveyor belt spline using the "Get Distance Along Spline at Location" UE function. If true, a function would be called (Mal) to resume their movement.

 

The mentioned UE function required a valid Coordinate Space input (world or local); It was found that using this function was not reliable in the context that we needed, regardless of which coordinate space I set it as. It would give an incorrect return value in the thousands even though it should have been within the threshold.

 

I found this only occurred when a PickUp actor stopped in a location where the spline wasn't fully flat (curved edges, slanted areas, etc.). So, when the UE function attempted to calculate the distance, the location provided (PickUp actor's world location) was not correctly translated to the correct point in the spline.

 

Moreover, I also found that I would have to change the Coordinate Space input in specific situations (local on flat areas and world for non-flat areas.) in order to fix this bug. This was not ideal as checking for this condition would be difficult to implement in the time that I had as well as the spline being prone to change in multiple levels.

The Cause Of The Issue

The Solution To The Issue

image.png

Image of the new code that gets the array of items on the spline (An Array of PickUp Actors; This array is updated in a separate script with the actors that are on the conveyor belt.) that are looped through. If they are valid, a function (Mal) is called which resumes their movement. 

To fix this issue, this method was scrapped and replaced by having the spline actor contain an array of PickUp actors (Item on Track) and have it keep track of what actors were "on the conveyor belt" so that, when they needed to be stopped and resume, it will simply loop through the array and call the necessary functions. This method not only fixed the issue with the PickUp actors, but it was also cheaper method to do as it didn't require getting all actors in the level every tick.

Malfunction Game Loop System
 

Video of multiple malfunctions: Conveyor Belt & Crusher

I co-designed and implemented the project's malfunction loop in each level's blueprint which randomly triggers equipment breakdowns to disrupt the player's workflow as obstacles for them to overcome:

​

  1. Core Malfunction Loop - Built a custom looping timer that periodically selects a malfunction via a Switch on Int node.

  2. Double Malfunction Safety Check - Built a safety function that if the chosen malfunction is already active, the system automatically re-rolls for a new one by calling a function that ensures the malfunction to be called is not the same active malfunction. This is done to save time on unnecessary calling and preventing activating the same malfunction whilst it is already active.

  3. Malfunction Event - Integrated malfunction events with each machines' blueprint, temporarily disabling their functionality until repaired by the player.

Reflection & Future Improvements

  1. Looking back, I realized that using a "Switch on Int" function for selecting malfunctions limited flexibility and scalability as increasing it would risk mismanagement. If I were to revisit the system, I would have replaced it with a data-driven malfunction manager that uses structs or data tables to the store key properties, which would make the system easier to expand and maintain while reducing hardcoded logic, such as:​​​​

    • Cooldown Durations

    • Priority or Severity Levels

    • Function References or Delegate Bindings

    • Overlap Permissions Between Malfunctions

  2. I would also move the malfunction loop into a central game instance blueprint so that it would be managed globally instead of being duplicated in each level's blueprint. This would maintain persistent malfunction states between levels, keep the logic consistent and optimize performance by avoiding redundant timers.

Machinery Functionality & Interactions
 

Video demonstrating crusher and jettison interacting with the player's actions

I developed the logic for most of the game's main factory machinery: the Crusher, Jettison and Conveyor Belt. All three components were needed to have both a player interaction to be used and a malfunction state which prevented player interaction until the malfunction was fixed. 

​

  1. Crusher - Converted body parts to meatloaves; Its malfunction process prevents the player from being able to convert the mentions objects. This malfunction is "repairable" when the player interacts with it in order to fix it.

  2. Jettison - Fires items given by the player out into space. I used an editable vector as to where the random items would spawn at with their gravity/physics disabled to simulate them being in space. This was done to prevent the use of particle and animation effects as adding them would cause noticeable drops in the FPS. This Jettison is the only exception where there was no malfunction. It simply functioned as a depository area to prevent object cluttery.

  3. Conveyor Belt (Gears) - In editor, I made an editable array of vectors that would act as the possible random locations as to where a gear may appear during a conveyor belt malfunction. A collision box would appear at that location as well that would detect when the player places the gear back in order to "repair the malfunction". During its malfunctioned state, all items on the belt are paused, and only resume following the belt when the player places the gear back. 

Reflection & Future Improvements

Originally, each machine relied on a Boolean variable that was toggled by the malfunction loop whenever a malfunction occurred. While this approach worked, it quickly became unnecessarily complicated as keeping track in calling these Booleans within the malfunction loop as more similar game mechanics were made. If I were to revisit the system, I would have implemented a Machine State structure or enumeration to replace the Boolean logic entirely. This would have given me finer control and make each machine's behavior easier to manage and expand (if it was needed).
 

Looking back, I would have replaced the particle effects (that indicated a malfunction with the conveyor belt malfunction and crusher') with an alternative solution such as an animated mesh.

The reason for this is that spawning or enabling visibility on one or a few, small mesh(es) with animated emissive noise in its material would be cheaper in performance rather than the Niagara system used.

 

You can see the fps drop when the sparks (the Niagara particle effects) are shown on screen compared to the fps when other malfunctions are activated.

Video demonstrating the particle effects causing a significant drop in FPS

© 2025 BY Jenica Ghayyoori. Powered and secured by Wix

bottom of page