Categories
Game Development

Game Development Meets Control Theory: Implementing PI Control in LÖVE

When developing games, I often look for tools that allow fast prototyping, simple syntax, and strong community support. That’s why I chose the Lua programming language together with the LÖVE framework—a lightweight, open‑source 2D game engine. It’s particularly well‑suited for experimenting with game mechanics.

LÖVE Framework Basics

In LÖVE, the game loop is structured around three main functions:

  • love.load() → runs once at the start, initializing the game.
  • love.update(dt) → updates the game state every frame, where dt is the delta time.
  • love.draw() → renders the updated state to the screen.

This simple structure makes it easy to integrate control algorithms directly into the update cycle.

“Screenshot of a Lua script in LÖVE showing the basic game loop with load, update, and draw functions.”
“Screenshot of a Lua script in LÖVE showing the basic game loop with load, update, and draw functions.”

This minimal template is where I later integrated the PI controller logic. Notice the line at the top:

“This disables output buffering, which ensures that print statements appear immediately in the console—very handy for debugging.
“This disables output buffering, which ensures that print statements appear immediately in the console—very handy for debugging.

One of the classic game types I’ve always been fascinated by is the “bricks breaker” (or breakout/arkanoid‑style) game. Using this as a foundation, I built a prototype and then decided to take it a step further: I implemented a PI controller algorithm to automatically control the paddle.

Why PI Control in a Game?

In industrial automation, PID controllers are widely used to regulate systems with feedback loops. They combine three effects:

  • Proportional (P): reacts to the current error.
  • Integral (I): accounts for accumulated error over time.
  • Derivative (D): predicts future error trends.

For this project, I focused on the PI controller (proportional + integral). My interest in PID control goes back to earlier experiments with Arduino boards and smart materials, where I used it for actuator position control. Bringing that concept into a game felt like a fun crossover between engineering and gameplay.

The Game Prototype

The layout includes:

  • Rows of bricks at the top of the screen.
  • A paddle at the bottom, which is normally player‑controlled.
  • A ball that bounces around the playfield.
“Screenshot of a breakout style game built with Lua and LÖVE, showing bricks arranged in rows, a paddle at the bottom, and a ball in play.”
“Screenshot of a breakout style game built with Lua and LÖVE, showing bricks arranged in rows, a paddle at the bottom, and a ball in play.”

Implementing the PI Algorithm

The PI controller was applied to the paddle’s horizontal movement. The algorithm works by:

  1. Calculating the error between the ball’s x‑position and the paddle’s x‑position.
  2. Using Kp (proportional gain) and Ti (integral time constant) to compute the control signal.
  3. Integrating the error over time with a trapezoidal integration function (trapez_integral).
  4. Updating the paddle’s velocity based on the control output.

Instead of manually moving the paddle, the algorithm automatically adjusts its position to follow the ball. The result is a paddle that feels almost “intelligent,” smoothly tracking the ball’s trajectory.

Here’s the function I used to update the paddle’s position automatically. It runs inside the love.update(dt) loop:

"Paddle Moving"
“Paddle Moving”

How It Works

  • Error calculation: The difference between the ball’s x‑position and the paddle’s center.
  • Integration: Errors are accumulated over time using a trapezoidal method (trapez_integral).
  • Control law: The paddle’s velocity is computed as a combination of proportional and integral terms.
  • Update step: The paddle’s position is adjusted each frame, making it smoothly track the ball.

By tuning Kp and Ti, you can change how aggressively or smoothly the paddle follows the ball.

  • A higher Kp makes it react faster but can overshoot.
  • A smaller Ti increases the effect of accumulated error, improving accuracy but risking oscillation.

Even with just proportional control, the paddle follows the ball reasonably well. But adding the integral term makes the movement more precise and stable, reducing steady‑state error. Since the PI controller was sufficient, I didn’t include the derivative term.

The resulting equation for paddle velocity is essentially:

$$
Kp \cdot \left( e(t) + \frac{1}{Ti} \int_{0}^{t} e(t)\, dt \right)
$$

where:

  • Kp = proportional gain
  • Ti = integral time constant
  • e(t) = error between ball and paddle positions

Numerical Integration with the Trapezoidal Rule

  • To implement the integral part of the PI controller, I used a trapezoidal integration function. This method approximates the area under the error curve by summing trapezoids between successive time steps. It’s simple, efficient, and works well in real‑time applications like games.
  • Here’s the Lua function:
"Integral Code"
“Integral Code”

How It Works

  • Inputs:
    • fonk → a table of error values over time.
    • t → a table of corresponding time values.
  • Loop: For each time step, it calculates the trapezoid area between two points.
  • Output: Returns the accumulated integral of the error signal.

This integral is then used in the PI control law to adjust the paddle’s velocity, ensuring it doesn’t just react to the ball’s current position but also accounts for past errors.

The outcome: a paddle that automatically moves toward the ball with smooth, responsive behavior. It was both effective and fun to implement!

“Lua code implementing a PI controller in LÖVE, showing proportional and integral terms used to automatically move the paddle toward the ball.”
“Lua code implementing a PI controller in LÖVE, showing proportional and integral terms used to automatically move the paddle toward the ball.”

Final Thoughts

By combining game development with control theory, I ended up with a paddle that intelligently tracks the ball using a PI controller. It’s a small but exciting example of how engineering concepts can enrich gameplay mechanics. And honestly—it was just plain fun to see control theory come alive in a simple arcade game!

Resources I Used

  • LÖVE Arkanoid Tutorial – step‑by‑step guide to building a breakout clone.
  • Sheepolution’s LÖVE Tutorials – beginner‑friendly learning material.
  • ZeroBrane Studio – the Lua IDE I used for development.
  • Automatic Control: System Dynamics and Control Systems by Prof. Dr. İbrahim Yüksel – for deeper theoretical background.
RUNONUR
Categories
Game Development

Seal of Solara

This might be the most interesting game project I’ve ever thought of—and now I’ve actually built it! 😊

“Arduino and LCD screen used to build a text-based adventure game console. Seal of Solara project coded with Copilot.”
Seal of Solara: A custom-built text adventure console using Arduino and LCD shield.

Using an LCD screen shield and Arduino, I created my own text-based adventure game console. With Copilot’s help, generating the game code was incredibly easy.

I had a lot of fun both building and playing this project. The buttons on the LCD shield provide intuitive control, and the game interface is surprisingly enjoyable.

Highlights from the Code

I used EEPROM to allow players to continue from specific stages—this feature is genuinely awesome.

“Using EEPROM to save game stages was a game-changer. It made the console feel real.”
“Using EEPROM to save game stages was a game-changer. It made the console feel real.”

In future versions, I might add sound effects or sensor inputs.

I’m even considering designing a text-based adventure engine someday… though maybe it’s better if that stays a dream 😄

The game I prototyped with Copilot follows a warrior on a quest to find the city of Solara. The journey takes you through forests, mountains, and lakes, all in search of the seal that unlocks the city gates.

In later stages, I might code a full “text adventure” and even design a plastic enclosure for the console. Of course, it needs a name too… maybe Adventuriono or Textuino? Just a few ideas off the top of my head 😄

In short, this project gave me a fun and creative experience without taking too much time—and I couldn’t have done it without Copilot’s support. Thanks again! Much love and respect 🙌

RUNONUR