Android SDK development starts with an activity, and the game runs on single or multiple views. Most of the time, it is considered to have a single view to run gameplay.
Unfortunately, the Android SDK does not provide a predefined game loop. However, the loop can be created in many ways, but the basic mechanism remains the same.
In the Android SDK library, the View
class contains an abstract method OnDraw()
in which every possible rendering call is queued. This method is called upon any change in the drawing, which invalidates the previous rendering pipeline.
The logic is as follows:
Let's have a look at a basic game loop created with Android View
. Here, a custom view is extended from the Android View
:
/*Sample Loop created within OnDraw()on Canvas * This loop works with 2D android game development */ @Override public void onDraw(Canvas canvas) { //If the game loop is active then only update and render if(gameRunning) { //update game state MainGameUpdate(); //set rendering pipeline for updated game state RenderFrame(canvas); //Invalidate previous frame, so that updated pipeline can be // rendered //Calling invalidate() causes recall of onDraw() invalidate(); } else { //If there is no active game loop //Exit the game System.exit(0); } }
In the current age of Android game development, developers use SurfaceView
instead of View
. SurfaceView
is inherited from View
and more optimized for games made with Canvas. In this case, a customized view is extended from SurfaceView
and implements the SurfaceHolder.Callback
interface. In this scenario, three methods are overridden:
/* Called When a surface is changed */ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } /* Called on create of a SurfaceView */ @Override public void surfaceCreated(SurfaceHolder holder) { } /* Called on destroy of a SurfaceView is destroyed */ @Override public void surfaceDestroyed(SurfaceHolder holder) { }
While developing a game, the developer need not change the surface each time. That's the reason the surfaceChanged
method should have an empty body to function as a basic game loop.
We need to create a customized game thread and override the run()
method:
public class BaseGameThread extends Thread { private boolean isGameRunning; private SurfaceHolder currentHolder; private MyGameState currentState; public void activateGameThread(SurfaceHolder holder, MyGameState state) { currentState = state; isGameRunning = true; currentHolder = holder; this.start(); } @Override public void run() { Canvas gameCanvas = null; while(isGameRunning) { //clear canvas gameCanvas = null; try { //locking the canvas for screen pixel editing gameCanvas = currentHolder.lockCanvas(); //Update game state currentState.update(); //render game state currentState.render(gameCanvas); } catch(Exception e) { //Update game state without rendering (Optional) currentState.update(); } } } }
Now, we are set to start the newly created game loop from the customized SurfaceView
class:
public myGameCanvas extends SurfaceView implements SurfaceHolder { //Declare thread private BaseGameThread gameThread; private MyGameState gameState; @Override public void surfaceCreated(SurfaceHolder holder) { //Initialize game state gameState = new MyGameState(); //Instantiate game thread gameThread = new BaseGameThread(); //Start game thread gameThread. activateGameThread(this.getHolder(),gameState); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } }
There can be many approaches to implementing a game loop. However, the basic approach follows either of the two ways mentioned here. Some developers prefer to implement the game thread inside the game view. Handling input is another important part of the game loop. We will discuss this topic later in this chapter.
Another part of this game loop is frames per second (FPS) management. One of the most common mechanisms is to use Thread.sleep()
for such a calculated time that the loop executes at a fixed rate. Some developers create two types of update mechanism: one based on FPS and another based on per frame without delay.
Mostly, physics-based games need an update mechanism that follows a real-time interval to function uniformly across all devices.
For small-scale development, few developers in the industry follow the first approach but do not follow typical looping. This system invalidates the current draw based on the required action. In this scenario, the game loop is not dependent on fixed FPS.
18.222.182.73