The demo in the video is a manual test to show the specific behavior.
The demo in the video is a manual test to show the specific behavior.
Once everything got integrated with a lot of tweaking, all the moving parts blur together.
Devlog 12/20/25
The racer AI were finally able to receive improved behaviors thanks to the changes and adjustments from waypoints to spline and the specific updates outlined below. I wanted to do junctions as well to create some interesting tracks and have the racers choose a forked path to take but it proved to be a bit complex to make so I think I'm moving on from working on the racer mechanics (finally). With all these improvements, I'm much more comfortable going back to designing a track and creating blockouts based on these behaviors.
Changing Lanes
This was a subtle change since the track itself does not have many lanes, but it allowed the racers to move more liberally on the spline while still appearing natural. This behavior allows for the racers to have a form of decision making with how they navigate a track or want to overtake their opponent.
Rubber-banding
This is common in a lot of racers, but with the new integration of splines, this became more feasible without the risk of many bugs. The racers will detect nearby opponents in a certain range and temporarily ramp up their current speed to pass them then go on a cooldown to keep it fair.
Improved wheel physics
Because of the changes with integrating the spline, the racers no longer used their wheel physics anymore so I had to go back and reintegrate them with the new system so their steering is improved as another subtle change.
I ended up choosing the basic Unity spline package since it would be the most lightweight comparatively.
Devlog 12/15/25
I began to feel that for when it's time to integrate the actual tracks I want to design, the racers' behavior was too limited that it would become noticeable to a playtester. So, I decided to look into spline plugins and see what I could do to improve the racers through 4 main iterations.
I initially tested to see how it would look to just have the racer primitively follow the spline through some plug and play. I then changed the initial "snapping" behavior to loosely follow the spline to make it appear more natural and have a bit of drag (since these changes currently didn't account for the existing wheel physics they already had). Then when it came to testing in the existing race scene, each racer got different parameters with how they behaved on the spline.
It needs some polish, but it's goofy and I like goofy.
Devlog 3/5/25
I experimented a bit with using "tools" (items) as potential obstacles in a race but one I ended up enjoying was the concept of sniping your opponent, or snapping a picture of them to potentially flashbang them and stun them for a second.
I wanted to find more sub-elements to integrate with the paparazzi and fame theme of the game and out of the ones I prototyped, I enjoyed this one the most.
Drifting through the highest point of the demo track felt like surfing through a giant wave in the ocean!
Devlog 1/22/25
The track used in this demo was to test how the current physics could handle "wider turns" on varying angles and levels of elevation. The camera blends during drifting really ended up adding a level of "sauce" to how it feels to drive the player vehicle, at least in this specific track.
The wheel physics, acceleration, and rigid body also presented a secondary effect I wasn't aware of before: there's a level of handling that the player must master to drive through an elevated wide turn like the one in this demo.
The new types of NPC to create this interaction are going to be Dealers, who represent different companies (possible sponsors, rumormongers) who offer the player a contract to sign, and Super Fans, who are brave enough to run onto the track to get a signature from their favorite racer!
Devlog 1/10/25
This feature was spontaneous but it felt necessary to include since it goes with both the celebrity theme and distracted driving gameplay. A lot of the heavy lifting to make the drawing aspect work came from this Youtube tutorial, where the canvas is made up of specified points and a texture is generated. This was changed to use a RectTransform so it can be used while in motion. It is stable when the player drifts, is elevated, and in mid-air, and also works with the existing paparazzi system (although it might need it's own variant). There's only one major bug as far as I know, where it is slightly reliant on good FPS; if your game is running at less than 40-30FPS then the drawing begins to act a bit dotty and streaky.
Meanwhile, map designs and character designs have been sitting in the oven and I also need to work on "pretend speed" so the game feels faster so those will come next.
This change didn't happen all together and was made sporadically in sections but the end result is smooth
I originally wanted this gag character to be a mascot or a superhero but I ended up here 💅
For some reason this took longer to do than the original post race camera...
Devlog 12/15/24
The past few months have consisted of traveling, moving, losing my GitHub account briefly, among other things but it's all ok because in the middle of all that I was experimenting, fixing bugs and doing QoL changes.
Drift, Power Brake, Camera Blends
The way drift was handled previously was always a bit primitive so it wasn't that noticeable or impactful. My goal was to create a sense of control and speed while moving so I tried something different out of no where because I thought it would be funny: camera blends. It uses Cinemachine's State Driven Camera to blend the main camera and the drift camera. I ended up refactoring how drifting works in general: now when drift is enabled, it checks the turn input and adjusts the drift friction for the direction of the steering wheel.
Character Design and Shape Language
Because of the nature of the visuals, a lot of care (trial and error) is taken for designing the characters and vehicles associated with them. This is a small teaser for a racer, Celebrity Cat and her vintage Cadillac, which has been the testing ground for how I can use the sprite swapping system to show their personalities through posing and emotes.
Improved Physics
As seen above, Celebrity Cat's vehicle has a bit of slip to it when she is turning away from the player. This is also a subtle change with all the racers since they all now have wheel colliders (after many custom bugs each vehicle had </3) so they all are one step closer to having custom physics better suited for them instead of their only differences being that one is faster. Below is one of my favorite iteration's of the Alien Cat's physics, where he decides he wants to go back to his planet.
Spectator Cameras
As a side change from all the racing talk, I did also get distracted and adjusted the post race camera to have multiple spectator cameras so it's more active now.
The actual racer names aren't on the banners but its on some placeholder text that's semi-transparent in the background (meant for alignment).
Devlog 9/12/24
After a big race, the idea is to have a broadcast and commenters talking about what occurred. There will be a segment about overall placements and stats, followed by scrolling audience/social media reactions. Then there's a story segment about the top 3 racers; the player's goal will be to try and get top 3 or to knock out specific characters from being a part of this segment or first place. Each character will get their own banner so all images are attached to the racer's data object. The racer's data object already included name, default position, and final position but now they've been updated also to include racer icons and sponsorship icons. The current build is using concept art as it mainly tests for functionality.
I don't know if the juicy hotrod bounce you see in old arcade games are custom physics or an illusion but I'll figure that out too 😤
Devlog 8/15/24
During this time I've been working on fleshing out my game's UI as my next goalpost. But the lack of car physics caught up to me when I started playing other kart racers so I spent about a day and a half learning to implements Unity's wheel colliders. I've attempted creating suspension before wayyy earlier in this project but scrapped it because it was too buggy. This iteration is a bit simpler but completely functional. The suspension physics will change per vehicle but for this one, it's limited as it is already a bit grounded. There's enough room for the axel to allow the wheels to move around on uneven terrain with a bit of a "bounce". There's also an additional camera recomposer that smooths out the bounciness while moving on terrain. Lastly, the wheels steer and rotate! (You can't see them rotate because it has a plain texture but trust me it's there otherwise the car wouldn't be moving!!)
Every update simultaneously feels small and big.
Devlog 7/17/24
Ignoring a few bugs, I'm surprised data persistence between scenes is much simpler than it sounds. Half the work was already set up with the save system and because I'm still learning I didn't fully know that it would rely on the JSON file handler but it makes complete sense.
Anyways, in order to actually test it, I had to make an additional dummy track and while I was at it, I worked on accurate post-race standings. I already had the Text object list holding all the racer's current positions but that's definitely not something we want. Post-race standings would need to include more custom visuals like character portraits, position banners, etc so it's functional but work in progress.
Pause to read and look around if needed. I had to make like 5 extra scripts to get all this working but I honestly don't even remember anymore 😵💫
Devlog 6/26/24
There's a dozen things going on here even though the video is spliced to show that those things happen in a few seconds or less 😭. It's weird to call this a few weeks of work when it looks so minor but extremely needed for the type of game I'm making - but that's the nature of game development where a lot of non-visual elements go unnoticed unless its buggy and we DO NOT like bugs around here.
To name some of the things going on here, we have a save system and a handler for player data, a race initializer, and a racer position sorter. Paparazzi reputation aka favor points and recent race positions (unless reset to default which will always be) are saved to the data file. When a race begins, it will load racer positions to their default (for example, the player should always begin last until they undergo a series of consecutive races). The timer and racer controller scripts are frozen until the countdown is completed. When the player crosses the finish line, the lap completion and the timer is frozen again and final positions are saved. When the player continues onto the next consecutive race, the recent racer positions are grabbed and the racers are assigned their matching starting position transform.
The racer sprites will always be looking towards the main camera so an unintended effect is having them stare at the finish camera which makes them feel like active participants.
Devlog 5/15/24
Creating the transition from playing to finishing required a number of steps but overall was straightforward. The camera transition was fun to do and planning to do more to fit better with intentionally designed tracks (I'm still using the first demo I made on EasyRoads LOL). I thought swapping the player racer from player input to AI would be hard but it was literally just enabling and disabling. It's incredible how some tasks are becoming "easy" as I continue on this project. Next I have to do race-starting checks so that the player can transition from different tracks upon completion.
Unfortunately real life interviews aren't the random stuff I wrote in 10 seconds like these.
Devlog 4/26/24
I honestly put off doing the interview system for a little bit only because I didn't understand how randomizing worked. Since the idea is to have the paparazzi represent different companies and networks gathering information, then they should have their own pool of exclusive interviews. This paparazzi contains about 4 different interview questions (along with associated player answers) that are randomly picked when an interview is triggered. The timer is now visually represented with the slider which will automatically end the interview when time is up or when the player picks a response.
For testing purposes, the interview is set to last 2 seconds but it doesn't stop me from going back to its waiting area and bullying it in return.
Devlog 4/2/24
After the previous update, I have been working on this in segments along with some bug fixes since I've been learning to compose music and got pretty distracted with that lol...
I've never used states before but I figured this behavior would utilize it pretty well. The paparazzi has 4 states, Waiting, Following, Interviewing, and Leaving. When the player passes a trigger, the paparazzi will leave its waiting area to begin following the player's position. A notification will appear signaling the player a paparazzi is targeting them. The paparazzis have high speeds but will copy the players velocity when they reach the player's position. When the paparazzi reaches the player position, it'll change to the interview state. In the interview state, a countdown timer will begin and the dialogue panel will also appear. When the countdown is over, the dialogue panel will go away and the paparazzi turns around and drives back home.
Will have to update the Text components to use TextMeshPro so that they have more clarity and also look nicer... we are testing no longer.
Devlog 2/8/24
And with that all the stat trackers are done!! The final but most important racey stat to measure was position, which required doing all the other stat trackers first as mentioned in the previous devlog but it works for the most part and the racers are ready for some actual real racing interactions with the player and paparazzi!!
After debugging so much, I figured out the most optimal route to outrun these suckers in the quickest time possible.
Devlog 2/1/24
After a short semi-break-not-really-a-break and finishing up a different project, I went back to figuring out race numbers and stats. Tracking checkpoints and laps wasn't too difficult in comparison to tracking lap times. It wasn't that getting the data for it was difficult, it was just inconsistent and had weird bugs where it would ignore lap 1 a lot of times. But it's okay but there are no bugs here anymore! When I had all that finalized in the CheckpointManager, I got started on setting up the HUD that displays all that information. Race time was very elementary. Lap number wasn't an issue. Lap times proved to be a constant problem child. I wanted to differentiate between seeing the last lap time and seeing all the lap times at once since it would eventually be compared for performance ratings.
Now you can turn sharp corners and feel cool about it.
Each AI has its stats in this demonstration; Blue is very fast, Orange is normal, and Yellow is slow. Blue is fast enough to almost catch up to poor Yellow but the player can catch up to Blue if they utilize their drift efficiently.
Devlog 1/14/24
Drifting got an upgrade because after some time, the quick and easy temporary version of it began to feel unsatisfying. To complete the fantasy of drifting, I would need proper animated sprites for the vehicle and character but that will be something for the future. Now there's an additional force that pushes the car in the direction you drift so it feels similar to actual kart racers. You can't play and compare for the before and after, but trust me there's a good difference. The only main thing that feels iffy is the camera movement but that's a solution for another time.
In other news, the lap system I wanted to create was shockingly buggy so I had to readjust it like 3 separate times and keep it relevatively basic for the sake of having something about it function as intended. As each racer passes the checkpoints, only checkpoint 0 is counted as lap start and lap finish and it also checks how many times a complete lap has been fulfilled by each racer. The laps can go for an infinite number of times but in this example I set it as 2 so that it counts as "completed".
There seems to be an interaction where even though they will reset their position, the waypoint destination does not change.
Devlog 12/21/23
In order to create laps or progression, checkpoint systems must be addressed. I've never really worked with save systems but I've heard they are annoying to do. Thankfully because checkpoints exist in a vacuum of the racing world I didn't have to worry about learning a way to store and retrieve game data (yet 😭).
I wanted to make the logic simple enough that I can understand what's happening. I wanted to set it up to where all checkpoints have their own reference (an integer) that each racer would hold until they pass a new checkpoint. When the racer hits a hazard, crashes, whatever, their transform will reset to the transform of their most recent checkpoint, whose referenced by the integer.
Say cheese! The paparazzi will follow the player to grab a good angle but even if the player speeds up and goes out of their sticking range... the paparazzi will find a way.
Devlog 12/7/23
Introducing a new type of driver, the paparazzi, or at least a very simple version of it. There was an earlier version where they used a navmesh, but their functionality was very awkward and limited so it was scrapped.
The paparazzi currently has two modes, chasing and sticking. If the target (presumably the player) and paparazzi are not near each other, the paparazzi will become the best driver on the track in order to catch up to the player. They will have max speed and track dominance (they don't care who is the way). When they do catch up, the paparazzi will be sticking to the player based on a distance threshold. If they are in range, they will match the speed by referencing the velocity of the player's RigidBody.
Rotating a floating camera around the AI to see the sprites update and swap based on current camera angle.
Bullying the AI now feels personal and infinitely funnier.
Devlog 11/29/23
Some time ago I found a really cool video of someone implementing 2D sprites in a 3D space. In most examples, 2D characters in "3D" spaces are generally in 2.5D and limit their usage of moving on the z-axis and use a fixed camera. This creator has it so that the sprite adapts to the camera angle when it rotates - which is super cool and wanted to utilize the logic for my own game. This would allow every NPC to not be static flat back sprites anymore and I finally got around to setting it up.
It has the logic set up to do all 8 directions but I started with 4 directions for testing purposes. It uses the animator to set up walk cycles and other gestures but for now there are no animations. Since there isn't going to be a floating camera during main play besides the player's camera, the actual perspective would be in the second example, where the poor AI isn't handling the physic material quite well so I push it to flip them over. In this interaction, we start bull fighting and its directional sprites adjusted based on my rotation so interacting with my drivers no longer felt robotic.
'Round the world, 'round the world...
Racing with the ulterior motive of taking away any personal space the CPU drivers have...
Devlog 11/22/23
The AI now has the bare minimum interactions needed to be able to race and interact with them during a race. I ended up opting out a navmesh since it made pathfinding and driving up ramps feel too stiff at certain points and decided it'd be entirely physics-based.
Each CPU has their own waypoint path (which I do want to optimize in future updates) and moves away from objects it detects in front or beside them. The avoidance works by having a short raycast and pushing the car in a direction when it detects something in the way. Sometimes it makes them freak out and dramatically steer away which is a little funny.
Otherwise, though, you can race with CPU and run laps around with them!
Temporary assets: Handpainted Grass & Ground Textures, Fantasy Skybox
The CPU has proper rotation and added forces to be able to drive up elevated surfaces.
Two cars complete to show off their ramp jumps.
Devlog 11/7/23
I've been working on AI in the meantime. The most refined version of a CPU works as intended. It can
Follow designated waypoints on a track without getting stuck and can complete full laps
Can climb ramps and push itself off them naturally with gravity
This is demonstrated by the blue CPU driver. The only standout about them is that they are entirely physics-based and don't use a navmesh agent -
This is where the yellow CPU driver comes in. It can
Follow designated waypoints on a track and can complete full laps
Has object avoidance
Blue interacts with the track naturally, but does not have the logic to avoid obstacles, while yellow interacts with the environment more intelligently at the cost of not being able to jump off ramps naturally and sometimes gets stuck on waypoints (perhaps because there are too many). My main issue is 100% with how it interacts with ramps. Although I'm using a navmesh link, I'm not satisfied with how it just floats down to the track. I want it to match the blue CPU driver but a work around will have to be researched to achieve this.
Maneuvering the car feels best with a gamepad over keyboard controls.
Each player has their own controller and their own inputs.
(It's kind of difficult to control two different ones at once)
Two billboards exist in the same spot but one is culled in each camera. Spooky.
"Cat Racer" Prototype (prototype)
Engine: Unity
Devlog 10/14/23
Huge changes, huge update. I feel pretty proud of myself for this one.
When I did research on how other developers handled drifting, it made me notice that about half of them had really complicated movement systems for their vehicles while the other half just used smoke and mirrors. I realized the definition of drifting was a bit loose, despite it existing in almost every car-related game so I decided to be just as flexible. The strength of turning was a set variable but whenever the player drifted, the turning strength was altered. Some minor tweaks are in order like limiting when and how the player can drift, such as setting certain speeds or higher and only working in conjunction with turning.
Drift Boost
Adding drifting made moving around a lot more fun but it was missing that juicy boost from a lot of kart games. The logic to set up receiving a drift was almost convoluted. Since the player had to stay drifting for a certain amount of time, say 3 seconds, then when that threshold is reached they're allowed a boost only after the drift is released.
Local Co-Op
There's nothing better than playing with friends so I figured I should get co-op out of the way as both a feature to include but also to use it for testing. Since I was using Cinemachine for the player cameras, I had to find a workaround with the Player Input Manager. This video found a solution, which involved referencing Input Actions as strings. Initially, this broke the entire movement system, but I fixed it so now co-op was real and each player could move individually with their own controls. Co-op caused other issues though, it broke how the sprites worked, partially my fault since I didn't update the sprites to use Action Maps - this had the directional sprite input be overwritten by another one of the player's inputs so even if P1 was facing left and moving left, P2 would be moving not left but still facing left. This had to be resolved in the same manner by referencing the Input Actions as strings.
Billboarding Adjustments
Billboarding was also broken by co-op since it introduced more than one camera into the scene. There were two possible solutions, either have the billboards look at the closest camera or have two of the same billboards target a camera while the camera culls the other ignoring it. The former I didn't really like because of how it would snap to each player if they were close by. It maaaybe wouldn't be an issue in game where you go fast, but it felt un-immersive when I noticed. My crackpot solution was the latter, which made the billboards behave exactly as intended. I feel like doubling the number of billboarded objects in the scene is not the smartest long term, but it allowed for some flexibility and customization.
I uploaded my current progress to GitHub since it's in a good enough state to share even at these beginning stages.
You can also crash and respawn too. Minor, but needed (and fun)
"Cat Racer" Prototype (prototype)
Engine: Unity
Devlog 9/29/23
The acceleration is a bit more realistic now that it gradually speeds up to the max speed over time. Placeholder UI displays the current internal speed of the Rigidbody rather than the actual MPH. Removed suspension for now since it will be revamped entirely so just the cube car remains.
There's a bug where the camera and vehicle jitters at high speeds when turning. It was technically fixed before I got the acceleration properly working but I'm not sure what's affecting it since the only thing that changed was the way the forward inputs are handled.
"Cat Racer" Prototype (prototype)
Engine: Unity
Devlog 9/21/23
I'm calling this a prototype of a prototype for a game I'm been wanting to work on for 2 years now with my friend Hane! The directional movement, car physics, camera movement, suspension, and 2.5D characters are just at their initial stages but it's a solid proof of concept for the direction I'm taking this project in. My next steps include setting up proper acceleration over time, a simple UI for a speedometer and a map, a realized environment, and a track.
Winter Run WIP 1
Engine: Unity
Devlog 7/30/23
This is a test run for an idea of a simple "runner" level with the goal of focusing on a shifting atmosphere. In concept, the capsule enemy will change the player's view by altering post-processing effects based on distance. I think it'll be an effective trick once immersion sets in with an actual moving enemy chasing the player along the cold path, camera shakes, and obstacles.
Tropical Beach
Duration: 3 hours
Engine: Unity
Devlog 6/19/23
This project was pretty fun. I came across a colorful jungle pack and fell in love with the art style that I just had to make a little scene with it. The construction of the scene took about two hours. When it was time to make test builds, some weird rendering and lighting bugs resulted in disappearing rocks, plants, and shadows but thankfully those were fixed. I learned some new tricks messing with some of the assets and feel very enticed to expand this into a full level.