Devlog 2












Gameplay Prototyping
In beginning game prototyping, I began by importing a third-party automobile controller from the Unity Asset Store. While the underlying asset used good driving physics, it wasn't implemented in our networked, role-based game. I used team feedback and the technical goals we'd established, and I set to work changing and building upon the system to meet our requirements.
The third-party car controller already had 1 car asset, other than that, I also imported one more vehicle for the game called "MiniVan". So there are a total of 2 cars in the game, but due to the scalability of the code, many more cars can be added in the future.
One of the basic elements of the process of changing the imported car controller was giving greater control over the manner in which the car would behave in different gameplay scenarios. The ApplyFriction method dynamically adjusts the grip of all wheels by modifying their sideways friction curves.
- extremumSlip defines how much a wheel can slip before the tire starts losing grip.
- A higher value results in more drift, useful for loose surfaces or high-speed turning.
- A lower value increases grip, ideal for stability and traction.
- The multiplier allows the car to dynamically adjust the grip on different terrain
The DecelerateCar() function was an early game controller asset that I had imported into the game prototyping process. Though the overall format of this function was already laid out, I tailored it in particular to better fit our game's feel and networked actions.
- The method uses Mathf.MoveTowards() to gradually ease out throttle input, creating an easing rather than an abrupt stop.
- The velocity decay line (carRigidbody.linearVelocity *=.) applies a custom exponential slowdown via a decelerationMultiplier, making it easier to make it more responsive to terrain or to design specifications.
- When the car slows down to nearly zero (< 0.25f), it hard-snaps to a complete stop and avoids any more deceleration calls by CancelInvoke().
While the foundation was solid, I tweaked the deceleration multiplier to make the car more responsive and heavier. I also integrated this logic with my custom input and friction systems to ensure consistent, smooth handling. This made the original asset more consistent with the cooperative feel and pacing of our four-player game.
I created the ICarMovement interface so that there could be a unified movement control. It has only two methods: Move() for steering and gas, and ApplyHandbrake() for brake handling. It was easy to connect different car controllers to our game system without needing to reimplement input handling. It also left me with space to replace or supplement vehicle movement in the future.
CarControllerWrapper handles all client-side player input and communicates it to the server through ServerRPCs. It initially verifies if the local player is the appointed driver and then processes the input. On the server side, it forwards input to the movement system using the ICarMovement interface. This configuration allows only the appropriate player to drive and synchronizes movements across all clients. It was crucial in allowing our two-player-per-car mechanic and facilitated dynamic role assignment with ease.
CarAdapter was developed to establish a link between the imported PrometeoCarController and our in-house game architecture. Since the asset wasn't developed for our role-based multiplayer system, I encapsulated it using the ICarMovement interface. This allowed us to treat the Prometeo controller like a plug-and-play module and drive it through our own network and input mechanisms. It simplified implementation and kept the asset dynamic for future adjustments or replacement.