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
-
Gnome 48 Debuts New Audio Player
To date, the audio player found within the Gnome desktop has been meh at best, but with the upcoming release that all changes.
-
Plasma 6.3 Ready for Public Beta Testing
Plasma 6.3 will ship with KDE Gear 24.12.1 and KDE Frameworks 6.10, along with some new and exciting features.
-
Budgie 10.10 Scheduled for Q1 2025 with a Surprising Desktop Update
If Budgie is your desktop environment of choice, 2025 is going to be a great year for you.
-
Firefox 134 Offers Improvements for Linux Version
Fans of Linux and Firefox rejoice, as there's a new version available that includes some handy updates.
-
Serpent OS Arrives with a New Alpha Release
After months of silence, Ikey Doherty has released a new alpha for his Serpent OS.
-
HashiCorp Cofounder Unveils Ghostty, a Linux Terminal App
Ghostty is a new Linux terminal app that's fast, feature-rich, and offers a platform-native GUI while remaining cross-platform.
-
Fedora Asahi Remix 41 Available for Apple Silicon
If you have an Apple Silicon Mac and you're hoping to install Fedora, you're in luck because the latest release supports the M1 and M2 chips.
-
Systemd Fixes Bug While Facing New Challenger in GNU Shepherd
The systemd developers have fixed a really nasty bug amid the release of the new GNU Shepherd init system.
-
AlmaLinux 10.0 Beta Released
The AlmaLinux OS Foundation has announced the availability of AlmaLinux 10.0 Beta ("Purple Lion") for all supported devices with significant changes.
-
Gnome 47.2 Now Available
Gnome 47.2 is now available for general use but don't expect much in the way of newness, as this is all about improvements and bug fixes.