In this mini-project we will draw a moving, controllable sprite to your Android device. We will draw Bob to the screen and when the screen is touched he will move to the right and when the screen is released he will stop. However, we will have achieved much more than this as this simple 2D game engine will be easy to upgrade to handle many more game objects. You will also be able to just copy/paste most of the code to get our first real, playable game; which will be the next project. You will also be able to use this code as a springboard to get started with 2D games of your very own design.

patreon

 

 

About this project

Skill level 1
Time to complete 1 hour

New Concepts:

  1. onPause and onResume Activity methods
  2. Constructor methods for setting up classes
  3. Introduce the concept of the main game loop

Recommended preparation tutorials

Create a simple game engine project

Create a new Android Studio project and call it Simple Game Engine. Create a blank Activity and call it SimpleGameEngine. Add the bob.png file (below) to the drawable folder as we did in the Drawing graphics demo.

 

bob

Here is a little bit of pseudo-code so we can appreciate the structure of the real code we will write soon. The real code is quite long and with just a quick glance might appear complex although it really isn’t. This pseudo code will clarify things a little and enable us to present and discuss the code in manageable chunks. You can also skip to the end of the article and see the code in its entirety for explicit clarification and context. You might like to simply copy and paste the full completed code into your project and get the simple game engine working; then come back and read all about it.

 

 

Pseudo code not real code…

How it works

Let’s run through how that works in sequence. Remember that although methods execute their code starting from the first line; the order in which methods are executed is determined by when they are called. So here is what will happen with our finished game engine.

The player presses the icon on their device to play our game. Android does some stuff in the background that we don’t need to worry about; it then calls our onCreate method. In onCreate we declare and initialize a new class that we will code, called GameView. The last thing that onCreate does is to set our new GameView object as the view for the app. Once onCreate completes the Android operating system calls the onResume method (in the SimpleGameEngine class). This method calls the resume method, that we will write, in our new  GameView class. Our resume method starts our thread which causes the run method to execute. The run method calls update and draw which essentially is the entire functionality of our game. The operating system will continually call run many times per second.

So the GameView class handles our entire game, specifically, from the run method, until the user presses a button on their device (perhaps back or home) that causes the operating system to execute the onPause method in the SimpleGameEngine class which in turn calls the pause method in the GameView class and stops our thread. The run method will not be called anymore and our game will cease to function.

In addition to the operating system calling our run method, it will also call our onTouchEvent method (also in GameView) in the main/default thread. It is here we can then code a response to the player’s touches.

Coding the Simple game engine class

Here is the code for our SimpleGameEngine class with the extra methods ( onPause and  onResume) as well as our GameView class left out for now. Copy and paste this into your project.

Above we add all the required imports we will need and an  GameView object called gameView. Then we coded the onCreate method which simply initializes our GameView object and sets it to the view of the entire game which is what the player will see on the screen.

Coding the GameView class

We will now code this all important GameView class and we will do so in chunks so we can talk about what is going on as we progress. We will add the simple extra methods ( onResume and onPause) in the SimpleGameEngine class when we have completed GameView.

If you think back to the Drawing Graphics demo, we drew everything to an object of the type ImageView. And we set the object using setContentView as the view for the app. We can’t just set any old object to be the view for the app. Fortunately Android has some ready-made classes that we can extend that provide us with everything we need. In the next block of code, you see we declare our GameView class and use the extends keyword to give it all the functionality of an Android SurfaceView. This not only means we can easily draw graphics on it as we did with ImageView but we can also use it in setContentView. Also in the very first line of code (excluding comments) we use the implements keyword followed by Runnable which means our class implements the Runnable interface that gives us all the thread functionality and allows us to use/override the run method that will become a kind of de-facto loop for our entire game.

We also declare some objects and variables that we will need in the game. Enter the code below where the comment // GameView class will go here indicates. We will discuss the variables and objects afterward.

In the code above, after the class declaration that we have already discussed, we declare and initialize an  Thread object called gameThread. We initialize it to null which is kind of like zero or no value as we are not ready to use it yet. After that, we declare an object of the type SurfaceHolder called surfaceHolder. This is new to us and it is an extra requirement when drawing graphics in a thread. As the operating system might like to draw to the screen as well, perhaps a text notification, etc, we need to lock the drawing surface each time the run method calls our draw method. We will see this in action soon.

We then declare a boolean called playing. You might have noticed the odd-looking volatile the keyword we used as well. The variable will be used to determine if the game is playing and we can then wrap the calls to draw and update in a while(playing) loop. We use volatile because it is a variable that can be used from inside and outside the thread, as we will see.

We then declare two variables fps and timeThisFrame. We will see how we use them to measure the frames per second of our game and use this measurement to make Bob move at the same speed on different devices with different hardware and therefore different frame rates. This consistency is essential for any game we code because a game shouldn’t give a different experience between devices.

