# Facing Direction

Whether your game is in 2-D or 3-D, you often have the need to make an object "turn" to face another direction. This could be a character's walking direction as they are moving, the direction they are shooting while sitting crouched, the direction a missile is flying in, the direction a car is racing towards, etc. This is the job of the "character controller", the piece of code in your system responsible for the basic "movement" operations that a character must undergo (seek, turn, arrive, etc.). Building games that use physics engines is a lot of fun and adds a level of realism to the game that can dramatically improve the gameplay experience. Objects collide, break, spin, bounce, and move in more realistic ways. Moving in more realistic ways is**not**what you usually think about, though, when you think about facing direction. Your usual concern is something like "The character needs to turn to face left in 0.5 seconds." From the standpoint of physics, this means you want to apply torque to make it turn 90? left in 0.5 seconds. You want it to stop exactly on the spot. You don't want to worry about things like angular momentum, which will tend to keep it turning unless you apply counter torque. You

**really**don't want to think about applying counter torque to make it stop "on a dime". Box2D will allow you to manually set the position and angle of a body.

**However, if you manually set the position and angle of a physics body in every frame, it can interfere (in my experience) with the collision response of the physics engine.**Most important of all, this is a physics engine. You should be using it as such to make bodies move as expected. Our goal is to create a solution to change the facing direction of the body by applying turning torque to it.

__If we decouple the problem of "how it turns" from "how it moves", we can use the same turning solution for other types of moving bodies where the facing direction needs to be controlled. For this article, we are considering a missile that is moving towards its target.__

**NOTE THAT PID CONTROL LOOPS CAN BE USED FOR LOTS OF OTHER THINGS. This example just happens to be the one I chose.**# Feedback Control Systems 101

The basic idea behind a control system is to take the difference of "what you want the value to be" and "what the value is" and adjust your input to the system so that, over time, the system converges to your desired value. From this wikipedia article:A familiar example of a control loop is the action taken when adjusting hot and cold faucets (valves) to maintain the water at a desired temperature. This typically involves the mixing of two process streams, the hot and cold water. The person touches the water to sense or measure its temperature. Based on this feedback they perform a control action to adjust the hot and cold water valves until the process temperature stabilizes at the desired value.There is a huge body of knowledge in controls system theory. Polynomials, poles, zeros, time domain, frequency domain, state space, etc. It can seem daunting to the uninitiated.

**It can seem daunting to the initiated as well!**That being said, while there are more "modern" solutions to controlling the facing direction, we're going to stick with PID Control. PID control has the distinct advantages of having only three parameters to "tune" and a nice intuitive "feel" to it.

# PID Control

Let's start with the basic variable we want to "control", the difference between the angle we want to be facing and the angle of the body/velocity:## Proportional Feedback

The first and most obvious choice is to apply a torque that is proportional to the \(e(t)\) itself. When the error is large, large force is applied. When the error is small, small force is applied. Something like:## Integral Feedback

The next term to add is the integral term, the "I" in PID:- If direction to the target suddenly changes a small amount, then over each time step, this difference will build up and create turning torque.
- If there is a bias in the direction (e.g. Steady State Error), this will accumulate over the time steps and be countered.

## Derivative Feedback

Most PID controllers stop at the "PI" version. The proportional part gets the output swinging towards the input and the integral part knocks out the bias or any steady external forces that might be countering the proportional control.**However**, we still have oscillations in the output response. What we need is a way to slow down the rotation as the body is heading towards the target angle. The proportional and integral components work to push towards it. By looking at the derivative of \(e(t)\), we can estimate its value in the near term and apply force to drive it towards not changing. This is a counter-torque to the proportional and integral components:

__Just like the integral, the derivative can be estimated numerically. This is done by taking differences over the last several \(e(t)\) values (see the code).__

*So the derivative term will apply counter torque hardest when the body is swinging through the point we want to be at, countering the oscillation, and least when we are at either edge of the "swing".*Using derivative control is not usually a good idea in real control systems. Sensor noise can make it appear as if \(e(t)\) is changing rapidly back and forth, causing the derivative to spike back and forth with it. However, in our case, unless we are looking at a numerical issue, we should not have a problem.

