This blog post is the first of many writeups about our (Mark, Nick, and my) progress on the top down racing game.
Users will be able to customize cars by the attributes they invest in them. The current game only has a few functional attributes (acceleration, weight, turning, traction) but we plan on expanding these in later iterations. Attributes are invested in a point-weighting system. You can give any attribute any number of points to invest, but the game ends up using the final ratio, not points to determine how well your car performs for each of the attributes. Investing a 9-1-1-1 attribute spread is the same as a 90-10-10-10 spread, as the ratio of points in each category is the same. This allows for the system to remain fair regardless of the total points, while allowing fine-tuned customization if desired.
One of the early challenges in designing a top down racer is teaching the AI to follow the track. Cars aren't aware of the track, and with a variety of environments and track layouts, pattern recognition would be very difficult. We initially decided to use a checkpoint system, which involves placing a predefined list of points for each track, so the cars have a "guidepost" to follow and attempt to aim for so they remain on track. Our early design was exactly as described, a JSON list of x, y points that corresponded to points on the track that the cars were meant to follow.
It worked - partially. There was difficulty in determining when a car should advance towards targeting the next checkpoint in this list. We didn't want every car to take exactly the same route, so the cars aren't going to move directly above the checkpoint. Instead, checkpoints were considered "passed" if a car moved within a certain radius from the center. This initially seemed to be a good compromise, but it had some drawbacks. Occasionally, cars would move slightly outside of this radius. The AI would react as if it had gone off-track, and force the car to turn around, go the wrong way to reach the missed checkpoint, breaking the immersion (and causing numerous collisions). Increasing the radius of the checkpoint was not a viable solution, as it meant cars could be capable of skipping portions of the track and going off-track.
Our solution was to turn checkpoints into a line instead of a fixed point. Checkpoints went all the way across the track, much like ski gates. Cars don't aim for the center checkpoint, they just attempt to cross the line at the best intersection point [best being the intersection point that involves the least turning to still intersect the checkpoint]. These line-checkpoints are invisible to the user, but the AI uses them as guides to navigate the track.
Another early issue was the AI design - we needed to provide an event driven AI that could guide the car through the track and also react to different situations. Our initial design was a completely reaction driven AI design. Cars had an AI that listened to events, and responded to each event. Events were fired for the race start, checkpoints being reached, if the car goes off-track, if an opponent moves in proximity, obstacles, and other related situations. The AI did not have any long term memory, it did not remember what previous events have been fired and did not have any long-term strategy.
There are several problems with this design that we encountered. In a best case, cars have little difficulty navigating the track, but other cars and obstacles often pose a problem. Because the AI only responds to the last event it receives, it might end up ignoring the track to escape another car, and end up worse off if it had simply collided. Or it might get stuck off track, and not be able to recover.
The Race-AI is not a problem we have completely solved, but we are experimenting with a strategy system that allows the AI to have longer-term goals, and pick and choose which events to respond to, based on the current situation.