Android Game Development Tutorials



Comments



Description

Android Game Development TutorialsPublished on June 15, 2011 | 171,043 views | Filed in: Android Games Tags: featured Some months ago we received an email from a fellow Java developer, Tamas Jano, asking to be part of our JCG partners program. To our surprise he maintains a blog named “Against The Grain” debating about game development for the Android platform. I have been reading all of his articles since then and I must admit that his writings have been an inspiration and a motivation for me and my colleagues here at Java Code Geeks so as to start developing our first game for the Android platform. With this post I would like to present Tamas‘s work to our community hoping that you will be inspired and motivated just like we did! What follows is a portion of Tamas‘s introductory article titled as “A little motivation and what’s the idea behind all this.” I am certain that after reading it you will realize (just like I did) that you have many many things in common with this guy! First of all I know no great coder who is not interested in games. Some love slow paced ones while outdoorsy geeks (yes they do exist) will have a go with any type that requires all those reflexes some just won’t develop. At some point in their lives they might have wondered how the hell is this done? Wouldn’t it be cool to make such a thing? I’d love to do that. And so they went, getting into computing fueled by a passion for creating worlds they own and command. Back in the days you would see these guys at the arcades, hanging around computer labs and dreaming of owning one of those magnificent machines they can create their universe on. I’m talking about the 80s. Many took the classes, went through all that necessary crap that comes with getting a degree one would not care about in the future and here they are. Some graduated and have decent paying “software engineer” positions working for a multinational corporation doing who knows what. But a percentage of these so called engineers dream of games. They own the latest gadgets but they do not have the one thing that would enable them to make games: Time. Working 9-5 sucks and many have families or other obligations but they still think of doing projects on the side. Unfortunately many never even get started. How many thought: man…I’ll be building the greatest game of all, I’ll be rich and famous. Then they meet someone, have to get a job to pay for “settling” down and pay the bills for a place where they go in the evenings to crash just to start it over the next day. All this by doing boring web stuff or working on a small part of a monstrous multi-threaded distributed enterprise application architected by an inexperienced halfwit architect wannabe who got the job by sticking with the company since he was an intern. Where is the game you dreamed of doing 10 years ago? To be precise I am in a similar situation and while I had a short gig with a game company I am well in the rat race leading nowhere. I have decided to try one more time and I will give it a go. Why? Just for the hell of it, to demonstrate that games are simple to build and you can sit at your computer and have some fun too. Actually this is why I ended up a coder, to make games not to configure some frameworks (yes, that is not programming, it is mostly configuration). Well was I right? I hope I was! As I told you before Java Code Geeks have been busy enough developing our first game for the Android platform. A new category named “Android Games” has been created in order to contain all game related articles from now on. Here is the list of all Android Game Development tutorials (up until now) for your reference: 1. The Game Idea 2. Create the Project 3. A Basic Game Architecture 4. A Basic Game Loop 5. Displaying Images 6. Moving Images 7. The Game Loop 8. Measuring FPS 9. Sprite Animation 10. Particle Explosion 11. Design In-game Entities – The Strategy Pattern 12. Using Bitmap Fonts 13. Switching from Canvas to OpenGL ES 14. Displaying Graphical Elements (Primitives) with OpenGL ES 15. OpenGL Texture Mapping 16. Design In-game Entities – The State Pattern 17. Building Games Using the MVC Pattern – Tutorial and Introduction 18. Android Game Development with libgdx – Prototype in a day, Part 1a 19. Android Game Development with libgdx – Prototype in a day, Part 1b 20. Android Game Postmortem – ArkDroid Development Last but not least we have established a new division, JCG Studios (Just Cool Games Studios) where all our games will be presented and promoted. Android Game Development – The Game Idea Published on July 2, 2011 | 60,489 views | Filed in: Android Games Coming up with an idea for the game This is the hardest part. Because I am just one guy having limited time I will choose one idea that is realisable in a short time and will contain all elements of an action game. So I came up with a story for the game. The story goes like this: The end is nigh! Evil robots from outer space have set up factories on the moon and are sending their ever increasing waves of machines to destroy humanity. For what reason? Beats me but they have laser cannons, missiles, brain washing weapons and a lot of other harmful stuff. Every man for himself! How long before the end? How long can one survive or maybe defeat the machines by reaching the moon base and annihilate the super brain? That should be enough. Now let’s design something around this story. Checking the Android specs we see that we have limited memory and 480×800 pixels to play with. The first game that comes to my mind is robotron. Waves of robots, missiles from everywhere and 2 joysticks. A perfect setup for a handheld device held horizontally. One thumb for directions and the other one for shooting the baddies in every direction. A classic shoot’em up. Let’s go retro. Pixelated graphics is cool and the art is in the effects. Will try to do that. Let’s design! We have one guy. He’s got 3 lives and a gun. He’ll be dropped in the middle of a room and some baddies are trying to kill him already. We have the basic information to sketch out our game structure. But, we don’t have a name. Let’s see, droids taking over the planet…checked google for “droidz” and “droidz game” guess what? No droidz game found. I will name this: “droidz”. I find it a cool name for the first game using android. Above you have a rough mock-up of what the game will look and feel like. The 2 grey circles are the controllers. Imagine the device being held horizontally and you have your thumbs on the circles. Your left thumb will move our hero while the right thumb will fire the weapon. The direction is being controlled by the position of your thumb relative to the circle’s centre. Now that we have the idea let’s identify what we need to get the game done. We need the game objects. Currently there are 2 types of actors in this. Our guy and the droids. To control our guy we need to receive user input. The user input will be the touch screen. To be more precise the 2 circles defined on the screen. One controls the guy’s position and the other his weapon. A typical game architecture looks like this: 1. Process input 2. Update state of game objects. This means calculate new positions for every item, check game logic, collisions etc 3. Produce sounds 4. Render state to screen 5. If game is not over repeat from step 1 For example: Our guy is in the middle. Droids move every 1/10 of the second towards him. Every tenth of a second we check if the screen was touched and if it was touched we move our guy or fire his weapon. If the weapon was fired we check every tick (that’s 1/10 s) if the bullett collided with any droid to destroy him. If collided then droid is destroyed and the bullett is also destroyed. If no collision then both droid’s and bullett’s new positions are calculated according to their speed (droid moves 5 pixels every 1/10 s for ex and the bullett moves 50). We also check if the droid collided (reached) our guy and if so our hero is dead and game over. This is an overview of how this game will work but will extend it as we go. Reference: The Game Idea from our JCG partner Tamas Jano from “Against The Grain” blog. Do not forget to check out our new Android Game ArkDroid (screenshots below). You feedback will be more than helpful! Android Game Development – Create The Project Published on July 3, 2011 | 88,812 views | Filed in: Android Games Now that we have our idea let’s get the environment up and start coding. To install Android follow the steps found on the official documentation page. I use eclipse so if you are a Java guy it should be pretty familiar. If you have never developed in Java but did some other coding in C++ or C# for example it should be pretty simple to catch up. I would recommend starting with some Java tutorials and then switch to Android. If you haven’t programmed before…well that’s though but it’s solvable. Google for some programming tutorials and don’t get discouraged! Then check back here. I will use Android 2.2 as it is the latest at the time of this writing and I suspect it will take a long time till I finish this project so it just might be quite used. Also because we plan to use multitouch we need version 2.x. First let’s create the AVD (Android Virtual Device). Click on the little Android icon or choose Window -> Android SDK and AVD Manager and click on the New… button. Set the name to MyDevice, the target to Android 2.2 – API Level 8. Set 128 MiB for the SD Card. Set the Skin to Built-in HVGA and the Hardware to Abstracted LCD density to 160. These are the current default settings. Click Create AVD and the virtual device should be created. Now let’s create the project. Select from the menu: New -> Project and choose Android Project. Fill in as per the screen-shot and click Finish. The Application name is the name given to our game. The package name is just the name space to group our classes. Select Android 2.2 for Build Target. The most important is the Create Activity. The Activity is the class instantiated when the application is started. Don’t have to worry about it right now just remember that is the first thing being called. In a nutshell the Activity handles our input (gets the touches on the screen), creates the window where we will display our game and so on. This usually is a full screen window and we will use one as such. Let’s run the created application. Right click on the project and choose Run As -> Android Application. Choose the configured device and wait for it to load. Remember not to close the Virtual Device once it has started as every time you will run your project, eclipse will redeploy it to the currently running device and will save you a lot of time if it’s already started. You should see a screen like the one below. If the device asks you to unlock the screen do it by dragging the unlock button with your mouse. Now let’s examine what has just happened. public class DroidzActivity extends Activity { /** Called when the activity is first created.Bundle.layout. setContentView(R.obviam. import android.droidz. view source print? package net. } } .onCreate(savedInstanceState). */ @Override public void onCreate(Bundle savedInstanceState) { super.os. Open the DroidzActivity.Activity.main). import android.app.java file. 01 02 03 04 05 06 07 08 09 10 11 12 13 package net.Bundle. It reads the main.obviam.java) which is the default resource view automatically generated by the android tools behind the scenes.layout. import android.droidz. import android. The onCreate() method on line 09.app.Activity. public class DroidzActivity extends Activity { /** Called when the activity is first created. setContentView(R. This file feeds on multiple configuration files to provide the activity with the view. } } You’ll notice one method. Let’s open the res/layout/main. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState).os.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout> .main).xml from the res (which stands for resources) directory and parses it. This method is called when the activity is being created at the application launch.xml file: <?xml version="1.android. It’s sets the view (the display) to be the default R (check R.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas. Line 3 tells that our orientation is horizontal while lines 4 and 5 instruct android to use the whole display (currently the parent is the display) for the view.0" encoding="utf-8"?> <resources> <string name="hello">Hello World.xml file: view source print? 1 2 3 4 5 6 <?xml version="1.xml file and add a new TextView that will display our @warning message. The new main. DroidzActivity!</string> <string name="app_name">droidz</string> <string name="warning">Robots are rising</string> </resources> These are the resource strings. Apart from line 5 which I added everything is generated.java file is regenerated after we modify strigs.android. Line 7 defines a TextView which is just a label that takes up a whole line of the contained text’s height.xml file and opening this file you’ll immediately notice that this is the place where the actually displayed value comes from. @string is also a placeholder for the strings.xml file looks like this: view source . To add the warning message to the display just after the hello message modify the main. Open the /res/values/strings.0" encoding="utf-8"?> 02 <LinearLayout xmlns:android="http://schemas. The value is a placeholder read from the @string file.xml and for each resource entry a corresponding constant is generated and it will be used internally.view source print? 01 <?xml version="1.com/apk/res/android" 03 android:orientation="vertical" 04 android:layout_width="fill_parent" 05 android:layout_height="fill_parent" 06 > 07 <TextView 08 android:layout_width="fill_parent" 09 android:layout_height="wrap_content" 10 android:text="@string/hello" 11 /> 12 </LinearLayout> You’ll notice that a LinearLayout is used that fills up the whole screen and has a vertical positioning (Line 2). Worth noting that the R. com/apk/res/android" 03 android:orientation="vertical" 04 android:layout_width="fill_parent" 05 android:layout_height="fill_parent" 06 > 07 <TextView 08 android:layout_width="fill_parent" 09 android:layout_height="wrap_content" 10 android:text="@string/hello" 11 /> 12 <TextView 13 android:layout_width="fill_parent" 14 android:layout_height="wrap_content" 15 android:text="@string/warning" 16 /> 17 </LinearLayout> If you run the activity then you should have a screen displaying the new warning message too.java file and if you open it you will notice a similar line to this: view source print? 1 public static final int warning=0x7f040002. Worth noting that eclipse regenerated the R.0" encoding="utf-8"?> 02 <LinearLayout xmlns:android="http://schemas. .android.print? 01 <?xml version="1. It is generated by the android tooling and it keeps the IDs and pointers to the actual resources that are used in the activity. Go ahead and play with the current setting and see what the options are for different display widgets. Next we will actually load some images and draw them onto the screen. The User Input In our game this is the event generated by touching the screen in one of the 2 defined control areas. . (see Step 1 – the coloured circles). I will try to give you my understanding of it. The following diagram represents a game architecture. Reference: Creating the Android Project from our JCG partner Tamas Jano from “Against The Grain” blog. If the coordinates are inside our defined control areas on the screen we will instruct the game engine to take action. Android Game Development – A Basic Game Architecture Published on July 4.341 views | Filed in: Android Games So we got our Android application up and running but you might be wondering what type of application is exactly a game. 2011 | 58. If the weapon controller circle is touched the equipped weapon will be instructed to fire its bullets. the microphone. All this translates to changing the actors’ states that are affected by our gestures aka input. For example if the touch occurs in the circle designated to move our guy the engine gets notified and our guy is instructed to move. the accelerometers or even the GPS receiver if equipped. The input is the touch-screen in our case but it can be a physical keyboard if the phone has one. The framework exposes the events when touching the screen through the View used in our Activity from the previous article. Game architecture on an Android phone In the schema above you see the Android OS running on the Phone and everything on top of that. the camera. Our game engine monitors the onTouch event and at every touch we record the coordinates. Game Logic The game logic module is responsible for changing the states of the actors in the game. So this is the audio in a nutshell. As almost every actor/object will produce sounds in their different states and because the devices we’ll run our game on are limited to just a few channels (that means briefly how many sounds can the device play at once) it has to decide which sounds to play. In the image above the light green circle represents our finger touching the control area. Audio This module will produce sounds considering the current state.I have just described the Game Logic part which follows. Graphics This is the module responsible for rendering the game state onto the display. dx and dy are the distances in pixels relative to the controller circle centre. Our hero. For example the droid posing the biggest threat to our hero will be heard as we want to draw attention to it and of course we will need to reserve a channel for the awesome shooting sound of our weapon as it is much fun listening to our blaster singing. For example we touch the upper half of the hero control area like in the drawing and this translates to: calculate the movement speed of our guy according to the position of our movement controller (our finger). . laser beams etc. bullets. If dx is positive that means he will go right and if dy is positive he will also move upward. The User Input module notifies the Game Engine (Game Logic) and also provides the coordinates. The game engine calculates the new speed it has to set for our hero and the direction he will move. This can be as simple as drawing directly onto the canvas obtained from the view or having a separate graphics buffer drawn into and then passed to the view which can be a custom view or an OpenGL view. terrain. droids. By actors I mean every object that has a state. Check the following diagram. Let’s keep it simple. In this article we are going to discuss and implement the basic game loop. This is guaranteed to be a minimum of 30FPS but it is likely to be more. Watch them walk but keeping your eyes open and you’ll see a fluid motion. For a mobile device 30 FPS is great so we will aim for that. update the internal state of the game and finally render it to the screen and also produce some sounds and/or vibrations. We’ll have our first game engine. Furthermore we have created an example Android project for our first game. Next we will set up our view and will try to make our first game loop which will take input from the touch screen. After opening your eyes you will see the person in the position after one second.527 views | Filed in: Android Games Following the series so far you we have an understanding of the game architecture. The only thing you want to know now that the higher the FPS the smoother the animation. . Output The output is the result of both sound and image and maybe vibration if we decide to produce some. 2011 | 82. Reference: A Basic Game Architecture from our JCG partner Tamas Jano from “Against The Grain” blog. If we have 30FPS that means that we display 30 images every second. Just imagine someone walking and close your eyes for exactly one second. More on this later. depending on your eyes. Android Game Development – A Basic Game Loop Published on July 5. If you have awesome receptors in pristine condition this could be 80-100 or more. This is a 2FPS. Even if just briefly but we know that we need to take input in some form.We measure the rendering in FPS which stands for frames per second. We see the line . The Activity will create a View.java from our project. Something like the following diagram: Android Game Loop Let’s open up DroidzActivity. Anything in Android happens inside an Activity. It is where the touch takes place and the resulting image gets displayed. The View is where everything happens. They are tied together and tend to be executed one after the other.A Basic Game Loop We handle input. That will be our touch and the actual chemistry happens on the paper so the result of our interaction with the View produces an image. We will use our pencil to draw something onto the paper. Think of the Activity as a table that holds a sheet of paper (the View) enabling us to draw something. update the state of our internal objects and render the current state. The Update and Render are grouped logically. The same is with Activity and View. for example when it is destroyed or the orientation of the device has changed.SurfaceView.view.SurfaceHolder. MainGamePanel.graphics.Callback to gain access to surface changes.addCallback(this).main). // adding the callback (this) to the surface holder to intercept events getHolder(). Let’s create a new View which we will use. The simplest way is to extend Android’s own SurfaceView.layout.droidz. import android.content. import android.view source print? 1 setContentView(R. import android. import android. import android.view.Callback { public MainGamePanel(Context context) { super(context). .Canvas. A View is a simple class that provides us with event handling (like onTouch) and a visible rectangle shaped space to draw on.view. This does nothing more than assigns the default (R) view to the activity when it is created. public class MainGamePanel extends SurfaceView implements SurfaceHolder. We will also implement SurfaceHolder.Context.java package net.MotionEvent. In our case it happens at startup.obviam. // make the GamePanel focusable so it can handle events setFocusable(true). } @Override public void surfaceChanged(SurfaceHolder holder. int format. int width. } @Override protected void onDraw(Canvas canvas) { . int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } @Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event). } } view source print? 01 package net. 35 } 36 37 @Override 38 protected void onDraw(Canvas canvas) { . 02 03 import android.MotionEvent.Callback { 11 12 public MainGamePanel(Context context) { 13 super(context).obviam. int 1 height) { 2 } 2 23 24 @Override 25 public void surfaceCreated(SurfaceHolder holder) { 26 } 27 28 @Override 29 public void surfaceDestroyed(SurfaceHolder holder) { 30 } 31 32 @Override 33 public boolean onTouchEvent(MotionEvent event) { 34 return super.droidz.view.graphics. 14 // adding the callback (this) to the surface holder to intercept events 15 getHolder().Canvas. 05 import android. int format. 07 import android. 04 import android.SurfaceView. 08 09 public class MainGamePanel extends SurfaceView implements 10 SurfaceHolder. int width. 18 } 19 20 @Override 2 public void surfaceChanged(SurfaceHolder holder.Context.onTouchEvent(event). 16 // make the GamePanel focusable so it can handle events 17 setFocusable(true).addCallback(this).view. 06 import android.SurfaceHolder.view.content. } . Let’s create the thread that will be our actual game loop.droidz.running = running. Nothing special apart from lines 15 and 17. This line sets the current class (MainGamePanel) as the handler for the events happening on the actual surface.39 40 } } The above code is a plain class that overrides the methods we are interested in. We added the callback and made it focusable in the constructor so we won’t miss. The over-riden methods (line 20 onwards) will all be used but currently keep them empty. The above line makes our Game Panel focusable.java package net. which means it can receive focus so it can handle events. view source print? 1 setFocusable(true). public void setRunning(boolean running) { this.obviam. public class MainThread extends Thread { // flag to hold game state private boolean running.addCallback(this). view source print? 1 getHolder(). MainThread. Currently the thread is not instantiated so let’s start it up when the screen loads.obviam. It overrides the run() method and while the running flag is set to true it does an infinite loop. public class MainThread extends Thread { // flag to hold game state private boolean running. .@Override public void run() { while (running) { // update game state // render state to the screen } } } view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 package net. } @Override public void run() { while (running) { // update game state // render state to the screen } } } As you can see this does not do much. public void setRunning(boolean running) { this.running = running. Let’s take a look at the modified MainGamePanel class.droidz. import android.Context.view. import android.graphics. public MainGamePanel(Context context) { super(context). public class MainGamePanel extends SurfaceView implements SurfaceHolder.content. import android. // create the game loop thread thread = new MainThread().view. setFocusable(true).droidz.Canvas. import android. } .package net.SurfaceHolder. import android.SurfaceView.addCallback(this).obviam.Callback { private MainThread thread.view.MotionEvent. getHolder(). thread. } @Override public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true.start(). while (retry) { try { thread. int format.@Override public void surfaceChanged(SurfaceHolder holder. int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { thread. } catch (InterruptedException e) { // try again shutting down the thread } } } .join().setRunning(true). int width. retry = false. onTouchEvent(event).graphics. 02 03 import android. 16 getHolder().view.MotionEvent.@Override public boolean onTouchEvent(MotionEvent event) { return super. int . 05 import android.view.SurfaceView.Callback { 11 12 private MainThread thread. 07 import android. 04 import android. 13 14 public MainGamePanel(Context context) { 15 super(context). int format. 08 09 public class MainGamePanel extends SurfaceView implements 10 SurfaceHolder. 22 } 23 24 @Override 2 public void surfaceChanged(SurfaceHolder holder. } @Override protected void onDraw(Canvas canvas) { } } view source print? 01 package net. 17 18 // create the game loop thread 19 thread = new MainThread().droidz.SurfaceHolder.Context. int width. 06 import android.addCallback(this).obviam.Canvas.content. 20 21 setFocusable(true).view. view source print? 1 thread = new MainThread().onTouchEvent(event). 50 } 51 52 @Override 53 protected void onDraw(Canvas canvas) { 54 } 55 } We added the following lines: Line 12 declares the thread as a private attribute. view source print? 1 private MainThread thread. 41 } catch (InterruptedException e) { 42 // try again shutting down the thread 43 } 44 } 45 } 46 47 @Override 48 public boolean onTouchEvent(MotionEvent event) { 49 return super. 40 retry = false.5 height) { 2 } 6 27 28 @Override 29 public void surfaceCreated(SurfaceHolder holder) { 30 thread. . 31 thread.setRunning(true).start().join(). In line 19 we instantiate the thread. 37 while (retry) { 38 try { 39 thread. 32 } 33 34 @Override 35 public void surfaceDestroyed(SurfaceHolder holder) { 36 boolean retry = true. Don’t worry about it as I will cover logging in a later chapter. We simply block the thread and wait for it to die. 2 private MainGamePanel gamePanel. 08 retry = false. If we touch it anywhere else we’ll just log the coordinates. Take a look at the surfaceDestroyed method. MainGamePanel gamePanel) { . By the time the this method is called the surface is already created and the game loop can be safely started. It is not the place to set the running flag but the code we put in ensures that the thread shuts down cleanly. 3 4 public MainThread(SurfaceHolder surfaceHolder. In the MainThread class we add the following lines: view source print? 1 private SurfaceHolder surfaceHolder.In the surfaceCreated method we set the running flag to true and we start up the thread (lines 30 and 31). Add interaction with the screen We will exit the application when we touch the lower part of the screen. view source print? 01 public void surfaceDestroyed(SurfaceHolder holder) { 02 // tell the thread to shut down and wait for it to finish 03 // this is a clean shutdown 04 boolean retry = true. 05 while (retry) { 06 try { 07 thread. 09 } catch (InterruptedException e) { 10 // try again shutting down the thread 11 } 12 } 13 } This method is called directly before the surface is destroyed. You can find more on the Android site. If we now run our project in the emulator won’t be able to see much but we’ll use some logging to test it.join(). Add the TAG constant to the MainThread class. It is important to have them both and not just the gamePanel as we need to lock the surface when we draw and that can be done through the surfaceHolder only. We are using Android’s own logging framework and that takes two parameters. } We declared the gamePanel and surfaceHolder variables and a constructor taking the instances as parameters. this.surfaceHolder = surfaceHolder. The value of the constant will be the name of the class containing it.5 6 7 8 super(). this). Every class will have its own String constant called TAG. A note on logging To open the log viewer go to Windows -> Show View -> Other… and in the dialog select Android -> LogCat . We are passing the current holder and the panel to its new constructor so the thread can access them. Change the line int the constructor of the MainGamePanel that instantiates the thread to view source print? 1 thread = new MainThread(getHolder(). We will create the game update method in the game panel and we’ll trigger it from the thread but currently just leave it as it is. The firs is the tag which is just a string to identify the source of the log message and the second is the message we want to log. this.gamePanel = gamePanel. It’s a good practice to use the name of the class for the tag as it makes it simple to look up the logs. 15 } 16 17 public MainThread(SurfaceHolder surfaceHolder. This is nothing more than a console where you can follow Android’s log.SurfaceHolder. 12 private boolean running. 13 public void setRunning(boolean running) { 14 this. MainGamePanel gamePanel) { 18 super(). 04 import android. 05 06 public class MainThread extends Thread { 07 08 private static final String TAG = MainThread. 09 10 private SurfaceHolder surfaceHolder.util.droidz. Let’s get back to our code.obviam. The MainThread.running = running.java class looks like this: view source print? 01 package net. It’s a great tool as you can filter for logs containing a specific text or logs with a certain tag which is quite useful.Show View -> LogCat Now you should see the LogCat view. 02 03 import android. 11 private MainGamePanel gamePanel.getSimpleName().view.Log.class. . setRunning(false).ACTION_DOWN) { if (event.d(TAG. } else { Log.d(TAG. We log the results. 20 this. "Coords: x=" + event.getY()). "Game loop executed " + tickCount + " times").d(TAG. } } return super. 27 while (running) { 28 tickCount++. If so we set the thread’s running status to false and call finish() on the main activity which basically exits the application. } Line 02 we check if the event on the screen is a start of a pressed gesture (MotionEvent.19 this. 26 Log. If so we check if the touch happened in the lower part of the screen. the Y coordinate of the gesture is in the lower 50 pixels of the screen. Let’s go back to MainGamePanel.java class where we modified the onTouchEvent method so we handle touches on the screen. 33 } 34 } In line 08 we define the tag for logging. "Starting game loop").onTouchEvent(event). 29 // update game state 30 // render state to the screen 31 } 32 Log.finish(). view source print? 01 02 03 04 05 06 07 08 09 10 11 public boolean onTouchEvent(MotionEvent event) { if (event.ACTION_DOWN).surfaceHolder = surfaceHolder. That is.y=" + event. .50) { thread. ((Activity)getContext()). 21 } 22 23 @Override 24 public void run() { 25 long tickCount = 0L. In the run() method we define tickCount which is incremented every time the while loop (the game loop) is executed.getAction() == MotionEvent.getX() + ".getY() > getHeight() .gamePanel = gamePanel. LayoutParams. 07 import android.FLAG_FULLSCREEN. 04 import android. 08 09 public class DroidzActivity extends Activity { 10 /** Called when the activity is first created.class.droidz.. 36 } 37 } .LayoutParams.d(TAG.view. 17 // requesting to turn the title OFF 18 requestWindowFeature(Window. view source print? 01 package net.onStop().Bundle.Log. 24 } 25 26 @Override 27 protected void onDestroy() { 28 Log.onDestroy().getSimpleName(). */ 11 12 private static final String TAG = DroidzActivity."). 23 Log. "View added"). 1 // making it full screen 9 2 getWindow()."). I have also modified the DroidzActivity.java class so we log its lifecycle.FEATURE_NO_TITLE).os.d(TAG.Activity. 06 import android.d(TAG. "Destroying. getHeight())... 29 super.WindowManager.util.view. 21 // set our MainGamePanel as the View 22 setContentView(new MainGamePanel(this)).app.. 30 } 31 32 @Override 33 protected void onStop() { 34 Log.FLAG_FULLSCREEN).Note: The screen is a rectangle with the upper left coordinates at (0. 35 super.obviam. 05 import android.onCreate(savedInstanceState).Window. 0 WindowManager. 13 14 @Override 15 public void onCreate(Bundle savedInstanceState) { 16 super.setFlags(WindowManager. "Stopping.0) and the lower right coordinates at (getWidth(). 02 03 import android. That is Frames Per Second and Updates Per Second. If you click around a few time on the upper half and then you click on the bottom of your emulator’s screen the application should exit. It is a very high number but next time we will be more considerate about the cycles as we will introduce FPS and UPS. The onDestroy() and onStop() methods were overridden just to log the activity’s lifecycle. Things we did so far:  Create a full screen application  Have a separate thread controlling the application  Intercepting basic gestures like pressed gesture  Shutting down the application graciously Download the source code here. At this stage it is worth checking the logs. LogCat The highlighted lines are the most interesting as if you match look the logs up in the code you will see exactly the order of the method calls. Let’s run the application by right-clicking on the project and select Run As -> Android application You should see a black screen. We will create a game loop that will actually draw something onto the screen and it will do it as many times per second as we specify it. Import it into eclipse and it should work right away.Line 20 makes the display fullscreen. You should also see how many times the thread’s while loop executed. 5 . To make it available for your application just copy the image into the /res/drawable-mdpi directory (the easiest way is to drag and drop it there).png formats and I have just created one named droid_1.java file. We obtain the bitmap from the application resources by passing the id of our image (resource). We need an image to display. Examine the new run() method.java class and change the onDraw(Canvas canvas) method to look like this: view source print? 1 protected void onDraw(Canvas canvas) { canvas. You can check it out here. I use Gimp or Photoshop. 2011 | 18. I have chosen mdpi which stands for normal screen medium density.png. 3 } The drawBitmap method draws the droid_1 image to the coordinates 10. Displaying an image using Android is extremely simple. . 10. The R. The size of the image is 20×20 pixels. To read on screen types check the android documentation.Android Game Development – Displaying Images with Android Published on July 7. 10. You can use whatever tool you like. I prefer .476 views | Filed in: Android Games Before moving to the actual game loop let’s display some graphics so we can get some measurements done. 2 R.10. When we copied the droid_1. view source print? 01 02 public void run() { Canvas canvas.png into the resource directory eclipse detected it and the plugin executed the necessary scripts in the background so we have the droid_1 identifier in the R.drawable. To scale the problem down we will just display the image in the top left corner.droid_1).drawBitmap(BitmapFactory. If you haven’t checked it out please do as it is imperative that you understand how a thread updates the screen. Modify the MainGamePanel.java holds the resource identifiers.decodeResource(getResources(). which is droid_1 in our case. null). The thread suffered some changes too. let’s try moving it.surfaceHolder. If the number of times per second the image is displayed drops below 20.d(TAG.lockCanvas(). The game panel just displays the image at coordinates 10. How? We will use our finger. On every execution of the game loop we get hold of the canvas and we pass it to the game panel to draw on it. synchronized (surfaceHolder) { // update game state // draws the canvas on the panel this.onDraw(canvas). Try running the code and you should see our droid displayed close to the top left corner.03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 Log. it starts to get noticeable by us humans. Droid in top left corner Moving the Image Now that we have displayed it. } } // end finally } } In line 02 we declare the canvas on which we will draw our image. The challenge is to keep this rate above a set level and we will see how shortly. Note that it is a synchronised block which means that we have exclusivity on it and nothing can modify it while we are using it.gamePanel. In line 08 we try to get hold of it and in line 12 we trigger the panel’s onDraw event to which we pass the obtained canvas. } } finally { // in case of an exception the surface is not left in // an inconsistent state if (canvas != null) { surfaceHolder. To pick up an image we will simply touch it and . // try locking the canvas for exclusive pixel editing on the surface try { canvas = this. Now back to the FPS. The canvas is the surface’s bitmap onto which we can draw and we can edit its pixels. while (running) { canvas = null.10.unlockCanvasAndPost(canvas). "Starting game loop"). We will implement a simple drag and drop functionality. The functionality is very simple and basic. x = x. this.droidz. int x. int y) { this. import android.y = y.obviam. } public Bitmap getBitmap() { return bitmap.bitmap = bitmap.model package.obviam.y = y. // the Y coordinate public Droid(Bitmap bitmap. view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package net.while our finger is on the screen we will update the image’s coordinates accordingly. } public void setY(int y) { this. public class Droid { private Bitmap bitmap.x = x. } public void setBitmap(Bitmap bitmap) { this. // the X coordinate private int y. } } . } public void setX(int x) { this. this. I have created Droid. We need to create an object that will hold our image and the coordinates. Once the touch is finished we leave the image there where the last touch was recorded.Bitmap.java for this. Note that I have put the class into the net.droidz. } public int getY() { return y. } public int getX() { return x.model.graphics. // the actual bitmap private int x.bitmap = bitmap. We keep the touched state true while we hold our finger down on the screen at the droid’s position. The bitmap holds the image that will be displayed as the droid. 06 07 public class Droid { 08 09 private Bitmap bitmap. int y) { 15 this. 18 } 19 20 public Bitmap getBitmap() { 21 return bitmap. // the X coordinate 11 private int y. 02 03 import android.droidz. 05 import android. view source print? 01 package net.x = x. // the actual bitmap 10 private int x.x = x. Check out the new droid class.view.Bitmap.bitmap = bitmap. 22 } 23 public void setBitmap(Bitmap bitmap) { 24 this. But to play around with it we need to add some state. the droid has only 2 states. By touched I mean when our finger touched the droid on the screen.graphics. // if droid is touched/picked up 13 14 public Droid(Bitmap bitmap. 28 } 29 public void setX(int x) { 30 this. 16 this.y = y.bitmap = bitmap. 25 } 26 public int getX() { 27 return x. Otherwise the droid remains untouched (state set to false). To keep it simple. 31 } 32 public int getY() { 33 return y. So far nothing special. It is the graphical representation of it. int x. Touched and untouched.It is a plain class with some attributes and a constructor.obviam.model.graphics. 17 this. // the Y coordinate 12 private boolean touched.Canvas. 04 import android. .MotionEvent. The x and y are the coordinates of the droid. getWidth() / 2).droidz. . view source print? 001 package net. 61 } 62 63 } 64 } We added the touched field to keep track of the state of our droid. 56 } else { 57 setTouched(false).bitmap.drawBitmap(bitmap. 41 } 42 43 public void setTouched(boolean touched) { 44 this. x .getHeight() / 2))) { 5 // droid touched 4 55 setTouched(true).34 } 35 public void setY(int y) { 36 this. 49 } 50 5 public void handleActionDown(int eventX.java.getWidth() / 2) && (eventX <= (x + 2 bitmap. y 8 (bitmap. These methods are discussed later.(bitmap. Now let’s have a look at the MainGamePanel. null). int eventY) { 1 5 if (eventX >= (x .getHeight() / 2) && (y <= (y + 3 bitmap.y = y. 45 } 46 4 public void draw(Canvas canvas) { 7 4 canvas. It changed quite a lot. You will notice two more methods: public void draw(Canvas canvas) and public void handleActionDown(int eventX.obviam. 58 } 59 } else { 60 setTouched(false).bitmap.getHeight() / 2). int eventY).touched = touched. 37 } 38 39 public boolean isTouched() { 40 return touched.getWidth()/2))) { 5 if (eventY >= (y . 005 import android. 004 import android.Activity.getSimpleName(). 013 014 public class MainGamePanel extends SurfaceView implements 015 SurfaceHolder.decodeResource(getResources(). 010 import android.Log.Context.view.BitmapFactory.Color. 011 import android. 021 022 public MainGamePanel(Context context) { 023 super(context).MotionEvent.view. 8 R. 008 import android. this).graphics. 047 thread.droidz.graphics. 007 import android.002 003 import net.model.Callback { 016 017 private static final String TAG = MainGamePanel.addCallback(this). 009 import android. int format.SurfaceView.drawable. 50. 026 02 // create droid and load bitmap 7 02 droid = new Droid(BitmapFactory. 032 033 // make the GamePanel focusable so it can handle events 034 setFocusable(true).obviam.Droid. 020 private Droid droid.view.setRunning(true).start(). 012 import android. 039 int height) { 040 } 041 042 @Override 043 public void surfaceCreated(SurfaceHolder holder) { 044 // at this point the surface is created and 045 // we can safely start the game loop 046 thread. 035 } 036 037 @Override 038 public void surfaceChanged(SurfaceHolder holder. . 018 019 private MainThread thread.SurfaceHolder. 029 030 // create the game loop thread 031 thread = new MainThread(getHolder().Canvas.util.content.class.droid_1). 006 import android.graphics.app. int width. 024 // adding the callback (this) to the surface holder to intercept events 025 getHolder(). 50). setRunning(false).ACTION_DOWN) { // delegating event handling to the droid droid.getY()). while (retry) { try { thread. "Coords: x=" + event. // check if in the lower part of the screen we exit if (event. } } if (event.handleActionDown((int)event.ACTION_MOVE) { // the gestures if (droid.ACTION_UP) { // touch was released if (droid. } catch (InterruptedException e) { // try again shutting down the thread } } Log. } } if (event.setX((int)event. (int)event. "Thread was shut down cleanly").getAction() == MotionEvent.getY()).setTouched(false). droid.getAction() == MotionEvent. // tell the thread to shut down and wait for it to finish // this is a clean shutdown boolean retry = true.getX() + ". retry = false.setY((int)event.d(TAG.isTouched()) { droid. } } return true. } else { Log.join().50) { thread.getAction() == MotionEvent. } @Override . "Surface is being destroyed").y=" + event.getY()).048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.d(TAG.d(TAG.getX()). ((Activity)getContext()).finish().getX(). } @Override public boolean onTouchEvent(MotionEvent event) { if (event.isTouched()) { // the droid was picked up and is being dragged droid.getY() > getHeight() . The touched state and the coordinates. That is it. We need to check if the event’s coordinates are inside the droid’s bitmap. It is simple. view source print? 0 public void handleActionDown(int eventX. If the action happened inside the area of our droid’s bitmap we’ll set its touched status to true Going back to the onTouched method. We have updated the state of our sole object in the game.ACTION_DOWN) we want to know if our finger landed on the droid.java class and check the handleActionDown method. This event happens when our finger started to move on the screen. 08 } 09 } else { 10 setTouched(false). In the onTouchEvent (method line 71) if the action is the touch of the screen (MotionEvent. It is declared as an attribute in line 20.bitmap. notice that there is a code block (lines 81-86) that is executed when the event is of type MotionEvent.getHeight() / 2))) { 0 // droid touched 4 05 setTouched(true).bitmap.BLACK).getHeight() / 2) && (y <= (y + 3 bitmap. int eventY) { 1 0 if (eventX >= (x .draw(canvas). This was the update game state. 06 } else { 07 setTouched(false). droid. To do this is easy. In order not to clutter the onTouch event we just delegate this to the droid object.getWidth()/2))) { 0 if (eventY >= (y .ACTION_MOVE. .50. Now it is time to display it. Now you can go back to the Droid. We check if the droid is touched and if so we just update its coordinates accordingly. } } Line 28 creates the droid object at the the coordinates 50.getWidth() / 2) && (eventX <= (x + 2 bitmap.097 098 099 100 101 102 protected void onDraw(Canvas canvas) { // fills the canvas with black canvas.drawColor(Color. 11 } 12 13 } It is very simple. It takes the bitmap it was instantiated with and draws it to the canvas at the coordinates the droid is at in that moment.3-graphics. It is dead simple.tar. That’s it. Download he code for the project here (droidz. By doing this is like me giving you a paper to draw yourself onto it. Do not forget to check out our new Android Game ArkDroid (screenshots below). Line 99 simply fills the canvas with black and line 100 tells the droid to draw itself on the canvas provided.gz) Reference: Displaying Images with Android from our JCG partner Tamas Jano from “Against The Grain” blog.696 views | Filed in: Android Games In the previous post we’ve displayed an image and implemented a very simple drag functionality. Things we should know by now following the series:  launch an Android application in full screen  use a separate thread which controls the application (the game loop)  load an image from the resources  acquire the canvas and draw the image onto it  handle basic touch gestures . Check Droid. You feedback will be more than helpful! 6 Android Game Development – Moving Images on Screen Published on July 9. This is triggered at every execution of the main loop inside the thread remember? It contains 2 lines.android. I’m sure you won’t find it hard to understand. Note that the coordinates of the droid are exactly in the center of the bitmap so we need to move the pointer to the top left corner of the image and draw it there. Run it and have a play with it. and give the paper back to me so I can continue my drawing.02. 2011 | 5.java for the draw implementation.Check the onDraw method. To achieve this we will add a move() method and this method will just update the X and Y coordinates based on its Speed. 18 this. If you remember the image is just a representation of the droid.The task I’m setting for this entry is simple: have the droid travel through the screen. float yv) { 22 this. view source print? 01 package net. 31 } . 23 this. 07 public static final int DIRECTION_UP = -1. 14 private int yDirection = DIRECTION_DOWN.droidz. 06 public static final int DIRECTION_LEFT = -1. This implies that it has speed. I will do a concrete implementation now but later on I will be using the Strategy Pattern.yv = 1.yv = yv. 08 public static final int DIRECTION_DOWN = 1.xv = 1. 15 16 public Speed() { 17 this. Speed will be a class in itself and the Droid will contain it. Create the Speed.xv = xv. It can move. Just one for the time being.java class. 28 } 29 public void setXv(float xv) { 30 this. // velocity value on the Y axis 12 13 private int xDirection = DIRECTION_RIGHT.model. 19 } 20 21 public Speed(float xv.components. It should never leave the surface and it should bounce back when it hits the wall which is the edge of the screen.obviam. 09 10 private float xv = 1. We will vest it with the ability of movement. So we will modify the droid object and we’ll add some abilities. // velocity value on the X axis 11 private float yv = 1.xv = xv. Our droid is movable. 24 } 25 26 public float getXv() { 27 return xv. 02 03 public class Speed { 04 05 public static final int DIRECTION_RIGHT = 1. 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 public float getYv() { return yv. That is a rectangle and our 2D coordinate system. } // changes the direction on the X axis public void toggleXDirection() { xDirection = xDirection * -1.xDirection = xDirection. To move towards the bottom right the directions will be: 1 (right) for the X axis and 1 (down) for the Y axis. So for the droid to start from the top left corner of the screen its coordinates will be 0.0. } // changes the direction on the Y axis public void toggleYDirection() { yDirection = yDirection * -1. } public void setyDirection(int yDirection) { this. } public void setYv(float yv) { this. } public int getyDirection() { return yDirection. } public void setxDirection(int xDirection) { this. The droid has a vertical and a horizontal speed and at each game update the coordinates are set considering the direction of the movement. } } We’ll use direction constants to determine the movement direction on the axis. To move in a diagonal line the speed will be 1 for both the X and Y components of the speed vector. . The droid will be allowed to move only on the area of the canvas. Unlike in the math classes the origin is in the top left corner. } public int getxDirection() { return xDirection.yDirection = yDirection.yv = yv. gamePanel.java) gets an important modification as it gets the game update method introduced. The two methods (toggleXDirection() and toggleYDirection()) just change the direction with one call. "Starting game loop"). In the Speed we have the vector components (x and y) and the directions along with the getters and setters.d(TAG. Log. The following code snippet is the updated run() method which has just one line added: view source print? 1 this.Canvas Coordinate System To have the droid move horizontally the speed of the Y vector must be 0. The run() method: view source print? 01 02 03 04 public void run() { Canvas canvas. Simple geometry.update(). while (running) { .5 for Y and 1 for X will make the droid travel at a 22.5 degrees to the X axis. A value of 0. The game loop (MainThread. We’ll see later at collision detection (with the wall of the screen) that it is pretty useful. The logic is simple.surfaceHolder.DIRECTION_RIGHT && droid.getSpeed().toggleXDirection().gamePanel.getSpeed(). } } finally { // in case of an exception the surface is not left in // an inconsistent state if (canvas != null) { surfaceHolder. . Check the previous post for this.gamePanel. To keep the update method simple we delegate the update of the droid’s position to the droid itself.getSpeed().05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 canvas = null.getSpeed(). Check the code: MainGamePanel. So the droid will get an update method which will keep updating its position if the droid is not being picked up by a touch gesture.getBitmap().lockCanvas().java view source print? 01 02 03 04 05 06 07 08 09 10 public void update() { // check collision with right wall if heading right if (droid.render(canvas).update().getWidth() / 2 <= 0) { droid. Check if the droid is moving towards left then check if the droid’s position is at the wall and if it is then change its direction. We also update the position of the droid. } // check collision with left wall if heading left if (droid. // render state to the screen // draws the canvas on the panel this. synchronized (surfaceHolder) { // update game state this. } } // end finally } } We will create the corresponding method in the MainGamePanel. Bear in mind that the droid’s position is the center of the image so we need to use the image’s width and height to get the accuracy right. Because the droid is moving we will introduce a basic collision detection with the walls.getX() + droid. // try locking the canvas for exclusive pixel editing // in the surface try { canvas = this.getxDirection() == Speed.droid.unlockCanvasAndPost(canvas). Currently only the droid.getxDirection() == Speed. This method is in charge of updating the state of all the objects in the application.DIRECTION_LEFT && droid.getBitmap().toggleXDirection().getX() .getWidth() / 2 >= getWidth()) { droid. toggleYDirection().getyDirection() == Speed.update().getY() + droid. 21 } 22 // Update the lone droid 23 droid.getXv() * speed. The panel is a view.11 } 12 // check collision with bottom wall if heading down 13 if (droid.DIRECTION_DOWN 14 && droid. Just that I like it better as it follows the update -> render naming. 5 } 6 } I also changed the render’s name in the MainThread.droid.getyDirection() == Speed.getxDirection()). You can also drag the droid around. Run the application and you should see a screen like the following one with the droid moving in a 45 degrees angle and bouncing off the walls as it hits them.getSpeed().java file’s update() method: view source print? 1 public void update() { 2 if (!touched) { 3 x += (speed.java so now it is render instead if onDraw.getSpeed().getYv() * speed. remember? The Droid. 16 } 17 // check collision with top wall if heading up 18 if (droid. To exit the application click (touch) the lower part of the screen.getyDirection()).getBitmap().getY() . .getSpeed().DIRECTION_UP 19 && droid.getHeight() / 2 <= 0) { 20 droid. 24 } getWidth() and getHeight() return the width and height of the view. 4 y += (speed.toggleYDirection().getSpeed().getBitmap().getHeight() / 2 >= getHeight()) { 15 droid. Moving Droid Download the full source code and eclipse project here. Reference: Moving Images on the Screen with Android from our JCG partner Tamas Jano from “Against The Grain” blog. Do not forget to check out our new Android Game ArkDroid (screenshots below). You feedback will be more than helpful! 7 Android Game Development – The Game Loop Published on July 12, 2011 | 32,726 views | Filed in: Android Games The game loop is the heartbeat of every game. We used a very rudimentary one so far (you can find it here) without any control over how fast or slow we update our game state and which frames to render. To recapitulate, the most rudimentary game loop is a while loop that keeps executing some instructions until we signal it to finish, usually by setting a variable called running to false view source print? 1 2 3 4 5 6 boolean running = true; while (!running) { updateGameState(); displayGameState(); } The above code runs blindly without a care for timing and resources. If you have a fast device then it will run very fast and if you have a slow one it will run slower. The updateGameState() updates the state of every object in the game and the displayGameState() renders the objects into an image which is displayed onto the screen. There are two things we should consider here: FPS and UPS. FPS – Frames per Second – the number of times displayGameState() is being called per second. UPS – Update per Second – the number of times updateGameState() is being called per second. Ideally the update and render methods will be called the same number of times per second (preferably not less than 20-25 times per second). 25 FPS is usually enough on a phone so us humans won’t notice the animation being sluggish. For example if we target 25 FPS then it means we have to call the displayGameState() method every 40ms (1000 / 25 = 40ms, 1000ms = 1s). We need to bear in mind that updateGameState() is also called before the display method and for us to reach 25 FPS, we have to make sure that the update – display sequence executes in exactly 40ms. If it takes less than 40ms, then we have a higher FPS. If it takes more than that, then we have a slower running game. Let’s see some examples to understand the FPS better. The following diagram shows exactly 1 FPS. It takes the update – render cycle exactly one second to execute. This means that you will see the image on the screen change once every second. 1 Frame per Second The following diagram shows 10FPS. An update – render cycle takes 100ms. This means every tenth of a second the image changes. 10 FPS But the above scenario means that the update-render cycle executes in 1/10 of a second EVERY time. That is an assumption and we can’t control the actual times on cycle executes, or can we? What happens if we have 200 enemies and every enemy is shooting at us? We need to update the state of each enemy and the states of their bullets and check for collisions in one single update. It’s different when we have just 2 enemies. The times will clearly differ. The same applies to the render method. Rendering 200 firing droids will clearly take more time than rendering only 2. So what are the scenarios? We could have an update-render cycle that finishes in less than 100ms (1/10 of a second), finishes in exactly 100ms or finishes in more than that. On a powerful hardware it will be faster than on a weaker one. Let’s see the diagrams. The cycle finishes before the desired timeframe so we have a small amount of free time before running the next cycle. Frame with time to spare The following diagram shows a cycle which falls behind. That means that the time it takes for a update-render cycle to finish is greater than the desired one. If it takes 12ms that means we are 2ms behind (still considering the 10FPS). This can mount up and every cycle we loose time and the game will run slowly. Overdue Frame The first situation is the desired one. This gives us some free time to do something before we kick off the next cycle. We don’t need to do anything so we just tell the game loop to go to sleep for the remaining time period and wake up when the next cycle is due. If we won’t do this the game will run quicker than intended. By introducing the sleep time we achieved constant frame rate. Imagine a droid approaching you at a constant speed. We might have to skip multiple renderings to keep the speed constant but we have to make sure that we set the maximum number of frames allowed to be skipped because it can take quite a few updates to catch up and in case we skipped 15 frames that means we lost a lot from the game and it will just be unplayable.The second situation (I skipped the ideal one as it almost never happens) when the loop is behind. We’ll do a normal cycle in the next frame with even some time to give to the CPU to rest. The MainThread. and the current speed of the droid. or we update the position (status) of the droid at constant intervals. To achieve constant speed in a game we need to update the state of our objects when required. It is a scenario in which the update-render cycle takes longer than the desired time so we have to catch up.java‘s run() looks like this: view source print? 01 02 03 // desired fps private final static int MAX_FPS = 50. so it will take another second to reach the other side of the screen. In this case we can do nothing to keep the game speed constant and the game will run slower. To calculate the position accurately we need to know either the time delta since the last postion. requires a different approach. To do that we will skip the rendering of this frame and will do another update so the game speed won’t be affected. // maximum number of frames to be skipped . To achieve a constant game speed we will have to skip displaying frames. I will choose the second one as playing with deltas in the game update can be tricky. Game speed is NOT FPS! Examine the following diagram. You can imagine the game update taking more than one full frame. You know if it travelled half the screen in one second. Constant Game Speed with Variable FPS The above scenario has many variations. // resetting the frames skipped // update game state this.update(). // the frame period private final static int FRAME_PERIOD = 1000 / MAX_FPS.timeDiff).sleep(sleepTime). } catch (InterruptedException e) {} } while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) { // we need to catch up // update without rendering this.d(TAG.update(). synchronized (surfaceHolder) { beginTime = System. // calculate sleep time sleepTime = (int)(FRAME_PERIOD . framesSkipped = 0. Log. // the time it took for the cycle to execute int sleepTime.render(canvas). while (running) { canvas = null.currentTimeMillis(). // try locking the canvas for exclusive pixel editing // in the surface try { canvas = this.beginTime.gamePanel.surfaceHolder. // ms to sleep (<0 if we're behind) int framesSkipped. long beginTime. "Starting game loop"). // add frame period to check if in next frame . @Override public void run() { Canvas canvas. // the time when the cycle begun long timeDiff.lockCanvas().gamePanel.currentTimeMillis() . // number of frames being skipped sleepTime = 0.gamePanel. // calculate how long did the cycle take timeDiff = System. if (sleepTime > 0) { // if sleepTime > 0 we're OK try { // send the thread to sleep for a short period // very useful for battery saving Thread. // render state to the screen // draws the canvas on the panel this.04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 private final static int MAX_FRAME_SKIPS = 5. It is constant game speed with maximum number of frames per second.53 sleepTime += FRAME_PERIOD. In other words you need the droid to advance 2 pixels every game update (when you have 50 game updates per second) to cover 40 pixels per second. You can find the full code in the downloadable project. Examine it and you have a constant game speed with variable frame rate. There is an awesome article on game loops here. Reference: The Game Loop from our JCG partner Tamas Jano from “Against The Grain” blog. The best I could find. You feedback will be more than helpful! 8 Android Game Development – Measuring FPS . 54 framesSkipped++. 62 } 63 } // end finally 64 } 65 } Examine the above code very carefully as it implements the logic behind the diagram. I personally understood the game loops reading this article so I highly recommend it. There is another approach which I like. Download the code here and play with it. Because we are setting our desired FPS to 50 that means that the speed will increase by 50*speed. It uses interpolation to draw the state and it occurs on fast hardwares when there is time left for another rendering before the next game update. Note that I also modified the default values in the Speed. Do not forget to check out our new Android Game ArkDroid (screenshots below).unlockCanvasAndPost(canvas).java class. giving the CPU some rest will save the battery quite a lot. This can enhance the visuals of a game as it enables smoother animation but because we use mobile devices.value every update. The speed is measured in units/second. To have the speed of let’s say 40 pixels/second you will need to set the speed delta for every tick to 2 (40 / (1000 / 50) = 2). 55 } 56 } 57 } finally { 58 // in case of an exception the surface is not left in 59 // an inconsistent state 60 if (canvas != null) { 61 surfaceHolder. 025 026 // Stuff for stats */ 027 private DecimalFormat df = new DecimalFormat("0.773 views | Filed in: Android Games In the previous entry we have created a game loop that runs at a constant speed and constant (more or less) FPS.SurfaceHolder.graphics.java class.class.DecimalFormat. view source print? 001 package net. How can we measure it? Check the new MainThread. 2011 | 21. 008 009 /** 010 * @author impaler 01 * 1 01 * The Main thread which contains the game loop.view.Canvas. The thread must have 2 access to 013 * the surface view and holder to trigger events every game tick.getSimpleName(). 014 */ 015 public class MainThread extends Thread { 016 017 private static final String TAG = MainThread. 004 005 import android.Published on July 18.Log. 023 // the frame period 024 private final static int FRAME_PERIOD = 1000 / MAX_FPS.obviam. 002 003 import java.text.##"). 018 019 // desired fps 020 private final static int MAX_FPS = 50. 021 // maximum number of frames to be skipped 022 private final static int MAX_FRAME_SKIPS = 5.droidz.util. //ms 030 // the average will be calculated by storing 031 // the last n FPSs . // 2 dp 028 // we'll be reading the stats every second 029 private final static int STAT_INTERVAL = 1000. 006 import android. 007 import android. gamePanel = gamePanel. 044 private long totalFrameCount = 0l. // number of frames being skipped .running = running. 035 // the status time counter 036 private long statusIntervalTimer = 0l. 057 058 // flag to hold game state 059 private boolean running. 067 this.0. 047 // the number of times the stat has been read 048 private long statsCount = 0. 076 077 long beginTime. 066 this. 049 // the average FPS since the game started 050 private double averageFps = 0.d(TAG. 073 Log.surfaceHolder = surfaceHolder. // the time when the cycle begun 078 long timeDiff. 037 // number of frames skipped since the game started 038 private long totalFramesSkipped = 0l.032 private final static int FPS_HISTORY_NR = 10. 074 // initialise timing elements for stat gathering 075 initTimingElements(). // the time it took for the cycle to execute 079 int sleepTime. 051 052 // Surface holder that can access the physical surface 053 private SurfaceHolder surfaceHolder. MainGamePanel gamePanel) { 065 super(). 033 // last time the status was stored 034 private long lastStatusStore = 0. 045 // the last FPS values 046 private double fpsStore[]. 062 } 063 064 public MainThread(SurfaceHolder surfaceHolder. 039 // number of frames skipped in a store cycle (1 sec) 040 private long framesSkippedPerStatCycle = 0l. 060 public void setRunning(boolean running) { 061 this. // ms to sleep (<0 if we're behind) 080 int framesSkipped. 068 } 069 070 @Override 071 public void run() { 072 Canvas canvas. "Starting game loop"). 054 // The actual view that handles inputs 055 // and draws to the surface 056 private MainGamePanel gamePanel. 041 042 // number of rendered frames in an interval 043 private int frameCountPerStatCycle = 0. 102 103 if (sleepTime > 0) { 104 // if sleepTime > 0 we're OK 105 try { 106 // send the thread to sleep for a short period 107 // very useful for battery saving 108 Thread.update(). 092 framesSkipped = 0. 086 // try locking the canvas for exclusive pixel editing 087 // in the surface 088 try { 089 canvas = this. // update without rendering 115 sleepTime += FRAME_PERIOD.gamePanel. 100 // calculate sleep time 101 sleepTime = (int)(FRAME_PERIOD . 124 // calling the routine to store the gathered statistics 125 storeStats().currentTimeMillis().surfaceHolder.currentTimeMillis() .beginTime. 090 synchronized (surfaceHolder) { 091 beginTime = System. 126 } 127 } finally { 128 // in case of an exception the surface is not left in 129 // an inconsistent state .081 082 sleepTime = 0.render(canvas).update(). "Skipped:" + framesSkipped). // resetting the frames skipped 093 // update game state 094 this. 083 084 while (running) { 085 canvas = null.gamePanel.gamePanel.timeDiff). 121 } 122 // for statistics 123 framesSkippedPerStatCycle += framesSkipped. // add frame period to check if in next frame 116 framesSkipped++. 109 } catch (InterruptedException e) {} 110 } 111 112 while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) { 113 // we need to catch up 114 this.sleep(sleepTime).lockCanvas().d(TAG. 098 // calculate how long did the cycle take 099 timeDiff = System. 117 } 118 119 if (framesSkipped > 0) { 120 Log. 095 // render state to the screen 096 // draws the canvas on the panel 097 this. 132 } 133 } // end finally 134 } 135 } 136 137 /** 138 * The statistics .currentTimeMillis() . 173 } else { 174 averageFps = totalFps / FPS_HISTORY_NR. 145 */ 146 private void storeStats() { 147 frameCountPerStatCycle++. 162 163 double totalFps = 0. 152 153 if (statusIntervalTimer >= lastStatusStore + STAT_INTERVAL) { 154 // calculate the actual frames pers status check interval 15 double actualFps = (double)(frameCountPerStatCycle / (STAT_INTERVAL / 5 1000)). i < FPS_HISTORY_NR. 149 150 // check the actual time 151 statusIntervalTimer += (System. i++) { 166 totalFps += fpsStore[i].statusIntervalTimer). 167 } 168 169 // obtain the average 170 if (statsCount < FPS_HISTORY_NR) { 171 // in case of the first 10 triggers 172 averageFps = totalFps / statsCount.0.130 if (canvas != null) { 131 surfaceHolder.unlockCanvasAndPost(canvas).it is called every cycle. 148 totalFrameCount++. 159 160 // increase the number of times statistics was calculated 161 statsCount++. 175 } 176 // saving the number of total frames skipped . 15 6 157 //stores the latest fps in the array 158 fpsStore[(int) statsCount % FPS_HISTORY_NR] = actualFps. The number of frames since 143 * the start of the period are summed up and the calculation takes part 144 * only if the next period and the frame count is reset to 0. it checks if time since last 139 * store is greater than the statistics gathering period (1 sec) and if so 140 * it calculates the FPS for the last period and stores it. 164 // sum up the stored fps values 165 for (int i = 0. 141 * 142 * It tracks the number of frames per period. The storeStats() is called every tick and if the 1 second interval (STAT_INTERVAL = 1000.setAvgFps("FPS: " + df.0. Line 171 logs the FPS every second while line 172 sets the avgFps value of the gamePanel instance to be displayed on the screen. i < FPS_HISTORY_NR. public void setAvgFps(String avgFps) { this.) is not reached then it simply adds the number of frames to the existing count. The MainGamePanel. 186 gamePanel. 187 } 188 } 189 190 private void initTimingElements() { 191 // initialise timing elements 192 fpsStore = new double[FPS_HISTORY_NR]. 178 // resetting the counters after a status record (1 sec) 179 framesSkippedPerStatCycle = 0. After this I just reset the counters for the current statistics cycle and add the results to a global counter.d(TAG + ". 193 for (int i = 0. 185 // Log.177 totalFramesSkipped += framesSkippedPerStatCycle. view source print? 01 02 03 04 // the fps to be displayed private String avgFps. If the one second is hit then it takes the number of rendered frames and adds them to the array of FPSs.currentTimeMillis(). The average is calculated on the values stored in the last 10 seconds.avgFps = avgFps.java class’s render method contains the the displayFps call which just draws the text onto the top right corner of the display every time the state is rendered. 180 statusIntervalTimer = 0. 197 } 198 199 } I introduced a simple measuring function.d(TAG. . It also has a private member that is set from the thread. "Timing elements for stats 6 initialised"). 181 frameCountPerStatCycle = 0. 184 lastStatusStore = statusIntervalTimer.format(averageFps)). "Average FPS:" + df. 19 } 5 19 Log. 182 183 statusIntervalTimer = System.initTimingElements()". i++) { 194 fpsStore[i] = 0. I count the number of frames every second and store them in the fpsStore[] array.format(averageFps)). 17 paint. avgFps). displaying images and moving them around.drawText(fps. String fps) { 15 if (canvas != null && fps != null) { 16 Paint paint = new Paint(). . 12 } 13 14 private void displayFps(Canvas canvas.50. 20.341 views | Filed in: Android Games If you followed the series so far we are pretty knowledgable in handling touches.05 } 06 07 public void render(Canvas canvas) { 08 canvas.setARGB(255.BLACK).getWidth() . 255. 10 // display fps 11 displayFps(canvas.draw(canvas). You feedback will be more than helpful! 9 Android Game Development – Sprite Animation Published on July 23. 18 canvas. FPS displayed Reference: Measuring FPS from our JCG partner Tamas Jano from “Against The Grain” blog. 255). this.drawColor(Color. Do not forget to check out our new Android Game ArkDroid (screenshots below). 255. 2011 | 35. 19 } 20 } Try running it. You should have the FPS displayed in the top right corner. 09 droid. paint). Let’s just resort to examining walking which is pretty complex in its own. Try blinking quite rapidly and you will see something like the old black and white comedies. we need to load up each frame as a separate image and display them at regular intervals one after each other. That is low frame rate. . right hand in front while the oposite limbs are behind. A human on the other hand. To illustrate it better check the following image. To give the characters some life we will need to do more than that. To get the above animation in android (or iPhone or in any other program for that matter). Imagine a human crossing your way (just in 2D). A rock is an inanimate object and even if it is thrown. You’ll notice different displays of the body. If you close your eyes and keep them closed for a bit and open them again the person already went on and is in a different position. That is what animation is all about. The rest you should fill in. It is a 150 pixels wide image and each frame is 30 pixels wide. it doesn’t change its shape. The walking presented above is a bit dodgy but it’s a ripped off version of the sprites from Monkey Island. To do that is trivial. We know that we have 5 frames and each frame is 30 pixels wide. If you don’t close your eyes you see the person progressing smoothly. just like this. To be able to re-create the above animation. This slowly changes so the left foot remains behind while the right progresses along with the body. We define a rectangle (that will be our selection) which has the width of one frame and the height of the image. OR we can load up the big image containing all the frames and use the methods provided by android do slice and dice them on the fly and to display only the relevant frame.But a moving image it’s a pretty dull sight as it looks really fake and amateurish. More on FPS here. She’s Elaine Marley. But at one point the cycle repeats. we need every frame from the walking cycle. The following image shows how I cut out the first two frames. It is a simple 2 dimensional image or animation. Left foot in front. Actually we do want a low frame rate walking for this tutorial. Try throwing one and you’ll see twitching limbs and even screams in the air. This is called a Sprite. is very animated. // the rectangle to be drawn from the animation 6 bitmap 07 private int frameNr. // the animation sequence 5 0 private Rect sourceRect. // the current frame 09 private long frameTicker. . 04 0 private Bitmap bitmap. It is the blue window in the image above. // the height of the sprite 14 15 private int x.class. // the X coordinate of the object (top left of the image) 16 private int y.  bitmap is the png file containing all the frames. // number of frames in animation 08 private int currentFrame. We will need an object to animate. We will use the knowledge from some previous chapters.Knowing all this let’s go create the project. // the time of the last frame update 10 private int framePeriod. The rectangle moves every frame onto the next. The second image in this article.getSimpleName(). most notably about the game loop and the one about the image display (here we set up the thread that triggers the drawing of the graphics item every frame). We use Elaine from Monkey Island so I will the class ElaineAnimated.  sourceRect is the selection rectangle. view source print? 01 public class ElaineAnimated { 02 03 private static final String TAG = ElaineAnimated. // milliseconds between each frame (1000/fps) 1 1 1 private int spriteWidth. // the width of the sprite to calculate the cut out 2 rectangle 13 private int spriteHeight.java. // the Y coordinate of the object (top left of the image) 17 18 } The private attributes are commented but worth mentioning a few. getWidth() / frameCount.bitmap = bitmap. 05 currentFrame = 0. int 1 fps. frameTicker this is the java timestamp of the last frame change in the walking sequence.getHeight(). int y.2 seconds. Elaine will have an update method of her own as she is an animated object and she needs to look good and she is in charge of dragging her feet. If the cycle completes in 1 second that means for 5 frames the period will be 0. That is. int width. Because the period of the game update cycle and Elaine’s one might be (in this case is) different we pass the actual game time as a variable so we know when we need to display the next frame. 08 spriteHeight = bitmap. the frames per second of the walk cycle not the game FPS.y = y. int frameCount) { 0 this. 11 frameTicker = 0l.  framePeriod is time in milliseconds that represents the period of time a frame is being displayed. Note that this is not the game FPS but the walking FPS. spriteHeight). spriteWidth. int x. I also pass in the fps which is again. each frame will be displayed for 0. 06 frameNr = frameCount. For example the game runs very fast and the update is called every 20 milliseconds and we need to update the frame every 200ms. 09 sourceRect = new Rect(0. Here’s the code: view source print? . 0. 10 framePeriod = 1000 / fps. 12 } I’m assuming that the frames are the same width so I calculate the width of the rectangle by dividing the width of the image with the number of frames. If we want Elaine to perform a complete walk cycle in a second we set the frame rate for walking to 5 because we have 5 frames. The constructor is as follows: view source print? 0 public ElaineAnimated(Bitmap bitmap. 2 03 this. To get a really smooth animation we need 30 frames but it’s not the point now. then the progression of the frame will happen at every 10th game update. 07 spriteWidth = bitmap. 04 this.2 seconds.x = x. int height. 12 this. getY() + 3 spriteHeight). 3 } The update method is simple (Elaine’s).left = currentFrame * spriteWidth. 13 } The update is called from the main game panel (check previous entries how that works). 08 } 09 } 10 // define the rectangle to cut out sprite 11 this.left + spriteWidth. 4 canvas. getY(). getX() + spriteWidth. we reset the cycle. After all that area from which the image will be cut out is defined as the sourceRect. If the next frame is beyond the last. sourceRect. null). This is the update method of the MainGamePanel class.right = this.drawBitmap(bitmap.sourceRect.01 public void update(long gameTime) { 02 if (gameTime > frameTicker + framePeriod) { 03 frameTicker = gameTime.sourceRect. That’s it. view source . It is at Elaine’s position (X and Y set in the constructor). view source print? 1 public void update() { 2 elaine.currentTimeMillis()). 04 // increment the frame 05 currentFrame++. 5 } That is all. view source print? 1 2 public void draw(Canvas canvas) { // where to draw the sprite Rect destRect = new Rect(getX(). destRect. We set the destination rectangle as to where to draw the cut out image.sourceRect. It increments the frame if the passed in time (which is the system time when the update method was called) is greater than the last time (frameTicker) the frame was updated plus the period of the next update. 06 if (currentFrame >= frameNr) { 07 currentFrame = 0.update(System. Now let’s go on to display it. 5). 15 16 //* .png and it was copied to /res/drawable-mdpi/ so android can pick it up automatically. The thread and activity classes haven’t changed at all. The last parameter is the number of frames in the cycle. null). sourceRect. If you run the application you should be seeing Elaine performing walking cycles in one place. view source print? 01 private ElaineAnimated elaine. removed . 50 // initial position 10 . The image is named walk_elaine..java differs slightly from the one from previous chapters. . removed . 47 // width and height of sprite 11 .. R. but you can modify the code. The FPS is very important and the number of frames too. */ 17 } Elaine is instantiated in the panel’s constructor and is given an initial positon of (X=10.. You can find them in the download as they are quite long to be pasted. tells android to cut out the image defined by sourceRect from the image contained in bitmap and draw it into the rectangle on the canvas defined by destRect.walk_elaine) 09 . 5. FPS says how many frames are to be shown in one second. I got rid of all the droidz and added just Elaine.drawBitmap(bitmap.decodeResource(getResources(). // FPS and number of frames in the animation 12 13 // create the game loop thread 14 thread = new MainThread(getHolder(). 10. */ 05 06 // create Elaine and load bitmap 07 elaine = new ElaineAnimated( 08 BitmapFactory... this). destRect. 02 03 public MainGamePanel(Context context) { 04 //* . Y=50).. We should have used jumping as that can be performed in one place but you get the idea.. 30.drawable.. The draw is called from the game panel’s render method triggered by the game loop (check previous entries).print? 1 canvas. The MainGamePanel. I pass in the width and the height of the sprite too but that is ignored anyway. 0. 150. After everything was drawn we paint a rectangle of the size of a frame onto the original image so you see which frame is being displayed in the motion.drawBitmap(bitmap. null).width()) + destRect. sourceRect. 0). null). 150. 6 Paint paint = new Paint(). destRect. getX() + spriteWidth. 150 + destRect. The method setARGB creates a semi-transparent green paint. 150) and creates a new paint object so we can paint over the current frame on the original image. view source print? 1 2 public void draw(Canvas canvas) { // where to draw the sprite Rect destRect = new Rect(getX().setARGB(50. 255. paint). 4 canvas. getY(). 9 } This just displays the image at (20. getY() + 3 spriteHeight).width().Elaine Walking Enhancement To make some neat additions modify Elaine’s draw method so it displays the original image containing the sprites from which the frames are extracted. .height(). 7 paint. The first value is 50 which means it’s 75% transparent. 5 canvas.width()). canvas. 20. 0 is completely transparent while 255 is fully opaque.drawRect(20 + (currentFrame * destRect. 20 + 8 (currentFrame * destRect.drawBitmap(bitmap. A tiny little rocket shoots up and explodes into hundreds of sparkling little stars that fade out as they fall down. we will place them in one place (the origin) and give them random forces. To make it simple we’ll create a few particles. 2011 | 19.Walking with Current Frame Painted That’s it. It means that it has magnitude and . Just think of fireworks.264 views | Filed in: Android Games Ever wondered how explosions are created? Let’s take a little detour and try to implement a basic particle explosion.tar.gz) Reference: Sprite Animation with Android from our JCG partner Tamas Jano from “Against The Grain” blog. A force is a vector quantity. What happens is that a huge force in the center of the rocket rips the body apart (thus creating particles) and scatters them randomly around the point of explosion. Not all the time but mostly and for the sake of simplicity we’ll assume that all particles originate from a single point. An explosion is nothing more than a bunch of particles (be them pixels. Do not forget to check out our new Android Game ArkDroid (screenshots below). Run it and you have your first sprite animation. You feedback will be more than helpful! 10 Android Game Development – Particle Explosion Published on August 2. Download the source code here (animation_walk. originating from a single point. small shapes or images) scattered across the screen. // internal use to avoid instantiation 19 } . // particle dies when it reaches this value 17 private int color. // the maximum width or height 08 public static final int MAX_SPEED = 10.direction. // height of the particle 13 private float x. // particle is alive or dead 11 private float width. // particle is dead 05 06 public static final int DEFAULT_LIFETIME = 200. // horizontal and vertical position 14 private double xv. The Particle The class file: view source print? 01 public class Particle { 02 03 public static final int STATE_ALIVE = 0. // width of the particle 12 private float height. // the color of the particle 18 private Paint paint. // vertical and horizontal velocity 15 private int age. // maximum speed (per update) 09 10 private int state. y. The magnitude will determine its speed and its direction will tell the particle which way to go. // current age of the particle 16 private int lifetime. // particle is alive 04 public static final int STATE_DEAD = 1. // play with this 07 public static final int MAX_DIMENSION = 5. yv. More on this a bit later. It has a position. But first we need to create the particle: view source print? 01 public Particle(int x. 255). 255). 03 this.y = y.7.age = 0. It also has a speed and a direction.STATE_ALIVE. A particle is alive when its color is not black (it hasn’t faded) and its age hasn’t reached its lifetime.7. 07 this. 14 yv *= 0. MAX_SPEED * 2) . 10 this. 11 // smoothing out the diagonal speed 12 if (xv * xv + yv * yv > MAX_SPEED * MAX_SPEED) { 13 xv *= 0. This indicates whether the particle is alive or dead.widht = rndInt(1. 04 this.xv = (rndDbl(0. As you recall speed is a vector so it has 2 components in 2D. 1 } 5 1 this.paint = new Paint(this. In 3D it will also have the z component but we stay in 2D for now. rndInt(0. 09 this.lifetime = DEFAULT_LIFETIME. 6 255)).The particle is nothing more than a little rectangle (this can be an image.argb(255. 17 this.yv = (rndDbl(0. rndInt(0. The rest are color and paint. MAX_DIMENSION).state = Particle. int y) { 02 this. rndInt(0. These are for drawing only. 08 this. 06 this.color). To keep it simple now we add two properties for this.x = x. It has a state. MAX_SPEED * 2) . The update method of the particle is pretty simple. the game update is nothing more than calling the update methods of every entities in the game and displaying them.MAX_SPEED). The lifetime is the maximum age a particle can reach before it dies. circle or any other shape. If you recall the previous entries.widht.MAX_SPEED). but in our case we use a rectangle) with a few properties. vx and vy The age of the particle is it’s 0 in the beginning and is incremented at each update. 05 this.height = this.color = Color. It’s position in a 2D coordinate system is represented by 2 points: x and y. 18 } . x += this. The smoothing is needed because if both components are near the maximum value then the resulting magnitude will be over the max speed.xv.color >>> 24. for this check the complete source code. // increase the age of the particle 15 } 16 if (this. The age is 0 of course as the particle has just been born. Next the lifetime is set. 14 this. // fade by 2 09 if (a <= 0) { // if reached transparency kill the particle 10 this.color & 0x00ffffff) + (a << 24).y. You will notice that a particle is created at position x.paint. We want to randomise the size of the rectangles because an explosion creates particles in different sizes and shapes but we’ll just randomise the size and colour. I have written a few helper methods that give me random numbers.state != STATE_DEAD) { 03 this. 05 06 // extract alpha 07 int a = this. The state is set to alive. The las thing to set is the color which again is randomised. You could use simple trigonometric functions with a random degree instead of this. // set the new alpha 13 this.color = (this. 11 } else { 12 this. Every particle will have the same lifetime. The update() method for the particle.age++.yv.age >= this. 08 a -= 2. 18 } 19 } . To set the speed I have used 2 random numbers for the 2 components of the speed vector (vx and vy).Check the creation of a particle and it should be straight forward. 04 this.setAlpha(a). view source print? 01 public void update() { 02 if (this.state = STATE_DEAD. It’s very amateurish. There you have it. Next is the interesting bit.state = STATE_DEAD.y += this.lifetime) { // reached the end if its life 17 this. polygonal. 255.20 } It’s pretty simple. r. int green = color >>> 8 & 0xFF. A color in hex is simple: 0x00FF00 is green for example. Green. the position is set according to the speed and the alpha component of the particle’s color is decremented. The draw() method is simple again. In other words the particle is being faded. Blue). If you’re familiar with rgb and argb that is great. I’m rubbish as well. view source print? . the values are between 00 and FF.de/2007/05/10/bitwise-gems-fast-integer-math/. int blue = color & 0xFF. It’s faster than using the objects but you can safely use the android methods too. Because it is in hex. Don’t worry. 0. To represent an int in hex you just prefix it with 0x. 0) creates a semi transparent red). It also has the alpha component which is transparency/opacity. Just as a side note on colours You can specify colours in Android as an int. This is how you would extract the components of an argb colour. just make sure you know where to look. view source print? 1 2 3 4 5 int color = 0xff336699. Every update. Now to add the alpha you will add it to the beginning. g. rgb is 24 bits color while argb is 32 bits. 0xAARRGGBB. int red = color >>> 16 & 0xFF. int alpha = color >>> 24. 0 being 0 and FF being 255 in decimal. you can simply create it with an integer expressed in hex like this: new Color(0x80FF0000). When you create a colour out of components like color(a. The pattern is: 0xRRGGBB (Red. b) (for example: new Color(125. Opacity values: 0 = transparent. Here is a good explanation of colour components and how to use bitwise operators to manipulate them: http://lab. If the age exceeded the lifetime or the opacity is 0 (that means that it is completely transparent) the particle is declared dead. If you wonder about the magic with colours. it is quite simple once you get the bitwise operators. 255 = completely opaque. y + this.color). // the explosion's origin 08 private int size. the origin. // particles in the explosion 07 private int x.widht. canvas.x + this. Each circle is one update. this. // number of particles 09 private int state. 3 paint). // all particles are dead 05 06 private Particle[] particles. The Explosion The explosion is nothing more than hundreds of particles originating from one place. In the image above you see the first 4 updates of a simple explosion.1 2 public void draw(Canvas canvas) { paint. // at least 1 particle is alive 04 public static final int STATE_DEAD = 1.setColor(this. this. y. this. The main properties of an explosion are: view source print? 01 public class Explosion { 02 03 public static final int STATE_ALIVE = 0. 4} At this stage try to create some particles in your game panel and see what happens.drawRect(this.height. // whether it's still active or not 10 } .x. All the particles have the same speed but they spread out in different directions.y. y).particles = new Particle[particleNr]. } this. i++) { Particle p = new Particle(x. i++) { 3 explosions[i] = null.particles[i] = p. for (int i = 0.length. i < this. In the surfaceCreated method we instantiate the array and fill it with null. 4 } The onTouchEvent is where we create explosions.length. view source print? 1 explosions = new Explosion[10]. An explosion is alive if it has at least one particle alive. this.state = STATE_ALIVE. "Explosion created at " + x + ". int x. .d(TAG. It iterates through all the particles and calls the update() method on each particle. The constructor is very simple: view source print? 01 02 03 04 05 06 07 08 09 10 public Explosion(int particleNr. } The array of particles is being filled at the touch down position. int y) { Log. So in the MainGamePanel we declare an array of explosions. In our application we will create explosions on the screen where we touch it. 2 for (int i = 0. The update is extremely simple. The draw() ditto. The size is the number of particles. In our application we will allow up to 10 explosions.particles. view source print? 1 private Explosion[] explosions." + y). i < explosions.It contains an array of particles. this. this.size = particleNr. view source print? 01 public boolean onTouchEvent(MotionEvent event) { 02 if (event. 2 13 } 14 } 15 return true. (int)event.isDead()) { 1 explosion = new Explosion(EXPLOSION_SIZE. 1 (int)event. In the final code I added a border for the screen as the wall and added a basic collision detection for the particles so they bounce off the walls. Use it as an exercise and remove the collision and try attaching an image to the particle instead of being a rectangle. 09 } 10 if (explosion == null || explosion. It should look like this: .length) { 07 currentExplosion++.getY()). 08 explosion = explosions[currentExplosion].getAction() == MotionEvent. Iterate through the explosions and if they are not null and are alive then call their update and draw methods respectively. 5 0 while (explosion != null && explosion.getX(). 0 Explosion explosion = explosions[currentExplosion]. The update and render methods are straight forward. 1 explosions[currentExplosion] = explosion.ACTION_DOWN) { 03 // check if explosion is null or if it is still active 04 int currentExplosion = 0. 16 } What we do is iterate through the explosions and when we find the first null (this means we never used it for an instance) or the first dead explosion we create a new one at the touch position. To create explosions just click on the screen. The wall is being transmitted as a reference and the update method checks for collision with it.isAlive() && currentExplosion < 6 explosions. tgz). I need a bit of a challenge and I want the enemy droid to fight back. So I need a pretty dumb enemy that does not do much but takes the shots. Reference: Particle Explosion with Android from our JCG partner Tamas Jano from “Against The Grain” blog. I will use droids in the examples and I will script a basic fight simulator to see how they behave. After I mastered that skill (shooting a helpless droid). The problem: I command a single robot and I want to obliterate my enemies. To face the same type of enemy all over again is boring.982 views | Filed in: Android Games In this part I will try to explain what I understand on good game design elements. 2011 | 14. I need new challenges and this means new types of enemies. but because I am still a . You feedback will be more than helpful! 11 Android Game Development – Design Ingame Entities – The Strategy Pattern Published on August 17. Download it here (android.particles. Do not forget to check out our new Android Game ArkDroid (screenshots below). For example in the first level I want only to practice my target.Explore the code and have fun. beginner I don’t want to die quickly so I need weak droids. The droid types:  Decoy Droid – will have no weapon and can’t move. It makes sense to create a Droid interface with these two methods and have each droid implement them. Not just stronger. I need better and stronger droids. . To keep it simple. each droid has 2 abilities: move and attack. The obvious solution: Create 3 classes for the 3 types of enemy droids. They can move and shoot. but different in behaviour as well as it can get boring killing the same type of enemy over and over again.  Assault Droid – will have a heavy weapon and moves slowly.  Scout Droid – will have a weak weapon and moves fast. Well. After I am over with them I want a tougher challenge. Looking at the 3 types we can implement the following simple class diagram: The interface has 3 simple methods which the droids need to implement: view source print? 01 02 03 04 public interface Droid { // display some info of the droid public void display(). not all of them but we can provide an empty implementation for the ones that do nothing. java view source print? 01 02 03 04 05 06 07 08 09 public class ScoutDroid implements Droid { private float damage = 0.println("I am a scout droid"). @Override public void display() { System. } .out.out. // attack position public void shoot(int x. int y).out. } @Override public void move(int x.5f. } The 3 classes are as follow: DecoyDroid."). } } ScoutDroid.out.").println("Have no weapon. int y) { System.println("Can't move.java view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 public class DecoyDroid implements Droid { @Override public void display() { System.05 06 07 08 09 10 11 // move the droid public void move(int x. int y). } @Override public void shoot(int x. int y) { System.println("I am a DECOY droid"). println("I am an ASSAULT droid").out.println("Heavy laser targeting: " + x + "."). Damage: " + damage). int y) { System. } } } Both ScoutDroid and AssaultDroid have the argument damage.5f.println("Moving QUICKLY to: " + x + ".println("Light Laser Canon targeting: " + x + ". } @Override public void move(int x. } else { System." + y + ". int y) { if (loaded) { System. } @Override public void shoot(int x.. private boolean loaded = true." + y + ". } @Override public void shoot(int x..out.out. .")." + y + ". int y) { System." + y + ". loaded = false. This holds the value of the damage inflicted by them.java view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class AssaultDroid implements Droid { private float damage = 2. int y) { System.println("Reloading. loaded = true. Damage: " + damage). @Override public void display() { System.out. } } AssaultDroid.out.").out.println("Moving SLOWLY to: " + x + ".10 11 12 13 14 15 16 17 18 19 20 @Override public void move(int x. 25 decoy. rand.nextInt(10). 26 System.nextInt(10)).display().out.nextInt(10)).println().out. 06 07 Droid scout = new ScoutDroid(). 27 } 28 } 29 } The result (console output) will look like this: view source .java view source print? 01 public class BadDroidSimulator { 02 03 public static void main(String[] args) { 04 // for generating random numbers 05 Random rand = new Random(). rand. 08 Droid assailant = new AssaultDroid().shoot(rand. 13 decoy.nextInt(10).nextInt(10).nextInt(10)). 24 decoy.nextInt(10). 21 assailant.println("<=== END TURN " + i + " ===>").nextInt(10)). rand. 12 assailant.nextInt(10)). 7 1 scout. I have created a simple simulator for the droids to take turns to move and shoot. Run the simulator for this design: BadDroidSimulator. rand.display(). i++) { 1 System.To give the AssaultDroid a heavy weapon with a slow reload time we added the loaded variable. This way it takes the assault droid two turns to fire its weapon once.out. 23 System. rand. rand.move(rand.shoot(rand.move(rand.display(). i <= 5.out. 09 Droid decoy = new DecoyDroid(). // we assume this is an 8 enemy position 19 scout. 22 assailant.nextInt(10).move(rand. 10 11 scout.println("\n<=== BEGIN TURN " + i + " ===>").nextInt(10).shoot(rand.nextInt(10)).println(). 20 System. 14 15 // shoot-out .each droid fires once per turn 16 for (int i = 1. Damage: 0. Can’t move. Damage: 0. <=== END TURN 4 ===> . Reloading… Moving SLOWLY to: 1.7.2. Heavy laser targeting: 6. Heavy laser targeting: 7. Can’t move. Can’t move.4.5 Moving QUICKLY to: 1. Damage: 2. Damage: 2.6.0. Can’t move.5 Moving SLOWLY to: 2. Damage: 0.7. Damage: 0. Have no weapon.0.1.5 Moving QUICKLY to: 9.print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 I am a scout droid I am an ASSAULT droid I am a DECOY droid <=== BEGIN TURN 1 ===> Light Laser Canon targeting: 9.5. Have no weapon.5 Moving SLOWLY to: 9.9. Reloading… Moving SLOWLY to: 5. <=== END TURN 3 ===> <=== BEGIN TURN 4 ===> Light Laser Canon targeting: 3.4. <=== END TURN 2 ===> <=== BEGIN TURN 3 ===> Light Laser Canon targeting: 6.6. Have no weapon. <=== END TURN 1 ===> <=== BEGIN TURN 2 ===> Light Laser Canon targeting: 3.5 Moving QUICKLY to: 4.1.7.5 Moving QUICKLY to: 6. Have no weapon. Heavy laser targeting: 1. It requires new droid classes to be created and each droid type will implement its methods separately.9. Composition is based on “has a” relationships. right?  Also imagine that the shooting mechanism is not that simple and it needs collision detection and so on. Can’t move. A ScoutDroid is a generic Droid with some peculiarities. This is all good. Many of these methods are identical. determines its type. For each droid the same redundant code needs to be rewritten. <=== END TURN 5 ===> Challenges to extend the design The droids take turns to move and shoot. Here is one proposed solution: Composition and the Strategy Pattern. The first design consisted of a “is a” type relationship. What type of components a droid has. Have no weapon. Damage: 0.5 Moving SLOWLY to: 3.  What if the fire power could be enhanced with power ups?  What if the droid gains self-conscientiousness and finds a weapon to use it instead of the current one? I am sure you have plenty ideas on how to enhance the gameplay and extend the world but the most obvious solution (described above) seems ill-suited for this. A Droid has a Weapon. Damage: 2.2.2.5 Moving QUICKLY to: 3. but:  What if you want to create a hybrid droid? A droid that moves as fast as the scout but with a heavy weapon? You will have to create a new class and copy paste the respective methods from the Scout and Assault droid. A Droid has a Chassis. The current design doesn’t allow you to change the droid’s internals at runtime without significant effort. Designing a Droid (properly) A very simple droid consists of a weapon put on a chassis. .47 48 49 50 51 52 53 54 55 56 57 <=== BEGIN TURN 5 ===> Light Laser Canon targeting: 0.8. 08 chassis. drive-shaft. All these components are produced separately. We make it abstract because we actually implement the methods that trigger the weapon. We want to make the scout move quickly with a light weapon. But to keep it simple we have only 2 components.out. fuel consumption can be completely different. The assembly of a concrete droid will be delegated to the type constructor along with the description method. The Assault Droid on the other hand is a Droid too but it has a Heavy Laser Canon and it runs on Tracks. We need one generic droid that has all the wirings built so its components will be triggered by the droid through those interfaces. How does a car production line work? You get the chassis with a specific place for the engine.print(id + " > " ). The engine is one of the car’s components. in order for us to give weapons to the droid to use.Let’s decompose the Scout Droid for example. 09 } 10 11 /** . We create the abstract Droid class. The droid needs to understand the pullTrigger method and to do this it needs to be implemented. The wheels or track or anti-gravity propulsion will take the droid there.. The droid only needs to set the coordinates. gear-box and so on. view source print? 01 public abstract class Droid { 02 03 protected Weapon weapon. capacity. Its internal design. power. The same thing with the changing of location. and action the moving mechanism but we don’t have concrete weapons and movement mechanisms attached to the droid. The engine has a similar story. For example a droid needs to only pull the trigger of the weapon and doesn’t care what type of weapon it is as long as it has a trigger. So is our droid. The teams that produce them have no idea of the other parts. The Scout Droid is a Droid which has a Light Laser Canon has a set of Wheels to move. The connector in this instance is the interface. This makes it extremely powerful but a bit slow. It needs to trigger the movement. Think from a factory perspective. // the chassis on which the droid is placed 05 06 public void moveToPosition(int x. // the weapon which will be used in fights 04 protected Chassis chassis. Different makes have different ways of doing this. They must fulfil one criteria: the gearbox must fit in perfectly in its place and connected up with the engine.moveTo(x. If it hooks up nicely with the wheels and gearbox then it can be fitted. To fulfil this we need a class with implemented methods instead of an interface. wheels. y). int y) { 07 System. 04 * @param target . 07 08 /** 09 * Returns the description of the weapon 10 */ 11 public String getDescription(). y)). Each strategy should decide how to do it. The components are interfaces so the droid does not know what it is doing when triggering the actions on them. int y) { 16 System. It is all delegated to the implementation.java view source print? 01 public interface Weapon { 02 /** 03 * The trigger to use the weapon. It also has two components: Weapon and Chassis.out.print(id + " > "). 18 } 19 20 /** 21 * Displays some info on the droid 22 */ 23 public abstract void display(). 17 weapon. The interfaces are as follows: Weapon.useWeapon(new Vector2f(x. 12 } Chassis. 24 } If you examine the class you will see that the Droid has 3 methods from which 2 are implemented.12 * Engages the position on the screen whether it is occupied by 13 * an enemy or not.java view source print? 01 public interface Chassis { 02 /** 03 * Delegates the movement to the supporting chassis and . 14 */ 15 public void attackPosition(int x.where on the map is the target 05 */ 06 public void useWeapon(Vector2f target). I use a very simple id generation strategy. I increment the nextId static field and append it to the concrete droid type prefix in the constructor for each type. This is what the strategy pattern is all about. Here is the new Droid class: view source print? 01 public abstract class Droid { 02 03 protected static int nextId = 0. int y). // the next available ID 04 05 protected String id. 16 } 17 public void setWeapon(Weapon weapon) { 18 this. 12 } 13 14 public Weapon getWeapon() { 15 return weapon. 07 08 /** 09 * Returns the description of the chassis 10 */ 11 public String getDescription(). These two strategies (behaviours) need to be implemented.y 05 */ 06 public void moveTo(int x. // the weapon which will be used in fights 07 protected Chassis chassis. // the chassis on which the droid is placed 08 09 // the unique ID of the droid in the game 10 public String getId() { 11 return id.04 * tries to move the unit to x. // unique id 06 protected Weapon weapon. 23 } . A Droid has behaviours: it can use a weapon and it can move. 12 } We will enhance our base Droid class. We also add an id which will be unique in our game for each droid instance.weapon = weapon. 19 } 20 21 public Chassis getChassis() { 22 return chassis. We will add setter and getter methods for both Weapon and Chassis. This will allow us to change the droid’s behaviour at runtime. 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public void setChassis(Chassis chassis) { this. y). int y) { System.chassis = chassis.out. } Let’s build some weapons NoWeapon.println("No weapon equipped!").print(id + " > " ). A null object is a dummy that does nothing and it 03 * is a mere place-holder and eliminates the need to check for null. } /** * Displays some info on the droid */ public abstract void display(). int y) { System. chassis.java view source print? 01 /** 02 * This is a null object.print(id + " > "). } public void moveToPosition(int x. y)).moveTo(x.out. Each strategy should decide how to do it. 13 } 14 15 @Override 16 public String getDescription() { .useWeapon(new Vector2f(x. */ public void attackPosition(int x.out. 04 * @author impaler 05 * 06 */ 07 public class NoWeapon implements Weapon { 08 09 @Override 10 public void useWeapon(Vector2f target) { 11 // We are doing nothing 12 System. weapon. } /** * Engages the position on the screen whether it is occupied by * an enemy or not. getY() + ". 15 } 16 17 @Override 18 public String getDescription() { 19 return "First generation laser canon. // after fire needs to be reloaded . // the damage inflicted 10 11 @Override 12 public void useWeapon(Vector2f target) { 13 System. Street use only!".java view source print? 01 /** 02 * This is a light laser cannon whit a quick reload time and high accuracy 03 * 04 * @author impaler 05 * 06 */ 07 public class LightLaserCanon implements Weapon { 08 09 private float damage = 0." 14 + (int)target.").5f. 20 } 21 } HeavyLaserCanon. 03 * @author impaler 04 */ 05 public class HeavyLaserCanon implements Weapon { 06 07 private boolean loaded = true.17 18 19 return "Nothing". Bang on! Done " + damage + " damage. LightLaserCanon. } } This is the null object.getX() + ".out. The class description should give you an idea what it is.java view source print? 0 /** 1 0 * This is a heavy assault laser cannon with high accuracy but slow reload 2 time.println("Shooting my laser canon to " + (int)target. ".println("Darn! Out of ammo! Reloading. 20 } 21 } 22 23 @Override 24 public String getDescription() { 2 return "DASS-5000 . Let’s build some chassis The getDescription() method says what the chassis is like.println("Eat this! Laser beam hit target (" + (int)target."). You can find it in the downloaded source. 15 // next time needs reloading 16 loaded = false.out.5f." + (int)target."). 06 } 07 08 @Override 09 public String getDescription() { 10 return "It's just a frame. This is a very basic 2D vector class which currently holds the x and y coordinates. NoChassis.out."). 2 } 6 27 } You might notice the Vector2f class.The ultimate in siege weaponry provided by Obviam 5 Enterprises. int y) { 05 System..java – null object (see weapons) view source print? 01 public class NoChassis implements Chassis { 02 03 @Override 04 public void moveTo(int x. // the damage is considerable 09 10 @Override 11 public void useWeapon(Vector2f target) { 12 if (loaded) { 1 // we fire the canon 3 1 System.getX() 4 + ". Nothing more.out. . 19 loaded = true.println("It's just a frame. 17 } else { 18 System..08 private float damage = 1.".getY() + ") and dealt " + damage + " damage. Can't move. println("Can't move.11 12 } } SteelStand. 06 } 07 08 @Override 0 public String getDescription() { 9 1 return "Unmovable reinforced steel stand ideal for turrets and defensive 0 units.java view source .". 11 } 12 } Track.out.println("Speeding to " + x + ".".out. 06 } 07 08 @Override 0 public String getDescription() { 9 1 return "4 wheel drive. very fast on flat terrain but struggling through 0 obstacles. int y) { 05 System. int y) { 05 System.").java view source print? 01 public class SteelStand implements Chassis { 02 03 @Override 04 public void moveTo(int x.java view source print? 01 public class Wheels implements Chassis { 02 03 @Override 04 public void moveTo(int x. 11 } 12 } Wheels." + y + " on my wheels!"). println("|\tWeapon: " + weapon.out.println("+-----------------------------------------------------1 --------------------------------------+").nextId). remember? DecoyDroid.java view source print? 01 public class DecoyDroid extends Droid { 02 03 public DecoyDroid() { 04 id = "DCY-" + (++Droid.out.println("|\tID: " + id). 1 System. 14 System.println("| I am a DECOY droid. 17 } . It’s for our target practice. This droid will have no weapon and will be placed on a steel stand.getDescription()). 1 System. 06 chassis = new SteelStand().out. 0 } 6 07 08 @Override 09 public String getDescription() { 10 return "Slow moving tracks but able to go through many obstacles.").println("|\tChassis: " + chassis.getDescription()). 2 13 System. int y) { 0 System. 05 weapon = new NoWeapon(). 11 } 12 } Now we can assemble our droids First let’s create a DecoyDroid.print? 01 public class Track implements Chassis { 02 03 @Override 04 public void moveTo(int x.println("+-----------------------------------------------------6 --------------------------------------+").out.out.out."). 07 } 08 09 @Override 10 public void display() { 1 System.out.println("Don't get in my way! Moving slowly to: " + x + "." + y + 5 ".". 5 1 System. If you instantiate a DecoyDroid and call its display method you will get a nice description of it.out. 05 weapon = new LightLaserCanon().nextId).out.getDescription()).println("|\tChassis: " + chassis. 14 System. 1 System.out.println("+-----------------------------------------------------1 --------------------------------------+"). 6 +——————————————————————————————–+ Let’s build the rest of the types: ScoutDroid.java view source print? 01 public class ScoutDroid extends Droid { 02 03 public ScoutDroid() { 04 id = "SCT-" + (++Droid. 06 chassis = new Wheels(). The display() method is more elaborate than before but just to describe the droid better.18 } Examine the default constructor.println("+-----------------------------------------------------6 --------------------------------------+"). 1 System.println("| I am a SCOUT droid.println("|\tID: " + id).out.").println("|\tWeapon: " + weapon. 2 13 System. view source print? 1 2 3 4 +——————————————————————————————–+ | I am a DECOY droid. It creates an id and assigns an instance of NoWeapon and SteelStand to the droid. 5 1 System. 07 } 08 09 @Override 10 public void display() { 1 System. It makes use of the components’ descriptions too. | ID: DCY-3 | Weapon: Nothing | Chassis: Unmovable reinforced steel stand ideal for turrets and defensive 5 units. 17 } .getDescription()).out.out. out.java view source print? 01 public class AssaultDroid extends Droid { 02 03 public AssaultDroid() { 04 id = "ASS-" + (++Droid.println("+-----------------------------------------------------6 --------------------------------------+").println("|\tWeapon: " + weapon.out.getDescription()). 14 System.nextId).out. 1 System.println("|\tID: " + id).println("|\tChassis: " + chassis. 17 } 18 } You will notice that the only things needed to be implemented are the constructor – which adds the chassis and weapon – and the display() method. 07 } 08 09 @Override 10 public void display() { 1 System.out. 2 13 System.out.out. 05 weapon = new HeavyLaserCanon(). 06 chassis = new Track().println("| I am an ASSAULT droid."). 5 1 System.println("+-----------------------------------------------------1 --------------------------------------+").18 } AssaultDroid. The following diagram shows the new architecture: .getDescription()). 1 System. This is a hybrid droid created on the fly at runtime. 14 15 // shoot-out .out.println("* " + decoy. We’ll simulate 5 turns in which each droid will use its weapon and move to a random location.setWeapon(new HeavyLaserCanon()).each droid fires once per turn 16 for (int i = 1.moveToPosition(rand. 27 assailant.nextInt(10). 08 Droid assailant = new AssaultDroid().attackPosition(rand.java): view source print? 01 public class DroidSimulator { 02 03 public static void main(String[] args) { 04 // for generating random numbers 05 Random rand = new Random(). in turn 4 we give a HeavyLaserCanon to DecoyDroid.println("\n<=== BEGIN TURN " + i + " ===>"). 2 System.nextInt(10)). rand. rand.nextInt(10). 31 System. 06 07 Droid scout = new ScoutDroid(). 12 assailant.out. // we assume this 3 is an enemy position 2 scout. 13 decoy. rand. rand.getDescription() + "\n"). The simulator code (DroidSimulator. rand.println().nextInt(10).nextInt(10)).out. Look at how it changes the droid’s behaviour and it starts firing. To make it interesting. 28 System. rand. 18 // in turn 3 decoy droid is given an assault canon 19 if (i == 4) { 20 decoy.println(). 4 25 System.Let’s create a test script for it.getId() + " acquired " + 1 decoy. 30 decoy.getWeapon(). 29 decoy. Check the behaviour of each weapon and you will notice that the heavy laser will fire once every 2 turns.moveToPosition(rand. 32 } 33 } .out.moveToPosition(rand.display(). 26 assailant.attackPosition(rand.attackPosition(rand. 10 11 scout.nextInt(10). i++) { 17 System.nextInt(10).nextInt(10).out. i <= 5.display().nextInt(10)).println("<=== END TURN " + i + " ===>"). 2 } 2 2 scout.nextInt(10)).nextInt(10)).display(). 09 Droid decoy = new DecoyDroid().nextInt(10)). 24 ASS-2 > Don’t get in my way! Moving slowly to: 3.6. 1 +——————————————————————————————–+ 8 19 <=== BEGIN TURN 1 ===> 20 SCT-1 > Shooting my laser canon to 0. 0 | ID: ASS-2 9 1 | Weapon: DASS-5000 – The ultimate in siege weaponry provided by Obviam 0 Enterprises.8.34 } The output: view source print? 01 +——————————————————————————————–+ 02 | I am a SCOUT droid. 25 26 DCY-3 > No weapon equipped! 27 DCY-3 > Can’t move. 28 <=== END TURN 1 ===> 29 30 <=== BEGIN TURN 2 ===> 31 SCT-1 > Shooting my laser canon to 4.0. 0 +——————————————————————————————–+ 6 07 +——————————————————————————————–+ 08 | I am an ASSAULT droid.4) and dealt 1.5 damage.5 damage.3. 12 +——————————————————————————————–+ 13 +——————————————————————————————–+ 14 | I am a DECOY droid. very fast on flat terrain but struggling through 5 obstacles. Street use only! 0 | Chassis: 4 wheel drive.2 on my wheels! 22 23 ASS-2 > Eat this! Laser beam hit target (3.5 damage. 11 | Chassis: Slow moving tracks but able to go through many obstacles. Bang on! Done 0. 21 SCT-1 > Speeding to 0. 15 | ID: DCY-3 16 | Weapon: Nothing 1 | Chassis: Unmovable reinforced steel stand ideal for turrets and defensive 7 units.0 on my wheels! 33 34 ASS-2 > Darn! Out of ammo! Reloading… 35 ASS-2 > Don’t get in my way! Moving slowly to: 1. Bang on! Done 0. . 03 | ID: SCT-1 04 | Weapon: First generation laser canon. 32 SCT-1 > Speeding to 5. 70 ASS-2 > Don’t get in my way! Moving slowly to: 3.4) and dealt 1. 5 4 55 SCT-1 > Shooting my laser canon to 8. 46 ASS-2 > Don’t get in my way! Moving slowly to: 8.4) and dealt 1.3 on my wheels! 57 58 ASS-2 > Darn! Out of ammo! Reloading… 59 ASS-2 > Don’t get in my way! Moving slowly to: 0. Bang on! Done 0.7.9 on my wheels! 68 69 ASS-2 > Eat this! Laser beam hit target (1. with shields.5 damage. You can create a very elaborate droid. it is easy to create new weapons. 56 SCT-1 > Speeding to 2.6 on my wheels! 44 45 ASS-2 > Eat this! Laser beam hit target (9. 43 SCT-1 > Speeding to 0. Bang on! Done 0.36 37 DCY-3 > No weapon equipped! 38 DCY-3 > Can’t move. 63 <=== END TURN 4 ===> 64 65 <=== BEGIN TURN 5 ===> 66 SCT-1 > Shooting my laser canon to 1.6.1) and dealt 1. 67 SCT-1 > Speeding to 1.5 damage.5 damage. Bang on! Done 0. an array of weapons and also an AI component which .0.5 damage. 62 DCY-3 > Can’t move.6.5 damage. 50 <=== END TURN 3 ===> 51 52 <=== BEGIN TURN 4 ===> 5 * DCY-3 acquired DASS-5000 – The ultimate in siege weaponry provided by 3 Obviam Enterprises. 71 72 DCY-3 > Darn! Out of ammo! Reloading… 73 DCY-3 > Can’t move. 39 <=== END TURN 2 ===> 40 41 <=== BEGIN TURN 3 ===> 42 SCT-1 > Shooting my laser canon to 3. 47 48 DCY-3 > No weapon equipped! 49 DCY-3 > Can’t move. 60 61 DCY-3 > Eat this! Laser beam hit target (9.6. Always favour composition over inheritance in these situations. Now you should understand the null object pattern as well. sensors.0. 74 <=== END TURN 5 ===> Note in turn 4 how DecoyDroid got the new weapon and changed its behaviour (the yellow line). chassis and droids by keeping the code to a minimum.5 damage. As it stands now. To use a consistent font face across devices I have used bitmap fonts. Do not forget to check out our new Android Game ArkDroid (screenshots below). But wait! Isn’t loading an image for every character overkill? Yes it is. All we need is a bitmap containing all the characters we want to use and slice it up into individual bitmaps. The downloadable project contains only the strategy pattern implementation. Object Composition Strategies. 2011 | 11.tgz). we draw the images of the characters from the string at the given position. . each character is represented by a bitmap. Reference: Design In-game Entities. A monospaced font is a font whose letters and characters occupy the same horizontal space. because a weapon can be a melee one too and not necessarily a ranged weapon. A simple character map can look like this. It is a simple Java application. Because of that it is pretty difficult to address font related issues regarding both size and appearance on these platforms.decides what weapons to use according to the situation. That is. If you have noticed. We can use android’s utilities for manipulating bitmaps to our advantage. Part 1 – The Strategy Pattern from our JCG partner Tamas Jano from “Against The Grain” blog. In other words.215 views | Filed in: Android Games Android is an OS running on many types of devices with different screen sizes. To do this the easy way we will use a monospaced font. The simple inheritance approach is left out. You feedback will be more than helpful! 12 Android Game Development – Using Bitmap Fonts Published on September 12. We can create an image for each letter in the alphabet and number for example and whenever we want to display a text.compositions. it is not Android enabled. the characters have the same width.part1. Dowload the source here (obviam. I used the term “use” instead of fire. In the following parts I’ll try to add some AI capabilities and how to compose the final droid from images of its components. Play with it and get the grips of this useful pattern as I will use it extensively and it is considered good design. To keep things simple I have created a map of only the English alphabet. Following this it is easy to slice it up. The above character map is arranged in a grid.Note that the background is transparent. We will draw onto that. The above image shows the beginning of the first row and how the characters are organised into cells. Create a simple Android project that use simple 2D canvas. This is just for simplicity. Here are plenty of bitmap fonts to choose from. The height is 12 pixels. The resources are in fact just the images of the glyphs/characters. Note that the second row starts at 15 pixels so there is a gap between the rows. I implemented the SurfaceView to hold my canvas and called it DrawingPanel. The width of a character is 8 pixels. int x. int y) I also pass the canvas object in. . You can extend it as you wish. But for the purpose of slicing images and displaying fonts let’s stick with this approach. In its constructor I simply register it to receive events when touching the surface and load the resources. digits and a few punctuation marks. Something like this will do it: view source print? 1 void drawString(Canvas canvas. String text. In case of an OpenGL renderer we will have to use billboards (squares with textures). How can we use this? My idea to display text onto the screen is to create a drawString method that takes the text to be displayed as a parameter along with the position where we want to display it. Use a monospaced font in Photoshop or Gimp or whatever image editor you fancy and create your own sheet. A simple for iteration will do the trick. onto which I want to draw the text. It’s just a choice and also how Photoshop broke the lines and I didn’t bother to change them. // the glyphs 05 06 public DrawingPanel(Context context) { 07 super(context).decodeResource(getResources(). You’ll see later in the onTouchEvent method. 16 } 17 18 /** Loads the images of the glyphs */ 1 private void loadResources() { 9 2 this. 22 } I omitted the other methods that need to be implemented as they are just stubs.addCallback(this). The canvas variable is used to draw the text onto and is obtained at every touch event. It calls the constructor of the Glyphs class with the character sheet image copied earlier. 0 R. "Green glyphs loaded"). 08 // adding the panel to handle events 09 getHolder().glyphs_green)). The glyphs variable is instantiated in the loadResources() method. 21 Log. 13 14 // making the Panel focusable so it can handle events 15 setFocusable(true). Create the DrawingPanel class.d(TAG.Download the following image file and drag it into your eclipse’s projects resource folder under: /res/drawable-mdpi for ADP to generate the id for the resource. .Callback { 0 2 03 private Canvas canvas.glyphs = new Glyphs(BitmapFactory.drawable. // the canvas to draw on 04 private Glyphs glyphs. 10 11 // initialise resources 12 loadResources(). The most interesting class is the Glyphs class which holds the association of characters with images. view source print? 0 public class DrawingPanel extends SurfaceView implements 1 SurfaceHolder. 'z' }. 34 35 public Glyphs(Bitmap bitmap) { 36 super(). 09 10 /** 11 * @author impaler 12 * 13 */ 14 public class Glyphs { 15 16 private static final String TAG = Glyphs. 17 private Bitmap bitmap. 21 22 private int width.Canvas. 'b'. // height in pixels of one character 24 25 // the characters in the English alphabet 26 private char[] charactersL = new char[] { 'a'. 'j'. 'v'. 'K'. 27 'h'.Check out the Glyphs class: view source print? 01 package net.height = 12. 'P'. 'W'.getSimpleName().width = 8. '9'. 'Q'. // width in pixels of one character 23 private int height.graphics. 37 this. 'g'. 'M'. 'T'. 'c'. '5'.class. 'q'.graphics. 'l'.util.fonts. 'G'. 'e'. 40 // Cutting up the glyphs 41 // Starting with the first row . Bitmap>(62). 'N'. 'k'. 02 03 import java. 'F'. '0' }. 's'. 'd'.util. '7'. 'L'. 'C'. 'Z' }. 33 '8'. 'r'. 28 'u'. 'f'. 'R'.lower cases 42 for (int i = 0. 29 private char[] charactersU = new char[] { 'A'. 31 'U'. 'i'.HashMap.obviam. 'm'. 'J'. '6'. 't'. 'y'. 'X'. '4'. i++) { .util. 'w'. 'V'. 'E'. 05 06 import android. 38 this. '2'. Bitmap> glyphs = new HashMap<Character. 'O'.Log. 'I'. 'Y'. 'D'. 'B'. 04 import java. 'o'. 'S'. 'n'. // bitmap containing the character map/sheet 18 19 // Map to associate a bitmap to each character 20 private Map<Character. 39 this. 30 'H'. '3'. 08 import android.Bitmap. 'x'.Map. 'p'. i < 26. 32 private char[] numbers = new char[] { '1'. 07 import android.bitmap = bitmap. i++) { 78 Character ch = text. i++) { 57 glyphs. 30. String text.length().d(TAG. 58 0 + (i * width).drawBitmap(glyphs. height)).d(TAG. 81 } 82 } 83 } 84 } The line view source print? . 44 0 + (i * width). "Numbers initialised").createBitmap(bitmap. width. height)). "Uppercases initialised"). 79 if (glyphs.d(TAG.hardcoded 50 for (int i = 0. 47 48 // Continuing with the second row . x + (i * width). 45 } 46 Log. Bitmap. 52 0 + (i * width). i++) { 51 glyphs.createBitmap(bitmap. width. 67 } 68 69 /** 70 * Draws the string onto the canvas at <code>x</code> and <code>y</code> 71 * @param text 72 */ 73 public void drawString(Canvas canvas.get(ch) != null) { 80 canvas. "Lowercases initialised").createBitmap(bitmap. "Canvas is null"). Bitmap. 0.get(ch). height)). i < 10. 15.upper cases 49 // Note that the row starts at 15px . width.43 glyphs. 61 62 // TODO .put(numbers[i]. Bitmap.d(TAG. int y) { 74 if (canvas == null) { 75 Log. 53 } 54 // row 3 for numbers 55 Log. y. i < 26. 56 for (int i = 0. int x.put(charactersL[i].put(charactersU[i].charAt(i). null). 76 } 77 for (int i = 0. i < text. 59 } 60 Log.4th row for punctuation 63 } 64 65 public Bitmap getBitmap() { 66 return bitmap. getX().ACTION_UP) { canvas. int y) method does the drawing.getAction() == MotionEvent. (int) event. Examine carefully and understand the constructor. String text. int x.ACTION_MOVE) { // clear the screen canvas. (int) event.getAction() == MotionEvent.BLACK).1 private Map<Character. The drawString(Canvas canvas. It takes the position where to draw. "Drawn string at " + (int) event. I have created 3 arrays for the characters for which I have bitmaps. For convenience I have created an array for each row from the image.BLACK).getY()). // draw glyphs glyphs. iterates through the passed in text and draws every character progressively. It is easy to calculate the horizontal offset as each character has the same width. That is it.drawString(canvas.ACTION_DOWN || event. Bitmap>(62). glyphs. To load this up we need the bitmaps for each character.drawColor(Color.drawColor(Color. Bitmap> glyphs = new HashMap<Character. creates the map which associates a bitmap to each character. As an exercise add the punctuation array as this one is missing.drawString(canvas.getX().lockCanvas().getX() + " " + (int) event. (int) event.getAction() == MotionEvent.getX() + " " + (int) event. charactersL[] holds the lower case letters of the English alphabet. charactersU[] the upper case letters and numbers[] holds the numbers.getY(). } } } finally { if (canvas != null) { . Having a fixed width for the characters. makes all this dead easy. To associate the images with the characters I will iterate through them and cut out the respective image from the sheet based on the index. Note that the order of the characters is the same as in the character sheet. } if (event.getY(). It does the slicing and association. "Drawing string at " + (int) event.getY()). synchronized (getHolder()) { if (event. To try it out add the following method to the DrawingPanel: view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public boolean onTouchEvent(MotionEvent event) { // draw text at touch try { canvas = getHolder(). (int) event. I will publish an OpenGL version of this article at some point so stay tuned. One last thing needed is to set the DrawingPanel to be our view. That is it.onCreate(savedInstanceState). Finally we release the canvas. } Every time we touch the screen. setContentView(new DrawingPanel(this)). view source print? 01 02 03 04 05 06 07 08 09 10 public class PrintingActivity extends Activity { /** Called when the activity is first created. } } // event was handled return true. In case of a touch or drag we simply clear the canvas and draw the string onto it. Make sure you return true to signal that the event was handled. .unlockCanvasAndPost(canvas). This one is done in the activity created with the project. When we stopped touching the screen we display a slightly different text at the last position. // turn off title requestWindowFeature(Window.FEATURE_NO_TITLE). } } The resulting application should look like this: To do this with OpenGL follow the same principle and use the bitmaps for textures. we try to get hold of the canvas to be able to draw onto it. I have also disabled the title. */ @Override public void onCreate(Bundle savedInstanceState) { super.24 25 26 27 28 29 getHolder(). Using OpenGL is not much different. Android comes with a dedicated implementation of the SurfaceView interface for displaying images rendered by OpenGL. Needless to say that offloading graphics handling to a dedicated GPU is way more optimal than doing it in the CPU. You feedback will be more than helpful! 13 Android Game Development – Switching from Canvas to OpenGL ES Published on September 30. Android supports the OpenGL ES API. If you followed the articles related to displaying graphics on an android device. Let’s create the android project the usual way. we need a surface and a renderer. OpenGL is an API for writing 2D and 3D graphics that is rendered on the GPU. Most android devices have such a dedicated GPU.886 views | Filed in: Android Games It is about time we delve into the graphical capabilities of the Android platform.bitmapfont.Download the code here (obviam. We used a basic SurfaceView from which we obtained the Canvas and we drew everything onto it by calling the supported draw method from within our game loop. Do not forget to check out our new Android Game ArkDroid (screenshots below). This will free up precious computing resources on the CPU to be used for more complex physics or more entities or anything not related to graphics. you already know that in order to display graphical elements.gz). There are a few notions that need to be understood but I will introduce them when we will bump into them during the course. . Reference: Using Bitmap Fonts in Android from our JCG partner Tamas Jano from “Against The Grain” blog. 2011 | 19.tar. New Project Wizard I call the activity simply Run. Check what the wizard has generated and it should look like this: view source print? 1 2 3 4 public class Run extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { . 5 6 7 8 super.onCreate(savedInstanceState); setContentView(R.layout.main); } } Nothing special. Creating the OpenGL renderer Let’s build the renderer. Create a class GlRenderer which implements the android.opengl.GLSurfaceView.Renderer interface. It will look like this: view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class GlRenderer implements Renderer { @Override public void onDrawFrame(GL10 gl) { } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { } } We need to implement the above 3 methods. Currently they are empty and do nothing. The methods onSurfaceCreated(GL10 gl, EGLConfig config)created or recreated. It is important to bear the recreated bit in mind as it means every time the device goes to sleep for example and awakes, the surface gets recreated. Because the context which holds the resources gets destroyed too, this is the place where we will load our resources (images for textures, etc). onSurfaceChanged(GL10 gl, int width, int height) is called whenever the surface size changes. This mainly affects our viewport. The viewport is just a rectangular region through which we see our game world. onDrawFrame(GL10 gl) is called by the rendering thread to draw each frame. This is where all the drawing happens. We don’t need to call it explicitly. A rendering thread is created by android for us and that will call it. Let’s switch to the OpenGL renderer. Check out the new Run activity. view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package net.obviam.opengl; import android.app.Activity; import android.opengl.GLSurfaceView; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; public class Run extends Activity { /** The OpenGL view */ private GLSurfaceView glSurfaceView; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // requesting to turn the title OFF requestWindowFeature(Window.FEATURE_NO_TITLE); // making it full screen getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // Initiate the Open GL view and // create an instance with this activity glSurfaceView = new GLSurfaceView(this); // set our renderer to be the main renderer with // the current activity context glSurfaceView.setRenderer(new GlRenderer()); setContentView(glSurfaceView); } 35 36 37 38 39 40 41 42 43 44 45 46 47 48 /** Remember to resume the glSurface */ @Override protected void onResume() { super.onResume(); glSurfaceView.onResume(); } /** Also pause the glSurface */ @Override protected void onPause() { super.onPause(); glSurfaceView.onPause(); } } In line 12 we declare a GLSurfaceView member variable. This is our OpenGL view provided by android. When we instantiate it (line 27) we have to make it context aware. That is, for the view to have access to the application environment. All we need to do is to add our renderer to this view. This we do in line 31. Line 32 tells the activity to use our OpenGL view. The onResume() and onPause() methods are being overridden and trigger the respective methods in our view. You can run the application as an Android app and you should see a blank black screen. That is it. We have switched from the canvas to the OpenGL renderer. Download the source code and eclipse project here (obviam.opengl.p01.tgz) Reference: OpenGL ES with Android Tutorial- Switching from Canvas to OpenGL from our JCG partner Tamas Jano from “Against The Grain” blog. Do not forget to check out our new Android Game ArkDroid (screenshots below). You feedback will be more than helpful! 14 Android Game Development – Displaying Graphical Elements (Primitives) with OpenGL ES Published on October 3, 2011 | 2,586 views | Filed in: Android Games This is part 2 of the android OpenGL ES series. In the previous article we looked at how to set up the android project to use the provided OpenGL view with our renderer. You can use the project from that article as a template for this. Before we start displaying things, we must know a few basic concepts of 3D programming and also familiarise ourselves with the terminology. I’s basic geometry really. 3D graphics happens in the Cartesian Coordinate System. That means that the coordinate system used has three dimensions. X, Y and Z. Traditionally X goes from left to right, Y from bottom to top, and Z from me into the screen so to speak. While we deal with objects to display (a robot for example or a car) OpenGL deals with components of these objects. Each object is created from primitives which in the case of OpenGL is a triangle. Every triangle has a face and a backface. A triangle is defined by 3 points in space. A point is called a vertex (vertices plural). The following diagram shows 2 vertices. A and B. Vertices I drew this diagram to show how we will differentiate between 2D and 3D. A vertex is defined by its X, Y and Z coordinates. If we use 0 for the Z component all the time, we have 2D. You can see vertex A is part of the plane defined by X and Y. Vertex B is farther in on the Z coordinate. If you think of Z as a line being perpendicular to the screen, we wouldn’t even see B. A triangle is called a primitive. A primitive is the simplest type OpenGL understands and is able to graphically represent. like quads but we’ll stick to the basics. The coordinates of the vertices is not measured in pixels. then it means that the second side is half the length of the first side’s length. When we use 2D then it means that the . let’s create a triangle and draw it. Clockwise order of the vertices means it is a backface (the red triangle). We will use float to represent the values and they will be relative to each other.5f. This is the default setting but it can be changed of course. Creating and Drawing a Triangle With all the theory understood. the player and parts facing away from you. A triangle is defined by 3 vertices. This is called backface culling. Imagine the viewport as a camera. There are other primitives as well. If the order is counter clockwise then it is a face (green triangle). The following diagram illustrates just that. How does OpenGL determine this? This is determined by the order of the vertices when drawing the triangle. Why is it important? In 3D you will have objects with parts facing towards you. We mentioned the face of the triangle before.0f and an other side’s length is 0. Backface Culling The red triangle won’t be drawn. In order to make the drawing efficient. OpenGL will not draw the triangles facing away from you as it is not necessary because they will be hidden by the triangles facing towards you anyway. If a side’s length is 1. 3 vertices define a triangle.It is very simple. Every shape can be broken down into triangles. How big it will be displayed depends on how the viewport is set up. GL10.nio.position(0).0f // V3 . 0. if it’s far.second vertex 16 0.5f. 08 09 public class Triangle { 10 11 private FloatBuffer vertexBuffer.z) 15 0.allocateDirect(vertices.0f.ByteOrder.y. 18 19 public Triangle() { 20 // a float has 4 bytes so we allocate for each coordinate 4 bytes 2 ByteBuffer vertexByteBuffer = ByteBuffer. 2 vertexByteBuffer.put(vertices).nio.5f. 2 23 24 // allocates the memory from the byte buffer 25 vertexBuffer = vertexByteBuffer. 0.camera is orthogonal to the screen.obviam. the triangle will appear big. // buffer holding the vertices 12 13 private float vertices[] = { 14 -0. 29 30 // set the cursor position to the beginning of the buffer 31 vertexBuffer. 26 27 // fill the vertexBuffer with the vertices 28 vertexBuffer. 05 import java. .5f. 06 07 import javax.opengles.nativeOrder()).asFloatBuffer().first vertex (x. then the triangle will be small. -0. // V1 .0f.length * 1 4).5f. 0. view source print? 01 package net.microedition.nio. 32 } 33 } Line 11 defines a FloatBuffer that will hold the vertices for our triangle.5f. 0. Let’s create the Triangle class.ByteBuffer. 02 03 import java. // V2 . We need to use the java.third vertex 17 }. 04 import java.order(ByteOrder.opengl.khronos. If the camera is very close.0f. -0.FloatBuffer.nio package as it is very intensive input output. we fill the vertexBuffer with the coordinates and set the cursor’s position to the beginning of the buffer.opengl. We calculate everything from the origin.khronos.opengles.The vertices[] array holds the actual coordinates for the vertices. // the triangle to be drawn 12 13 /** Constructor */ 14 public GlRenderer() { .egl. The triangle we will draw is represented in the following diagram.GL10.obviam. 08 09 public class GlRenderer implements Renderer { 10 11 private Triangle triangle. We will be using this buffer in the OpenGL call to display triangle strips. 05 06 import android.GLU.Renderer.khronos. Triangle In the constructor we initialise the triangle from this vertices[] array. 02 03 import javax.opengl.GLSurfaceView. The GlRenderer view source print? 01 package net.microedition. What we do is. We currently have just one. 07 import android. 04 import javax.microedition.opengl. Let’s take a look at the renderer.EGLConfig. 22 23 // Reset the Modelview Matrix 24 gl.glClear(GL10.glMatrixMode(GL10. 25 26 // Drawing 27 gl.0f). // move 5 units INTO the screen 28 // is the same as moving the camera 5 units away 29 triangle.GL_MODELVIEW). . 0. width.GL_DEPTH_BUFFER_BIT). //Select The Projection Matrix 41 gl.triangle = new Triangle(). The onDrawFrame(GL10 gl) is of the most interest for us.glLoadIdentity().0f.0f). //Reset The Current Viewport 40 gl. //Making Height Equal One 37 } 38 39 gl. 45. //Reset The Projection Matrix 42 43 //Calculate The Aspect Ratio Of The Window 44 GLU.glTranslatef(0. height). 0. //Select The Modelview Matrix 47 gl.GL_PROJECTION).1f. 16 } 17 18 @Override 19 public void onDrawFrame(GL10 gl) { 20 // clear Screen and Depth Buffer 21 gl. int height) { 35 if(height == 0) { //Prevent A Divide By Zero By 36 height = 1.gluPerspective(gl. 0. // Draw the triangle 30 31 } 32 33 @Override 34 public void onSurfaceChanged(GL10 gl. (float)width / (float)height.glMatrixMode(GL10. 45 46 gl. int width.15 this. 100. //Reset The Modelview Matrix 48 } 49 50 @Override 51 public void onSurfaceCreated(GL10 gl.GL_COLOR_BUFFER_BIT | GL10. Every method we call on the OpenGL context changes its internal state.0f. EGLConfig config) { 52 } 53 } We create the triangle in the constructor.glLoadIdentity().draw(gl).glLoadIdentity().0f. -5.glViewport(0. OpenGL works with state variables. // Point to our vertex buffer gl. Note that the values of the rgb are floats and are between 0.glColor4f(0. Line 02 does just that. GL10.GL_TRIANGLE_STRIP.length / 3).GL_FLOAT.GL_FLOAT. First it sets the viewport to the current width and height of the surface (so it works with the GL_PROJECTION state). The onSurfaceChanged on the other hand. 0. . GL10. vertexBuffer). our vertices follow each other and there is no offset. transitions the OpenGL context between a few states. 0. 1. 0. then it transitions the state to the GL_MODELVIEW so we can work with our models – the triangle in our case.glDisableClientState(GL10. Because we don’t store extra data. the ModelView matrix is reloaded (don’t worry if you don’t understand this at the moment). gl.0f. the camera is moved away 5 units (we’re dealing with units here. the buffers get cleared.GL_VERTEX_ARRAY). not pixels) and the triangle’s draw() method is called.0. // Draw the vertices as triangle strip gl. don’t worry.GL_VERTEX_ARRAY). Line 05 sets the colour for the entity (triangle in our case) that will be drawn.0 and 1.glEnableClientState(GL10. vertexBuffer).0f. Let’s check out the draw method for the triangle: view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 public void draw(GL10 gl) { gl.glVertexPointer(3. The second lets OpenGL know what type the data the buffer holds. //Disable the client state before leaving gl. The first parameter (value = 3) represents the number of vertices in the buffer. It will make sense later on. vertices.glVertexPointer(3. will tell OpenGL to use the vertexBuffer to extract the vertices from. // set the colour for the triangle gl. } Because we store the triangle’s vertices’ coordinates in a FloatBuffer we need to enable OpenGL to read from it and understand that is a triangle there.0f.glDrawArrays(GL10. The third parameter is the offset in the array used for the vertices. 0. 0.Following the onDrawFrame method we see that every time a frame is drawn.5f). GL_TRIANGLE_STRIP.p02.opengl. Just like this: Download the source here (obviam.length / 3). Run the project and you should be able to see your first accelerated triangle. starting with the first element. It also lets it know how many vertices there are. We will also find out how we can use textures on elements. vertices.glDrawArrays(GL10. tells OpenGL to draw triangle strips found in the buffer provided earlier. That is it. gl. Reference: OpenGL ES Android – Displaying Graphical Elements (Primitives) from our JCG partner Tamas Jano from “Against The Grain” blog. 0.tgz): I was inspired by code from the nehe android ports.Finally the last parameter is our buffer containing the vertices. Do not forget to check out our new Android Game ArkDroid (screenshots below). You feedback will be more than helpful! 15 . To learn the guts of OpenGL I warmly recommend the nehe tutorials. Next we will see how we can create basic 3D objects and rotate them. 2011 | 17. The square is ABDC instead of the usual ABCD. We’ll cover 3D later. In the previous articles we managed to display triangles. How to display a square then? A square is composed of 2 triangles. Now let’s take it further and build on them. This is very useful to use in 2D games and is the preferred way to display images using OpenGL. Why is that? Because of how OpenGL chains triangles together. In this article we will create a billboard (which is a square) and we will apply a texture onto it. It is very fast indeed. A texture is nothing more than a bitmap image. The following diagram shows you this: Square from Triangles There is an interesting thing to note here. OpenGL draws the following triangle strip (which is a square) using the vertices in the following order: Triangle 1: V1 -> V2 -> V3 Triangle 2: V3 -> V2 -> V4 .Android Game Development – OpenGL Texture Mapping Published on October 6. What you see here is a triangle strip. A triangle strip is a series of connected triangles.582 views | Filed in: Android Games In the previous two articles (article 1 and article 2) I have tried to introduce OpenGL ES on android. When we work in 2D we set the Z coordinate to 0. 2 triangles in our case. 0f.0f.nio.bottom right 17 1. 06 07 import javax.ByteBuffer. Grab the project from the previous article and create a new class called Square. 0.khronos.0f.0f. 1.opengl. -1.0f.nio.obviam. 08 09 public class Square { 10 11 private FloatBuffer vertexBuffer.top left 16 1. -1.0f. 05 import java.microedition. // V2 .0f.FloatBuffer. // V1 .GL10. 02 03 import java.0f.0f. 0. you will notice just one difference: view source print? 01 package net. 1.nio. 04 import java. // V3 . then it takes the last vertex from the previous triangle and uses the last side of the triangle as the basis for the new triangle. If you compare the Square class with the Triangle class.Triangle Strip It draws the first triangle using the vertices in order. This also has benefits: we eliminate redundant data from the memory.top right 18 }. 0.opengles.0f // V4 . . 0.0f.bottom left 15 -1.ByteOrder.0f. // buffer holding the vertices 12 13 private float vertices[] = { 14 -1. GL10. 33 } 34 35 /** The draw method for the square with the GL context */ 36 public void draw(GL10 gl) { 37 gl.length / 3). 02 03 import javax.asFloatBuffer(). vertexBuffer).5f).microedition.GL_VERTEX_ARRAY).khronos. 30 31 // set the cursor position to the beginning of the buffer 32 vertexBuffer.order(ByteOrder. 1.nativeOrder()). 0.GL_FLOAT. 44 45 // Draw the vertices as triangle strip 46 gl. 0. 23 vertexByteBuffer. 0.position(0). That’s right.length * 2 4). view source print? 01 package net. vertices.glDisableClientState(GL10.glVertexPointer(3.obviam.GL_TRIANGLE_STRIP.EGLConfig.egl.GL_VERTEX_ARRAY).allocateDirect(vertices. 41 42 // Point to our vertex buffer 43 gl. 38 39 // set the colour for the square 40 gl. Now change the GlRenderer so instead of a Triangle we use a Square.19 20 public Square() { 2 // a float has 4 bytes so we allocate for each coordinate 4 bytes 1 2 ByteBuffer vertexByteBuffer = ByteBuffer.glColor4f(0. 47 48 //Disable the client state before leaving 49 gl. .0f.put(vertices). 27 28 // fill the vertexBuffer with the vertices 29 vertexBuffer.glEnableClientState(GL10.0f. 24 25 // allocates the memory from the byte buffer 26 vertexBuffer = vertexByteBuffer.glDrawArrays(GL10. 0. we’ve added one more vertex to the vertices array.0f. 50 } 51 } The difference is in the highlighted lines (13-18).opengl. gluPerspective(gl. 07 import android.square = new Square(). 25 26 // Drawing 27 gl.0f.glLoadIdentity().opengl. (float)width / (float)height. //Reset The Modelview Matrix 48 } 49 50 @Override .0f).draw(gl). 0. //Select The Projection Matrix 41 gl.0f.0f).GL10.GL_COLOR_BUFFER_BIT | GL10. 100.GL_DEPTH_BUFFER_BIT). width. height).glClear(GL10. 16 } 17 18 @Override 19 public void onDrawFrame(GL10 gl) { 20 // clear Screen and Depth Buffer 21 gl. 0.0f. int width.04 import javax.1f. //Reset The Current Viewport 40 gl.khronos. //Making Height Equal One 37 } 38 39 gl.GLU.glMatrixMode(GL10. 08 09 public class GlRenderer implements Renderer { 10 11 private Square square. 45. 45 46 gl.glLoadIdentity().GL_PROJECTION).GLSurfaceView.glViewport(0.GL_MODELVIEW). -5. 0. // move 5 units INTO the screen 28 // is the same as moving the camera 5 units away 29 square. 22 23 // Reset the Modelview Matrix 24 gl. // the square 12 13 /** Constructor to set the handed over context */ 14 public GlRenderer() { 15 this. //Select The Modelview Matrix 47 gl.Renderer. 05 06 import android.opengl.glTranslatef(0.opengles.microedition. // Draw the triangle 30 31 } 32 33 @Override 34 public void onSurfaceChanged(GL10 gl. //Reset The Projection Matrix 42 43 //Calculate The Aspect Ratio Of The Window 44 GLU.glMatrixMode(GL10. int height) { 35 if(height == 0) { //Prevent A Divide By Zero By 36 height = 1.glLoadIdentity(). 0. //Disable the client state before leaving gl.GL_FLOAT.0f.51 public void onSurfaceCreated(GL10 gl. } .GL_VERTEX_ARRAY). vertices. 0. 1.5f).GL_TRIANGLE_STRIP.glDrawArrays(GL10.glColor4f(0. // set the colour for the square gl. // Draw the vertices as triangle strip gl.glDisableClientState(GL10.glVertexPointer(3. view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 public void draw(GL10 gl) { gl.glEnableClientState(GL10. 0. EGLConfig config) { 52 } 53 } Running this will produce the following result: Triangle Strip forming a Square Examining this. 0.length / 3). GL10. // Point to our vertex buffer gl.GL_VERTEX_ARRAY). vertexBuffer).0f. the draw() method in the Square class should make sense now.0f. z). . gl. the colour. Think of glEnableClientState and glDisableClientState as begin … end statements in a program. Let’s load up an image and create a texture. Creating the Texture Now the fun part. check out this article. The 3rd parameter is the offset between the vertices in the array.glDrawArrays in line 11 tells OpenGL to draw the primitive. It takes the vertices from the previously set vertex buffer and it follows the rules of the triangle strips described earlier.glVertexPointer) we specified that 3 coordinates define a vertex.glVertexPointer (line 5) tells the opengl renderer from where to take the vertices and of what type they are. Once we entered a routine. Our vertex array contains the vertices for our square.y. Make sure you run the application at this stage and understand what is going on. glDisableClientState(GL10. What kind of primitive? The one specified in the first parameter: GL10. The first parameter tells how many coordinates are used for a vertex. we will provide the length of our vertex array divided by 3. Of course it is our buffer vertexBuffer. etc) and we execute other subroutines (draw vertices). There are 9 elements in the array defining 3 vertices. We need to load up the image. We work in isolation inside the renderer.First we enable OpenGL to use a vertex array for rendering. We will be working with the Square class as we want to apply the texture to the square.GL_VERTEX_ARRAY) disables the state of rendering from an array containing the vertices. we exit the subroutine. To find out how you can load up images in your android app. we set up variables (the vertex buffer. about to be rendered. tell the opengl renderer that we want to use it as a texture. Finally the last parameter tells where the vertices are held. The second parameter specifies the starting index for the vertices in the array. A texture IS an image. After we’re done. gl. and finally we will tell the renderer where exactly onto our primitive (square) to display it.GL_TRIANGLE_STRIP. It is called the strife. The 3rd parameter tells OpenGL. how many vertices to use for the polygon. We use 3 (x. We basically enter subroutines in the OpenGL renderer. Because in the previous statement (gl. We have a tightly packed array so it is 0. The second parameter tells that the values are of type float. allocateDirect(vertices.position(0). Check the new constructor: view source print? 01 public Square() { 02 ByteBuffer byteBuffer = ByteBuffer.length * 4). 10 textureBuffer = byteBuffer.put(texture). 11 textureBuffer. let’s get to work.0f. 04 vertexBuffer = byteBuffer.position(0). // buffer holding the texture coordinates 2 private float texture[] = { 3 // Mapping coordinates for the vertices 4 0.asFloatBuffer().put(vertices). 05 vertexBuffer.0f. 0. view source print? 1 private FloatBuffer textureBuffer.Think of it as if you were putting a foil onto a window or a wall.order(ByteOrder. It happens in the onSurfaceCreated method.nativeOrder()). // top left (V2) 5 0. The loadGLTexture method. But this time. 1. 12 textureBuffer. 03 byteBuffer. // bottom left (V1) 6 1.0f // bottom right (V3) 8 }. I provide you with a foil containing an image of the size of the window and tell you to cover the window with it. This will be called from the renderer when it starts up.0f. We need to create the textureBuffer in a similar way to the vertexBuffer. a flat plane. . 13 } We will add an important method to the Square class. That is it. 1. this will be 2D as a bitmap is like a sheet of paper. 06 vertexBuffer.0f. so the top left corner of the foil will be on the top left corner of the window.asFloatBuffer(). 0.allocateDirect(texture. It will basically assign an internal ID for the processed image and will be used by the OpenGL API to identify it among other textures. // top right (V4) 7 1. This happens in the constructor and we’ll just reuse the byteBuffer. So we need to create an array for the image. This will load up the image from the disk and bind it to a texture in the OpenGL repository. 09 byteBuffer.nativeOrder()).0f. Add the coordinate array for the texture. OpenGL uses the vertices to work out where to put stuff.0f.order(ByteOrder. 07 08 byteBuffer = ByteBuffer.length * 4).0f. GL_TEXTURE_MAG_FILTER. 16.drawable. 128×128. 11 // .glTexParameterf(GL10. 03 04 public void loadGLTexture(GL10 gl.glGenTextures(1. textures[0]).glTexParameterf(GL10. 1 7 1 // Use Android GLUtils to specify a two-dimensional texture image from our 8 bitmap 19 GLUtils. A note about this bitmap. It is encouraged to be square. 08 09 // generate one texture pointer 10 gl. . Context context) { 05 // loading texture 06 Bitmap bitmap = BitmapFactory.texImage2D(GL10.GL_TEXTURE_2D. 6 GL10. 07 R. 0). 5 GL10. bitmap. 1 gl. 0).getResources(). 32. GL10.GL_TEXTURE_2D. make sure the width and height are powers of 2 (2.and bind it to our array 12 gl.GL_TEXTURE_2D.).GL_LINEAR). so the ID is already generated. 12×12. 13 14 // create nearest filtered texture 1 gl.GL_TEXTURE_2D. we will create an array of size 1. 8. 23 } We need a texture pointer array. You can have a bitmap 128×512 and it is perfectly usable and it is optimised. 4. but it is how it is.decodeResource(context..recycle(). etc. Line 06 loads the android bitmap which was previously copied into the /res/drawable-mdpi directory.view source print? 01 /** The texture pointer */ 02 private int[] textures = new int[1].android).. So make sure your bitmaps for textures are squares (6×6. GL10. Because we have just one image. Even if it says name. A bit confusing. 0. In our case generates one name and stores it in the textures array. This is where OpenGL will store the names of the textures we will use in our application. Line 10 generates the names for the textures.GL_NEAREST). If not square. 20 21 // Clean up 22 bitmap.glBindTexture(GL10. it actually generates an int. It helps a lot with scaling. textures.GL_TEXTURE_MIN_FILTER. …). length / 3). textureBuffer).glBindTexture(GL10. If we would have had multiple textures and multiple squares to use them. that anything using textures in this subroutine. It creates the image (texture) internally in its native format based on our bitmap. We have chosen some basic algorithms on how to scale the image. We have just told OpenGL what types of filters to use when it needs to shrink or expand the texture to cover the square. GL10.glTexCoordPointer(2. // Point to our buffers gl. vertices. 0. // Point to our vertex buffer gl. In line 19 we use Android’s utilities to specify the 2D texture image for our bitmap.glEnableClientState(GL10. //Disable the client state before leaving gl.GL_FLOAT.Line 12 binds the texture with the newly generated name (texture[0]).glDisableClientState(GL10. gl.GL_TEXTURE_COORD_ARRAY). in line 22 we free up the memory. will use the bound texture.glFrontFace(GL10. we would have had to bind (activate) the appropriate textures for each square just before they were used to activate them.glVertexPointer(3. } } It’s not a huge modification from the previous article.GL_TEXTURE_2D. Lines 15 and 16 set some filters to be used with for texture.GL_CW). view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public void draw(GL10 gl) { // bind the previously generated texture gl. textures[0]).GL_FLOAT. gl.glEnableClientState(GL10. A bound texture is the active texture. gl. GL10. 0. // Draw the vertices as triangle strip gl.GL_TEXTURE_COORD_ARRAY).glDisableClientState(GL10. It practically activates the texture.GL_VERTEX_ARRAY). Now let’s see how the draw() method has been modified. // Set the face rotation gl. Don’t have to worry about this now. What this means is. vertexBuffer). This you should not forget as memory on a device is very limited and images are big. 0.glDrawArrays(GL10.GL_VERTEX_ARRAY).GL_TRIANGLE_STRIP. The additions are documented and do the following: . The texture coordinates will be in the order: 1 -> 3 -> 2 -> 4 Just bear this mapping in mind and rotate it if you start your shape from a different corner.blogspot. the vertex order in the texture mapping coordinates array doesn’t follow the order present in the square’s vertex coordinates array.com/2009/05/opengl-es-from-ground-up-part-6_25. There is a very good explanation of texture mapping coordinates here: http://iphonedevelopment. Line 07 enables the texture mapping in the current OpenGL context. Important – UV Mapping If you look carefully.html.Line 03 binds (activates) the texture with the name (integer ID) stored in textures[0]. I will try to explain it quickly though. To read up on UV mapping check the wikipedia entry or search the net for it. Examine the following diagram. 1 – bottom left 2 – bottom right 3 – top left 4 – top right Notice the counter clockwise path. Square and Texture Coordinates Ordering The square is composed of 2 triangles and the vertices are in the following order. After drawing the primitive with textures. we switch off the texture mapping along with the primitive rendering. . Line 14 provides the OpenGL context with the texture coordinates. because the object itself loads the texture and needs to know the path to the bitmap. view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 public void onSurfaceCreated(GL10 gl. 03 04 /** Constructor to set the handed over context */ 05 public GlRenderer(Context context) { 06 this. this. //Depth Buffer Setup gl. //Enable Smooth Shading gl. //Black Background gl. // the square 02 private Context context.loadGLTexture(gl.0f. Make sure the renderer has the context declared and set via the constructor.For the final part.glClearDepthf(1.GL_NICEST). //Enables Depth Testing gl. view source print? 01 private Square square.) and it’s done. 07 .GL_TEXTURE_2D).glHint(GL10. 0. Excerpt from the GlRendered class.GL_LEQUAL).glDepthFunc(GL10.GL_DEPTH_TEST). 0. gl. 0. //Enable Texture Mapping ( NEW ) gl. GL10.glClearColor(0.0f. You will need to provide the application context to the Square object. The onSurfaceCreated method will look like this. //The Type Of Depth Testing To Do //Really Nice Perspective Calculations gl.5f). You don’t have to worry about them now. EGLConfig config) { // Load the texture for the square square. Just provide the context to the renderer in the Run activity’s onCreate method (glSurfaceView.glShadeModel(GL10. we need to provide the context to our renderer so we can load up the texture at startup.glEnable(GL10. The rest of the lines just configure the renderer with some values.setRenderer(new GlRenderer(this)).0f.GL_SMOOTH).glEnable(GL10. to make this work.GL_PERSPECTIVE_CORRECTION_HINT. } Line 03 loads the texture.0f).context).context = context. You feedback will be more than helpful! 16 Android Game Development – Design Ingame Entities – The State Pattern Published on October 7. Square with Android Texture Download the source code and project here (obviam.tgz). An internal state is best described as being the soul and mind of the entity.p03.opengl.08 09 10 // initialise the square this. In the first part I described why composition is better than inheritance. } If you run the code you should see the square with a nice android laid on top of it. 2011 | 2.square = new Square().739 views | Filed in: Android Games In this part I will try to explain how to design easily extensible and maintainable game elements that control their own internal state and behaviours. In a nutshell composition provides the . Do not forget to check out our new Android Game ArkDroid (screenshots below). Reference: Texture Mapping – OpenGL Android (Displaying Images using OpenGL and Squares) from our JCG partner Tamas Jano from “Against The Grain” blog. like weapons. Let’s see it on paper: Initial Rifle State Diagram Let’s examine the diagram and figure out what it is and what is that we want. Breaking it down. The rifle behaves in certain ways depending in which state it is in and some action is needed to take it to another state. Each state is just a different configuration of the rifle. to go to another state. I strongly suggest to go and check out the previous article as I will be picking up those droids and make them utterly clever during the next articles. See the arrows on the diagram. Now think of all the scenarios. you will need to do something like pull the trigger or insert clip. State on the other hand helps objects to control their own behaviors. So. What happens if I pull the trigger and there is no clip? Or when there is one but it’s empty? Apparently a simple thing became a bit more complicated.means to interchange the algorithms associated with their behaviours. We identify the following states: . Let’s design an old fashioned rifle and learn from the process how to design the next gen weapons to fend off the invading droid army. If you are not familiar with the behaviors and strategies. eject the ammo clip). The above diagram is called a State Diagram. Each of those circles is a State and each of those arrows is a State Transition. But first we need to take a closer look to how I design less clever entities. what can one do with a rifle? Pull the trigger of course and reload (insert. The whole thing described above is also called a Finite State Machine. what would be our first choice for the implementation? A class that has all the possible states and actions. 08 09 int state = NO_CLIP. right? It should also hold the current state. Our First Implementation Knowing all this. Create the Rifle. view source print? 01 public class Rifle { 02 03 // defining the states 04 final static int NO_CLIP = 0. // instance variable holding the current state 10 int ammoCount = 0. // we count the ammo . No Clip  Has Clip  Ammo fired  Out of Ammo and actions (transitions):  inserts clip  ejects clip  pulls trigger  fire ammo Note: I used third person for 3 of the actions. 07 final static int OUT_OF_AMMO = 3. Simple. 06 final static int AMMO_FIRED = 2. 05 final static int HAS_CLIP = 1. It is because the user of the weapon will trigger these actions while fire ammo is more of an internal action. It is nothing more than an object that holds a finite number of states that govern behaviour and the object can be in only one state at any given time.java class. view source print? 01 // ********************** 02 // Creating the actions 03 // ********************** 04 05 public void insertClip() { 06 // We check each possible state and act according to them 07 if (state == HAS_CLIP) { 08 System. But beware! Exposing all the actions to someone handling the weapon is dangerous.println("There is already a clip loaded. 09 } else if (state == AMMO_FIRED) { 10 System.11 } Great! We created the structure of the rifle.").println("The magazine is empty.println("Use up all your ammo first.")."). 25 } else if (state == HAS_CLIP) { 26 // You could still eject it if you want but for the sake of 27 // simplicity let's use up the ammo first 28 System. Now let’s add the actions. 32 } 33 } . so we added the ammoCount variable.out. 23 } else if (state == AMMO_FIRED) { 24 System. The rifle holds no clip thus the ammo is 0 when it is created. 1 ammoCount = 10. 17 } 18 } 19 20 public void ejectClip() { 21 if (state == NO_CLIP) { 22 System.println("You have unloaded a clip.println("You have loaded a clip with " + ammoCount + " 6 bulletts. 29 } else if (state == OUT_OF_AMMO) { 30 state = NO_CLIP. We also want to know when we are out of ammo. 13 } else if (state == NO_CLIP) { 14 state = HAS_CLIP. 5 1 System.out.out.println("You'll hurt yourself!!!").println("You need to take out the empty clip first.")."). 31 System. They are set to default values.out. 11 } else if (state == OUT_OF_AMMO) { 12 System.println("You'll hurt yourself!!!").out.out.out.out. What will happen when someone tries to pull out the clip while firing? We need to take these into consideration when triggering the actions."). out. 40 } else if (state == OUT_OF_AMMO) { 41 System.out.println("Bullet already on its way to kill someone!"). 44 state = AMMO_FIRED. 65 } else { 66 state = HAS_CLIP. it's empty 63 System.println("Out of ammo. 59 System.println("Empty magazine. 60 // we check if the clip is empty 61 if (ammoCount == 0) { 62 // yes. 56 } else if (state == HAS_CLIP) { 57 state = AMMO_FIRED.println("Bullet on its way!").34 35 public void pullTrigger() { 36 if (state == NO_CLIP) { 37 System. 64 state = OUT_OF_AMMO. 52 } else if (state == AMMO_FIRED) { 53 System.out.out. 42 } else if (state == HAS_CLIP) { 43 System.println("Jammed!"). view source print? 01 02 03 04 public class RifleTest { public static void main(String[] args) { Rifle rifle = new Rifle().println("Darn! Out of ammo").java class.out.out.println("Empty Click!"). 45 fireAmmo().println("Click! Out of ammo. 46 } 47 } 48 49 public void fireAmmo() { 50 if (state == NO_CLIP) { 51 System. 38 } else if (state == AMMO_FIRED) { 39 System. 54 } else if (state == OUT_OF_AMMO) { 55 System.").out.").out. 67 } 68 } 69 } Let’s put the rifle to the test.").out.println("BANG!!!"). 58 ammoCount--. Create the RifleTest. . As when trying to force in a second clip or pulling the trigger when it’s out of ammo. 03 > BANG!!! 04 > Bullet on its way! 05 > BANG!!! 06 > Bullet on its way! 07 > BANG!!! 08 > Bullet on its way! 09 > Darn! Out of ammo 10 !* Click! Out of ammo. System. Some may be good some bad. rifle. rifle. Check out the result and examine it carefully. rifle. } } It is a very simple scripted scenario which performs some actions on the rifle. 14 !* Empty Click! – No clip! Note that I have omitted the toString() method for the Rifle.pullTrigger(). 11 << RIFLE [state=Out of Ammo. rifle. ammo=0] >&g.pullTrigger().out. Well done! We have our first state machine. But . view source print? 01 << RIFLE [state=Empty Magazine (No Clip).pullTrigger().println(rifle).t 12 !* You need to take out the empty clip first.insertClip().println(rifle).ejectClip(). ammo=0] >> 02 > You have loaded a clip with 3 bullets.pullTrigger(). rifle.pullTrigger(). How cool is that? We are the Kalashnikovs of our age. rifle. rifle.out.05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 System.insertClip(). 13 > You have unloaded a clip. rifle. that’s easy. right? We’ll have a few more states and a few more transitions. Flipping the switch changes the behaviour. Both states will have . We need automatic fire! Oh. It basically has a sub-state now. It must be some other way. Let’s see how does it look? Final Rifle State Diagram What you should notice is that the Has Clip is now Manual/Auto and has a switch transition. The Solution What if we give each state a behaviour and put it into its own class? This way each state will implement its own actions only. we will need to rework the Rifle class a bit. But wait. We will have the rifle class delegating the action to the state object that represents the current state. and we can’t just let people running around with rifles without the safety ON.We can’t do much firing bullet by bullet. Ah. Let’s see what we need to modify just to support automatic and manual fire:  we need to add the two states  but then we need to modify every single method to handle the states by adding conditional statements  pullTrigger() will get complicated as it will need to know what state it is in and check bullets and fire them as such That is a LOT of work. java view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 public class Rifle { // the states of the rifle RifleState emptyState. First. RifleState ammoFiredState. RifleState manualFireState. but will have all the states and will delegate the actions to its current state. } The new Rifle class will have none of the implemented actions.the pull trigger action but each state will behave differently. let’s create the state interface. Remember. public void pullTrigger(). This is easily achieved with interfaces. right? Let’s start coding then. // constructor public Rifle() { // creating states this. int ammoCount = 0. RifleState state = emptyState.emptyState = new NoClipState(this). public void swithManualAuto(). public void ejectClip(). RifleState autoFireState. each state will implement its transition and will provide the dummy implementation for the rest. The methods map directly to all the actions that can happen with the Rifle view source print? 1 2 3 4 5 6 7 8 public interface RifleState { public void insertClip(). RifleState outOfAmmoState. Rifle. The interface will contain all the actions. . RifleState roundFiredState. public void fireAmmo(). ammoCount = 0.state. } public void ejectClip() { this. It has a constructor too. The constructor is needed to set up the rifle and pass itself as a reference to all of the states to give them access to the rifle’s properties. It has all the states and a current state.state. this.ejectClip().autoFireState = new AutoFireState(this).ammoFiredState = new AmmoFiredState(this). . this. Examine the source code for the complete listings. Also the fireAmmo() is missing as it is a state internal action. omitted } You see that the class has changed a bit.state.java view source print? 01 public class OutOfAmmoState implements RifleState { 02 03 private Rifle rifle.state.delegating only public void insertClip() { this..manualFireState = new ManualFireState(this). this. } public void switchManualAuto() { this. I will list one full class and for the rest only the methods that change the state. } // getters and setters // .switchManualAuto().pullTrigger(). Now let’s map the states to actual classes.18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 this.outOfAmmoState = new OutOfAmmoState(this). this. } public void pullTrigger() { this.state = this. this.. OutOfAmmoState.roundFiredState = new RoundFiredState(this). These are the same as in the original rifle class. this.insertClip(). In our case just the ammo count and current state need to be accessed. } // convenience methods .emptyState. 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public OutOfAmmoState(Rifle rifle) { this."). .getEmptyState()).out. System.out. } @Override public void ejectClip() { rifle. } @Override public void pullTrigger() { System.println("!* Out of ammo!"). Also note the constructor. } } Notice that the only way out of the OutOfAmmoState is by ejecting the clip. Check out the other classes too: AmmoFiredState view source print? 01 public class AmmoFiredState implements RifleState { 02 03 private Rifle rifle. } @Override public void switchManualAuto() { System.out. } @Override public void insertClip() { System.println("!* You can't fire with no ammo. Every other attempt will do nothing.println("!* There is an empty clip inserted already!"). } @Override public void fireAmmo() { System.println("!* Plesea reload first").println("> Clip ejected.out.").rifle = rifle.out.setState(rifle. We are passing the reference to the rifle there. 26 } .rifle = rifle.println("> Fired 1 bullet.getManualFireState()).getEmptyState()). 20 } 21 22 @Override 23 public void switchManualAuto() { 24 rifle.rifle = rifle.setAmmoCount(0).").fireAmmo().04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 public AmmoFiredState(Rifle rifle) { this. Hope they are slow and few!"). 06 } 07 08 @Override 09 public void ejectClip() { 10 rifle.out. 18 rifle. 13 } 14 15 @Override 16 public void pullTrigger() { 17 System.getState(). 12 System. System. } @Override public void fireAmmo() { rifle.setAmmoCount(rifle.. 25 System.getAmmoCount() . 11 rifle."). Please reload..setState(rifle.println("> Pulled trigger.setState(rifle. } else { rifle.out. } } // .println("> Clip ejected.setState(rifle.println("> Switched to manual.out.getOutOfAmmoState()).setState(rifle.getAmmoCount() == 0) { rifle. ommited } AutoFireState view source print? 01 public class AutoFireState implements RifleState { 02 03 private Rifle rifle. 19 rifle.setState(rifle. 04 public AutoFireState(Rifle rifle) { 05 this.getManualFireState()).1). if (rifle.out.").getRoundFiredState()). getState(). public ManualFireState(Rifle rifle) { this.println("> Clip ejected. Please reload.out.getEmptyState()). ManualFireState view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class ManualFireState implements RifleState { private Rifle rifle.").out. System. rifle.setState(rifle. the manual state is the active one even if the auto was set before.println("> Switched to auto.setState(rifle. } @Override public void pullTrigger() { System. But I’m sure you can figure out a quick fix. There is a trick there as the Manual and Auto modes are very similar and I just transition between them. } @Override public void ejectClip() { rifle.")..getAmmoFiredState())..rifle = rifle. } // . Bring'em on!!!"). ommited } If you follow the diagram then you should be able to figure out the transitions.27 28 // . There is a drawback as after a reload. } @Override public void switchManualAuto() { rifle. rifle. rifle. ommited NoClipState view source } .setAmmoCount(0).println("> Pulled trigger.getAutoFireState()).setState(rifle.out.. System.fireAmmo().. getOutOfAmmoState()).setState(rifle.out.getManualFireState()).setState(rifle. 15 } 16 System.print? 01 public class NoClipState implements RifleState { 02 03 private Rifle rifle.setState(rifle. 06 } 07 08 @Override 09 public void fireAmmo() { 10 int count = 10. 1 System.setAmmoCount(0). 23 } .getAutoFireState())..out.out.. 1 if (rifle. 21 } else { 22 rifle.getAmmoCount() .count) + " bullets. 06 } 07 08 @Override 09 public void insertClip() { 10 rifle.ommited 15 } RoundFiredState view source print? 01 public class RoundFiredState implements RifleState { 02 03 private Rifle rifle.print("> BANG! ").ammoCount = 50.setAmmoCount(rifle. 14 count--.rifle = rifle.rifle = rifle.println("> Fired a round of " + (10 .println(). 12 } 13 14 // . 20 rifle. 7 Yeah!").getAmmoCount() <= 0) { 8 19 rifle. 13 rifle. 04 public RoundFiredState(Rifle rifle) { 05 this.getAmmoCount() > 0) { 12 System. 11 while (count > 0 && rifle.1). 04 public NoClipState(Rifle rifle) { 05 this. 11 rifle. rifle.insertClip(). rifle. Bring’em on!!! > Pulled trigger. RifleTest view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 public class RifleTest { public static void main(String[] args) { Rifle rifle = new Rifle(). view source print? 01 02 03 04 05 06 07 > !* You can’t fire with an empty magazine. > Switched to auto.switchManualAuto().pullTrigger(). rifle. rifle. rifle. > Fired 1 bullet. rifle.pullTrigger(). > Pulled trigger.ejectClip().insertClip(). !* The magazine is empty. rifle. rifle. rifle.pullTrigger().switchManualAuto().pullTrigger(). rifle.switchManualAuto()..pullTrigger(). You should try adding new features or think of other scenarios.pullTrigger(). rifle.24 25 26 } // . rifle. rifle. rifle. rifle.pullTrigger().. BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! > BANG! >BANG! >BANG! .ommited } Great! Let’s throw together a test for the new shiny Rifle. } Examine the output very carefully and go through the source code.pullTrigger(). rifle.pullTrigger().pullTrigger(). We will return to our beloved droids to give them wits to outrun you. that’s the Pause State. You could use public attributes and access them directly for example. Download the source code and project here (obviam. Hope they are slow and few! 13 > Pulled trigger. 18 > BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! > BANG! >BANG! >BANG! 19 > Fired a round of 10 bullets. 15 !* Clip is already present! 16 > Switched to auto. Note that I used normal Java practices to write the code for clarity. 10 >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! > BANG! >BANG! >BANG! 11 > Fired a round of 10 bullets. as it is a very important element of game design. I strongly encourage you to extend it and build your own.08 > Fired a round of 10 bullets. But it was not the scope of this article. you might not need to overload your classes with getters and setters and you should adhere to the optimized ways.java and RifleOldTest. Note that the first attempt was renamed to RifleOld. Yeah! 23 > Pulled trigger.tgz). 24 > BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! 25 > Fired a round of 8 bullets. Next time I will introduce event and/or message driven behaviours. Bring’em on!!! 17 > Pulled trigger. Also understanding this is crucial to make a step towards autonomous agents (automatons). Yeah! 12 > Switched to manual. I do hope this gave you a good introduction on how to implement state driven behaviours. Yeah! 09 > Pulled trigger. You could create a framework and easily add different game states. Voila! We have state machines and easily extensible game elements. when you’re in the paused screen. Yeah! 26 !* Out of ammo! 27 !* Out of ammo! Again. Think of the game as a whole and when you’re on the menu screen (that’s the Menu State). Meaning that when writing a game. the yellow lines show you when you tried something dodgy.java . 14 > Fired 1 bullet. Yeah! 20 > Pulled trigger.states. You can apply this principle for the whole game and infrastructure. especially for Android. or the main screen that’s the Running State. 21 > BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! > BANG! >BANG! >BANG! 22 > Fired a round of 10 bullets. 062 views | Filed in: Desktop Java Tags: Game Design One useful architecture pattern in game development is the MVC (model-view-controller) pattern. Part 2 – The State Pattern from our JCG partner Tamas Jano from “Against The Grain” blog. The usefulness is quickly noticeable in the early stages of any game development project because it allows to change things quickly without too much rework of code in all layers of the application. It helps separate the input logic.  2 – The controller handles the click/tap and converts the event into an appropriate action. Object Composition Strategies. Do not forget to check out our new Android Game ArkDroid (screenshots below). an attack action is created. The following diagram is the simplest logical representation of the model view controller concept. if it is . 2012 | 7.Reference: Design In-game Entities. Model-View-Controller pattern Example Usage In an example game where the player controls a robot the following can happen:  1 – User clicks/taps somewhere on the screen. For example if the terrain is occupied by an enemy. You feedback will be more than helpful! 17 Building Games Using the MVC Pattern – Tutorial and Introduction Published on February 14. the game logic and the UI (rendering). or how to change their state (position. in order to draw them.  4 – The renderer (view) gets notified about the state changes and renders the world’s current state. They are dumb entities. In Java they are also called POJOs (plain old java objects). that the models (robots) don’t know anything about how to draw themselves. hit points). We know from the typical game architecture that the main loop acts as a super controller. then a move action is created and finally if the place where the user tapped is occupied by an obstacle. If the move action was created.empty terrain. The renderer has to have a reference to the models (robots and any other entities) and their state. do nothing. then it fires. What this all means is. We can put all the update and rendering into the main loop along with the robots but that would be messy.  3 – The controller updates the robot‘s (model‘s) state accordingly. The models  The droid controlled by the player  An arena where the droid can move  Some obstacles  Some enemies to shoot at The controllers  The main loop and the input handler  Controller to process player input  Controller to perform actions on the player’s robot (move. if the attack. Let’s identify the different aspects (concerns) of our games. The controller is in charge of changing the models’ state and notify the renderer. attack) The views  The world renderer – to render the objects onto the screen Creating the Project . then it changes the position. which updates the states and then renders the objects onto the screen many times a second. 06 import java. 23 Graphics g = screen.getGraphics(). 15 } 16 17 public void run() { 18 19 setSize(480. 2 BufferedImage.image.start(). remove later. 04 import java.awt.BufferedImage. 25 26 long delta = 0l.Color. 07 import java.Applet.java is the applet and contains the main loop. 320). 1 2 BufferedImage screen = new BufferedImage(480. // For AppletViewer.For simplicity I have chosen the applet this time and will try to keep it very brief. view source print? 01 package net.TYPE_INT_RGB).droids. The project has the following structure: MVC – Project structure The file Droids. 24 Graphics appletGraphics = getGraphics(). .applet.awt.awt.Graphics. 08 09 public class Droids extends Applet implements Runnable { 10 11 private static final long serialVersionUID = -2472397668493332423L. double-buffering. 02 03 import java.Event. 05 import java. 12 13 public void start() { 14 new Thread(this). 20 2 // Set up the graphics stuff.awt. 320.obviam. net.obviam.model will contain all the models net. 40 if (delta < 20000000L) { 41 try { 42 Thread.sleep((20000000L . 49 } 50 } 51 } 52 53 public boolean handleEvent(Event e) { 54 return false. 0. 37 38 // Lock the frame rate 39 delta = System. 480.obviam.setColor(Color. 320). 31 32 g.fillRect(0.java view source print? . 55 } 56 } Running the above code as an applet does nothing more than to sett up the main loop and to paint the screen black.27 28 // Game loop.lastTime. 43 } catch (Exception e) { 44 // It's an interrupted exception.droids. 0. 33 g.drawImage(screen. 0.nanoTime() . 36 appletGraphics.black). 34 35 // Draw the entire results on the screen. There are 3 packages in the structure and the respective components will go there. 29 while (true) { 30 long lastTime = System.droids.controller will contain all the controllers Creating the models The Droid Droid.obviam.delta) / 1000000L). null).nanoTime(). and nobody cares 45 } 46 } 47 if (!isActive()) { 48 return.droids.view will contain all the renderers net. These states are defined by the member variables and are accessible through the getter and setter methods. private float y.speed = speed. } public void setY(float y) { this.rotation = rotation.y = y. } public void setRotation(float rotation) { this.droids.model. speed and damage. public class Droid { private float x.obviam. rotation. } public float getY() { return y. } } It is a simple java object without any knowledge of the surrounding world.x = x. The game requires a few more models: obstacles and enemies on a map. private float damage = 2f. The map will be a 2 dimensional array holding the enemies. private float rotation = 0f. } public void setX(float x) { this. } public void setSpeed(float speed) { this. } public float getSpeed() { return speed.01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package net. private float speed = 2f. obstacles and the droid. } public float getRotation() { return rotation.damage = damage. The map will be called Arena to differentiate from the standard Java map and will be populated with obstacles . For simplicity the obstacles will have just a position on the map and the enemies will be standing objects. } public float getDamage() { return damage. public float getX() { return x. It has a position. } public void setDamage(float damage) { this. private int hitpoints = 10.obviam. float y) { this. } public float getX() { return x.x = x.model. this.x = x. public Obstacle(float x. public Enemy(float x. float y) { this. } } Enemy. private float y.and enemies when it is constructed.model.y = y. . private float y. public class Obstacle { private float x.droids. } public float getY() { return y. Obstacle.java view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 package net. public class Enemy { private float x.java view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 package net. this.obviam. } public float getX() { return x.droids.y = y. 04 import java.util. 10 public static final int HEIGHT = 320 / 32.nextInt(WIDTH). 02 03 import java. 31 int y = random.ArrayList. 17 private Droid droid. 23 for (int i = 0. 06 07 public class Arena { 08 09 public static final int WIDTH = 480 / 32.droids.util. j < HEIGHT.List.Random. 21 22 grid = new Object[HEIGHT][WIDTH].obviam.hitpoints = hitpoints.util. i < 5. 11 12 private static Random random = new Random(System. 15 private List<Obstacle> obstacles = new ArrayList<Obstacle>(). 16 private List<Enemy> enemies = new ArrayList<Enemy>(). i < WIDTH. i++) { 30 int x = random. } } Arena.droid = droid. j++) { 25 grid[j][i] = null.model.java view source print? 01 package net. } public void setHitpoints(int hitpoints) { this.16 17 18 19 20 21 22 23 24 25 26 } public float getY() { return y. 05 import java. } public int getHitpoints() { return hitpoints. 26 } 27 } 28 // add 5 obstacles and 5 enemies at random positions 29 for (int i = 0. 13 14 private Object[][] grid.currentTimeMillis()). . 18 19 public Arena(Droid droid) { 20 this. i++) { 24 for (int j = 0.nextInt(HEIGHT). . y = random. In order to keep the main loop tidy. } } The Arena is a more complex object but reading through the code should make it easy to understand. update the states of the models and will render the world.droids. import java. y).Graphics. obstacles.Event.obviam. we’ll delegate the update and rendering to the GameEngine. enemies and obstacles.nextInt(WIDTH). } public Droid getDroid() { return droid.nextInt(HEIGHT).nextInt(WIDTH). It is a tiny glue framework to make all these happen.controller. enemies. This will make up the starting arena and our game world. Our game world is the arena which contains all the elements like our droid. It basically groups all the models together into a single world.nextInt(HEIGHT). import java. The WIDTH and HEIGHT are calculated based on the resolution I have chosen. y = random. y). In the constructor (line #19) the grid is set up and 5 obstacles and 5 enemies are randomly placed. while (grid[y][x] != null) { x = random.java stub view source print? 01 02 03 04 05 package net.awt.add((Obstacle) grid[y][x]). A cell (tile) on the grid will be 32 pixels wide and tall so I just compute how many cells go onto the grid.32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 while (grid[y][x] != null) { x = random. } } public List<Obstacle> getObstacles() { return obstacles. } public List<Enemy> getEnemies() { return enemies.add((Enemy) grid[y][x]). } grid[y][x] = new Enemy(x. The GameEngine.awt. This is a simple class that will process the user input. } grid[y][x] = new Obstacle(x. KEY_PRESS: 12 case Event. We need to create an instance of the GameEngine class and call the update() and render() methods at the appropriate times. 27 case Event.id) { 11 case Event.java class needs to be modified.06 public class GameEngine { 07 08 /** handle the Event passed from the main applet **/ 09 public boolean handleEvent(Event e) { 10 switch (e. 15 case Event. Also we need to delegate the input processing to the engine. 24 case Event.MOUSE_DOWN: 19 // mouse button pressed 20 break. 32 } 33 34 /** the update method with the deltaTime in seconds **/ 35 public void update(float deltaTime) { 36 // empty 37 } 38 39 /** this will render the whole world **/ 40 public void render(Graphics g) { 41 // empty 42 } 43 } To use the engine the Droids.KEY_ACTION: 13 // key pressed 14 break.KEY_RELEASE: 16 // key released 17 break. view source . 30 } 31 return false.MOUSE_UP: 22 // mouse button released 23 break.MOUSE_MOVE: 25 // mouse is being moved 26 break. Add the following lines: Declare the private member and also instantiate it. 18 case Event.MOUSE_DRAG: 28 // mouse is being dragged (button pressed) 29 break. 21 case Event. Also the render should be called after the update so it will display the current state of the objects. 06 07 // Update the state (convert to seconds) 08 engine. 05 g.nanoTime() .black). 03 04 g.sleep((20000000L . 14 15 // Lock the frame rate 16 delta = System. 480. 320). Important: The update needs to happen after the delta (time elapsed since the last update) has been calculated. The modified game loop looks like this: view source print? 01 while (true) { 02 long lastTime = System.nanoTime(). 11 12 // Draw the entire results on the screen. 20 } catch (Exception e) { 21 // It's an interrupted exception.0)). 0.drawImage(screen. 0. Note that there is a conversion to seconds from nano seconds.render(g). Replace the current handleEvent method with the following snippet: view source .print? 1 private GameEngine engine = new GameEngine().lastTime. 17 if (delta < 20000000L) { 18 try { 19 Thread. It’s very useful to work in seconds as we can work with real world values. 13 appletGraphics. 09 // Render the world 10 engine.update((float)(delta / 1000000000. 0. The last thing to be done is to delegate the input handling. null).fillRect(0.setColor(Color.delta) / 1000000L). and nobody cares 22 } 23 } 24 } The highlighted lines (#7-#10) contain the delegation to the update() and render() methods. Note that the screen is cleared each time before the render (painted black). It makes sense as everything is just a stub apart from the screen being cleared every cycle. the world is our Arena. view source print? 1 .setY(Arena. private Droid droid.. By design. Is good to have it separate as the droid will be controlled by the player. 3 } Very simple straightforward delegation. public GameEngine() { droid = new Droid().getX()] = droid.WIDTH / 2).setX(Arena.handleEvent(e). so the Droid gets added to the grid before the obstacles and enemies.print? 1 public boolean handleEvent(Event e) { 2 return engine. Running the applet yields no particular exciting result. we have created a world (check the constructor in Arena). Add the following members to the GameEngine along with the constructor which initialises the world. Just a black screen.HEIGHT / 2). .getY()][(int) droid. 2 // add the droid 3 grid[(int)droid. } Note: Arena‘s constructor needs to be modified.. By instantiating it. arena = new Arena(droid). view source print? 01 02 03 04 05 06 07 08 09 10 private Arena arena. We will create the world in the GameEngine as the engine is responsible for telling the view what to render. // position droid in the middle droid. droid. Initialising the models (world) Our game needs a droid and some enemies. We also need the Droid to be created here because the Arena requires it its constructor. 4 ... import java. Let’s create our first view which will reveal our world.  Draw the grid to see where the cells are.  Obstacles will be drawn as blue squares and they will occupy the cells  Enemies will be red circles  The droid will be a green circle with a brown square First we create the renderer interface. Creating the first View/Renderer We’ve put a lot of effort in creating the arena and world. This is where the power of decoupling shines. The concrete implementation looks like this: . public interface Renderer { public void render(Graphics g). It contains one single method: render(Graphics g).java view source print? 1 2 3 4 5 6 7 package net.droids. Because we have chosen applet we need the Graphics object.awt. Once we are happy that the game elements are in we can work on a more elaborate view to replace the squares and circles with fancy graphics.view. We use this to establish a single way to interact with the renderer and it will make it easy to create more views without affecting the game engine.Running the applet again. won’t change the output but we have our world created. } That is all. we will create a quick and dirty renderer to reveal the world. Ideally the interface will be agnostic of this and each implementation will use a different back-end but the purpose of this exercise is to describe the MVC not to create a full framework. We can add logging to see the result but that won’t be interesting. Create an interface in the view package. To read more on why is a good idea check this and this.Graphics. The Graphics g is the canvas that is passed from the applet. Because of this. By quick and dirty I mean no fancy images or anything but simple squares. circles and placeholders. we’re eager to actually see it. Steps to render the world.obviam. Renderer. . for (Enemy enemy : arena.getY() * cellSize).obviam. cellSize . } // render the enemies g.Color. import java. public SimpleArenaRenderer(Arena arena) { this. // hard coded g.getObstacles()) { int x = (int) (obs.awt.awt.droids.obviam. 0.droids.setColor(new Color(1f.WIDTH) g.droids. 0.4). i <= Arena.droids. cellSize . 0)). import java. } // render the obstacles g. g. i * cellSize. i * cellSize). int y = (int) (obs.5f.getX() * cellSize) + 2. 0.HEIGHT * cellSize).arena = arena.model. Arena.Graphics.model.WIDTH * cellSize. import net.model.obviam. 1f)). i++) { g.getEnemies()) { int x = (int) (enemy.75f)).WIDTH.model. public class SimpleArenaRenderer implements Renderer { private Arena arena.Arena. import net.fillRect(x. Arena.Droid. 0.4.getY() * cellSize) + 2.obviam.setColor(new Color(0. 0.SimpleArenaRenderer. i * cellSize.obviam.java (in the view package) view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package net.setColor(new Color(0.drawLine(i * cellSize. y.getX() * cellSize). int y = (int) (enemy. 0. if (i <= Arena. } @Override public void render(Graphics g) { // render the grid int cellSize = 32.drawLine(0. import net. for (Obstacle obs : arena.view. import net.Enemy.droids. for (int i = 0.Obstacle. .4. #23 – #28 – The grid is being drawn. cellSize .getDroid(). 1f. 0)). int y = (int) (droid. cellSize .20). 5) and the renderer works out its position on the screen by using a unit measure conversion. view source print? 01 02 03 04 05 public class GameEngine { private Arena arena. 0f)). } // render player droid g.4.getY() * cellSize). 0. In this case is 1 unit in world coordinate is 32 pixels on the screen. I called it ArenaRenderer because we will render the arena (world). y + 10. g. It is 32. By modifying the GameEngine to use the newly created view (SimpleArenaRenderer) we get the result. int x = (int) (droid. g. The only method in the renderer is the render() method.setColor(new Color(0. #39 – #44 – Sets the color to red and by iterating through the enemies in the arena. Let’s see what it does step by step. cellSize . #32 – #36 – Iterate through all the obstacles in the arena and for each it draws a blue filled rectangle slightly smaller than the cell on the grid. #47 – #54 – Finally draws the droid as a green circle with a brown square on top.fillOval(x + 2.7f. } } Lines #13 – #17 declare the Arena object and make sure that it is set when the renderer is constructed. It’s hard coded as in the Arena class. It is a simple grid. First the colour is set to dark green and lines are drawn at equal distance. cellSize . // render square on droid g.fillOval(x + 2.setColor(new Color(0. Drawing the obstacles – blue squares #31 – Set the brush color to blue. So the droid will always be at the same position (7. y + 2. y + 2.4). cellSize .5f.43 44 45 46 47 48 49 50 51 52 53 54 55 56 g. private Droid droid. cellSize .getX() * cellSize). private Renderer renderer.4). Droid droid = arena. #22 – Declare a cell size in pixels.fillRect(x + 10. Note that the arena in the real world has a width of 15 (480 / 32).20. it draws a circle at the respective position. 22).setX(Arena. } /** . These are the lines where the renderer (view) is added to the game. 15. // position droid in the middle droid. . // setup renderer (view) renderer = new SimpleArenaRenderer(arena). It’s extremely easy to create a new view that instead of shapes (squares and circles) displays actual sprites. droid.WIDTH / 2). arena = new Arena(droid). } } Pay attention to the highlighted lines (5.. code stripped . The result should look like the following image (the positions are random apart from the player’s droid): The result of the first view This is a great view to test out the arena and see the models.06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public GameEngine() { droid = new Droid().render(g)..setY(Arena.HEIGHT / 2).. **/ /** this will render the whole world **/ public void render(Graphics g) { renderer.. getX() != targetX) { 29 droid.obviam.model.getX() + bearing * droid.Droid. This means that it does contain any objects which can be Enemy or Obstacle instances. 04 import net. For simplicity we will update just one state of the droid. view source print? 01 package net. The steps to move the droid based on user input are:  On mouse up check if the clicked cell on the grid is empty.controller. 25 if (droid.droids. 30 // check if arrived 31 if ((droid. 13 /** true if the droid moves **/ 14 private boolean moving = false.droids. the controller will create an action that will move the droid at a constant speed until it reaches the destination. 27 } 28 if (droid. 05 06 public class ArenaController { 07 08 private static final int unit = 32. 22 if (moving) { 23 // move on X 24 int bearing = 1. 15 16 public ArenaController(Arena arena) { 17 this.obviam.Arena. 18 } 19 20 public void update(float delta) { 21 Droid droid = arena. 09 private Arena arena. 10 11 /** the target cell **/ 12 private float targetX.setX(droid. 02 03 import net.  If the cell is empty.Controller for Handling Input and Update Models So far the game does nothing but displays the current state of the world (arena).getX() < targetX && bearing == -1) .obviam. targetY. its position.getSpeed() * delta).droids.model.arena = arena.getDroid().getX() > targetX) { 26 bearing = -1. we’ll hack an action together inside the controller. #14 – It is true when the droid is moving. It’s hard-coded and not optimal but for the demo is good enough. #09 – The Arena the controller will control.setY(targetY).getY() > targetY) { bearing = -1. } return false. return true.getX() == targetX && droid. it updates the droid’s respective position (X or Y) considering its speed.32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 || (droid. // check if arrived if ((droid. int y) { targetX = x / unit.getY() < targetY && bearing == -1) || (droid. This is the “move” actions’ state. . } if (droid.getY() == targetY) moving = false.getGrid()[(int) targetY][(int) targetX] == null) { // start moving the droid towards the target moving = true. it checkes both X and Y positions and if they are not the same as the target position. If the droid is in the target position.getY() != targetY) { droid.getY() + bearing * droid. } } The following breakdown explains the logic and important bits. It is set when the controller is constructed (line #16). } } /** triggered with the coordinates every click **/ public boolean onClick(int x. if (arena. #12 – The target coordinates of the click in world units. but to demonstrate the controller and keep it concise.setX(targetX). Ideally this should be a stand alone class. It is extremely simple.getY() > targetY && bearing == 1)) droid. } // move on Y bearing = 1.setY(droid. #20 – The update method that updates the position of the droid according to the time passed at a constant speed.getX() > targetX && bearing == 1)) droid. then the move state variable is updated completing the move action.getSpeed() * delta). } // check if arrived if (droid. if (droid. #08 – The unit represents how many pixels are in a cell which represents 1 unit in world coordinates. targetY = y / unit. awt.Event. 29 } 30 31 /** handle the Event passed from the main applet **/ 32 public boolean handleEvent(Event e) { 33 switch (e.view.model. 02 03 import java. 20 // position droid in the middle 21 droid. 16 private ArenaController controller.obviam.obviam.SimpleArenaRenderer.awt. 05 06 import net.WIDTH / 2).setY(Arena.droids. 24 25 // setup renderer (view) 26 renderer = new SimpleArenaRenderer(arena).droids. 07 import net. It just updates state. 27 // setup controller 28 controller = new ArenaController(arena). 17 18 public GameEngine() { 19 droid = new Droid().setX(Arena.java view source print? 01 package net.obviam. It checks if the clicked cell is empty and if so.droids. 15 private Renderer renderer.Arena.obviam. To use it. 08 import net.droids. 22 droid.controller.Graphics. 14 private Droid droid. 09 import net. #52 – The onClick(int x. there is no collision checking on obstacles or enemies found along the way. the GameEngine needs to be updated. then it starts the “move” action by setting the state variable to true #53-#54 – Converts screen coordinates to world coordinates.droids.Renderer.This is not a very well written action.obviam. This is the controller. 04 import java. The updated GameEngine. 10 11 public class GameEngine { 12 13 private Arena arena. int y) method will be called when the “mouse up” event occurs.HEIGHT / 2). no path finding.Droid.view. 23 arena = new Arena(droid).model.id) { . KEY_RELEASE: 39 // key released 40 break.MOUSE_UP: 45 // mouse button released 46 controller.x. . 54 } 55 return false.MOUSE_DRAG: 52 // mouse is being dragged (button pressed) 53 break.onClick(e. Run the applet and you can click on the map and if the cell is empty. 48 case Event. the droid will move there.y).  Extract the move action into a new class. #28 – Instantiate the controller. 56 } 57 58 /** the update method with the deltaTime in seconds **/ 59 public void update(float deltaTime) { 60 controller.KEY_PRESS: 35 case Event. 47 break. e. #16 – Declare the controller. 41 case Event. #46 – Delegating the mouse up event. #60 – Call the update method on the controller.MOUSE_MOVE: 49 // mouse is being moved 50 break.render(g). 61 } 62 63 /** this will render the whole world **/ 64 public void render(Graphics g) { 65 renderer. Hint: Use BufferedImage to achieve that.34 case Event. Excercises  Create a view that will display images/sprites for entities instead of the drawn shapes. 44 case Event.MOUSE_DOWN: 42 // mouse button pressed 43 break. 38 case Event. 51 case Event.update(deltaTime).KEY_ACTION: 36 // key pressed 37 break. 66 } 67 } The changes are highlighted. com/obviam/mvc-droids or download as zip file. Draft up some scenarios on paper to resemble your vision and how will it look like. then the enemy is destroyed. Add new actions (attack) when an enemy is clicked Hint:Create a bullet entity that gets fired to the target. Part 1a Published on May 3.com/obviam/mvc-droids.  2.  What different entities make up a game and how they are tied together in a game world. You can also use git $ git clone git://github. Source Code https://github. it’s that magic. . When the hitpoint gets down to 0. 18 Android Game Development with libgdx – Prototype in a day. Use a different image to represent different states. You can use the move action with a higher speed. Have an idea for a game. What you will learn:  Create a very simple 2D shooter platformer game. Steps to create a game  1.104 views | Filed in: Android Games In this article I will take a detour from the building blocks of a game engine and components and I will demonstrate how to prototype a game quickly using the libgdx library.git Reference: Building Games Using the MVC Pattern – Tutorial and Introduction from our JCG partner Impaler at the Against the Grain blog. 2012 | 12.  How to use 2D Graphics with OpenGL without knowing anything about OpenGL.  What a complete game architecture looks like.  How to add sound to your game.  How to build your game on the desktop and deploy in onto Android – yes. Analyse the idea. Create a simple java project in eclipse.  5. . The idea is to guide our hero through the levels by killing enemies and and dodging everything that tries to kill us. It allows developers to create their games on the desktop and deploy it to Android without any modification. Polish and release! The Game Idea Because this will be a one day project. The controls are simple. I will call it star-assault. He can change direction in the air and also shoot. Go get the game and check it out. It will become more obvious as we go along. the arrow keys move the hero to the left or right. I will be using libgdx library to create the game. I will be borrowing heavily from a game called Star Guard. Play-test. The next steps (2 and 3) can be skipped over as we will already have this taken care of because of the functioning game.  6. Why libgdx? It’s the best library (in my opinion) that makes developing games easy without knowing much about the underlying technology. not the actual process. It offers all the elements to use it in games and hides the complexity of dealing with specific technologies and hardware.  7. there is very limited time at disposal and the goal is to learn the technology to make games.zip file and unpack it. It’s a little gem made by Vacuum Flowers. and continuously make small steps towards finishing it. Start your Eclipse This is where we start. Z jumps and X shoots the laser. We’ll see how we can translate these controls to Android later on. A very simple shooter platformer with a simplistic style and old school arcade feel.badlogicgames. 3. Setting up the project By following the instructions from libgdx’s documentation we have to first download the library. Start coding and creating the assets for the game. the higher the hero jumps. improve.com/nightlies/ and download the libgdx-nightlylatest.  4. Go to http://libgdx. The longer the jump button is held. For this purpose I took the liberty to borrow ideas from other games and focus on the technical aspects of this process. Pick a technology and start prototyping. iterate over a few versions by tweaking it and decide what the game will have in its initial version. jar file.jar node. To do this. expand the gdx. From the unpacked libgdx-nighly-latest directory. then click OK. The structure should look like the following image: Add gdx. it’s a good idea to add the sources to the gdx. or finder or any other means. If you copy them using explorer. don’t forget to refresh your eclipse project after by pressing F5.jar file into the newly created libs directory. On this screen pick Java Build Path and click onto the Libraries tab. right click on it and select New>Folder and create a directory named libs.Leave the default settings and once the project was created.jar.jar as a dependency to the project. It is in the sources sub-directory of the unpacked gdx directory. Also copy the the gdx-sources. copy the gdx. In order to have access to the gdx source code and to be able to debug our game easily. Click Add JARs…. Do this by right-clicking the project title and select Properties. select . navigate to the libs directory and select gdx. You can do this by simply dragging the jar files into your directories in eclipse.jar file into the libs directory. Each platform has a specific implementation and we will need to include only those implementations (bindings) that are required targeted. the platform specific implementations reside in different JAR files and only those need to be included that are required for the platform we are targeting. audio. click Edit…. We will need to create two more projects.jar. .Source attachment. the asset loading (loading of images.). One for Android and one for Desktop. This project will be the core project for the game. etc. sounds. The complete documentation for setting up projects with libgdx can be found on the official wiki. Also follow the steps to create the libs directory. the engine. Why do we need separate projects for these? Because libgdx hides the complexity of dealing with the underlying operating system (graphics. It will contain the game mechanics.jar then OK until all the pop-up windows are closed. user input. These projects will be extremely simple and will contain only the dependencies required to run the game on the respective platforms. everything. then Workspace… and pick gdx-sources. This time the required jar files from the downloaded zip file are: gdx-natives. The Desktop Version Create a simple java project as in the previous step and name it star-assault-desktop. basically launchers for the 2 platforms we are targeting. etc) and other common aspects of an application are heavily simplified. Also because the application life-cycle. Think of them as the class containing the main method. file i/o. Name it star-assault-android. Important! We need to make the star-assault project a transitive dependency.jar. Create a new Android project in eclipse: File -> New -> Project -> Android Project. Next to “Create Activity” enter StarAssaultActivity. meaning that dependencies for this project to be made dependencies of projects depending on this.3?.gdx-backend-lwjgl. check the star-assault project and click OK.) We also need to add the star-assault project to the dependencies.jar and the armeabi and armeabi-v7a directories in the newly created libs directory. From the nightly zip.obviam or your own preference. The Android Version For this you will need the Android SDK installed. For build target. click Add.jar. . Click Finish. check “Android 2. Also add these jar files as dependencies to the project as in the previous project. gdx-backend-lwjgl-natives. place gdx-backend-android. select the three JARs and click OK. Specify a package name net. (right click the project -> Properties -> Java Build Path -> Libraries -> Add JARs. Go to the project directory and create a sub-directory named libs (you can do this from eclipse). To do this. To do this: right click on the main project -> Properties -> Java Build Path -> Order and Export -> check the gdx. click the Projects tab.jar file and click OK. . The following image shows the new state. the gdx-backend-android.jar. (step 3). Click Add JARs again.jar under the main project (star-assault) and click OK.jar. This is how the structure should look like: Important! For ADT release 17 and newer. e. click Add. select gdx-backend-android.In eclipse. check the main project and click OK twice. To do this Click on the Android Project Select Properties Select Java Build Path (step 1) Select Order and Export (step 2) Check all the references. the gdx. select gdx. Click the Projects tab. the gdx jar files need to be explicitly marked to be exported. right click the project -> Properties -> Java Build Path -> Libraries -> Add JARs.g.jar and click OK. the main project etc. Ideally this would be in the main project as it is included in both Android and desktop bu because Android has a strict rule on where to keep all these files. Sharing the Assets (images. You can also extend the Variables… instead of browsing to the assets directory. right click on the assets directory in eclipse (the desktop project). It is in the automatically created assets directory in the Android project. Also the game has a very straight forward architecture based around an continuous loop. To do that. we want to keep the images. You can find out more about the architecture and the loop here and here. we will have to keep the assets there. A computer game is a specific type of application in which the “does something” part is filled with a game. Also make sure the assets directory is included as a source folder. Creating the Game A computer application is a piece of software that runs on a machine. In eclipse there is the possibility to link directories as in symbolic links on linux/mac or shortcuts in windows.Also. It is recommended as it makes the project file system independent. sounds and other data files in a shared location. To link the assets directory from the Android project to the desktop project do the following: Right click the star-assault-desktop project -> Properties -> Java Build Path -> Source tab -> Link Source… -> Browse… -> browse to the asssets directory in the star-assaultandroid project and click Finish. does something (even if that’s nothing) and stops in a way or another. sounds and other data) Because the game will be identical on both desktop and Android but each version requires to be built separately from different projects. The start and end is common to all applications. select Build Path -> Use as Source Folder. At this stage we are ready with the setup and we can go ahead to work on the game. more information on this issue here. It starts up. . badlogic. Hand the control to the player.java in the star-assault project. To create the Game we simply need just one class.  6. Load up all the images and sounds and store them in memory.ApplicationListener. the actors.  3. I will be introducing the notions and elements as they appear. but we will delegate the choreography to the player.starassault. Determine when the play ends. to think of the game as a theatrical play. Start application. view source print? 01 package net. int height) { . It looks quite simple and it really is.  7. End the show. All you need to do is.gdx. 04 05 public class StarAssault implements ApplicationListener { 06 07 @Override 08 public void create() { 09 // TODO Auto-generated method stub 10 } 11 12 @Override 13 public void resize(int width. We will define the stages.Thanks to libgdx our game can be pieced together as a staged play in a theatre. Every class will be created in this project with 2 exceptions. Create the engine that will manipulate the actors on the stage based on the input received from the controller.  5. their roles and behaviours. Let’s create StarAssault. 02 03 import com.obviam. So to set up our game/play we need to take the following steps:  1. Create the stages for our play along with the actors and their behaviours (rules for interactions between them).  2.  4. . int height) is called every time the drawable surface is resized. This happens when the application is ready and we can start loading our assets and create the stage and actors. The heart of every game is the render() method which is nothing more than the infinite loop. The method resize(int width. Depending on where the theatre is and how you get there. Think of building the stage for the play in a theatre AFTER all the things have been shipped there and prepared. You can ship things by hand. This is what libgdx is doing for us. This is the play in progress. or by plane or trucks…we don’t know. It is very simple considering all the setup code needed for Android. We’re inside and have the stuff ready and we can start to assemble it. This gets called continuously until we decide that the game is over and want to terminate the program.14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 // TODO Auto-generated method stub } @Override public void render() { // TODO Auto-generated method stub } @Override public void pause() { // TODO Auto-generated method stub } @Override public void resume() { // TODO Auto-generated method stub } @Override public void dispose() { // TODO Auto-generated method stub } } Just implement ApplicationListener from gdx and eclipse will generate the stubs for the methods needed to be implemented. This gives us the chance to rearrange the bits before we go on to start the play. These are all the methods that we need to implement from the application lifecycle. The method create() is called first. the logistic can be a nightmare. It happens when the window (if the game runs in one) is resized for example. or on desktop to initialise the OpenGL context and all those boring (and difficult) tasks. Shipping our stuff and delivering it regardless of the platform. For simplicity we have just blocks. More on the lifecycle here. When the game is done and the application is being closed. He can also move (in both directions) and he can also jump. The Blocks are the other actors. The pause() method will be called whenever the application enters into the background on the desktop or Android. The first mile-stone is to have a world in which our guy can move. Having played Star Guard we can see that Bob has a few states. The program is in a state of game over. We have the guy (let’s call him Bob – libgdx has tutorials with Bob) and the blocks that make up the world. he can’t do anything. It’s similar when the play is over. The world is composed of levels and each level is composed of a terrain. Also when he’s dead. Of course that the play can be interrupted bu pauses and they can be resumed. The terrain is nothing more than some blocks through which our guy can’t go. will look something like this: . When we don’t touch anything. spectators have left and the stage is being dismantled. Turn the start of Star Guard into a block and Bob structure.Note: For computers the game over is not equivalent of program over. Bob is idle. There are other states as well but we’ll leave them out for now. The level consists of blocks placed in a 2 dimensional space. So it’s just a state. For simplicity we will use a grid. Bob can be in only one of the 4 identified states at any given time. The Actors Let’s start taking steps towards the actual game. Identifying the actors and entities so far in the game is easy.  Jumping – also facing left or right and high or low. No more coming back. The states for Bob:  Idle – when not moving or jumping and is alive  Moving – either left or right at a constant speed. the dispose() is called and this is the time to do some cleanup. but is still running. When the application comes to the foreground it resumes and the resume() method is being called.  Dead – he’s not even visible and respawning. it makes him half a meter.The top one is the original and the bottom one is our world representation. For simplicity we will say that one block in the world is one unit wide and 1 unit tall. We have imagined the world but we need to work in a measure system that we can make sense of. Let’s say 4 units in the game world make up 1 meter so Bob will be 2 meters tall. We can use meters to make it even simpler but because Bob is half a unit. . math. .math.starassault.gdx. // unit per second 13 static final float JUMP_VELOCITY = 1f. JUMPING.It is important because when we will calculate the speed with which Bob runs for example. DYING 10 } 11 12 static final float SPEED = 2f.gdx. // half a unit 15 16 Vector2 position = new Vector2().Vector2. 02 03 import com.obviam.java class looks like this: view source print? 01 package net. The Bob. 14 static final float SIZE = 0.model. Let’s create the world.Rectangle. WALKING. Our main playable character is Bob.badlogic. we need to know what we’re doing.badlogic. 04 import com.5f. 17 Vector2 acceleration = new Vector2(). 05 06 public class Bob { 07 08 public enum State { 09 IDLE. position = position. Vector2 position = new Vector2(). the state will be WALKING and based on this state. Lines #12-#15 define some constants we will use to calculate the speed and positions in the world. Rectangle bounds = new Rectangle(). acceleration – This will determine the acceleration when Bob jumps.bounds.math. When we issue the walk action.badlogic. got killed by a bullet or shot an enemy and hit. Being a simple 2D platformer.width = SIZE. Left and right. This is expressed in world coordinates (more on this later). this. } } Lines #16-#21 define the attributes of Bob.obviam. in order to know if Bob ran into a wall. import com.IDLE.model. We also need some blocks to make up the world. public class Block { static final float SIZE = 1f. boolean facingLeft = true.bounds. Think of playing with cubes. The Block.Rectangle.gdx. we know what to draw onto the screen.18 19 20 21 22 23 24 25 26 27 28 Vector2 velocity = new Vector2(). State state = State. public Bob(Vector2 position) { this. This is nothing more than a rectangle. import com.height = SIZE.Vector2. position – Bob’s position in the world. state – the current state of Bob.java class looks like this: view source print? 01 02 03 04 05 06 07 08 09 10 11 package net.starassault. It will be used for collision detection. facingLeft – represents Bob’s bearing. bounds – Each element in the game will have a bounding box. The values of these attributes define Bob’s state at any given time. Rectangle bounds = new Rectangle(). we have just 2 facings. velocity – Will be calculated and used for moving Bob around.badlogic.gdx. These will be tweaked later on. . this.math. In our star assault world. It is easy to imagine placing a table 1 meter wide and 1 meter tall in the middle.12 13 14 15 16 17 18 public Block(Vector2 pos) { this. } } Blocks are nothing more than rectangles placed in the world. We will use vectors to position entities.bounds. height and depth. this.position = pos. We will make it 2 dimensional and will get rid of the depth. the world represents the room. We will use these blocks to make up the terrain.bounds. this. our world has dimensions. . we will need to jump on top of it. Examine the following diagram of representing the bounding boxes and Bob in the world coordinate system. It has a width. we will say that to resemble a 10km/h speed. the blocks the table and the unit. walk 1 meter and jump off. About the coordinate system and units As the real world. We can use multiple tables to create a pyramid and create some weird designs in the room.width = SIZE. and to move thing around.height = SIZE. We can’t go through the table. This makes our life considerably easier as it provides everything we need to work with Euclidean vectors. to calculate speeds.77777778 metres / second ( 10 * 1000 / 3600). If the room is 5 meters wide and 3 meters tall we can say that we described the room in the metric system. we will use 2. Nothing can penetrate them. to cross it. libgdx note You might have noticed that we are using the Vector2 type from libgdx. Think of a room in a flat. If I run with 10km/h that translates to 2. We have one simple rule. the meter in the real world.7 units/second. To translate this to Star Assault world coordinates. Also note that the access to the members is package default and the models are in a separate package. This is the world we will be creating our simulations in. We will place Bob and the blocks following the image shown below.The red squares are the bounding boxes of the blocks. The empty squares are just empty air.7 units every second. The grid is just for reference.000 units/hour means that Bob’s position’s X coordinate will decrease with 2. . It will be 10 units wide and 7 units tall. so walking left at 10. The green square is Bob’s bounding box. The coordinate system’s origin is at the bottom left. Creating the World As a first step we will just create the world as a hard-coded tiny room. We will have to create accessor methods (getters and setters) to get access to them from the engine. add(new } blocks.add(new blocks. blocks. // Getters ----------public Array<Block> getBlocks() { return blocks.add(new blocks. } private void createDemoWorld() { bob = new Bob(new Vector2(7. .add(new Block(new Vector2(6.badlogic. Vector2(9. 1))). 2))).Vector2.add(new blocks.The World. for (int i = 0. blocks. Block(new Block(new Block(new Block(new Vector2(9.badlogic.obviam. } public Bob getBob() { return bob. /** Our player controlled hero **/ Bob bob.add(new i < 10. 5))). public class World { /** The blocks making up the world **/ Array<Block> blocks = new Array<Block>().model.math.add(new Block(new Vector2(6.add(new blocks. Vector2(9.utils. 5))).Array. 4))).starassault. i++) { Block(new Vector2(i.gdx. 2)). 7))). blocks. 4))). Block(new Vector2(i. import com. blocks.java looks like this: view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package net.add(new Block(new Vector2(6. } // -------------------public World() { createDemoWorld(). Block(new Vector2(i.gdx. 3))). Vector2(9. 0))). import com.add(new if (i > 2) blocks. 3))). The GameScreen. Part 1b Published on May 3. Even our game will have 3 basic screens. whose sole purpose is to display the high scores and listen to clicks on the Replay button. Currently the entities are the blocks and Bob. The Start Game screen for example will contain the menu options Play and Quit. We will skip the start and game over screens. it notifies the main Game to load the Play Screen and get rid of the current screen. we need to create a screen for it and tell it to render the world. It has two elements (buttons) and it is concerned about handling the clicks/touches on those elements. The Play Screen will run our game and will handle everything regarding the game. Check out the rest of the tutorial here. Let’s refactor the code and create just the main screen for the game for the time being. Each screen is concerned with the things happening on it and they don’t care about each other. 2012 | 6.304 views | Filed in: Android Games Creating the Game and Displaying the World To render the world onto the screen. In the constructor the blocks are added to the blocks array and Bob is created. Once the Game Over state is reached. the Play Screen and the Game Over screen.java view source . Remember that the origin is in the bottom left corner.43 44 } } It is a simple container class for the entities in the world. 19 Android Game Development with libgdx – Prototype in a day. In libgdx there is a convenience class called Game and we will rewrite the StarAssault class a subclass of the Game class provided by libgdx. About Screens A game can consist of multiple screens. The Start Game screen. Reference: Getting Started in Android Game Development with libgdx – Create a Working Prototype in a Day – Tutorial Part 1 from our JCG partner Impaler at the Against the Grain blog. It’s all hardcoded for the time being. It renders tirelessly those two buttons and if the Play button is clicked/touched. it tells the main Game to transition to the Game Over screen. print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package net.starassault.screens.Screen. view source } .java will become very simple.badlogic.obviam. public class GameScreen implements Screen { @Override public void render(float delta) { // TODO Auto-generated method stub } @Override public void resize(int width.gdx. import com. int height) { // TODO Auto-generated method stub } @Override public void show() { // TODO Auto-generated method stub } @Override public void hide() { // TODO Auto-generated method stub } @Override public void pause() { // TODO Auto-generated method stub } @Override public void resume() { // TODO Auto-generated method stub } @Override public void dispose() { // TODO Auto-generated method stub } The StarAssault. print? 01 package net. the GameScreen is shown only when the game starts. Currently. Remember that the game loop is the render() method.badlogic.obviam. 06 07 public class StarAssault extends Game { 08 09 @Override 10 public void create() { 11 setScreen(new GameScreen()). it creates it. 12 } 13 } GameScreen implements the Screen interface which is very much like an ApplicationListener but it has 2 important methods added.obviam.glClearColor(0.gl.1f. show() – this is called when the main game makes this screen active hide() – this is called when the main game makes another screen active has just one method implemented.1f. The create() does nothing more than to activate the newly instantiated GameScreen. 04 05 import com.GameScreen.screens.starassault. Gdx. view source print? 01 02 03 04 05 06 07 08 09 private World world.gl. . calls the show() method and will subsequently call its render() method every cycle. The world can be created in the show() method as we don’t have any other screens that can interrupt our gameplay.starassault.Game. private WorldRenderer renderer. 1). But to have something to render we first need to create the world.1f.GL_COLOR_BUFFER_BIT). 02 03 import net. In other words.glClear(GL10. /** Rest of methods ommited **/ @Override public void render(float delta) { Gdx. 0. We will add two members to the class and implement the render(float delta) method. StarAssault The GameScreen becomes our focus for the next part as it is where the game will live.gdx. 0. badlogic.badlogic.starassault.5f.Block.x.gdx.starassault. The renderer is a class which will draw/render the world onto the screen (I will reveal it shortly).World.cam.10 11 renderer.ShapeRenderer. import com.badlogic. 7).badlogic. import com.x + rect.cam = new OrthographicCamera(10.Rectangle. import net.model. } The world attribute is the World instance which holds the blocks and Bob.GL10.graphics.getBounds().getBlocks()) { Rectangle rect = block. 3. this.glutils. for (Block block : world. WorldRenderer.Rectangle). float x1 = block. import net. float y1 = block. import net. public WorldRenderer(World world) { this. import com.ShapeType.getPosition().getPosition(). this.position.ShapeRenderer.model.java view source print? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package net.obviam.starassault. The render(float delta) Let’s create the WorldRenderer class. public class WorldRenderer { private World world. debugRenderer. 0). private OrthographicCamera cam.combined).gdx.y + rect. } public void render() { // render blocks debugRenderer. .gdx.OrthographicCamera. import com.set(5.world = world.graphics.glutils.model.view.starassault.obviam.y.update().graphics.graphics.begin(ShapeType.gdx.badlogic.Bob. /** for debug rendering **/ ShapeRenderer debugRenderer = new ShapeRenderer(). this.setProjectionMatrix(cam.math.obviam. import com.render().gdx.cam.obviam. It also means that 320 pixels represent 7 units so the boxes on the screen will be 45. debugRenderer. but when we will have an extensive level and Bob moves around in it. rect.width. . debugRenderer. we will have to move the camera following Bob. The aspect ratio in our case is 10:7.y.7 pixels tall. Drawing primitives in OpenGL is quite tedious but libgdx comes with a ShapeRenderer which makes this task very easy. rectangles.height).0) which is the corner of the room. 1. that means that 480 pixels represent 10 units. rect. } // render Bob Bob bob = world. #20 – The constructor which takes the world as the parameter.getPosition(). The important lines are explained. y1. rect. 0. #18 – The ShapeRenderer is declared. We will use this to draw primitives (rectangles) for the entities. It won’t be a perfect square. y1. More on orthographic projections can be found here. we will render the bounding boxes of the elements (blocks and Bob) to see what we have so far.35 36 37 38 39 40 41 42 43 44 45 46 47 debugRenderer. Important: This is resolution independent. If the screen resolution is 480×320.getBounds().rect(x1.y + rect. Rectangle rect = bob. debugRenderer. } } The WorldRenderer has only one purpose. circles.end(). It has a single public render() method which gets called by the main loop (GameScreen). 0. 0. This is due to the aspect ratio. #23 – This lines positions the camera to look at the middle of the room.setColor(new Color(0. By default it looks at (0. We will use this camera to “look” at the world from an orthographic perspective. This is a helper renderer that can draw primitives like lines. For the first step. Currently the world is very small and it fits onto one screen. this should be easy. #22 – We create the camera with a viewport of 10 units wide and 7 units tall. 1)). It’s analogous to a real life camera. The renderer needs to have access to the world so we will pass it in when we instantiate the renderer.setColor(new Color(1. For anyone familiar with canvas based graphics. rect.getBob().0) is in the middle as you would expect from a normal camera.x. #14 – Declares the world as a member variable. The following image shows the world and camera set-up coordinates.getPosition(). float y1 = bob.width. #15 – We declare an OrthographicCamera.x + rect. The camera’s (0.rect(x1. debugRenderer. This means that filling up the screen with unit blocks (width = height = 1) will result in showing 10 boxes on the X axis and 7 on the Y. so a box will be 48 pixels wide. 1)).height). To take the current state of the world and render its current state to the screen. float x1 = bob. WorldRenderer. Modify the GameScreen like this: view source print? 01 package net.screens.gdx.starassault.Screen. etc). but this time the rectangle is green.badlogic.badlogic.obviam. 07 import com. #39 – #44 – We do the same with Bob.model. y1 with the given width and height.gdx.starassault.gdx.GL10. #45 – We let the renderer know that we’re done drawing rectangles. 04 import net.obviam.World. #31 – We will draw the blocks so we iterate through all of them in the world. Notice that we work in camera coordinates which coincides with the world coordinates. We need to add the renderer and the world to the GameScreen (main loop) and see it in action. #36 – Draw the rectangle at the x1. The render() method: #29 – We apply the matrix from the camera to the renderer.obviam. OpenGL hidden beautifully. This is necessary as we positioned the camera and we want them to be the same.badlogic. #30 – We tell the renderer that we want to draw rectangles. 05 06 import com.view. The update method must be called every time the camera is acted upon (move.graphics. 08 import com. 09 10 public class GameScreen implements Screen { . OpenGL works with vertices (points) so for it to draw a rectangle have to know the coordinates for the starting point and the width. 02 03 import net. #35 – Set the color of the rectangles to red. #32 – #34 – Extract the coordinates of the each block’s bounding rectangle. zoom.starassault. rotate.Gdx.#24 – The internal matrices of the camera are updated. view source print? 1 package net. 4 5 public class StarAssaultDesktop { 6 public static void main(String[] args) { 7 new LwjglApplication(new StarAssault(). For the desktop project is dead simple. 2 3 import com.render().starassault. 0.1f. 480. rest of method stubs omitted . we have to create the launchers for both platforms.badlogic. } @Override public void render(float delta) { Gdx. 8} 9 } .backends.obviam. true). renderer. 1). To test it on both the desktop and Android. renderer = new WorldRenderer(world).1f.. The World and WorldRenderer are created when the screen is shown.LwjglApplication.gl. @Override public void show() { world = new World(). We need to create a class with a main method in it which instantiates an application provided by libgdx. } /** .. Creating the Desktop and Android Launchers We have created 2 more projects in the beginning..GL_COLOR_BUFFER_BIT).java class in the desktop project. 320. The first 2 lines clear the screen with black and the 3rd line simply calls the renderer’s render() method. the latter being an Android project. star-assault-desktop and star-assault-android. **/ } The render(float delta) method has 3 lines.lwjgl. Gdx.11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 private World world. "Star Assault".glClear(GL10.gdx.gl.1f. private WorldRenderer renderer.glClearColor(0.. Create the StarAssaultDesktop. 0. This is it. The Android Version In the star-assault-android project there is a single java class called StarAssaultActivity.android. including checking gdx.backends.obviam.jar at the export tab on the star-guard Project properties -> Build Path. 02 03 import android.gdx.gdx.AndroidApplication. 04 05 import com. Running the application as a normal Java program should produce the following result: If you are getting some errors. It instantiates a new LwjglApplication application passing in a new StarAssault instance which is a Game implementation. 06 import com.backends.Bundle. Line #7 is where everything happens.badlogic.starassault.badlogic.java view source print? 01 package net.os.android.AndroidApplicationConfiguration. I opted for 480×320 because it is a resolution supported on many Android phones and I want to resemble it on the desktop. 07 . The 2nd and 3rd parameters tell the window’s dimension. track back and make sure the set-up is correct and all the steps are followed. The last parameter tells libgdx to use OpenGL ES 2. Change it to: StarAssaultActivity. They are self explanatory but note that if we want to use the Wakelock. config). view source print? 1 <uses-permission android:name="android. 17 config.useAccelerometer = false.WAKE_LOCK"/> Also in line #17 we tell Android to use OpenGL ES 2.onCreate(savedInstanceState). it gets directly deployed and below you can see a photo of the application running on a nexus one. .xml file also needs to be modified. Add the following line to the AndroidManifest. This means we will be able to test it only on a device as the emulator does not support OpenGL ES 2. 18 initialize(new StarAssault(). 1 config. 16 config.xml file somewhere inside the <manifest>tags. the AndroidManifest. 1 AndroidApplicationConfiguration config = new 3 AndroidApplicationConfiguration(). Having a device connected to eclipse. 4 15 config. In line #13 an AndroidApplicationConfiguration object is created. Line #18 initialises the Android application and launches it.permission. This asks permission from Android to keep the device on and to prevent dimming the screen if we don’t touch it. 19 } 20 } Pay attention that the new activity extends AndroidApplication.useCompass = false.08 public class StarAssaultActivity extends AndroidApplication { 09 /** Called when the activity is first created.useWakelock = true. It looks identical to the desktop version. In case there is a problem with it.useGL20 = true. switch this to false. */ 10 @Override 11 public void onCreate(Bundle savedInstanceState) { 12 super. We can set all types of configurations regarding the Android platform. obviam. Bob is a copycat of the Star Guard chap. First it needs to be loaded.starassault. check out my other article or search for it on the net.view. .Bob. Eventually Bob will become an animated character so I suffixed it with a number (panning for the future). namely.obviam. The view draws the models onto the screen. import net.model.model.png and bob_01. The view is the renderer.starassault.obviam. turned into a texture and then mapped to a surface which is described by some geometry. I have two images: block. Note the use of the MVC pattern. Now we need to interact with the entities (especially Bob) and we will introduce some controllers too. a block and Bob. We will need to load the textures and render them accordingly to the screen. These are simple png files and I will copy them into the assets/images directory.Block. Adding Images So far it’s all nice but definitely we want to use some proper graphics.starassault. Take a look at the new WorldRenderer. The models are the entities we want to display.png. One texture for Bob and one for the blocks. import net. The power of MVC comes in handy and we will modify the renderer so it will draw images instead of rectangles. First let’s clean up the WorldRenderer a bit. We will use 2 images hence 2 textures. It’s very useful. to extract the drawing of rectangles into a separate method as we will be using it for debug purposes.java view source print? 01 02 03 04 package net. libgdx makes this extremely easy. I have created two images. In OpenGL to display an image is quite a complicated process.The MVC Pattern It’s quite impressive how far we came in such a short time. It’s very efficient and simple. To turn an image from the disk into a texture is a one liner. To read more on the MVC pattern. this.SpriteBatch. import com.badlogic.math. import com.gdx. public class WorldRenderer { private static final float CAMERA_WIDTH = 10f.Rectangle. import com.gdx. spriteBatch = new SpriteBatch(). ppuY = (float)height / CAMERA_HEIGHT. import com. // pixels per unit on the Y axis public void setSize (int w. /** Textures **/ private Texture bobTexture.05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import net.ShapeType. int h) { this. this. import com.glutils.cam.glutils.starassault. ppuX = (float)width / CAMERA_WIDTH.update(). private World world.gdx. private int height. this.gdx.Gdx.set(CAMERA_WIDTH / 2f.ShapeRenderer.badlogic. } public WorldRenderer(World world.model. private static final float CAMERA_HEIGHT = 7f.obviam.Texture. CAMERA_HEIGHT). CAMERA_HEIGHT / 2f. private int width.gdx.badlogic.badlogic. private float ppuX.gdx. import com.cam = new OrthographicCamera(CAMERA_WIDTH.ShapeRenderer.position.graphics.graphics. this.World.badlogic.gdx.g2d.cam. private Texture blockTexture.badlogic.gdx.debug = debug.OrthographicCamera. private SpriteBatch spriteBatch.graphics. boolean debug) { this.badlogic. import com. 0). private boolean debug = false. this. private OrthographicCamera cam. /** for debug rendering **/ ShapeRenderer debugRenderer = new ShapeRenderer(). } .width = w.Color.graphics.badlogic.world = world. loadTextures().height = h. import com.graphics. // pixels per unit on the X axis private float ppuY.graphics. files. rect. 1)).y.setProjectionMatrix(cam.getPosition(). y1.x + rect.setColor(new Color(1.combined). 81 debugRenderer. Block.getBob().getBob(). rect. 0.getBlocks()) { 6 spriteBatch.png")). 62 spriteBatch.SIZE * ppuY).draw(bobTexture. 91 Rectangle rect = bob.Rectangle). y1.end(). 60 drawBlocks().rect(x1. 61 drawBob(). 82 for (Block block : world.internal("images/bob_01. 85 float y1 = block.x. 1.y + rect.png")). bob.getPosition().files.x. 7 } 0 71 } 72 73 private void drawBob() { 74 Bob bob = world.getPosition().getPosition().x + rect. 95 debugRenderer. 96 debugRenderer.width. 56 } 57 58 public void render() { 59 spriteBatch.getBounds().getPosition(). 55 blockTexture = new Texture(Gdx.53 private void loadTextures() { 54 bobTexture = new Texture(Gdx. 88 } 89 // render Bob 90 Bob bob = world. Block. block.x * ppuX.setColor(new Color(0.internal("images/block. 63 if (debug) 64 drawDebug().y + rect. 0. 7 spriteBatch. 84 float x1 = block. 0.y * ppuY.SIZE * ppuY). 86 debugRenderer. 65 } 66 67 private void drawBlocks() { 68 for (Block block : world. Bob.end().SIZE * ppuX.begin(ShapeType. 1)).draw(blockTexture.getBounds(). 93 float y1 = bob.y.getPosition().width.getPosition().y * ppuY.height). 92 float x1 = bob. 87 debugRenderer. 97 } 98 } .begin(). rect. Bob. rect. 7 } 6 77 78 private void drawDebug() { 79 // render blocks 80 debugRenderer.rect(x1.height).getPosition(). 9 block. 94 debugRenderer. 5 bob.getBlocks()) { 83 Rectangle rect = block.SIZE * ppuX.x * ppuX. It’s perfectly fine and OpenGL does that very easily. The file handlers in libgdx are very helpful. That means that 480 pixels horizontally are equivalent of 10 units. #36 – The setSize (int w. as we don’t differentiate between Android or deskop. The ppuX and ppuY are the number of pixels per unit. Note that we . It instantiates the SpriteBatch and loads the textures (line #50). the debug rendering will just render the boxes for the game elements. #60 & #61 – simply call 2 methods to render first the blocks and then Bob. #58 – the new render() method contains just a few lines. #53 – loadTextures() does what it says: loads the textures. The second and third parameters tell the spriteBatch where to display the image. So assets acts as a root directory. The drawDebug method was detailed previously. meaning everything from that directory gets copied into the root of the final bundle. The width and height hold the screen size in pixels and are passed in from the operating system at the resize step. we get that 1 unit vertically will be 320 / 7 = 45. otherwise it won’t work. or we just simply choose the option to cut the image off but maintain the aspect ratio. It’s used for the camera. You can read more on SpriteBatch here. Doing the same for the vertical part. This happens when we change the aspect ratio on our TV set and sometimes the image gets elongated or squashed to fit everything on the screen. OpenGL prefers floats and so do we. draw our stuff and end() when we’re done. #67 – #76 – the drawBlocks and drawBob methods are similar. displaying and so on for us. #59 & #62 – enclose a SpriteBatch drawing block/session. #32 – #35 – these variables are necessary to correctly display the elements. To create a texture. meaning a unit will consists of 48 pixels on the screen. But we have only 320 pixels available and we want to show the whole 7 blocks height. even if the screen resolution deals with ints. we need to map those values to the actual pixel coordinates. #63 & #64 – if debug is enabled. #31 – It’s an attribute set in the constructor to know if we need to render the debug screen too or not. OpenGL will work out the dimensions and where to place pixels. It is important to understand this. call the method to render the boxes. Remember. #27 & #28 – Declare the 2 textures that will be used for Bob and the blocks. int h) method will be called every time the screen is resized and it simply (re)calculates the units in pixels. Every time we want to render images in OpenGL through the SpriteBatch we have to call begin().I’ll point out the important lines: #17 & #18 – Declared constants for the viewport’s dimensions.71 pixels. If we try to use the same unit for the height (48 pixels) we get 336 pixels (48 * 7 = 336). #43 – The constructor changed just a little but it does very important things. we just specify that we want to use an internal file and it knows how to load it. The first parameter is the texture (the image loaded from the disk). Each method calls the draw method of the spriteBatch with a texture. We need to distort every image a bit to fit in our world. #30 – The SpriteBatch is declared. Look how incredibly simple it is. Note that for the path we skipped assets because assets is used as a source directory. Because we set the camera to have a view port of 10×7 in world coordinates (meaning we can display 10 boxes horizontally and 7 boxes vertically) and we are dealing with pixels on the end result. We have chosen to work in a 480×320 resolution. we need to pass in a file handler and it creates a texture out of it. The SpriteBatch takes care of all the texture mapping. It is important to do that. Note: we use float for this. } public void resize(int width. Just make sure you modify the GameScreen class so the resize gets called on the renderer and also to set the renderer’s debug to true. 0) in the bottom left corner. } /** . omitted .. omitted .. That’s it. SpriteBatch by default uses a coordinate system with the origin (0. **/ public void show() { world = new World(). int height) { renderer. You can do the calculations by hand and see where the images get displayed. true)....use the conversion of coordinates from world coordinates to screen coordinates.setSize(width.. The modified bits of GameScreen view source print? 01 02 03 04 05 06 07 08 09 10 /** . Here is where the ppuX and ppuY are used. **/ Running the application should produce the following result: without debug and with debug rendering . height).. renderer = new WorldRenderer(world.. To follow the MVC pattern. . we’ll separate the class that controls Bob and the rest of the world from the model and view classes. Because we will use 2 types of input (keyboard and touch-screen). Processing Input – on Desktop & Android We’ve come a long way but so far the world is static and nothing interesting is going on. For the start we will control Bob by key presses. Each action is triggered by an event. The control schema on the Desktop is very simple. z will make Bob jump and x will fire the weapon.java view source print? 01 package net. jump and fire. to intercept keys and touches and create some action based on those. Let’s create a very simple controller called WorldController. We will designate some buttons for these functions and will lay it down on the screen and by touching the respective areas we will consider one of the keys pressed. The jump action is triggered when the z key is pressed and so on. To play the game we to track the status of 4 keys: move left. move right.controller and all controllers will go there.obviam.Great! Give it a try on Android too and see how it looks. The arrow keys will move Bob to the left and right. Create the package net.controller.obviam. we need to add input processing. On Android we will have a different approach. WorldController. the actual events need to be fed into a processor that can trigger the actions. The move left action is triggered by the event when the left arrow key is pressed or a certain area of the screen is touched. To make it a game.starassault.starassault. get(keys.JUMP. 24 }.bob = world.get(keys.obviam.State. 06 import net. true)).model.model. true)). FIRE 13 } 14 15 private World world. 04 import java.starassault.FIRE.put(Keys. false).Bob.put(Keys.World. 29 } 30 31 // ** Key presses and touches **************** // 32 33 public void leftPressed() { 34 keys. 05 import net.LEFT.starassault. false).starassault.put(Keys.util.put(Keys.obviam. 39 } 40 41 public void jumpPressed() { 42 keys.util.model.put(Keys.JUMP. JUMP.put(Keys.world = world.put(Keys. 08 09 public class WorldController { 10 11 enum Keys { 12 LEFT. 28 this. RIGHT.LEFT.get(keys.Keys. false). Boolean> keys = new HashMap<WorldController.obviam. 47 } . 25 26 public WorldController(World world) { 27 this.RIGHT. 07 import net.HashMap.Map. 1 7 1 static Map<Keys. 8 Boolean>().put(Keys. 35 } 36 37 public void rightPressed() { 38 keys.get(keys.02 03 import java. 22 keys.Bob. 43 } 44 45 public void firePressed() { 46 keys. 19 static { 20 keys. false)).getBob().FIRE. false). 21 keys. 23 keys. true)).RIGHT. 16 private Bob bob. x = Bob.get(Keys.get(Keys. 93 } 94 } 95 } . 76 bob.update(delta).RIGHT)) || 87 (!keys.x = 0. 84 } 85 // need to check if both or none direction are pressed.x = -Bob.setState(State. 91 // horizontal speed is 0 92 bob. 83 bob.WALKING). 89 // acceleration is 0 on the x 90 bob.getVelocity(). 78 } 79 if (keys.FIRE.get(keys. 77 bob. 63 } 64 65 /** The main update method **/ 66 public void update(float delta) { 67 processInput(). 59 } 60 61 public void fireReleased() { 62 keys.get(Keys. false)).get(Keys.get(Keys.LEFT)) { 74 // left is pressed 75 bob.WALKING).put(Keys.JUMP.IDLE). 69 } 70 71 /** Change Bob's state and parameters based on input controls **/ 72 private void processInput() { 73 if (keys.setState(State. 82 bob. then Bob is idle 86 if ((keys.RIGHT)) { 80 // left is pressed 81 bob. 51 } 52 53 public void rightReleased() { 54 keys.LEFT.get(keys.getVelocity().LEFT) && !(keys.setState(State.RIGHT. 55 } 56 57 public void jumpReleased() { 58 keys.SPEED.LEFT) && keys.getVelocity(). false)).setFacingLeft(false).48 49 public void leftReleased() { 50 keys.get(keys.get(Keys. false)).put(Keys.x = 0.put(Keys.put(Keys. 68 bob.SPEED.getAcceleration().setFacingLeft(true).get(keys.RIGHT)))) { 88 bob. false)). java. #66 – #69 – the update method which gets called every cycle of the main loop. These methods are the ones that get called from whatever input we’re using. then sets the facing for Bob to the left. Bob becomes State. Bob has a dedicated update method which we will see later. As you can see. but we will need it as it’s easier to refer to it than retrieving it every time we need him. Let’s see what changed in Bob.add(velocity. #16 – declare Bob as a private member and it is just a reference to Bob in the game world. #26 – This is the constructor that takes the World as the parameter and gets the reference to Bob as well.IDLE and his horizontal velocity will be 0.state = newState. which is called from . left the negative direction (origin is in the bottom left and points to the right). Each keypress/touch can trigger one action. We will be controlling the entities found in the world. The same thing for the right.tmp().#11 – #13 – define an enum for the actions Bob will perform. #72 – #92 – the processInput method polls the keys map for the keys and sets the values on Bob accordingly. #33 – #63 – These methods are simple callbacks that are called whenever an action button was pressed or a touch on a designated area happened. the controller is a state machine too and its state is given by the keys map.mul(delta)). it’s true. // unit per second public void setState(State newState) { this. currently it does 2 things: 1 – processes the input and 2 – updates Bob. It is statically initialised. Also added the setState method because I forgot it before. The most interesting is the newly acquired update(float delta) method. If the key is pressed. For example lines #73 – #78 check if the key is pressed for the movement to the left and if so. view source print? 1 2 3 4 5 6 7 8 9 public static final float SPEED = 4f. They simply set the the value of the respective pressed keys in the map. #15 – declare the World that is in the game. his state to State. This map will be used in the controller’s update method to work out what to do with Bob. } public void update(float delta) { position. The sign is because on the screen. There are some extra checks if both keys are pressed or none and in this case. } Just changed the SPEED constant to 4 units (blocks) per second. #18 – #24 – it’s a static HashMap of the keys and their statuses.WALKING and his velocity to Bob’s speed but with a negative sign. false otherwise. we just need to call the correct events when they happen.Input. 026 Gdx.setInputProcessor(this). false).badlogic.gdx. 011 import com. We use vector math here and libgdx helps a lot. 005 import net. 025 controller = new WorldController(world).badlogic.java view source print? 001 package net. To do this.badlogic.input. 016 private WorldRenderer renderer. More on vectors here http://en.starassault. it makes sense to use it as the input handler too.starassault.wikipedia.the WorldController. This method simply updates Bob’s position based on his velocity.obviam.Keys.badlogic.Gdx.graphics. Because we are using the GameScreen as the playing surface.gdx. 008 import com. 017 private WorldController controller.screens.InputProcessor.badlogic. InputProcessor { 014 015 private World world.World. In Java we have to be careful on how we’re using references as velocity and position are both Vector2 objects. 027 } . 018 019 private int width.GL10. The new GameScreen. 020 021 @Override 022 public void show() { 023 world = new World(). 024 renderer = new WorldRenderer(world.org/wiki/Euclidean_vector. 006 007 import com. the GameScreen will implement the libgdx InputProcessor.gdx. We simply add the distance travelled in delta seconds to Bob’s current position.gdx. height.obviam. 002 003 import net.view. libgdx has an input processor which has a few callback methods.obviam.starassault. 009 import com.tmp() because the tmp() creates a new object with the same value as velocity and we multiply that object’s value with the elapsed time delta. For simplicity we do only that without checking his state and because the controller takes care to set the velocity for Bob according to his facing and state.WorldController.gdx.obviam.starassault.WorldRenderer.Screen. 012 013 public class GameScreen implements Screen.controller. 010 import com. We have almost everything. We use velocity.model. 004 import net. 1f. 063 } 064 065 // * InputProcessor methods ***************************// 066 067 @Override 068 public boolean keyDown(int keycode) { 069 if (keycode == Keys.input.glClear(GL10.gl. 035 renderer. 071 if (keycode == Keys. int height) { 040 renderer.setInputProcessor(null).update(delta).1f. 036 } 037 038 @Override 039 public void resize(int width.1f.input.RIGHT) 072 controller. 075 if (keycode == Keys.gl. 048 } 049 050 @Override 051 public void pause() { 052 // TODO Auto-generated method stub 053 } 054 055 @Override 056 public void resume() { 057 // TODO Auto-generated method stub 058 } 059 060 @Override 061 public void dispose() { 062 Gdx.LEFT) 070 controller.setInputProcessor(null). 032 Gdx. 0.glClearColor(0.rightPressed(). 042 this.jumpPressed(). 073 if (keycode == Keys. 1).height = height. height). 041 this.X) .setSize(width. 043 } 044 045 @Override 046 public void hide() { 047 Gdx.028 029 @Override 030 public void render(float delta) { 031 Gdx.GL_COLOR_BUFFER_BIT).render(). 0.width = width. 033 034 controller.Z) 074 controller.leftPressed(). } return true.Z) controller.rightPressed(). . } if (x > width / 2 && y > height / 2) { controller. } @Override public boolean touchUp(int x. int y.leftPressed().rightReleased(). int button) { if (x < width / 2 && y > height / 2) { controller. int pointer.RIGHT) controller. } @Override public boolean touchDown(int x.leftReleased().LEFT) controller. return true.rightReleased(). int pointer) { // TODO Auto-generated method stub return false. return true.076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 controller.fireReleased(). int button) { if (x < width / 2 && y > height / 2) { controller. } @Override public boolean keyUp(int keycode) { if (keycode == Keys. } @Override public boolean touchDragged(int x. if (keycode == Keys. if (keycode == Keys. if (keycode == Keys. int y.X) controller.jumpReleased(). } if (x > width / 2 && y > height / 2) { controller. int y.leftReleased(). } @Override public boolean keyTyped(char character) { // TODO Auto-generated method stub return false.firePressed(). int pointer. } return true. When the key is released. To fix this add the following line to the beginning of touchDown and touchUp methods: . int y) { // TODO Auto-generated method stub return false. The method also returns true to let the input processor know that the input was handled. it is treated as a move left action trigger and passes the same event as the desktop to the controller. The controls are utterly simple and are made just for simple demo purposes. } @Override public boolean scrolled(int amount) { // TODO Auto-generated method stub return false. we pass on the event to the controller. This is exactly what’s happening. Running the application on both desktop and Android will demonstrate the controls. This happens only on touch-screens and the coordinates are passed in along with the pointer and button. On desktop the arrow keys and on Android by touching the lower corners of the screen will move Bob. #47 & #62 – we set the active global input processor to null just for cleanup. #111 – #118 – this is where it gets interesting. The screen is divided into 4 and if the touch falls int to lower left quadrant. Based on the keys we want. libgdx treats this as a global input processor so each screen has to set a different one if they don’t share the same. it simply delegates to the WorldController. Exactly the same thing for the touchUp. On desktop you will notice that using the mouse to simulate touches will also work. #25 – instantiate the WorldController with the world. This will be fixed of course. do something. #81 – the keyUp is the exact inverse of the keyDown method. the purpose is to demonstrate the multiple hardware inputs and how to tie them together. } } The changes: #13 – the class implements the InputProcessor #19 – the width and height of the screen used by the Android touch events. The parameter keycode is the value of the pressed key and this way we can poll it and in case it’s a desired key. #26 – set the this screen as the current input processor for the the application. This is because touchXXX also handles mouse input on desktop. Warning: – This is very buggy and unreliable. as the touchDragged is not implemented and whenever the finger is dragged across quadrants it will mess up things.125 126 127 128 129 130 131 132 133 134 135 136 137 138 } @Override public boolean touchMoved(int x. The pointer is for multi-touch and represents the id of the touch it captures. In this case the screen itself handles the input. #68 – the method keyDown(int keycode) is triggered whenever a key is pressed on the physical keyboard. view source print? 1 if (!Gdx. Short Recap So far we have covered quite a bit of game development and we already have something to show. We still need to add:  Terrain interaction (block collision. jump)  Animation  A big level and camera to follow Bob  Enemies and a gun to blast them  Sounds .getType(). As we can see. Remember that false means that the input was not handled.equals(ApplicationType. This returns false if the application is not Android and does not execute the rest of the method. Bob has moved.Android)) 2 return false. Gradually we have introduced working pieces into our app and step by step we have achieved something.app. we have recently delved into the world of mobile game programming. except for Java Code Geeks of course. This was done after creating JCG Studios. Our platform of choice is Android and our first attempt of developing a game from scratch resulted in the creation of ArkDroid. ArkDroid is an Arkanoid clone for Android. 2011 | 5. As its name suggests.git You can also download it as a zip file.com/obviam/star-assault To check it out with git: git clone [email protected]:obviam/star-assault. As you might have noticed. Reference: Getting Started in Android Game Development with libgdx – Create a Working Prototype in a Day – Tutorial Part 1 from our JCG partner Impaler at the Against the Grain blog. But go ahead and do it yourself by all means and any feedback is much appreciated. 20 Android Game Postmortem – ArkDroid Development Published on December 30. . Also check out libgdx and its awesome community. The source code for this project can be found here: https://github. Refined controls and fine tuning  More screens for game over and start  Have more fun with libgdx Make sure you check out Part 2 (which is still in progress) in order to tick the aforementioned list. it is our other acronym. Greece. It is what we would like to call “Brick Breaker Evolved”.334 views | Filed in: Android Games Tags: featured Hello guys. JCG here stands for Just Cool Games. an independent mobile game studio based on Athens. Let’s begin with a short overview of the game creation. Byron and me. each of us dedicating about 15 hours per week during that period. deep space music themes. appealing visual effects. similar to the ones you might have read if you have some experience in game programming. We followed the usual approach of creating both a full version and a lite version.ArkDroid features cinematic story line. Consider this as a basic game postmortem. campaign and free play modes and sophisticated weaponry system among others. Having finished the development of ArkDroid a while ago. Following are some insights regarding game programming in general and more specifically about programming for the Android platform. The development team consisted of two people. . The development lasted about 4 months. I would like to share some of the experiences I gathered while being a member of the development team. It was actually a side project running along with our regular jobs and Java Code Geeks. We would love it if you took a look at it and let us know what you think about it. There are also a bunch of sites that provide private repositories.T. Collaborate Efficiently Collaboration is critical when a distributed team is involved. but any modern source management tool would be fine. libgdx is cross-platform. It would be quite easy to get started if you have previous experience into making games.R. a versioning system goes without saying. we used Skype and for a loose “project management” we played with Google Docs. provides an abundance of features and shortcuts and I guarantee that it will help you kick-start your project in no time. if performance is critical to your game’s success. That being said. we evaluated some of the available Android game engines and we decided to go with the very nice AndEngine. meaning that it can be used to write both desktop and mobile (Android) games. AndEngine is quite mature. . As an added bonus. It should definitely be noted tha libgdx was a close second and we decided to skip it because it is a bit low level for us. but make sure you dedicate the appropriate time before delving into the magic world of Android game programming. For our online communication. libgdx is a no-brainer. Our Android tutorials could be of help for this. since this is what we have the most experience with. We also recently introduced Android Game Development Tutorials. We decided to go with good-old Subversion. do your search. A text document and a spreadsheet should be more than enough for two people in order to track bugs and assign new features. Rev up your engine Resist falling victim of the “Not Invented Here” syndrom and embrace the power that a game engine can give you. Regarding the code itself. We decided in favour of the lower development time that AndEngine ensures.F. These are also available in the Android SDK for offline browsing. Check out the developer’s guide and make sure to bookmark the Javadoc pages. Don’t worry.M. nothing fancy is required. When starting development. (Read The Fine Manual) Do yourself a favor and make sure you have a good grasp of the Android fundamentals before embarking on the journey of making an Android game. Make sure that all corners are covered. Before writing a single line code however. You have to avoid hiccups . Provide random input and witness how your game is going to react on that. Be warned. CPU powers and the list goes on. from low-end to the high-end devices. due to the nature of games. GC is your enemy Good games provide first of all a smooth experience to their players. Test. you will have to get more that one device in order to cover all bases. you got the source code available. AndEngine was used to provide the core framework for building our game. I mean come on. as you might have guessed. there are no Javadocs (weird) so you will have to rely only on the examples and the public forums. test. Act as a non-experienced mobile user. right? Hit that device One of the most major issues we had during development was the ridicuslouly slow time that the applications take in order to be deployed into the SDK’s emulator. Cover the spectrum Android fragmentation is a real thing and it can be a major PITA.Know thy engine As stated above. if you are thinking of Android game programming in a more professional way. Byron and I made sure to purchase real devices for ourselves and perform the majority of debugging and testing on them instead of the emulator. I have a cutting edge laptop and it takes forever (ok about a minute and so) to redeploy the game on it. test And yes. let alone debug the game and fix it. it might be difficult to even reproduce a bug. we made sure to got through all the available tutorials. Unfortunately. And hey. You have to test the game in every possible way. screen sizes. I mean test in the real device. So. Different resolutions. For this reason. creating a non-trivial game requires a great amount of effort and above all. do it without thinking twice. make sure to beta test your game. Find some friends or relatives and let them experiment with your game. so this makes things worse. trust me on that. Eleftheria. you should be around when they play with it. patience. We used GIMP for our image editing needs and I think that we actually managed to create some decent art work (mainly Byron). If you can afford to hire someone to create your graphics and sound. This feedback is invaluable. Ben). We were lucky enough to have some great beta testers which helped us track some bugs and gave helpful advice (thank you Pelagia. Your game consists actually of a main loop. Yeah. I believe that the term programmer’s art is a very successful and representative one. Ideally. Be Patient You probably have heard all those stories about creating a “game” in a weekend or a “few hours” time. you will have to make the most out of the available tools. Watch them and see what they liked. The resources are rather scarce in the mobile world. right… Let me warn you. It is really a “stop the world” procedure which unfortunately gets noticed by the users. what troubled them and what felt weird to them. The best advice on this is to make absolutely sure that you do not create unnecessary objects. .during game play and as you might have guessed. hiccups are caused by Garbage Collections in Android. that is executed multiple times per second. Otherwise. Hardcore. Assets? What is this? Ok. Beta testers wanted When near the end of development. Byron and I are programmers at heart. so proceed with big caution. Creating “art” sounds a bit bizarre to us. make sure that you make something you actually like yourself. this function does not perform as well… . Game dev however is a totally refreshing change.Just ship… . Don’t rush into making quick decisions like quitting your day job. You probably know the drill: persist some data.Hey. do not forget to check out our new Android Game.Just ship!! . Applications that could have changed the world and games that could have written history. generate some reports. move the data again. Don’t quit your day job just yet This is a very common advice but I would like to repeat it here. etc etc.Just ship!! . but instead they gather dust forgotten inside old hard disks. If you get bored by your very own game. This can get boring after a while. Fight all excuses and take the dive: . We decided to start our endeavor with an all-time classic. commit that transaction. Mobile market is a very strange beast and while it could make you a millionnaire. that’s all folks… Don’t forget to share! And of course. it is not done… . You feedback will be more than helpful! .I cannot ship yet. Game development is life changing I personally come from a hardcore enterprise programming background (JEE to the max).Just ship It is quite common among developers to find unfinished projects.Just ship!!! Just ship the thing. it is almost certain that you will drop out midway… or that you will end up with a horrible game. it could also leave you scratching your head as why your super-duper game does not make a damned sell. but my competition has feature Y… . ArkDroid. Who does not love Arkanoid? So.Just ship! . get your user’s feedback and build on that. Enjoy the game Finally. a brave new world that I am happy to have found.With only 100 levels?… .Yes.But I haven’t finished feature X… .
Copyright © 2024 DOKUMEN.SITE Inc.