I’ve been developing a top-down tank game, and I needed a way to accurately represent the movement of a vehicle with independently mobile treads. Obviously controls such as left/right/up/down needed to be polled from the keyboard, but their specific interaction with eachother and the rate of movement corresponding to a key being continuously held down needs to be representative of gas/brakes, etc. Additionally, when a tank turns, its speed is negatively affected by the nature of treads; To turn a tank slows or reverses one tread, thus causing a differential in the speed one tread is traveling in relation to another. Here’s what I came up with:
private void gameLoopInput()
{
Tank tank = _state.getTank();
if(_input.left())
tank.rotateLeft();
if(_input.right())
tank.rotateRight();
if((_input.left() == false) && (_input.right() == false))
if(_input.up())
tank.increaseDirectionalForce();
if(_input.down())
tank.decreaseDirectionalForce();
if(_input.up() == false && _input.down() == false)
tank.decayDirectionalForce();
}
The specifics behind the rotation methods of the tank sprite:
public void rotateLeft()
{
if(_velocity > 80)
_angle = clampAngle(_angle - Constants.ROTATE_ANGLE_FAST);
else
_angle = clampAngle(_angle - Constants.ROTATE_ANGLE_SLOW);
}
public void rotateRight()
{
if(_velocity > 80)
_angle = clampAngle(_angle + Constants.ROTATE_ANGLE_FAST);
else
_angle = clampAngle(_angle + Constants.ROTATE_ANGLE_SLOW);
}
private double clampAngle(double angle)
{
double result = angle % 360;
if (result < 0)
result = result + 360;
return result;
}
And the wrappers around those methods for the tank, as well as the other tank methods:
public void increaseDirectionalForce()
{
long millis = System.currentTimeMillis();
if((millis - Constants.SPEED_DELAY) < _lastDirectionalForceChangeMillis)
return;
if(_directionalForce < 10)
{
_directionalForce++;
_lastDirectionalForceChangeMillis = System.currentTimeMillis();
}
}
public void decreaseDirectionalForce()
{
long millis = System.currentTimeMillis();
if((millis - Constants.SPEED_DELAY) < _lastDirectionalForceChangeMillis)
return;
if(_directionalForce > -10)
{
_directionalForce--;
_lastDirectionalForceChangeMillis = System.currentTimeMillis();
}
}
public void decayDirectionalForce()
{
long millis = System.currentTimeMillis();
if(millis - Constants.SPEED_DELAY < _lastDirectionalForceChangeMillis)
return;
if(_directionalForce > 0)
{
_directionalForce--;
_lastDirectionalForceChangeMillis = System.currentTimeMillis();
}
else if(_directionalForce < 0)
{
_directionalForce++;
_lastDirectionalForceChangeMillis = System.currentTimeMillis();
}
}
public void rotateLeft()
{
_sprite.rotateLeft();
long millis = System.currentTimeMillis();
if(millis - Constants.SPEED_DELAY < _lastDirectionalForceChangeMillis)
return;
if(_directionalForce > 5)
_directionalForce--;
_lastDirectionalForceChangeMillis = System.currentTimeMillis();
}
public void rotateRight()
{
_sprite.rotateRight();
long millis = System.currentTimeMillis();
if(millis - Constants.SPEED_DELAY < _lastDirectionalForceChangeMillis)
return;
if(_directionalForce > 5)
_directionalForce--;
_lastDirectionalForceChangeMillis = System.currentTimeMillis();
}