System Design : Vehicle Simulation - IAMColumbia/gp2portfoliogame-JSchoppe GitHub Wiki
Architectural Goals
Since the game is meant to run on Android; I have made the following design choices to facilitate efficiency in physics calculations.
- Although the game renders 3D models, physics simulations are done on the 2D plane.
- To increase modularity, the collision implementation is not required on Vehicles. This is injected via
IVehicleCollider
, a similar pattern is used for rendering(IVehicleRenderer
) and controlling(IVehicleController
) the vehicle. This allows vehicles to run headless in cases where they are outside a context requiring these features. - Vehicles use a simplified model of moving along their forwards axis and rotating about their collider center. This reduces overhead and edge cases from simulating wheels, at the tradeoff of being less realistic.
Challenges
The abstraction of collision simulation has introduced some challenges; it puts the base vehicle class in a place that dictates movement; and it is hard for it to react to collisions in a meaningful way. This makes me question whether this is the best way to architect this because it creates multiple layers when something such as the CruiserAgent
wants to respond to a collision from its assigned vehicle.
Design Goals
Going into this project I had a lot of affordances I wanted to add but was unable to get to. Some of these things that still need to be addressed;
- Vehicles should enter a drift/slip state when turning quickly with a brake input.
- Vehicle camera should be dampened better relative to the rotation of the vehicle.
- Vehicle values could be more finely tuned.
Current UML
In this UML diagram I've shown the core vehicle class and some Unity implementations of its optional injected components. I like the granularity of the component interfaces as they've made fairly easy to implement them in multiple different ways. I think the base vehicle class could be improved by abstracting many of the properties into their own data structures. An example of this would be to bundle up all of the steering factor traits into their own class or struct. Partitioning the data this way may also have benefits for abstracting more reusable interfaces in the future.