Steering Game Objects with P.I.D. Control

in #gaming7 years ago

lunar lander

In a video game, objects move around, otherwise it could be a boring game. And movement means that the object position changes over time. How these position changes are implemented in code fall in one of three levels of indirectness:

  1. Direct: every frame, the code sets a position.
  2. Indirect: the code sets velocity, then every frame a new position is derived.
  3. Doubly indirect: the code sets an acceleration, then every frame a new velocity is derived with which a new position is derived.

Early games with digital controls, like e.g. Pacman, directly set a position as there is no concept of acceleration, and no real concept of velocity (other than a travel direction.)

As computer games got more sophisticated, physics simulations took over the control of calculating the object's position. Now, forces are used (which for a given body mass directly correspond to acceleration vectors) to move objects.

With this added realism, a new challenge cropped up for the steering of computer controlled objects, like Non Player Characters (NPCs.) If the game with a physics simulation wants to move an NPC to a location in the world, it cannot simply set the position, or even set the velocity as that would be a discontinuity in the simulation. The game needs to calculate the forces that can be applied to the NPC so that the NPC will end up at the desired location in the world.

Think for a moment on how you would achieve this. A naive approach of applying a force in the direction towards the goal does not work, as the NPC would overshoot its goal. If the NPC is close to its goal, but it is rapidly approaching the goal at high speed, we should be applying an opposite force that points away from the goal, not towards it so that we will come to a halt at the target location.

Because we are setting a force (acceleration) which leads to a change of velocity, and the velocity leads to a change in position, the game's control over the position is doubly indirect. This makes steering the NPC non-trivial.

Fortunately for us, the problem of steering with lag has already been solved for us in other industries. Consider for instance, the process of heating a room. A thermostat is set to 20℃ and the room temperature is 19℃. What should the heater do? Well, if the heater had been running at full blast in the last ten minutes, in which the room temperature went from 10℃ to 19℃ then the heater better shut off, because it will overshoot.

The tool of choice to use in both cases is a Proportional Integral Differential Controller, or a P.I.D. Controller. Don't let the math and the confusing terms on that wikipedia entry scare you. P.I.D. just means that you will be steering based on the current error, based on the historic error, and based on how the error is changing over time.

The tool is quite magical in that appears almost prescient. It will know how to avoid overshoot. And it can also handle changing conditions. For instance, if the wind is pushing against the NPC (or the room temperature is influenced by a harsh winter or open doors.) The P.I.D. Controller will make the NPC still come to a nice halt on the target spot, and make the room reach the desired temperature without overshoot.

Before P.I.D. Controllers can work their magic, they need to be tuned tough. I wrote a primer on P.I.D. that walks you through the process of tuning, and also comes with an implementation in C. If hope I made a convincing case for the use of P.I.D. Control and that my primer will help you implement it.

Sort:  

I always wondered about the "mechanism" how games display the movement of an object on screen. Just for my curiosity (I have little experience in programming), how does the code/engine of the game (for e.g. the old Pong game) define the object that needs to be displayed on screen? As a variable that has value for x, y position and a certain colour for the pixel?

Indeed. In it's simplest form, a 2D game that is moving a green pixel from left to right on the screen would clear the screen and then set the colour of pixel (x,y) to green and vary x from 0 to Max (and using the same y value each frame.) All current computers use framebuffers that contain all the pixels on the CRT or LCD screen.

The actually setting a pixel colour is just writing to a location in the framebuffer. If the framebuffer holds 320x200 pixels, then setting pixel X,Y to colour C would mean writing the value C at location Y×200+X.

Interestingly, this wasn't always the case. In the early days, there were vector displays. These did not have the concept of scanlines nor pixels. The computer driving a vector display would actually move an electron beam over a screen (in any direction) and turning the beam on and off. Very similar to an oscilloscope actually. Asteroids arcade machines worked that way. The electron beam would trace out the shapes on the screen.

Later computer monitors all wrote the screen left to right top to bottom as pixels on scanlines.

In 3D games it is a little more involved. A world composed of triangles is drawn a triangle at a time, and each triangle is projected onto the screen using linear algebra with 4x4 matrices, after which the corresponding pixels in the framebuffer for that triangle are set to a colour.

Thank you for your answer! I wanted to code games... but didn't have the technical expertise or education... I've started (recently) to dabble with Unity to gain some experience in coding games (to create a game engine is a titanic task), so later on I can start my own projects or look for opportunities in the game industry (currently I work as a SysAdmin for an outsourcing company).

Happy to help. For a gentle introduction that is easier than unity, I would first attempt something really simple, maybe a snake game (or pong) in Python e.g.

I'll try that. Thank you!

You actually gave me an idea. I learned to program on a micro computer in the early 80s, which was a much lower threshold for learning to code. You plug the computer in the wall, and you see the prompt of a basic interpreter.

No need for complex tools, no compiler, no GPUs, or window management.

I decided to start a tutorial on how to program Snake for Python, just with a simple output to a command line window. No loading assets, just a gentle introduction to making a video game.

A simple step-by-step programming from zero to snake in 3600 seconds, or something :-) Hey, that's a catchy title! Keep an eye out for it on my feed, in case it interests you.

That would we really great :D! I'll keep my voting power :)). I'll follow every post :D