Sprint 6
November 6 - November 19, 2025
For this sprint, I added 3 new enemies and worked on applying some of the feedback we have been getting in the game.
I started off with some bug fixing, making sure that the GPS line worked at all elevations. Previously our GPS line would spawn at 300 units above ground so there were parts of the level where the roads were taller than the line and would hide it. I had to dig through the package script of it since we used a road system plugin for the roads and it had a magic number for setting the height of the GPS line.
I also fixed the sound settings to stay throughout the entire game and even when you exit the game. Previously, the save system we had supported the old audio system and not FMOD, which is the one we currently have, so I had to double check to make sure that the save system was saving the correct FMOD strings.
First, I worked on learning how to utilize unity's AI navigation system using nav surfaces and nav agents. This was going to be used on multiple enemies in the game, and I did not want to create a custom movement system for enemies that run on the ground. To integrate Unity's existing system, I basically baked a nav surface, added nav agents to all enemies that need it, and added SetDestination() to the player's truck position in the Update() function whenever they are active. I also made it so that it activates / deactivates the nav agent of the monster when they are teleported in / out of the scene to save on performance costs and also to be able to teleport them out of the scene. I also added more customizable settings for the Wendigo, Alien, La Llorona, and Grassman for my designers.
I then worked on adding monsters which were the Alien, Grassman, and La Llorona. The Alien simply spawns on the side of a road and runs across the road repeatedly, jaywalking from side to side and causing the truck to crash if hit. The Grassman also spawns at the side of the road but behaves differently. It stays on the side until it is stared at, creeping towards the player slowly at first. Once they are stared at for too long, it will charge at the player and deal massive damage while also shaking the truck. Lastly, I added La Llorona which spawns in the passenger seat of the truck after the player gets far enough into the level.
Next up I added UFO's to the scene utilizing the level difficulty scriptable object as well as making them only play an animation when the player gets somewhat close. You can also place cows manually, but putting the amount of cows to be spawned into the level evenly distributes the cows throughout the level. These automatically placed cows are also placed on the side of the road system, utilizing the waypoint system to properly place them laterally to the road.
I also worked on adding animations and sounds to the truck. I added truck sounds to the game that our sound designer worked on for braking, acceleration, headlight, and air releasing when the truck stops completely. I also added Duckbob's (our player character's name) hand animations that our animator made to the truck whenever the player honks the horn and turns the wheel which was really fun to mess with.
Lastly, I worked on added the Sanity UI animations and image changing. It shakes when the player takes damage, and vibrates more as the sanity gets lower. The image also changes to become more damaged as the sanity bar gets lower, hopefully indicating to the player that they are about to become insane and need to drink energy drinks in order to not die.
Oh and I got the truck trailer to work : )
Sprint 5
October 22 - November 5, 2025
This sprint, I worked a lot with improving the functionality of the monsters in the game as well as some other small things.
First thing I added this sprint was adding additional off-roading mechanics to the trucking driving in the game. Previously, players went offroad often for performing shortcuts which isn't bad but it got to the point where some players never drove on the road itself. To counteract this while not removing it completely, I added a screen shake that gets crazier the faster the truck is, capped the top speed even more when offroad, and slowed the acceleration of the truck while it is offroad.
I then added a magnetism effect to the Dark Watchers we have in the game, inspired by the Peeper in R.E.P.O. It basically drags the player's camera to force them to look at the dark watcher if the player was looking towards its direction, reaching its strongest magnetism and sanity drain per second if the player's cursor is practically on it. This made them much more of a threat since it messes with the player controls, rather than just something that you would see on the road and drive past. This took me quite a bit of time because I had to convert the rotation values from world space rotation to local rotation values since I am using the Cinemachine player camera controls.
| Magnetism effect, where you have to put extra effort into moving the camera to break away from looking at the Dark Watcher |
| Converting the world direction from the player to the monster to a local value that would be added to the pan / tilt of the camera to look towards the monster |
I also edited the behavior and functionality when looking at enemies, as previously all enemies were playing the same sounds when looked at. I basically made it so that only the Dark Watcher was able to use the magnetism effect as well as play a slightly higher pitched sound on top of the default vignette effects that the system has.
Next up, I got to learning how the road spline system works so that I can spawn enemies along the road points rather than just in front of the player. This would be used for a couple enemies, like ones that cross the road at random points and ones that stop at the side of the road. I found that the road system plugin that we were using were actually using a similar format to how Roblox does it with their pathfinding, where it stores an array of waypoints of the path.
| Returning the furthest point ahead on the road from the player based on the 'stepsAhead' integer and returns the position and index of the waypoint |
After figuring out the waypoint system and adding a function to get a future point of the road, I was able to start working on the Wendigo monster. I made it so that it spawns left or right at future waypoint, and had it moving towards the player at a constant rate as soon as it spawns. It damages the player if it touches the truck, so I high beams to the truck so that they can flash the Wendigo and have them fade away. For now, the Wendigo does not utilize a navigation system that Unity has because I initially had fears of the performance costs of it, so I made a custom movement script that moves the Wendigo towards the player, updating its position and rotation to the ground below it every frame. It can snap its position when making jumps to higher / lower elevations, so I am planning to use the nav agent system in the future to handle enemy movement, especially since there will be trees and other props that the monsters must navigate around.
I also added one of my animator's animation to the rig, and made it so that the wendigo is always facing the player. I also watched some people's reactions to the Wendigo going towards the truck and it was fun to see some of them get spooked!
| Wendigo Monster moving towards the player, dealing damage if it touches the truck or disappearing if the player turns on the high beams. |
Lastly, I worked on a build for the game as I always do each sprint. Our goal was to have a new playable level we could use in the final, an updated tutorial, and the new wendigo monster added in along with the previous monsters working properly in the new level. I made a quick little tutorial UI setup that shows the controls of the game that fade out once the player travels a certain distance away from their starting point, and made sure the wendigo and dark watcher monsters could spawn on the new terrain set up that we had.
| Tutorial Images fading in when the game starts and fades out once the player traveled a certain distance |
Overall, I think this Sprint was definitely backend heavy regarding the monster system we have, which is good because that sets me up to do a few more monsters in this next upcoming Sprint. Thank you for checking out my blogpost once again!
Sprint 4
October 9 - 22, 2025
For the fourth sprint, I reworked a lot of the managers / systems, added a new monster type, imported models, improved past features, and put together the alpha build of the game.
The first thing I finished this sprint was adding line of sight functionality with the dark watcher monster. Previously, this monster was able to damage and distort the player's view whenever the player was looking at its direction, even if the monster was behind a wall. To fix this, I simply added a raycast to see if there were any colliders in the way between the player's camera position and the monster itself.
The next thing I worked on was getting the player's screen to become more blurry and distorted as their sanity got lower. To find these effects, I basically went through all the post processing effects until I found panini projection and depth of field. I used panini projection to lower the player's field of vision, which gave a fun effect of the player's screen snapping back to a normal perspective whenever they drank an energy drink to restore sanity. I also used depth of field to add a blurring effect that got closer to the player the more insane they were.
| As sanity gets low (top left health bar), screen zooms in and gets more blurry as shown by the dark watcher getting blurred out |
I then added a bunch of models in with their textures early in the sprint for my designers to decorate the upcoming level for the playtest. They also have their colliders set and ready to go.
| A collection of models set up (including some from the last sprint) that I added into the game |
Before adding the ghost into the game, I had to rework the Game Manager script in how it made monsters appear in the scene of the world. Initially, I rolled a chance for the dark monster to show up every 4 seconds, which is different than how we wanted the Ghost to spawn. We wanted the ghost to spawn every so often, so for example anytime between 30-40 seconds. To solve this, I added an overridable function for checking if the monster can appear. The default function does the roll functionality of the Dark Watcher because I believe that it can be applied to other monsters, but allows monsters with more niche spawning mechanics like the ghost to be integrated with the game logic loop.
| Part of the game loop function, where the overridable ShouldAppear() returns if the monster can appear or not before spawning the monster to interact with the player |
Then I added the ghost monster. Basically, every so often, the ghost jump scares the player and the player has to honk them off. If the player doesn't honk them off, the ghost will continuously scare the player until finally honked off. I also hooked up all the animations and logic in in the animation controller, so that the animations can cancel or transition to other states. I also hooked up the sprite sheet animation of the game, which was really fun because Unity's sprite sheet editor automatically can separate sprites on a sprite sheet for you with the click of one button!
Next up, I got to on overhauling the UI system. It was nice that our UI menus were decoupled, but we did not have a shared system we could use to manage the pause state of the game. So if you died and were frozen in place, you could technically pause and unpause to unfreeze the game and keep on playing. To solve this, I made a UI manager singleton that lets any other script manage the pause state of the game. There is also a LockPause() function, which prevents all other calls to pause the game until the pause state is either unlocked or the UI manager ForcePaused(). This is useful for cases like when the player dies and is on the death screen, so that the player can't just pause and unpause to keep on playing the game. Another neat feature of this script is that other scripts can call for the game to be paused really easily by just referencing the Instance of the UIManager and calling ForcePause().
Lastly, I made the build for the alpha stage of the game. The only thing I did was add trigger areas which starts the spawning loop of the enemies, which also can just be excluded and have the spawning of the enemies start immediately.
Sprint 3
September 25 - October 8, 2025
For the third sprint, I added uphill torque on the vehicle, enhanced the sanity system, added a monster into the game loop, made a difficulty system, added our 3D artists' props, updated our entire project's unity version (there was a malware spreading in the exe's of previous versions), and made the "first" build of the game. I say "first" build with quotations because we have made another build for the prototype before this.
For the uphill torque on the vehicle, I decided on amplifying the existing velocity of my truck. I have already committed to adding force at the tire positions of the truck at Rigidbody.AddForceAtPosition(), so if I were to utilize Rigidbody.AddTorque() instead it would apply at the center of the truck which I did not want. However, I would now need to find a way to smoothly incorporate the additional force into the existing forces of the vehicle.
To add uphill velocity into the mix, I first got the dot product between the direction the truck is facing as well as the up vector of the world. Depending on how high up the truck is facing, there would be more acceleration applied during the existing forward calculations. However, if the player was facing too high up, the uphill acceleration would turn off because we don't want a semi truck to climb Mount Everest. After getting the orientation of the truck figured out, I then applied the player's current forward input which smoothly moves to 100% the longer the player holds the forward input. I took all these values and multiplied it to the 'upHillTorqueMultiplier' (float variable we can adjust for the uphill strength of the truck) and applied it in the final forward acceleration calculation.
| Dot product between the truck forward and the world up vector to determine how high up the player is facing while also disabling it if the |
| Adding more force based on how high up the truck is pointing + how long the player has held down the forward input, and adding the multiplier to the forward force calculations |
| Going uphill on the truck |
For the sanity system improvements, I added damage from monsters, converted the UI system from UI Toolkit to UGUI, and a death screen / detection when you run out.
For monster damage, there is a giant sphere collider that keeps track of all enemies within its range, logging when they leave / enter the trigger zone. Once an enemy appears within the radius, the camera handler script I made checks to see if a player is looking towards any of the enemies in the radius using the dot product between the player's forward looking direction and the direction of the player to the enemy. Afterwards, it would keep track of how long the player is looking at the enemy and increase the intensity of a distortion effect I made for the camera as well as an eerie static sound that my sound designer made.
I also added damage to the sanity meter whenever you looked at them, which can be adjusted from the difficulty data.
I then programmed the functionality of the dark watcher enemy in the game. It is an enemy that appears in front of the truck in a random position in front of it, and hurts the player's sanity as well as makes them dizzy when they look towards its direction. Credits to the other programmer and 2D artist for importing the monster sprite. In the future, I might also make it so that the damage and visual effects scale with how close you are looking to the enemy.
| Sphere collider of the truck to detect enemies in radius |
| Camera effects when looking in the direction of an enemy |
| Sound effect + distortion darkening effect of the camera when looking at an enemy |
| Lose screen when the sanity meter runs out (the bar is at the top left of the screen) |
I based the difficulty system based off of Five Nights at Freddy's 1's system, where the enemies have a chance to pop up every x seconds. The chance to appear is represented by 'Aggressiveness' value, and I added all that logic to run in the existing Game Manager, and made it a scriptable object for my designer and me to change and tweak. You are also able to change the starting and total sanity, as well as the natural draining sanity rate.
In the future, I plan to add individual damage values for each enemy.
| Level difficulty scriptable object, where the Dark Watcher monster has a 50% chance to appear every 4 seconds and deals 10.79 damage per second you look at it. |
I also imported a bunch of models and textures that my 3D artists have been making, making sure they had the right emission values, box colliders, and sizes. We are opting to use box colliders for the hitboxes because they will mainly be props in the background that the player probably won't be interacting with. Some of the box colliders like the electricity pole may seem inaccurate because I made them in mind of the semi-truck rather than a player character.
Lastly I worked on getting the build together, making sure everyone's scripts were working when put together in a scene. I also added some smaller features, like adding a restart button + its functionality for the pause menus and death screens. There were also some other features that I fixed up in the UI, but that is all for this sprint. Thanks for reading!
| Models setup |
| Imported the energy drink can into the game, which restores sanity when used |
Lastly I worked on getting the build together, making sure everyone's scripts were working when put together in a scene. I also added some smaller features, like adding a restart button + its functionality for the pause menus and death screens. There were also some other features that I fixed up in the UI, but that is all for this sprint. Thanks for reading!
Sprint 2
September 11-24, 2025
For the second sprint, I worked on improving the truck functionality and started on the game manager of the game.
The first task I tackled this sprint was dealing with the truck falling over way to easily. At first, I tried to apply centrifugal force, which gave the truck a weird ability to randomly fix its orientation when it falls. I then realized that the centripetal force that I was applying to the truck was interfering with the other forces applied for steering and acceleration. To try to fix this, I applied a forward force in order to blend it alongside the other forces. It worked at lower speeds, but anytime the truck would move more than 20 meters per second, the truck would again flip super easily as soon as you tried to turn the truck.
The actual fix to making the truck not flip so easily was simply reduce the height of the box collider; no additional programming required. I found the solution to be pretty silly because I literally got the idea from a friend who said the truck felt "top heavy" and decided to just take the top off. I was actually planning to keep this 'feature' for the future in case we did want the truck to be more susceptible to flipping over when encountering a monster or event. So if we ever wanted the truck to be more sensitive to turning, we could simply adjust the height of the box collider during runtime.
I also added a system to detect when the truck has flipped over or crashed really hard. To detect when the truck is flipped over, I took the dot product between the trucks up vector and the world's up vector which returned a value between 1 and -1. 1 tells us the the truck is upright, while -1 tells us the truck is completely upside down. Using this information, I would determine that the truck is flipped over if its value was anywhere below 0.1 (when the truck is on its side) for more than 3 seconds.
For detecting when the truck crashes really hard into something, I replicated what some cars do, and that is to calculate the sudden deceleration of the vehicle. For that, I logged the speed of the vehicle every frame, averaged it every 1/10s of a second, and compared the difference between the highest and lowest speed for the last 0.5 seconds. If the speed difference was more than the crash threshold, then the system would fire that the vehicle has crashed.
Next up, I started with working on the sanity bar. I used unity toolkit to make the progress bar that comes with it, and set up a scriptable object to bind to the progress bar. There is also an energy drink you can consume to replenish it, and the drain rate / maximum sanity is adjustable. I plan on integrating this in the game manager script next sprint so that the designers can adjust the difficulty of the level in one scriptable object.
| Hovering over the drink and pressing 'e' replenishes some sanity at the top left |
Afterwards, I started getting the horn, the side mirrors, and headlights to work. The horn plays an in-sound, looping sound, and then an end sound (made by my sound designer) when the horn is turned off. The side mirrors have their own cameras that replicate what they see on a render texture on the mirror planes. The headlights are just light objects that are turned off and on whenever they need to be toggled. Right now, the horn and headlights are toggled with a keyboard input, but later on the player will need to click on a physical button in the truck interior to control them.
Lastly, I worked on getting the electronic prototype of the game. For this playtest, our goal was to test out the truck controls, our main mechanic, to see if it felt good to use or if there were any tweaks we needed to . I put on the new model of the truck that one of the 3D modelers made, duplicated a level that my level designer made, and made sure the pause menu UI from my other programmer worked. I quickly put together the steering wheel feedback and speedometer needle moving, and created the build!
Sprint 1
September 2-10, 2025
For CAGD 495, I am working on Trucking Time as a programmer on a team of 11, a horror game inspired by the Five Night's At Freddy's games. It is a game where the player drives a truck from point A to point B while sleep deprived in the night, maintaining your sanity and battling monsters and obstacles that may or may not be even real. Beat the five nights and you win! We are using Unity 6 as the game engine to create our game.
For the first sprint, I was tasked with programming the movement and feel of the semi-truck that the player will be using throughout the game. The truck needed to be able to crash, drive forward, turn, and brake since there will be stop signs and traffic lights that the player will be needing to stop at. I did not want to spend money on buying vehicle system plugins, so I opted to instead create my own. I also never have taken physics or anything past trigonometry in or out of school, so I decided to look up a bunch of YouTube tutorials and forums in order to find a place to start.
In order to begin coding physics with no knowledge of physics or anything of the sort, I decided that I needed an equation to base everything around. Thankfully, I found an amazing YouTube tutorial that showcased how they got their car physics to work for free! It was a video by a Very Very Valet! developer that walked through and visualized the process of how to hook up vehicle physics and movement.
The first thing I hooked up were the raycasts of the tire points. I started off with four wheels that were positioned at each corner of the vehicle, and made sure the raycasts were hitting the ground. If a raycast of a tire did not hit the ground, then the physics would not be applied to that specific tire point. Next up, I decided to implement suspension.
For suspension, I had a smooth time implementing the bounciness you would get from dropping the vehicle from a high place. However, when I added more mass on the rigid body of the vehicle, the suspension would start to not work, either being too floaty (like a drone landing on the ground) or just plopping straight onto the ground and dying. I decided to make a function that would automatically calculate the spring strength, dampener, and spring distance based on how many tires there are, the mass of the vehicle, and so forth. For now, it functions as a way to make a truck feel heavy, but I will most likely have to tweak it when we add car AI later on.
After getting suspension to work, I decided to implement acceleration next, since I could not really test out steering and tire grip without being able to move. Through a lot of experimentation, I managed to get a system you slowly increase your acceleration when you start to move forward / backwards, use 100% of the acceleration multiplier when at the middle of top speed, then slow down acceleration when nearing top speed. I also added a braking system which adds backwards force to the entire vehicle depending on the direction it is going. The vehicle system also auto brakes when there is no forward / backward input at a slower rate. Lastly, I added a reverse system, which brakes the vehicles first if it is moving forward then starts to reverse when stopped.
Now that acceleration, braking, and reversing worked, steering and tire grip was the last thing that I needed to add. All I did for rotating was turn the wheel points physically and let the other two systems do the heaving lifting. I was not able to really get the tire gripping to work how I wanted, and I will explain that later.
Then I added a cinematic camera that the player could use to look at the road as well as look around the truck cabin / mirrors. Here is the result of that:
After getting the main movement mechanics of the truck in, allowing the player to move forwards, backwards, left, and right, I imported the truck mesh created by one of our modelers and this is how it turned out so far.
However, I ran into an issue with the tire grip. Every time the truck would go more than 10% of its top speed, the truck would flip over way to easily when turning. This meant I had to add centripetal force in order to counteract the centrifugal force that the truck was experiencing. This actually tied into my next task, which was to detect when the truck flipped over or crashed really hard for the lose condition of the game.
Comments
Post a Comment