# Classes and Sequences

Because we are software minded, whatever algorithm we want to use for a PID controller, we want to wrap it into a convenient package, give it a clean interface, and hide everything except what the user needs. This needs to be "owned" by the entity that is doing the turning.*MovingEntityInterface*represents a "Moving Entity". In the case of this demo, it can be an entity like a

*Missile*, which moves forward only, or a "character", which can turn while moving. While they have different methods internally for "applying thrust" they both have nearly identical methods for controlling turning. This allows the implementation of a "seek" behavior tailored more to the entity type. The interface itself is generic so that the

*MainScene*class can own an instance and manipulate it without worrying about what type it is. The

*PIDController*class itself has this interface:

```
/********************************************************************
* File : PIDController.h
* Project: Interpolator
*
********************************************************************
* Created on 10/13/13 By Nonlinear Ideas Inc.
* Copyright (c) 2013 Nonlinear Ideas Inc. All rights reserved.
********************************************************************
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must
* not claim that you wrote the original software. If you use this
* software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef __Interpolator__PIDController__
#define __Interpolator__PIDController__
#include "CommonSTL.h"
#include "MathUtilities.h"
/* This class is used to model a Proportional-
* Integral-Derivative (PID) Controller. This
* is a mathemtical/control system approach
* to driving the state of a measured value
* towards an expected value.
*
*/
class PIDController
{
private:
double _dt;
uint32 _maxHistory;
double _kIntegral;
double _kProportional;
double _kDerivative;
double _kPlant;
vector
``` _errors;
vector _outputs;
enum
{
MIN_SAMPLES = 3
};
/* Given two sample outputs and
* the corresponding inputs, make
* a linear pridiction a time step
* into the future.
*/
double SingleStepPredictor(
double x0, double y0,
double x1, double y1,
double dt) const
{
/* Given y0 = m*x0 + b
* y1 = m*x1 + b
*
* Sovle for m, b
*
* => m = (y1-y0)/(x1-x0)
* b = y1-m*x1
*/
assert(!MathUtilities::IsNearZero(x1-x0));
double m = (y1-y0)/(x1-x0);
double b = y1 - m*x1;
double result = m*(x1 + dt) + b;
return result;
}
/* This funciton is called whenever
* a new input record is added.
*/
void CalculateNextOutput()
{
if(_errors.size() < MIN_SAMPLES)
{ // We need a certain number of samples
// before we can do ANYTHING at all.
_outputs.push_back(0.0);
}
else
{ // Estimate each part.
size_t errorSize = _errors.size();
// Proportional
double prop = _kProportional * _errors[errorSize-1];
// Integral - Use Extended Simpson's Rule
double integral = 0;
for(uint32 idx = 1; idx < errorSize-1; idx+=2)
{
integral += 4*_errors[idx];
}
for(uint32 idx = 2; idx < errorSize-1; idx+=2)
{
integral += 2*_errors[idx];
}
integral += _errors[0];
integral += _errors[errorSize-1];
integral /= (3*_dt);
integral *= _kIntegral;
// Derivative
double deriv = _kDerivative * (_errors[errorSize-1]-_errors[errorSize-2]) / _dt;
// Total P+I+D
double result = _kPlant * (prop + integral + deriv);
_outputs.push_back(result);
}
}
public:
void ResetHistory()
{
_errors.clear();
_outputs.clear();
}
void ResetConstants()
{
_kIntegral = 0.0;
_kDerivative = 0.0;
_kProportional = 0.0;
_kPlant = 1.0;
}
PIDController() :
_dt(1.0/100),
_maxHistory(7)
{
ResetConstants();
ResetHistory();
}
void SetKIntegral(double kIntegral) { _kIntegral = kIntegral; }
double GetKIntegral() { return _kIntegral; }
void SetKProportional(double kProportional) { _kProportional = kProportional; }
double GetKProportional() { return _kProportional; }
void SetKDerivative(double kDerivative) { _kDerivative = kDerivative; }
double GetKDerivative() { return _kDerivative; }
void SetKPlant(double kPlant) { _kPlant = kPlant; }
double GetKPlant() { return _kPlant; }
void SetTimeStep(double dt) { _dt = dt; assert(_dt > 100*numeric_limits::epsilon());}
double GetTimeStep() { return _dt; }
void SetMaxHistory(uint32 maxHistory) { _maxHistory = maxHistory; assert(_maxHistory >= MIN_SAMPLES); }
uint32 GetMaxHistory() { return _maxHistory; }
void AddSample(double error)
{
_errors.push_back(error);
while(_errors.size() > _maxHistory)
{ // If we got too big, remove the history.
// NOTE: This is not terribly efficient. We
// could keep all this in a fixed size array
// and then do the math using the offset from
// the beginning and module math. But this
// gets complicated fast. KISS.
_errors.erase(_errors.begin());
}
CalculateNextOutput();
}
double GetLastError() { size_t es = _errors.size(); if(es == 0) return 0.0; return _errors[es-1]; }
double GetLastOutput() { size_t os = _outputs.size(); if(os == 0) return 0.0; return _outputs[os-1]; }
virtual ~PIDController()
{
}
};

