Simulated F1 Track using Attractors – Assignment 3

The Concept

I wanted to create an F1 race car simulation using pure physics and particle systems . The idea was to use gravitational attractors positioned around a track like invisible “apex guides” that would pull the car through racing lines, just like how planets use gravity assists in space. I also thought that playing with attractors would give the car freedom or a factor of random drifting just like it happens in real life if drivers took a turn on a wrong speed; and it turned out as I expected.

The big challenge was making the car follow a racing line without getting trapped by the attractors or flying off into oblivion.

The Physics Behind It

The core of this simulation uses Newton’s law of universal gravitation as we did in class: F = G × (m₁ × m₂) / r²

Each attractor pulls on the car with a force that depends on:

  • The masses of both objects
  • The distance between them (squared)
  • A gravitational constant G that I tuned to 8000 (after trial and error with the numbers)

The tricky part was constraining the distance to prevent extreme forces when the car gets too close or too far.

Smart Attractor Activation

My first huge challenge was that the car would just get stuck orbiting the first attractor like a satellite. As expected, whatever I tried didn’t work to avoid getting the car trapped around one attractor or skipping all of them and getting lost. Nothing worked until I explored the idea of turning attractors on and off dynamically with their order through the track.

This was my breakthrough moment. Instead of having all attractors active at once, I created a workflow where only two are active at any time, and they activate/deactivate based on the car’s distance and velocity direction.

The code I’m most proud of uses the dot product to detect when the car is moving away from an attractor. When the dot product is negative, it means the car has passed the attractor and is heading away, so it’s safe to deactivate it and move to the next one. This prevents the car from getting pulled back!

Yellow attractors are active and pulling the car, while green ones are waiting their turn. Watch how they light up as the car approaches and turn off after it passes!

Here is the initial sketch I built while experimenting trying to figure out the physics details:


 

This proof-of-concept showed me the path was working. You can see the overlapping circles creating the racing line as the car laps around the track.

Building It Up: Milestones & Challenges

Milestone 1: Speed Management

Even with the activation system working, the car was either crawling or shooting off into space. I needed consistent speed for realistic racing. I added speed clamping that keeps the car between 4-9 units per frame. If it goes too fast, it gets clamped down. If it’s too slow, it gets boosted up. This gives it that consistent racing feel where you can actually follow the motion.

Milestone 2: Positioning the Attractors

Designing the track layout took forever. I had to position 9 attractors perfectly so they’d create smooth curves without sharp angles or weird wobbles. Each attractor has:

  • A specific mass (controls pull strength)
  • An attraction radius (how far out it affects the car)
  • A position that creates the racing line

The key insight was positioning them inside the curves. The car gets pulled toward the inside of the corner, creating this kinda perfect racing line, then slingshots out on the exit.

I spent a lot tweaking these positions, running the sketch, adjusting by a few pixels, running again… over and over until the car flowed smoothly through every turn.

Milestone 3: Visual Polish

Once the physics worked perfectly, I went all-in on the visuals. This is where it transformed from a proof-of-concept into something that actually looks like a racing game.

I added:

  • A proper asphalt track
  • Red and white rumble strips on the edges
  • A grass infield and grass surroundings
  • White racing line markings
  • A detailed F1 car with cockpit, front wing, rear wing, and wheels
  • Drift smoke trails that fade out gradually
  • A checkered start/finish line positioned horizontally across the track

The car rotates based on its velocity heading using vel.heading(), so it naturally points in the direction it’s moving. I implemented another visual trick to save the last 80 positions and draws an effect with fading opacity and decreasing stroke weight for that realistic drift smoke effect.

Milestone 4: Interactive Features

I added keyboard controls to make it more interactive:

  • Press ‘A’: Toggle attractor visibility so you can see the physics at work or hide them for a cleaner look
  • Press ‘R’: Reset the car to the start position for another lap
  • Press 1-9: Manually toggle individual attractors – this is great for experimenting with different configurations and seeing how each attractor affects the car’s path

The Final Result

Reflection & Future Work

This project taught me SO much about physics simulation and the importance of tuning parameters. The gravitational constant G, the masses, the attraction radii, the speed limits – they all needed to be just right to work together. Change one value and the whole thing falls apart!

What I learned:

  • Vector math is incredibly powerful for physics simulations
  • Small tweaks to physics parameters can have massive effects
  • Visual polish takes just as much time as getting the physics right
  • Breaking down complex problems (like “make a car race around a track”) into smaller pieces (activation system, speed management, visual layers) makes them manageable

What I’d add next:

  • Multiple cars racing against each other with different colors
  • Collision detection between cars
  • Lap counter and timing system to track bests scores
  • Different track layouts – maybe even let users draw their own tracks? I think is a bit challenging
  • Damage system – if you hit the walls too hard, you slow down
  • Pit stops – strategic element where you can reset speed but lose time

Leave a Reply

Your email address will not be published. Required fields are marked *