Hi, I am a newbie developer.
I am trying to understand the main loop of the game.
I am creating really simple game. The idea is a falling ball , the direction of which is controlled by a click.
Here some requirements for the game I am trying to achieve:
1. To have fixed frame rate on any device. For example, I need the ball to move to a new position with a fixed time interval (ex. 10ms).
2. To be able to increase the speed of the ball. It should be consistent with frame rate to provide the same experience of any device.
I've read a lot about this, but still have a lot of misunderstandings.
Let me explain the problem step by step.
Some parts of my Game
The Main Loop
public void run() {
while (mIsRunning) {
processGameInput();
updateGameState();
drawGame();
}
}
This loop is being running in a separate thread.
The drawGame method
@Override
public void drawGame() {
AbstractCanvas canvas = prepareAndGetCanvas();
canvas.clear(canvasBgColor);
ball.draw(canvas);
// Draw other objects
releaseCanvas();
}
The updateGameState method
public void updateGameState() {
Point canvasSize = getCanvasSize();
ball.updateState(canvasSize);
// Update state of other objects
}
The Ball class
public class Ball extends BaseBallShape {
private VelocityVector velocityVector;
public VectorBall(float centerX, float centerY, float radius, int color) {
super(centerX, centerY, radius, color);
velocityVector = new VelocityVector(0, 2);
}
public VectorBall(float centerX, float centerY, float radius, VectorGeometry.VelocityVector velocityVec) {
super(centerX, centerY, radius);
velocityVector = velocityVec;
}
@Override
public void draw(AbstractCanvas canvas) {
canvas.drawCircle(getCenterX(), getCenterY(), getRadius(), getColor());
}
@Override
public void updateState(Point canvasSize) {
updatePosition(canvasSize);
}
public void updatePosition(Point2d canvasSize) {
centerX += velocityVector.x;
centerY += velocityVector.y;
}
public void increaseVelocity(float deltaVelocity) {
increaseXVelocity(deltaVelocity);
increaseYVelocity(deltaVelocity);
}
public void decreaseVelocity(float deltaVelocity) {
decreaseXVelocity(deltaVelocity);
decreaseYVelocity(deltaVelocity);
}
public void decreaseYVelocity(float velocity) {
velocityVector.y -= velocity;
}
public void decreaseXVelocity(float velocity) {
velocityVector.x -= velocity;
}
public void increaseXVelocity(float velocity) {
velocityVector.x += velocity;
}
public void increaseYVelocity(float velocity) {
velocityVector.y += velocity;
}
}
As you could see, I am using velocity vector in order to control ball direction and magnitude size (size of pixels to increase on each update).
Let me explain this in a greater details.
Each time the main loop does an iteration three method are called.
So update method of the ball object increases its position by the constant stored now in the velocityVector.
Consider the ball initial position is (10,10);
The velocity vector is (0,2);
1 Iteration - The Ball (10,12);
2 Iteration - The Ball (10,14);
I think this is clear.
The problem is that the game runs with different speed on different devices.
I have read a lot of articles but still cannot get an idea why such solution is chosen.
Here are main articles I've taken as base example.
1. http://gafferongames.com/game-physics/fix-your-timestep/
2. http://gameprogrammingpatterns.com/game-loop.html
3. And my question on stack overflow - http://gamedev.stackexchange.com/questions/137658/game-loop-delay-the-right-way-and-game-speed/137660#137660
Lets consider the solution from the second link at first. They both have the same thing I cannot get.
double previous = getCurrentTime();
double lag = 0.0;
while (true)
{
double current = getCurrentTime();
double elapsed = current - previous;
previous = current;
lag += elapsed;
processInput();
while (lag >= MS_PER_UPDATE)
{
update();
lag -= MS_PER_UPDATE;
}
render();
}
The main questions I am interested in - Why the update method is called inside the loop, not the render ?
MS_PER_UPDATE = 100
As far as I can understand this example. It could be read like that.
"Measure current time, calculate elapsed time for the previous iteration, if it is greater than MS_PER_UPDATE that means that the render and processInput methods took more time that they should, so just update game while GPU is lagging"
So in this case the ball will be moving 2pixels down only if lag is greater than 0.1s.
What is the purpose of such solution ?
Another example I have suggested to use is following solution
double previous = getCurrentTime();
double totalElapsed = 0.0f;
while (true)
{
double current = getCurrentTime();
double elapsed = current - previous;
previous = current;
processInput();
update( elapsed);
totalElapsed += elapsed;
if(totalElapsed > MS_PER_FRAME)
{
render();
totalElapsed -= MS_PER_FRAME;
if(totalElapsed > MS_PER_FRAME)
std::cout<<"Performance warning, rendering or update took too long"<< std::endl;
}
}
And the update method
public void updatePosition(double elapsed) {
mCenterX += mVector.x * elapsed; // framerate indipendent
mCenterY += mVector.y * elapsed;
}
This is much clearer for me. But I have just tested this approach on different devices and the game runs differently.
So, I've completely lost here (
I would be grateful for any help to get better understanding of this topic. My goal is to have game running the same way on all devices and to be able to control the speed of the ball.