This is a very simple class to use. You set it up calling the *SetKXXX*functions as needed, set the time step for integration, and call

*AddSample(...)*each update cycle with the error term. Looking at the

*Missile*class, which owns an instance of this, the step update (called in

*Update*) looks like this:

```
void ApplyTurnTorque()
{
Vec2 toTarget = GetTargetPos() - GetBody()->GetPosition();
float32 angleBodyRads = MathUtilities::AdjustAngle(GetBody()->GetAngle());
if(GetBody()->GetLinearVelocity().LengthSquared() > 0)
{ // Body is moving
Vec2 vel = GetBody()->GetLinearVelocity();
angleBodyRads = MathUtilities::AdjustAngle(atan2f(vel.y,vel.x));
}
float32 angleTargetRads = MathUtilities::AdjustAngle(atan2f(toTarget.y, toTarget.x));
float32 angleError = MathUtilities::AdjustAngle(angleBodyRads - angleTargetRads);
_turnController.AddSample(angleError);
// Negative Feedback
float32 angAcc = -_turnController.GetLastOutput();
// This is as much turn acceleration as this
// "motor" can generate.
if(angAcc > GetMaxAngularAcceleration())
angAcc = GetMaxAngularAcceleration();
if(angAcc < -GetMaxAngularAcceleration())
angAcc = -GetMaxAngularAcceleration();
float32 torque = angAcc * GetBody()->GetInertia();
GetBody()->ApplyTorque(torque);
}
```

# Nuances

If you look carefully at the video, there is a distinct difference in the way path following works for the missile vs. the character (called the*MovingEntity*in the code). The missile can overshoot the path easily, especially when its maximum turn rate is reduced. The

*MovingEntity*

**always**moves more directly towards the points because it is using a "vector feedback" of its position vs. the target position to adjust its velocity. This is more like a traditional "seek" behavior than the missile. I have also, quite deliberately, left out a bit of key information on how to tune the constants for the PID controller. There are numerous articles on Google for how to tune a PID control loop, and I have to leave something for you to do, after all. You will also note that the default value for

*_dt*, the time step, is set for 0.01 seconds. You can adjust this value to match the timestep you actually intend to use, but there will be tradeoffs in the numerical simulation (error roundoff, system bandwidth concerns, etc.) that you will encounter. In practice, I use the same controller with the same constants across multipe sized physical entities without tweaking and the behavior seems realistic enough (so far) that I have not had to go and hunt for minor tweaks to parameters. Your mileage may vary. The source code for this, written in cocos2d-x/C++, can be found on github here. The

*PIDController*class has no dependencies other than standard libraries and should be portable to any system.

## Create an account or sign in to comment

You need to be a member in order to leave a comment

## Create an account

Sign up for a new account in our community. It's easy!

Register a new account## Sign in

Already have an account? Sign in here.

Sign In Now