Next, we declare a Bitmap, bitmapBob to hold our image of Bob. Following this, we have a  boolean isMoving. We will use this to decide when to move Bob and when to leave him stationary. We then declare and initialize walkSpeedPerSecond which will determine the speed in pixels per second that Bob can walk. Finally bobXPosition will be used when we call canvas.drawBitmap to position Bob on the horizontal axis; so we can manipulate it and Bob will glide across the screen as intended.

In the next block of code, we have a curiously named method  GameView. Even more curious is it has no return type. This is a special method called a constructor. We do not have to code a constructor unless we want to, but here it is really useful. When we initialize our gameView object, that is, when we call gameView = new GameView(), this constructor method is called. It allows us to do all sorts of initialization ready for when we use our class for its main intended purpose.

Also in the method signature, we can see the this object is passed in. We need this to initialize our bitmap and call the constructor of the SurfaceView class.

In our constructor method, we see that we first call the SurfaceView constructor using the super keyword, then initialize ourHolder, paint and bitmapBob objects. Enter the code below that we have just discussed and we will take a look at our run method.

Now we come to the center of the universe as far as our simple game engine is concerned. The run method. Remember that the operating system continuously calls this method from when we start our thread right around to when we stop it. So we can think of the run method as an infinite loop that will execute until the game is shut down. This is sometimes referred to as the game loop or game main.

In it, we wrap our code in a while (playing) loop because the thread can feasibly start before we are fully set up.

The first thing we do if playing is true is to get the system time in thousandths of a second and store it in the startFrameTime variable.

Then we call update and draw. These two methods will hold the logic and graphics code of our game.

After this, we get the current system time again, subtract startFrameTime from it and store the result in timeThisFrame. This is the number of milliseconds it took to execute our update and draw methods this frame.

The if statement that follows makes sure the answer is not zero and if it isn’t we assign the result of 1000 divided by timeThisFrame to fps. This is our current frames per second. We will see how we use that really soon. Enter the run method below and we can move on to discussing the update method.

Here is update below. All we do is check if  isMoving is true and if it is we increase Bob’s x position ( bobXPosition) by walkSpeedPerSecond divided by fps. This will achieve the same movement speed for Bob regardless of the current frames per second ( fps) the device is running at. That’s it for update.

Now we will draw Bob and some extra text to display the current frames per second. We have seen all the drawing code before in the Drawing graphics demo but there are some extra lines of code and one more subtle difference as well.

First, we attempt to get a lock on the drawing surface and if successful we make the drawing surface our canvas.

If you look closely at the call to canvas.drawBitmap, instead of providing a number for the x coordinate we use bobXPosition. We have already seen in the update method how we manipulate this variable. The only thing we haven’t seen but we will very soon is how we toggle between isMoving being true or false. Lastly, we draw everything to the screen, unlock the drawing surface, and hand control back to the operating system- for a few milliseconds anyway. Add the draw method to your project.

Now we have our two methods which are called by the methods of the similar name in SimpleGameEngine. Remember that the near namesakes in SimpleGameEngine are called by the operating system when our game is started and stopped.

The pause method looks more complicated than it really is. The unusual looking try and catch blocks are a requirement forced upon us because of the design of the Thread class. We don’t need to completely understand them in order to make games. The try block is the code to execute and the catch block is what to do if the try block fails. Not unlike if and else. The important code for the pause method is when we call gameThread.join() and set playing to false this will shut down our game thread.

The resume method sets the  playing variable to true, initializes our thread then starts it. The game is now running.

Getting player input

One extra benefit of the SurfaceView class which we extended to make GameView is that it allows us to override the onTouchEvent method. The onTouchEvent method is called directly by the operating system every time the screen is touched. Within this method, we can use the data passed in, in the MotionEvent object to determine if the player is telling our game to do something.

This method will get more complicated depending on the control system you are trying to implement. Future game projects will go into this method in much more detail. For now, all we need to do is switch as shown in the code below, and handle two cases. ACTION_DOWN when the player touches the screen and ACTION_UP when they remove their finger from the screen.

All we do is set isMoving to either true or false for each of those cases respectively and we have implemented our game controls.

Now we are at the end of our GameView inner class so add the closing curly brace }.

Finishing off the main class

Now we are back in the SimpleGameEngine class where we add the overridden methods onResume and onPause which will be called by the operating system when the game is started or stopped. All they do is call the near-namesake methods in the GameView class to control our thread- and by default our entire game. Enter the last block of code for our simple game engine. Be sure to do so within the final closing curly brace } of the SimpleGameEngine class.

 

Running the simple game engine

You can now run the game on a device and see Bob glide smoothly across the screen when it is pressed. Albeit backward:-D.

Although that was a slightly more lengthy project than some of the previous ones; we have achieved even more than it might seem. We now have a framework/engine which we can reuse again and again. If every single line of code is not crystal clear don’t worry because as we expand and improve the code we will become more familiar with what is going on. As each of the future projects gets progressively more advanced we will also introduce more Java and Android concepts.

Let’s move on and make a full, playable game or you might want to add a scrolling parallax background to this simple engine.

Complete code listing

Here is all the code for quick copying and pasting.

 

patreon