A desktop car racing game in Go
Go Faster!
The fastest way through a curve on a racetrack is along the racing line. Instead of heading for Indianapolis, Mike Schilli trains his reflexes with a desktop application written in Go, just to be on the safe side.
A few years ago, I got to test the physical limits of my Honda Fit during a safety training session. A short time later, I discovered I was interested in car racing. It's also a more popular hobby than you might think among Silicon Valley employees, who let their tuned private cars off the leash on racetracks like Laguna Seca in California – maybe because of the strict speed limit that typically applies on freeways in the US.
While studying the topic, I was surprised to learn that it's by no means just a matter of keeping your foot on the gas. If you want to break track records, you have to take the turns exactly in line with physical formulas and always find the ideal line in order to knock those vital seconds off your time in each lap. The physical principles of racing are explained in the reference work Going Faster by Carl Lopez [1]. The book describes exactly how quickly you can enter a turn without the car starting to skid and tells you the angle and time at which the driver needs to turn the steering wheel to lose as little time as possible while cornering.
Learning How to Race
The ideal line through a turn is never going to be the shortest path, which runs along the inside. Instead, the aim is to drive through the curve on a trajectory with as large a radius as possible (Figure 1). Before the 90-degree right-hand bend shown in Figure 1, a world-class driver like Jos Verstappen will initially steer to the left-hand edge of the road and then pull sharply to the right towards the apex. This means that the race car just barely scrapes past the inside of the curve, only to run over to the left side of the road again shortly afterwards on the straight that follows the turn. This means that the radius followed by the car is far larger than that of the turn, and that the car can negotiate the turn at a far faster speed without the tires losing traction or the vehicle skidding.
World of Geometry
Figure 2 shows the simulation of a 90-degree turn as a desktop game written in Go with racing animation. The race car, depicted as a green square, speeds upwards towards the curve. The player has to steer the vehicle to the left and right with the H and L keys so that it doesn't hit the side of the road at this breakneck speed, but safely reaches the end of the turn at the top right of the game window. The stopwatch next to the two buttons runs during the animation and displays the elapsed lap time in seconds with an accuracy of two decimal figures.
With a little prior knowledge of geometry and video game technology, a simple 2D game like this can be quickly put together using Go and the Fyne framework [2]. To do this, the program runs through a number of frames per second, in each of which it computes the current position of the game figures, which it then refreshes in the graphics. At the same time, it fields user input such as keystrokes or mouse clicks and incorporates these events into the calculations, for example, by adjusting the steering.
In the Beginning Was the Circle
But how do you write a game like this in Go? First of all, you need to draw the "world" for the game. This is best done in such a way that the program can later compute the game's status at lightning speed for each video frame that it is running through. First and foremost, it needs to give feedback about whether the race car is still driving on the road or has already left the contours of the turn and is lying somewhere in the bushes.
The program draws the racetrack's right turn as an overlap of two concentric circles (Figure 3) with the radii r2
(outside) and r1
(inside). But only the upper left quadrant of this shape is of interest for the curve; this is why I used some cleverly placed rectangles in Figure 4 to mask the irrelevant parts of the circles. The blue, gray, and orange areas later disappear in the display, and two additional salmon-colored rectangles define the road at the entry to the turn and its exit. Listing 1 implements this "world," as gamers call it, using the Circle()
and Rectangle()
functions on a canvas
object provided by the Fyne framework.
Listing 1
world.go
01 package main 02 03 import ( 04 "fyne.io/fyne/v2" 05 "fyne.io/fyne/v2/canvas" 06 "fyne.io/fyne/v2/container" 07 col "golang.org/x/image/colornames" 08 "image/color" 09 ) 10 11 func drawWorld(r1, r2 float32) (fyne.CanvasObject, Car) { 12 bg := drawRectangle(col.Grey, 0, 0, 2*r2, 2*r2) 13 co := drawCircle(col.Lightsalmon, r2, r2, r2) 14 ci := drawCircle(col.Grey, r2, r2, r1) 15 mb := drawRectangle(col.Grey, 0, r2, 2*r2, r2) 16 mr := drawRectangle(col.Grey, r2, 0, r2, r2) 17 in := drawRectangle(col.Lightsalmon, 0, r2, r2-r1, r2) 18 out := drawRectangle(col.Lightsalmon, r2, 0, r2, r2-r1) 19 20 car := Car{Ava: canvas.NewRectangle(col.Green), 21 StartPos: fyne.NewPos(10, r2+r2-1), 22 } 23 24 car.Ava.Resize(fyne.NewSize(10, 10)) 25 car.Ava.Move(car.StartPos) 26 objects := []fyne.CanvasObject{bg, co, ci, mb, mr, in, out, car.Ava} 27 play := container.NewWithoutLayout(objects...) 28 29 return play, car 30 } 31 32 func drawCircle(co color.RGBA, x, y, r float32) *canvas.Circle { 33 c := canvas.NewCircle(co) 34 pos := fyne.NewPos(x-r, y-r) 35 c.Move(pos) 36 size := fyne.NewSize(2*r, 2*r) 37 c.Resize(size) 38 return c 39 } 40 41 func drawRectangle(co color.RGBA, x, y, w, h float32) *canvas.Rectangle { 42 r := canvas.NewRectangle(co) 43 r.Move(fyne.NewPos(x, y)) 44 r.Resize(fyne.NewSize(w, h)) 45 return r 46 }
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
New Steam Client Ups the Ante for Linux
The latest release from Steam has some pretty cool tricks up its sleeve.
-
Gnome OS Transitioning Toward a General-Purpose Distro
If you're looking for the perfectly vanilla take on the Gnome desktop, Gnome OS might be for you.
-
Fedora 41 Released with New Features
If you're a Fedora fan or just looking for a Linux distribution to help you migrate from Windows, Fedora 41 might be just the ticket.
-
AlmaLinux OS Kitten 10 Gives Power Users a Sneak Preview
If you're looking to kick the tires of AlmaLinux's upstream version, the developers have a purrfect solution.
-
Gnome 47.1 Released with a Few Fixes
The latest release of the Gnome desktop is all about fixing a few nagging issues and not about bringing new features into the mix.
-
System76 Unveils an Ampere-Powered Thelio Desktop
If you're looking for a new desktop system for developing autonomous driving and software-defined vehicle solutions. System76 has you covered.
-
VirtualBox 7.1.4 Includes Initial Support for Linux kernel 6.12
The latest version of VirtualBox has arrived and it not only adds initial support for kernel 6.12 but another feature that will make using the virtual machine tool much easier.
-
New Slimbook EVO with Raw AMD Ryzen Power
If you're looking for serious power in a 14" ultrabook that is powered by Linux, Slimbook has just the thing for you.
-
The Gnome Foundation Struggling to Stay Afloat
The foundation behind the Gnome desktop environment is having to go through some serious belt-tightening due to continued financial problems.
-
Thousands of Linux Servers Infected with Stealth Malware Since 2021
Perfctl is capable of remaining undetected, which makes it dangerous and hard to mitigate.