In this project, we will build a really simple but fun version of the classic Breakout game for Android. Often known as the “Brick breaker game” the history of the game is interesting and if you like nostalgia I urge you to read this history of Breakout. Breakout sometimes called Arkanoid was developed by Atari in the early 1970s and was a kind of spiritual successor to Pong. What made it exciting at the time was that it had all the proven game mechanics of Pong, and some extras but was playable by a single player. Let’s build a Breakout/Arkanoid game.
So what we are left with is a BreakoutView who’s run method constantly calls update and draw whilst keeping track of the frame rate. There is a slight change in the run method as I have wrapped the call to update with an if(!paused) statement so the player can start the game with a touch of the screen. We will build classes to represent the player’s paddle, a single brick, and of course a ball. We will then see how we can use the objects of these classes to make our game.
Create a new project in Android Studio, call it Breakout Game, and name the Activity BreakoutGame then enter the slightly modified simple game engine code below that we have just discussed. You could run this code but all you will get is a blank screen.
1 2 3 4 5 6 7 8 9 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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; public class BreakoutGame extends Activity { // gameView will be the view of the game // It will also hold the logic of the game // and respond to screen touches as well BreakoutView breakoutView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Initialize gameView and set it as the view breakoutView = new BreakoutView(this); setContentView(breakoutView); } // Here is our implementation of GameView // It is an inner class. // Note how the final closing curly brace } // is inside SimpleGameEngine // Notice we implement runnable so we have // A thread and can override the run method. class BreakoutView extends SurfaceView implements Runnable { // This is our thread Thread gameThread = null; // This is new. We need a SurfaceHolder // When we use Paint and Canvas in a thread // We will see it in action in the draw method soon. SurfaceHolder ourHolder; // A boolean which we will set and unset // when the game is running- or not. volatile boolean playing; // Game is paused at the start boolean paused = true; // A Canvas and a Paint object Canvas canvas; Paint paint; // This variable tracks the game frame rate long fps; // This is used to help calculate the fps private long timeThisFrame; // When the we initialize (call new()) on gameView // This special constructor method runs public BreakoutView(Context context) { // The next line of code asks the // SurfaceView class to set up our object. // How kind. super(context); // Initialize ourHolder and paint objects ourHolder = getHolder(); paint = new Paint(); } @Override public void run() { while (playing) { // Capture the current time in milliseconds in startFrameTime long startFrameTime = System.currentTimeMillis(); // Update the frame // Update the frame if(!paused){ update(); } // Draw the frame draw(); // Calculate the fps this frame // We can then use the result to // time animations and more. timeThisFrame = System.currentTimeMillis() - startFrameTime; if (timeThisFrame >= 1) { fps = 1000 / timeThisFrame; } } } // Everything that needs to be updated goes in here // Movement, collision detection etc. public void update() { } // Draw the newly updated scene public void draw() { // Make sure our drawing surface is valid or we crash if (ourHolder.getSurface().isValid()) { // Lock the canvas ready to draw canvas = ourHolder.lockCanvas(); // Draw the background color canvas.drawColor(Color.argb(255, 26, 128, 182)); // Choose the brush color for drawing paint.setColor(Color.argb(255, 255, 255, 255)); // Draw the paddle // Draw the ball // Draw the bricks // Draw the HUD // Draw everything to the screen ourHolder.unlockCanvasAndPost(canvas); } } // If SimpleGameEngine Activity is paused/stopped // shutdown our thread. public void pause() { playing = false; try { gameThread.join(); } catch (InterruptedException e) { Log.e("Error:", "joining thread"); } } // If SimpleGameEngine Activity is started theb // start our thread. public void resume() { playing = true; gameThread = new Thread(this); gameThread.start(); } // The SurfaceView class implements onTouchListener // So we can override this method and detect screen touches. @Override public boolean onTouchEvent(MotionEvent motionEvent) { switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) { // Player has touched the screen case MotionEvent.ACTION_DOWN: break; // Player has removed finger from screen case MotionEvent.ACTION_UP: break; } return true; } } // This is the end of our BreakoutView inner class // This method executes when the player starts the game @Override protected void onResume() { super.onResume(); // Tell the gameView resume method to execute breakoutView.resume(); } // This method executes when the player quits the game @Override protected void onPause() { super.onPause(); // Tell the gameView pause method to execute breakoutView.pause(); } } // This is the end of the BreakoutGame class |
Now we will do something else new.
Making the game a full-screen landscape
We want to use every pixel that the device has to offer so we will make changes to the app’s AndroidManifest.xml configuration file.
- In the project explorer pane in Android Studio double click on the manifests folder, this will open up the AndroidManifest.xml file in the code editor.
- In the AndroidManifest.xml file find the following line of code, android:name=".BreakoutGame"
- Immediately below type or copy and paste these two lines to make the game run full screen and lock it in the landscape orientation.
1 2 |
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:screenOrientation="landscape" |
That’s it. If you run the game it will be full-screen and landscape. Note however that some tablets don’t allow true full-screen.
Getting the screen resolution
In this project, we are going to make a much fuller system than in our simple game engine. Having said that we will still not be making a fully featured engine; we will progress steadily in complexity with each game project. One improvement this game will have is that we will detect and respond to the individual device resolutions that our Breakout game might run on. Add two variables to hold the horizontal and vertical resolution of the device just after the declaration of timeThisFrame. For more context, you can see the entire listing of BreakoutGame.java at the end of this page.
1 2 3 |
// The size of the screen in pixels int screenX; int screenY; |
Now we can initialize those variables via an object of the type Point using a Display object in the next block of code. Add this code into the BreakoutView constructor just after we initialize the paint object.
1 2 3 4 5 6 7 8 |
// Get a Display object to access screen details Display display = getWindowManager().getDefaultDisplay(); // Load the resolution into a Point object Point size = new Point(); display.getSize(size); screenX = size.x; screenY = size.y; |
Creating the player paddle
Right-click the java folder in the Android Studio project explorer as shown in the next image.
Now select New|Java class then select …\app\source\main\java and click OK. Now enter Paddle as the name for our new class and click OK. We have now created a new Java class in a separate file called Paddle. The code is not amongst the rest of our code but we can still access it as we will soon see. This helps us to compartmentalize our code and keep it organized into logical areas. We will do the same for our ball and for a brick.
The code for the Paddle class
Let’s code this class in its entirety then we can switch back to the BreakoutGame class and its inner BreakoutView class and put our paddle to work.
Take a look through the entire code listing for the Paddle class. Be sure to read all the comments for clarification we will talk about it afterward. Copy and paste this code below the package declaration in your Paddle.java file.
1 2 3 4 5 6 7 8 9 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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
import android.graphics.RectF; public class Paddle { // RectF is an object that holds four coordinates - just what we need private RectF rect; // How long and high our paddle will be private float length; private float height; // X is the far left of the rectangle which forms our paddle private float x; // Y is the top coordinate private float y; // This will hold the pixels per second speed that the paddle will move private float paddleSpeed; // Which ways can the paddle move public final int STOPPED = 0; public final int LEFT = 1; public final int RIGHT = 2; // Is the paddle moving and in which direction private int paddleMoving = STOPPED; // This the the constructor method // When we create an object from this class we will pass // in the screen width and height public Paddle(int screenX, int screenY){ // 130 pixels wide and 20 pixels high length = 130; height = 20; // Start paddle in roughly the sceen centre x = screenX / 2; y = screenY - 20; rect = new RectF(x, y, x + length, y + height); // How fast is the paddle in pixels per second paddleSpeed = 350; } // This is a getter method to make the rectangle that // defines our paddle available in BreakoutView class public RectF getRect(){ return rect; } // This method will be used to change/set if the paddle is going left, right or nowhere public void setMovementState(int state){ paddleMoving = state; } // This update method will be called from update in BreakoutView // It determines if the paddle needs to move and changes the coordinates // contained in rect if necessary public void update(long fps){ if(paddleMoving == LEFT){ x = x - paddleSpeed / fps; } if(paddleMoving == RIGHT){ x = x + paddleSpeed / fps; } rect.left = x; rect.right = x + length; } } |
Variables, access specifiers, and constants
First of all, before the class declaration we import a class called RectF. We will see RectF in action soon. It basically allows us to create a rectangle based on four float coordinates. This is perfect for representing the coordinates that we need to draw and as we will see when we handle collision detection the RectF class has a method to do all the hard work for us.
Next, we declare a whole bunch of member variables that are self-explanatory apart from one thing which we have not seen before but we did talk about in the Understanding OOP for Java games tutorial. All of the variables have an access specifier; either private or public. The private specifier means that the variable can only be read or changed within this ( Paddle) class and public means that any class that has an object of type Paddle can access it.
The private variables protect themselves from being changed in ways that they were not intended. By doing things this way we improve our code because we control how it operates to within the scope of just this class. It is called encapsulation and as our code gets longer and longer and we add more classes it is invaluable for keeping our code manageable. But if these variables are private, how on earth do we make use of them? We will see how very soon.
Before we do, it also raises the question of why are three of our variables STOPPED, LEFT and RIGHT declared as public. They are not technically variables, they are constants, as defined by the final keyword. They cannot be changed. What they do is they make obvious to classes that use the Paddle class exactly what three states a Paddle object can be in. They can then refer to those states without worrying about how they are used internally in the Paddle class. We will see exactly how they work later in this class and also back in the BreakoutView class when we handle the player’s input.
The Paddle class constructor
Next, we  have the constructor method that starts public void Paddle(...). This is the method that sets up the object when we initialize it. When we initialize an object of the type Paddle we need to pass in values that match those in the signature. In this case, two int variables, screenX and screenY. These variables will hold the screen’s horizontal and vertical resolution of pixels.
Inside the constructor, we then initialize the length and height variables for our future paddle, divide the screen width by two and subtract 20 from the height to get the approximate center bottom of the screen as a starting place for the paddle.
Then we initialized our RectF object by passing in four coordinates x, y, x+ length, y + height. This object now holds four coordinates that start with the top left corner of ( x,y)and completes with the bottom right corner of x+ length, y + height. The constructor will now alter the length and height variables to cope with positioning the paddle almost center bottom of the screen regardless of the device’s screen resolution.
Finally, in the constructor, we set the speed of the paddle to 350 pixels per second by initializing paddleSpeed to 350.
Accessing private variables with getters and setters
The next method is getRect. It is called a getter because it gets the value of variables and returns them. Notice it is public. This means that our BreakoutView class will be able to use it. And look what it does. Just one thing. It returns a copy of rect. BreakoutView will now be able to use this method to get the coordinates of the paddle so it can draw it to the screen or detect if it has hit the ball.
The next method setMovementState does just one thing. It receives a int parameter and assigns it to the private paddleMoving variable. In BreakoutView soon we will use the constant variables STOPPED, LEFT and RIGHT in conjunction with this method to alter the paddleMoving variable. When we do so it will control what happens when the next public method we will see is called.
The Paddle update method explained
The update method of the Paddle class is separate from the update method of our BreakoutView class. Once per frame, the update method of the BreakoutView class will call the update method of the Paddle class. In this update method, the paddle will be assigned new coordinates if necessary, ready for when the draw method is called.
In the update method, we check for two possible conditions paddleMoving == LEFT and paddleMoving == RIGHT. We then change the x coordinate by the speed per second divided by the frames per second passed into the method. After the two if statements we update the starting and finishing ( rect.left and rect.right) coordinates of rect. Notice that if paddleMoving == STOPPED is true then nothing would change that frame.
Now we have coded and discussed the Paddle class we can put it to use.
Using the Paddle class
We will do this in a few steps. As we need to insert code in various different places within our game engine (BreakoutGame.java) I will explain as clearly as possible where each bit of code goes. For absolute clarity check the code listing at the very end of the article where the finished code for the BreakoutGame class including the BreakoutView inner class is listed in its entirety.
First of all, we declare an object of the type Paddle called paddle. You can add this code anywhere after the BreakoutView declaration but before the constructor; I added it after the declaration of screenX and screenY.
1 2 |
// The player's paddle Paddle paddle; |
Now we need to instantiate it. As we need to pass in the screen’s horizontal and vertical resolution. The ideal place to do this is in the BreakoutView constructor after we initialized screenX and screenY.
1 |
paddle = new Paddle(screenX, screenY); |
Now we simply add a call to the paddle object’s update method. This code goes, as we might expect in the update method of the BreakoutView class.
1 2 |
// Move the paddle if required paddle.update(fps); |
Then, in the draw method, we can draw the rectangle that represents the paddle. Notice that when we use drawRect, compared to the Drawing graphics demo project, we replace the actual rectangle coordinates with a call to paddle.getRect. As we discussed this method returns whatever the current coordinates of the paddle are. Add this code to the draw method just after the call to paint.setColor.
1 2 |
// Draw the paddle canvas.drawRect(paddle.getRect(), paint); |
One more step before we can see our paddle in action.
Detecting input and moving the paddle.
Here we will add code to the onTouchEvent method. All we need to do is get the coordinates that the touch occurred at within the ACTION_DOWN case with motionEvent.getX(), we can then determine which half of the screen was pressed by determining if the coordinate is smaller or larger than screenX divided by two. If it’s larger we call setMovementState(paddle.RIGHT), if not we use paddle.LEFT. Also in, ACTION_DOWN case we set paused to false which will start our game engine updating because we wrapped a if(!paused) statement around the call to update in the run method.
Also, notice that for the, ACTION_UP case it doesn’t matter about the coordinates where the action happened we just call setMovementState(paddle.STOPPED).  Here is the entire code for the onTouchEvent method with the new code we just discussed as well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// The SurfaceView class implements onTouchListener // So we can override this method and detect screen touches. @Override public boolean onTouchEvent(MotionEvent motionEvent) { switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) { // Player has touched the screen case MotionEvent.ACTION_DOWN: paused = false; if(motionEvent.getX() > screenX / 2){ paddle.setMovementState(paddle.RIGHT); } else{ paddle.setMovementState(paddle.LEFT); } break; // Player has removed finger from screen case MotionEvent.ACTION_UP: paddle.setMovementState(paddle.STOPPED); break; } return true; } |
We now have full control over the paddle and can start the game. Run the game, tap the screen to un-pause, and move the paddle left and right by holding and releasing the appropriate half of the screen.
Let’s make a ball.
Creating the ball
As we did for our Paddle class, right-click the java folder in the Android Studio project explorer and select New|Java class then select …\app\source\main\java and click OK. Now enter Ball as the name for our new class and click OK. We have now created a new Java class in a separate file called Ball.
After everything, we learned while coding the Paddle class our Ball class will be quite straightforward. Let’s get an overview of what we need to do.
- Our ball will be square so it will need an RectF object and a getRect method to share the coordinates with BreakoutView.
- Our ball needs to move around in all four directions so it will need an x and a y velocity. In order to be able to update its coordinates as it moves around, it will need its own update method.
- Furthermore when our ball bumps into something it will need to reverse its velocity in the appropriate direction. The ball itself does not ‘know’ when it bumps into something so it will need public methods to reverse velocity; one for x and one for y.
- At the start of a game, the ball will need to reset its coordinates to a sensible starting situation sitting just above the bat and moving upwards.
- Also, because we are doing a very rudimentary implementation of the physics of bouncing we want the ball when it hits the paddle to bounce back in a random horizontal direction. We will need a method to create this randomness.
- Finally, from experience, I know that the ball will sometimes get stuck. For example, if we detect a collision when the ball is a couple of pixels into another object and reverse its velocity it is possible that it will remain stuck for eternity, constantly going back and forth. We need to be able to clear obstacles and we will write methods that achieve this for both the x and y-axis.
With these requirements in mind, we will need the following methods.
- A simple Ball constructor to give our ball its shape.
- A getRect method to pass the coordinates to BreakoutView
- AÂ update method to move our ball around based on its velocities.
- A reverseXVelocity and reverseYVelocity methods.
- A reset method to set the ball into its starting state each game.
- A setRandomXVelocity method to randomly choose which way the ball heads after hitting the paddle.
- And for when it gets stuck, clearObstacleX and clearObstacleY methods will do the job.
Here is the full code listing for the Ball class. We will look at each method in more depth, be sure to read the comments for clarification.
1 2 3 4 5 6 7 8 9 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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
import android.graphics.RectF; import java.util.Random; public class Ball { RectF rect; float xVelocity; float yVelocity; float ballWidth = 10; float ballHeight = 10; public Ball(int screenX, int screenY){ // Start the ball travelling straight up at 100 pixels per second xVelocity = 200; yVelocity = -400; // Place the ball in the centre of the screen at the bottom // Make it a 10 pixel x 10 pixel square rect = new RectF(); } public RectF getRect(){ return rect; } public void update(long fps){ rect.left = rect.left + (xVelocity / fps); rect.top = rect.top + (yVelocity / fps); rect.right = rect.left + ballWidth; rect.bottom = rect.top - ballHeight; } public void reverseYVelocity(){ yVelocity = -yVelocity; } public void reverseXVelocity(){ xVelocity = - xVelocity; } public void setRandomXVelocity(){ Random generator = new Random(); int answer = generator.nextInt(2); if(answer == 0){ reverseXVelocity(); } } public void clearObstacleY(float y){ rect.bottom = y; rect.top = y - ballHeight; } public void clearObstacleX(float x){ rect.left = x; rect.right = x + ballWidth; } public void reset(int x, int y){ rect.left = x / 2; rect.top = y - 20; rect.right = x / 2 + ballWidth; rect.bottom = y - 20 - ballHeight; } } |
First, we declare some variables to hold the coordinates, velocity, and size of the ball and in the constructor initialize the velocities and the rect object. Note that we have not yet assigned coordinates to the rect object, just initialized it with zero for each corner.
In update we change the coordinates of the ball with the same formula we used in the paddle class only without the conditions ( paddleMoving) and this time on both the x and y coordinates.
In getRect we return rect as we did for our Paddle class. In reverseYVelocity we make velocityY equal to -velocityY reversing whatever its current sign (+-) is and hence reversing the direction of the ball on the y-axis. In reverseXVelocity we do the same but for the x-axes of movement.
In setRandomXVelocity we use an object of type Random and generate a number with two possible values. If it is the first we reverse velocityX in the usual way if it is the second possible number we do nothing so velocityX remains the same.
To be clear, when the ball hits the left or right wall we will always reverse the velocity but when the ball hits the paddle we will randomly either change it or maintain it. This gives an effect of different types of impact with the paddle. It is scientifically inaccurate but is nice and simple. We will do some more advanced physics in the next full-game project.
The next methods we implemented were clearObstacleY and clearObstacleX where we respectively amend the vertical and horizontal coordinates of the ball. We will see soon where we use this but it is to avoid the ball getting stuck.
We can now go and play with our ball.
Using a ball object
Declare an object of type Ball below where we declared paddle.
1 2 |
// A ball Ball ball; |
Initialize ball right after the initialization of paddle.
1 2 |
// Create a ball ball = new Ball(screenX, screenY); |
Call the ball.update method below where we called the paddle.update method in the BreakoutView update method.
1 |
ball.update(fps); |
Use drawRect in exactly the same way as we did for the paddle but use the getRect method on ball. Add the code right after the code to draw the paddle.
1 2 |
// Draw the ball canvas.drawRect(ball.getRect(), paint); |
Now we need to create a new method which we will call each time a new game is started. We will add more code to this later in the project but for now, we just call ball.reset. Add the createBricksAndRestart method right after the constructor in BreakoutView. The method could actually go anywhere within the BreakoutView class but this seems like a logical place for it.
1 2 3 4 5 6 |
public void createBricksAndRestart(){ // Put the ball back to the start ball.reset(screenX, screenY); } |
Finally, for this part of the project, we want to call this new method as the very last line of code in the BreakoutView constructor.
1 |
createBricksAndRestart(); |
Now we can run the game, tap the screen to start, and watch the ball fly off into oblivion.
Creating some bricks
As we have done before to create a new class select right-click the java folder and select  New|Java class then select …\app\source\main\java and click OK. Now enter Brick as the name for our new class and click OK. We have now created a new Java class in a separate file called Brick.
Our Brick class is the simplest of them all. All that a brick needs to do is sit there looking brick-like until it is bashed by a ball at which time it should disappear. Knowing this we can work out that a brick will need an RectF object and a boolean variable so our game engine knows if it is destroyed or visible.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import android.graphics.RectF; public class Brick { private RectF rect; private boolean isVisible; public Brick(int row, int column, int width, int height){ isVisible = true; int padding = 1; rect = new RectF(column * width + padding, row * height + padding, column * width + width - padding, row * height + height - padding); } public RectF getRect(){ return this.rect; } public void setInvisible(){ isVisible = false; } public boolean getVisibility(){ return isVisible; } } |
In the class above we can see that we have an RectF as expected and a boolean isVisible. In the constructor, we can see that we pass in a row number, column number and a width and height for the brick. Next, in the constructor, we initialize the location of the brick using the row number, column number, width height and one pixel of padding so we can distinguish each individual brick from the others.
As we have come to expect rect and isVisible are private so we need a getRect method a setInvisible method for when a brick is hit by the ball and a getVisibility method which will let us check on the current visibility status of a brick.
Now we will see how we draw all our bricks.
Drawing the bricks
In order to manage our bricks, it will be really tidy to keep them in an array. Declare an array called bricks and a variable to keep track of its size called numBricks. Add this code after the ball declaration in the BreakoutView class.
1 2 3 |
// Up to 200 bricks Brick[] bricks = new Brick[200]; int numBricks = 0; |
Perhaps unsurprisingly we will create our bricks in the createBricksAndRestart method. First, we define the size of the bricks based on the resolution of the screen and initialize numBricks to zero so we can keep track of the number of bricks that we draw. We will use this variable in a number of places as we will see.
Next, we set a nested for loop an outer one for each column and the inner one for each row. The code below loops through 3 rows with 8 columns in each. In the centre of the two loops we create a new brick based on the column number, row number, width and height. And of course, our Brick class will use this information to set the coordinates of each accordingly. Each Brick object is neatly tucked away in our bricks array. After we declare and initialize each brick we increment numBricks to keep track of the number of bricks in the array. You can easily alter the number of rows and columns as well as the size of the bricks and the code will still work. Add this code after the code to reset the ball.
1 2 3 4 5 6 7 8 9 10 11 12 |
int brickWidth = screenX / 8; int brickHeight = screenY / 10; // Build a wall of bricks numBricks = 0; for(int column = 0; column < 8; column ++ ){ for(int row = 0; row < 3; row ++ ){ bricks[numBricks] = new Brick(row, column, brickWidth, brickHeight); numBricks ++; } } |
Now we will draw all our bricks, again using a for loop to loop through the bricks array. Just before we do so we change the color of the brush to make our bricks a different color than the paddle and ball. Add this code in the draw method just after we draw the ball. Notice that as we loop through the bricks array we first check if getVisibility returns true. Only if it does will the brick be drawn. We make sure we don’t access an empty slot in the array by using i < numBricks as the condition of the for loop.
1 2 3 4 5 6 7 8 9 |
// Change the brush color for drawing paint.setColor(Color.argb(255, 249, 129, 0)); // Draw the bricks if visible for(int i = 0; i < numBricks; i++){ if(bricks[i].getVisibility()) { canvas.drawRect(bricks[i].getRect(), paint); } } |
We can now run the game and see the bricks.
The problem, of course, is that the ball just flies straight through them. What we need is to detect when things bump into each other. When these collision events occur we can then take appropriate action. As these actions include things like playing a sound, changing the score, and restarting the game, let’s add some code to play sounds and handle the score then we will see how to detect the collision events.
Making some noise and keeping score
We will now add the ability to keep score and play sound FX. If you want to learn more details about how this sound code works have a look at the Playing sound FXÂ tutorial. Let’s get started because we are not far away from a complete working Breakout game. Add this code to hold references to a bunch of sound FX and to keep track of the score and lives that the player has. The code goes right after the declaration of numBricks in the BreakoutView class.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// For sound FX SoundPool soundPool; int beep1ID = -1; int beep2ID = -1; int beep3ID = -1; int loseLifeID = -1; int explodeID = -1; // The score int score = 0; // Lives int lives = 3; |
Next, in the BreakoutView constructor, just BEFORE the call to createBricksAndRestart add this code to load the sound FX from their files.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// Load the sounds // This SoundPool is deprecated but don't worry soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC,0); try{ // Create objects of the 2 required classes AssetManager assetManager = context.getAssets(); AssetFileDescriptor descriptor; // Load our fx in memory ready for use descriptor = assetManager.openFd("beep1.ogg"); beep1ID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("beep2.ogg"); beep2ID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("beep3.ogg"); beep3ID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("loseLife.ogg"); loseLifeID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("explode.ogg"); explodeID = soundPool.load(descriptor, 0); }catch(IOException e){ // Print an error message to the console Log.e("error", "failed to load sound files"); } |
Of course, we need to add the sound files to our project. You can create your own or download mine by right-clicking on the files listed below. Just make sure you use exactly the same file names. You can also listen to each of the sounds by using the media controls below the links.
beep1
beep2
beep3
explode
loseLife
When you have your preferred sound FX, using your operating system’s file browser go to the app\src\main folder of the project and create a folder called assets. Add your sound file to this folder.
Now at the very end of the createBricksAndRestart method, we can initialize our score and lives variables like this.
1 2 3 4 |
// Reset scores and lives score = 0; lives = 3; } |
Now in the draw method, near the end, just after we draw the bricks add this code to draw the score, and lives, and announce either victory or defeat based on clearing all the bricks or losing all their lives.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// Draw the HUD // Choose the brush color for drawing paint.setColor(Color.argb(255, 255, 255, 255)); // Draw the score paint.setTextSize(40); canvas.drawText("Score: " + score + " Lives: " + lives, 10,50, paint); // Has the player cleared the screen? if(score == numBricks * 10){ paint.setTextSize(90); canvas.drawText("YOU HAVE WON!", 10,screenY/2, paint); } // Has the player lost? if(lives <= 0){ paint.setTextSize(90); canvas.drawText("YOU HAVE LOST!", 10,screenY/2, paint); } |
Now we will see how we can detect collisions, play the sounds and change the score.
Collision detection
All of this code goes in the update method right after we update the paddle. I will present the code in manageable chunks in the order it should be entered. If at any time you are unsure of exactly where some code goes just jump to the end of this page and you can see the whole of the BreakoutGame class in a single listing.
Here we loop through the bricks array with a for loop. For each brick, we check if it is visible by calling getVisibility and if it is we use a method of the RectF class called intersects. The intersects method takes two RectF parameters so we pass in our ball and the brick currently being checked. If they intersect(have collided) it returns true and the code inside the if block will execute. Before we look at the code inside the if block you might notice the slightly strange-looking call to intersects.
The syntax is RectF.intersects(.... We are actually calling the method on the class, not on the object OF the class. This is a special type of method known as a static method. When a method is declared static it allows this functionality. Methods are often declared static when the action performed in the method is not actually on an individual object yet it makes sense for the functionality to be available with objects of that type.
Inside the if statement we set the brick to be invisible, reverse the balls y direction of travel, add ten to the score, and play the exploding sound.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Check for ball colliding with a brick for(int i = 0; i < numBricks; i++){ if (bricks[i].getVisibility()){ if(RectF.intersects(bricks[i].getRect(),ball.getRect())) { bricks[i].setInvisible(); ball.reverseYVelocity(); score = score + 10; soundPool.play(explodeID, 1, 1, 0, 0, 1); } } } |
In this next block of code, we again use the static intersects method to check for a collision between two objects of the type RectF. This time the paddle and the ball objects. If we have a collision we set a random x velocity so the ball could bounce off to either the left or the right and we reverse the y velocity so it heads back up the screen. Now we use our clearObstacleY method to make sure the ball doesn’t get stuck to the paddle and we pass in the position of the top of the paddle minus two pixels so the method will make sure that the ball resumes it’s upwards journey starting two pixels away from the top of the paddle. We play another beep and we are done here.
1 2 3 4 5 6 7 |
// Check for ball colliding with paddle if(RectF.intersects(paddle.getRect(),ball.getRect())) { ball.setRandomXVelocity(); ball.reverseYVelocity(); ball.clearObstacleY(paddle.getRect().top - 2); soundPool.play(beep1ID, 1, 1, 0, 0, 1); } |
Now we handle a collision with the bottom of the screen. The bottom of the screen is obviously not a RectF so we can’t use the intersects method but we do know the exact coordinate of the bottom of the screen; it is screenY. So we just test for the bottom of the ball being greater than screenY. If it is the ball has hit the bottom. We then reverse the y velocity use the clearYObstacle to clear the bottom of the screen by two pixels, deduct a life and play a gloomy thud sound. Finally in the block of code below we test to see if the player has zero lives and if they do we pause the game and call createBricksAndRestart to build the game again from scratch.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// Bounce the ball back when it hits the bottom of screen // And deduct a life if(ball.getRect().bottom > screenY){ ball.reverseYVelocity(); ball.clearObstacleY(screenY - 2); // Lose a life lives --; soundPool.play(loseLifeID, 1, 1, 0, 0, 1); if(lives == 0){ paused = true; createBricksAndRestart(); } } |
The next block of code tests if the ball has hit the top of the screen. I love it when the ball bounces along the top of the blocks, I get a little dopamine rush and it reminds me of playing this game as a child. Yes, I am that old. Back to the code. We test for the top of the ball being less than zero and if so reverse the y velocity clear the top of the screen by 12 pixels and play a beep. The reason we cleared the top of the screen by 12 pixels is that the clearObstacleY method works on the bottom of the ball and the ball is ten pixels high.
1 2 3 4 5 6 |
// Bounce the ball back when it hits the top of screen if(ball.getRect().top < 0){ ball.reverseYVelocity(); ball.clearObstacleY(12); soundPool.play(beep2ID, 1, 1, 0, 0, 1); } |
The next block of code bounces the ball off of the left of the screen. All the code is self-explanatory at this point just note that we reverse the x velocity, not the y velocity.
// If the ball hits left wall bounce if(ball.getRect().left < 0){ ball.reverseXVelocity(); ball.clearObstacleX(2); soundPool.play(beep3ID, 1, 1, 0, 0, 1); }
1 |
The next block of code bounces the ball off of the right of the screen. All the self-explanatory at this point just again note that we reverse the x velocity not the y. |
1 2 3 4 5 6 |
// If the ball hits right wall bounce if(ball.getRect().right > screenX - 10){ ball.reverseXVelocity(); ball.clearObstacleX(screenX - 22); soundPool.play(beep3ID, 1, 1, 0, 0, 1); } |
Here we check if score equals numBricks multiplied by ten. This would indicate all the blocks have been cleared so we restart the game in the usual way.
1 2 3 4 5 |
// Pause if cleared screen if(score == numBricks * 10){ paused = true; createBricksAndRestart(); } |
You can now run the game and play it for real.
What next
Congratulations on completing the game! There will be some more complete game projects really soon. In these projects, we will increase the number and variety of objects in our game and we will also significantly enhance the features of the game engine. A good next step would be to try the Android Space Invaders project.
And finally as promised here is the complete listing for the BreakoutGame class and its BreakoutView inner class.
1 2 3 4 5 6 7 8 9 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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 |
import android.app.Activity; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.graphics.RectF; import android.media.AudioManager; import android.media.SoundPool; import android.os.Bundle; import android.util.Log; import android.view.Display; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import java.io.IOException; public class BreakoutGame extends Activity { // gameView will be the view of the game // It will also hold the logic of the game // and respond to screen touches as well BreakoutView breakoutView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Initialize gameView and set it as the view breakoutView = new BreakoutView(this); setContentView(breakoutView); } // Here is our implementation of BreakoutView // It is an inner class. // Note how the final closing curly brace } // is inside the BreakoutGame class // Notice we implement runnable so we have // A thread and can override the run method. class BreakoutView extends SurfaceView implements Runnable { // This is our thread Thread gameThread = null; // This is new. We need a SurfaceHolder // When we use Paint and Canvas in a thread // We will see it in action in the draw method soon. SurfaceHolder ourHolder; // A boolean which we will set and unset // when the game is running- or not. volatile boolean playing; // Game is paused at the start boolean paused = true; // A Canvas and a Paint object Canvas canvas; Paint paint; // This variable tracks the game frame rate long fps; // This is used to help calculate the fps private long timeThisFrame; // The size of the screen in pixels int screenX; int screenY; // The players paddle Paddle paddle; // A ball Ball ball; // Up to 200 bricks Brick[] bricks = new Brick[200]; int numBricks = 0; // For sound FX SoundPool soundPool; int beep1ID = -1; int beep2ID = -1; int beep3ID = -1; int loseLifeID = -1; int explodeID = -1; // The score int score = 0; // Lives int lives = 3; // When the we initialize (call new()) on gameView // This special constructor method runs public BreakoutView(Context context) { // The next line of code asks the // SurfaceView class to set up our object. // How kind. super(context); // Initialize ourHolder and paint objects ourHolder = getHolder(); paint = new Paint(); // Get a Display object to access screen details Display display = getWindowManager().getDefaultDisplay(); // Load the resolution into a Point object Point size = new Point(); display.getSize(size); screenX = size.x; screenY = size.y; paddle = new Paddle(screenX, screenY); // Create a ball ball = new Ball(screenX, screenY); // Load the sounds // This SoundPool is deprecated but don't worry soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0); try { // Create objects of the 2 required classes AssetManager assetManager = context.getAssets(); AssetFileDescriptor descriptor; // Load our fx in memory ready for use descriptor = assetManager.openFd("beep1.ogg"); beep1ID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("beep2.ogg"); beep2ID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("beep3.ogg"); beep3ID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("loseLife.ogg"); loseLifeID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("explode.ogg"); explodeID = soundPool.load(descriptor, 0); } catch (IOException e) { // Print an error message to the console Log.e("error", "failed to load sound files"); } createBricksAndRestart(); } public void createBricksAndRestart() { // Put the ball back to the start ball.reset(screenX, screenY); int brickWidth = screenX / 8; int brickHeight = screenY / 10; // Build a wall of bricks numBricks = 0; for (int column = 0; column < 8; column++) { for (int row = 0; row < 3; row++) { bricks[numBricks] = new Brick(row, column, brickWidth, brickHeight); numBricks++; } } // if game over reset scores and lives if (lives == 0) { score = 0; lives = 3; } } @Override public void run() { while (playing) { // Capture the current time in milliseconds in startFrameTime long startFrameTime = System.currentTimeMillis(); // Update the frame if (!paused) { update(); } // Draw the frame draw(); // Calculate the fps this frame // We can then use the result to // time animations and more. timeThisFrame = System.currentTimeMillis() - startFrameTime; if (timeThisFrame >= 1) { fps = 1000 / timeThisFrame; } } } // Everything that needs to be updated goes in here // Movement, collision detection etc. public void update() { // Move the paddle if required paddle.update(fps); ball.update(fps); // Check for ball colliding with a brick for (int i = 0; i < numBricks; i++) { if (bricks[i].getVisibility()) { if (RectF.intersects(bricks[i].getRect(), ball.getRect())) { bricks[i].setInvisible(); ball.reverseYVelocity(); score = score + 10; soundPool.play(explodeID, 1, 1, 0, 0, 1); } } } // Check for ball colliding with paddle if (RectF.intersects(paddle.getRect(), ball.getRect())) { ball.setRandomXVelocity(); ball.reverseYVelocity(); ball.clearObstacleY(paddle.getRect().top - 2); soundPool.play(beep1ID, 1, 1, 0, 0, 1); } // Bounce the ball back when it hits the bottom of screen if (ball.getRect().bottom > screenY) { ball.reverseYVelocity(); ball.clearObstacleY(screenY - 2); // Lose a life lives--; soundPool.play(loseLifeID, 1, 1, 0, 0, 1); if (lives == 0) { paused = true; createBricksAndRestart(); } } // Bounce the ball back when it hits the top of screen if (ball.getRect().top < 0) { ball.reverseYVelocity(); ball.clearObstacleY(12); soundPool.play(beep2ID, 1, 1, 0, 0, 1); } // If the ball hits left wall bounce if (ball.getRect().left < 0) { ball.reverseXVelocity(); ball.clearObstacleX(2); soundPool.play(beep3ID, 1, 1, 0, 0, 1); } // If the ball hits right wall bounce if (ball.getRect().right > screenX - 10) { ball.reverseXVelocity(); ball.clearObstacleX(screenX - 22); soundPool.play(beep3ID, 1, 1, 0, 0, 1); } // Pause if cleared screen if (score == numBricks * 10) { paused = true; createBricksAndRestart(); } } // Draw the newly updated scene public void draw() { // Make sure our drawing surface is valid or we crash if (ourHolder.getSurface().isValid()) { // Lock the canvas ready to draw canvas = ourHolder.lockCanvas(); // Draw the background color canvas.drawColor(Color.argb(255, 26, 128, 182)); // Choose the brush color for drawing paint.setColor(Color.argb(255, 255, 255, 255)); // Draw the paddle canvas.drawRect(paddle.getRect(), paint); // Draw the ball canvas.drawRect(ball.getRect(), paint); // Change the brush color for drawing paint.setColor(Color.argb(255, 249, 129, 0)); // Draw the bricks if visible for (int i = 0; i < numBricks; i++) { if (bricks[i].getVisibility()) { canvas.drawRect(bricks[i].getRect(), paint); } } // Choose the brush color for drawing paint.setColor(Color.argb(255, 255, 255, 255)); // Draw the score paint.setTextSize(40); canvas.drawText("Score: " + score + " Lives: " + lives, 10, 50, paint); // Has the player cleared the screen? if (score == numBricks * 10) { paint.setTextSize(90); canvas.drawText("YOU HAVE WON!", 10, screenY / 2, paint); } // Has the player lost? if (lives <= 0) { paint.setTextSize(90); canvas.drawText("YOU HAVE LOST!", 10, screenY / 2, paint); } // Draw everything to the screen ourHolder.unlockCanvasAndPost(canvas); } } // If SimpleGameEngine Activity is paused/stopped // shutdown our thread. public void pause() { playing = false; try { gameThread.join(); } catch (InterruptedException e) { Log.e("Error:", "joining thread"); } } // If SimpleGameEngine Activity is started then // start our thread. public void resume() { playing = true; gameThread = new Thread(this); gameThread.start(); } // The SurfaceView class implements onTouchListener // So we can override this method and detect screen touches. @Override public boolean onTouchEvent(MotionEvent motionEvent) { switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) { // Player has touched the screen case MotionEvent.ACTION_DOWN: paused = false; if (motionEvent.getX() > screenX / 2) { paddle.setMovementState(paddle.RIGHT); } else { paddle.setMovementState(paddle.LEFT); } break; // Player has removed finger from screen case MotionEvent.ACTION_UP: paddle.setMovementState(paddle.STOPPED); break; } return true; } } // This is the end of our BreakoutView inner class // This method executes when the player starts the game @Override protected void onResume() { super.onResume(); // Tell the gameView resume method to execute breakoutView.resume(); } // This method executes when the player quits the game @Override protected void onPause() { super.onPause(); // Tell the gameView pause method to execute breakoutView.pause(); } } // This is the end of the BreakoutGame class |
hi john, also getting alot of red errors here too, would cleaning the project help?
Hi James,
Please give me an example of the errors. I appreciate the conversation as it helps make my website better.
Thanks.
Can you give me a source code completely running? i can pay you
Hi there,
Every line of code is on the page and the main class you can copy paste from the bottom of the article. No charge.
Hi John,
Can u make a tutorial for coding line98 game for android too ?
thanks
Hi Kelvin,
Just added it to my list of possibilities. Unfortunately it is looking like I might need to spend 6 months away from the site so it might not be soon. I will know more soon.
Thanks for your comment.
hi john, il list what they are in red in order……
paddle paddle //first word in red
ball ball //first word in red
brick [] //both words brick in array are red
paddle = new paddle //second word paddle in red
ball = new ball //second word ball in red
ball.reset //reset in red
bricks[numBricks] = new Brick //last word brick in red
paddle.update(fps); //both updates in red
ball.update(fps);
if (bricks[i].getVisibility()){ //get visability in red
if(RectF.intersects(bricks[i].getRect(), ball.getRect())) { //both getRect in red also setInvisible and reverseYVelocity
bricks[i].setInvisible();
ball.reverseYVelocity();
if(RectF.intersects(paddle.getRect(),ball.getRect())) { //getRect in red on all 3, as is setRandomVelocity and clearObstacle
ball.setRandomXVelocity(); //exactly the same for all If statements
ball.reverseYVelocity(); //and in the ourHolder if statement block
ball.clearObstacleY(paddle.getRect().top – 2);
setmovementstate right,left and stopped // are all in red as well
Hi James,
With that many errors and they all refer to brick, ball and paddle I have to ask if you have implemented the brick, ball and paddle classes? As games get more complicated we need to separate out the code into multiple files. So copy/pasting the main game engine class from the end of the tutorial isn’t enough to get it working any more. You need to step through the instructions and add the extra classes and the resources like sound FX. If I have completely missed the problem I apologise but it does seem like it might be what is going wrong.
I’d be really interested to know if this is the case because if it isn’t there must be a missing curly bracket somewhere which could be throwing the whole structure out. If that is the case I will look into this further.
Good luck and let me know how you get on.
Hey John, I don’t know if you are still active or not on this site but here goes.
I have the same problem as stated above. And I did make the paddle class. But the error is still there.
//Paddle paddle; the first paddle is red and says “Cannot resolve symbol Paddle”.
and when I go over to the Paddle class. and hover over the paddle class, it says “class Paddle is never used”. I guess the two classes are not merging with each other or something like that please help!!!
Many thanks for your comment. There are two possible solutions to your problem which I can think of.
1)The Paddle class has been created in the test module. If you look in the project explorer window (where the files and folders are shown on the left), you can expand the Java folder and there will be two options for placing new classes. All your Java files should be in the top one? Not the (androidTest) one.
2) The only other possibility I can think of is that the package declarations at the top of the file are different or there is a subtle typo in the class name.
I hope this helps. Let me know either way and I will try and think of some other possible causes if this is not the solution.
Thanks for the reply!
I think I found out the problem! The thing is the Paddle class is generated directly in the java folder instead of java/com.appname.BreakoutGame… Now how do I move the paddle class in the com.apk.BreakoutGame folder?
Try dragging and dropping or if that doesn’t work create a new class by right clicking on the folder you want the class in and choosing New | Class. Then copy & paste the code or type it again. This should work. Good luck.
Sorry but I have got one more problem. Actually two.
1. “Method does not override method from its superclass” for the @Override method for the public void run() class. I actually kind of solved it by removing the @Override from it. But does that affect anything?
2. “Cannot resolve constructor Thread(simplegames.breakoutgame.BreakoutGame.BreakoutView)” in the public void resume() class for the line gamethread = new Thread(this); The “this” is underlined for the error.
Sounds like the implements runnable from this line of code could be missing?
class BreakoutView extends SurfaceView implements Runnable {
Let me know if not and I will try and think of another possible cause.
Thank you! I solved the paddle class problem by directly dragging and dropping it in the folder.
We’re getting there!
Yeah! the error’s gone. Thanks a lot!!
Yay
just move it into com.domain.breakoutgame
Thanks for sharing the solution.
hi john, ive managed to get rid of the errors, can i ask some advice? ive read the book learning java by bulding android games and i have done a couple of game projects yet everything seems to be going right over my head and cant seem to memorize everything, im fine with the java i have learned but i want to be able to to start making my own games and knowing exactly what i am doing! i know about the life cycle of apps and games but wondering if there is a set order to buld a game from scratch? really hoping things clear up for me eventually but seems so confusing! do you have any reccomendations and next steps? any advice would be greatly appreciated.
regards
Just keep making games. I have left some specific responses to your air hockey question but practice is key. If you understand the Java then you should have no trouble handling slightly tougher projects.
Have a look at the spec of this book.
http://gamecodeschool.com/blog/android-game-programming-by-example/
It has 3 projects the first is probably of similar difficulty to the Space Invaders game on this site. The second is a fairly fully featured platform game and the third has limited features but is more complex because it uses OpenGL to draw the graphics. (And it covers radius overlap collision detection.)
I don’t like asking people to buy my books because I don’t like to be forward so you could contact Sunitha from Packt Publishing on sunithap@packtpub.com and see if she is still giving out review copies. Tell her that I suggested it.
Let me know how you get on and thanks for the conversation.
i.e id love to make a air hocky style game and learn the physics of using a round puck with good speeds
The basics of this are not too tough. You have round sprites to represent the puck and mallets. Use the radius overlap method for collision detection. Then when you have a collision you calculate the horizontal distance between the centre of the puck and mallet to determine an angle and combine that with the angle the puck was travelling at to determine the angle of reflection (the new angle the puck should be travelling at.)
Unfortunately I don’t have a tutorial on radius overlapping collision detection but here is one (unchecked)
http://gamedev.stackexchange.com/questions/74872/how-to-solve-the-overlap-of-two-circles-that-collide
The space invaders project uses sprites
http://gamecodeschool.com/android/coding-a-space-invaders-game/
The two introductory articles on trigonometric ratios will get you started on bouncing physics
http://gamecodeschool.com/essentials/calculating-heading-in-2d-games-using-trigonometric-functions-part-1/
Along with the related project
http://gamecodeschool.com/android/2d-rotation-and-heading-demo/
Hi john, been a year since last contact so just thought i would give you an update, since we last spoke i have managed to release some apps onto play store and am now learning unity! it was thanks to your books i was able to make some apps and get them out! i am now pushing towards game development as this was my original aim but by making apps i have been able to learn java and understand it better! i now to plan to work through your website tutorials and also unity to see where that leads! just feels great to know i can make and publish apps now! just wish i had some good ideas to make me rich lol
Hi James,
Really nice to hear from you again! Especially so to hear you have published some games. Re ideas, just think about what motivates you. Politics, a sport, family life, a simulation of a favorite/worst job? My problem is I have too many games that I want to make.
Keep in touch.
I have many ideas it is just a case of executing them! my problem is i get easily overwhelmed with ideas and find my self starting a project only to have another idea and then start that one. Im sure il get there at some stage!
In some ways, that’s a good thing and some ways not. It’s good because you are constantly reinforcing old concepts and trying new ones. It’s bad if finishing your project is important to you. So don’t beat yourself up about that as long as you are happy with the results.
thank you for this john i really appreciate it and i shall learn all of it.
best regards
i get these errors
breakout.java:183: error: method does not override or implement a method from a
supertype
@Override
^
breakout.java:185: error: cannot find symbol
super.onResume();
^
symbol: variable super
location: class BreakoutGame
breakout.java:192: error: method does not override or implement a method from a
supertype
@Override
^
…
…
63 errors
Hi there,
Seems the class isn’t valid at all. Probably because the class called BreakoutGame is in a file named breakout.java and it is required to be in a file with an identical name to the class. Try:
1) start again
2) follow carefully this part of the tutorial “Create a new project in Android Studio, call it Breakout Game and name the Activity BreakoutGame”.
Hopefully this will work for you.
Good luck!
hi there i have tried making your game and i was wondering if you could post how to make the paddle not move out of the screen and maby move with the motion of users finger
hope you will take the time to answer me
otherwise thanks for this awsome tutorial
Hi Jimmi,
To prevent the paddle going off the screen you could wrap the code that set the movement state in onTouchEvent method. For example to stop going off the right-hand side you could amend the code to look like this.
if(motionEvent.getX() > screenX / 2){ // Only set state if not too far over already! if(paddle.getRect().right < screenX){ paddle.setMovementState(paddle.RIGHT); }}
Have a go at working out the equivalent to stop it going off the left 😉
I haven’t had time to test this but it seems like it would work. Do let me know.
With regard to gestures it is hard for me to think of a gesture that is useful for this type of control. But what do you think?
Good luck.
I try it, but it doesn’t work. Help!
Hi there. Give me some details and I will try and help. Thanks for commenting.
Hi John!
I tried what you said above about the paddle going out of the screen.
But it doesn’t work. There is no error. It runs but to no effect. The paddle still goes of the screen. I think adding some kind of walls to the sides will do it. But then how to code them. Like adding two rectangles using Rectf or something like that will do…
Also I am unable to play any sound. Is it because of Soundpool class being deprecated as I run an android 4.2.2 Jellybean. Any alternative method for the sounds if it is the problem of SoundPool class..
Also I tried to bring the paddle to the starting point after it the game is over using the same structure used for the ball i.e reset method.
The paddle does come in between but now the ball bounces off the floor instead off the paddle as if the paddle doesn’t exist.
This is a flaw in the app and not easily fixed. I would recommend doing the Space Invaders demo which is structured differently and then try and start the Breakout game again using what you have learnt (if it is important to you).
Regarding the sound; the deprecated class should be fine. Try making sure the folder creation step was done exactly right and all the assets/sounds are named correctly.
Regarding the paddl; the code above should stop the x coordiante becoming larger than the screen width. So the paddle would still go off screen but it would(should) stop just off-screen. You could try changing the condition if(paddle.getRect().right < (screenX - 130)). This might do the trick.
Thanks for your comment!
The sounds started working. When declaring the sounds I typed in .ogg instead of .wav. Still the explode sound doesn’t work. But now worries.
The paddle still goes out of the screen so no luck there.
Also according to your code, the “You Have Won” & “You Lose” paints it on the screen but calling the createBricksAndRestart method happens too fast to ever see that paint it on your screen. So I added a sleep thread in between of nearly 2 secs and that did the trick.
One last thing, sorry. But i tried to add a splash screen to the game with all the sleep thread and stuff but the game crashes after the splash screen ends. Any suggestions…
Well, I am going to start with the space invaders project now. And come back to this game later.
Thanks for the feedback.
You could create a splash screen using a separate activity with a timer that starts the game activity after a short wait. I haven’t got a tutorial that does this on this site but you could search for “switching activities with the Intent class”.
Another way to stop the paddle going off the screen would be to add some code in the Paddle class’ update() method. Something like if (rect.right > ...) {rect.right = ...}. You could either hardcode the width of the screen or add a member variable that you could initialize with the screen width in the constructor of the Paddle class.
I am going to update these tutorials based on feedback like yours but I will probably not get round to it for a month or two.
Thanks again!
*no worries
If you want to make it so the paddle can’t move out of screen, just make somthing like this in paddle class:
if(paddleMoving == LEFT && x > 0){ ... }if(paddleMoving == RIGHT && x < 1657){ // (2nd value may be different for different phones). }
Not sure if it gona work for everyone but its working for me.
Thanks Forest. Sounds like a good tip.
Am i aloud to use your code as a basic structure to expand on this, to later release it on Google Play?
Hi Bill,
Thanks for the question. I make no claim to copyright on the use of the code. It is my interpretation of what I have learned from others over the years. The only thing that would make me grumpy is if it was made into another and not substantially different tutorial. I get a free thrill every time I hear someone has made a game and I might have helped a bit. Good luck and I would be glad to hear of your progress.
John
Is it possible to upload the full source code?
Hi there,
I hope to have a downloadable zip sometime in the future.
hello John,
have you upload the full cource code?
Hi Zahid,
Unfortunately I don’t have a download for this but you can copy & paste the code from the end of the article.
I’m getting the following error when I try to run the app on my Nexus 5 (not 5X) running Marshmallow:
java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
Please HALP!
Hi Raffi,
Which version of Activity does your code extend? Check that your BreakoutGame class starts like this:
public class BreakoutGame extends Activity {
….
And not like this:
public class BreakoutGame extends ActionBarActivity {
// gameView will be the view of the game
Let me know how you get on, good luck and thanks for the comment.
If you use AppCompatActivity, then you need to change some things in the styles.xml file.
In between the “” tags, replace what you have with the following:
true
false
true
@null
That should clear up the error you’re getting.
true false true @null
Hey my problem is that sometimes when the ball hits the paddle i lose one life.
sry for bad english. 😀
Hi Lukas,
Is it a low frame rate? This would cause the ball to travel further between collision checks. Or it could just be the very simplistic way this is implemented. Another way you could solve it is to amend the code to move the paddle off of the bottom of the screen?
Good luck, let me know how you get on.
Yes it was just the emulator. i tried it on my phone and it worked fine.
But another problem is that if i destroy all Bircks my game does reset but when i press the screen the ball doesnt move.
i hope you understand my question.
your tutorials are pretty great i learn a lot from them 😀
Hi Lukas,
Thanks very much for your kind comment. Yes, I think I understand your question. I have just been looking at the code because it has been a while and I have to say I can’t see why that is happening. If you are calling ball.reset all should be well. Try outputting some debugging variables to the screen. Like the x,y of the ball and the value of the paused variable. See if that turns up any solutions.
I would be interested to know if you can solve it. I have to be honest I don’t think I tested the game as far as restarting and the fault might well be mine.
Good luck and thanks!
I solved that question but now i wanted the height and lenght of the ball to be dependent on the size of the screen but if the ball gets bigger then 10 pixels. the Ball just doesnt bounce of the paddle.
i have a lot of fun with this game 😀 I invented a few new things.For example the game now has level where the ball gets faster and the paddle smaler and even more rows of bricks.
Thank you for your answers ;P
Try looking at the defence brick class in the space invaders project as a hint to achieve your ball requirements. But to be really accurate remember that there are small screens with a high resolution and big screens with low resolution so you need to get the screen size and come up with a formula based on both.
Hey,
I would like to add some background music, so where should I add the soundpool.play code? I tried adding it to the on resume code when the player starts the game, but the game doesn’t install. Any tips?
Hi Henry,
To play music in your game you really need to use some techniques I haven’t written about yet.
If the music sample is very short you might get away with using the SoundPool class as described.
It is probably best to Google and research the MediaPlayer class and use that instead.
Thanks for the question!
Hi, thanks for the reply!
Can I use soundPool and MediaPlayer in the code at the same time or do I have to replace soundPool with MediaPlayer?
They will work fine together so use SoundPool for fx and MediaPlayer for music.. I have added it to my todo list so my next Android tutorial will have music in it. Might be a month ish though.
And what to do with the xml file having the design view. As mine is still blank and is showing nothing but a “Hello World” text.
Help me out.
HI Aqsa,
You can safely ignore/delete the layout XML. If you look in the onCreate method you will see that the call to setContentView uses our custom class instead of the xml file.
Hope this helps.
So, we have to run this app on android studio. Right? As I am running there.
Yes. For more details on getting the project started check the links in the “Assumed previous experience column” near the top of the article.
Now i have rename my project to BreakJail and it’s paddle class is showing me an error over RectF. What should i now?
It depends how you renamed it. Are the package declarations at the top of the files the same?
Which RectF error?
Have you imported RectF.
Hope this helps. If not let me have a few more details and I’ll try again.
Hey John,
I am trying to make this game again using sprites and stuff that I learned in the Space Invaders tutorial. I did the paddle and ball successfully but I am stuck on the Bricks. I can’t seem to find out how to create a array of the bitmap. I am getting two errors:
In the BreakoutView class:
1.private Brick[] brick; — the variable is greyed out and says it says private field brick is never assigned.
2. In the draw method:
canvas.drawBitmap(brick.getBitmap(), brick.getX(), screenY – 520, paint); — the “.getBitmap()” and “.getX()” methods are red and says “cannot resolve
method”
In the Brick class:
public Bitmap getBitmap(){return bitmap;}
public float getX(){return x;}
— the getX() and getBitmap() methods are greyed out.
and i can’t find the way to get around this.
I tried stackoverflow.com, but it says about adding an arraylist but then more errors pop up.
Any help??
Hi there,
I see you have declared the array but have you initialized the array as well?
Perhaps something like this:
private Brick[] bricks = new Brick[400];
then prepare the array something like this:
// Build the array of bricks
int numBricks = 0;
for(int column = 0; column < 20; column ++ ){ for(int row = 0; row < 5; row ++ ){ bricks[numBricks] = new Brick(Whatever parameters your constructor takes); numBricks ++; } } Hope this helps
Well the “private Brick[] brick” is not greyed out now. But the “getBitmap()” and “getX()” errors still persists and the methods are still greyed out in the Bricks class… Help??
The methods would probably appear grayed out until they are used in some code somewhere.
Look at a snippet on how the invaders are drawn in the space invaders project.
// Draw the invaders
for(int i = 0; i < numInvaders; i++){ canvas.drawBitmap(invaders[i].getBitmap(), invaders[i].getX(), invaders[i].getY(), paint); } Can you adapt the above code to your situation? Do the methods still appear grayed out?
Thanks john.
The errors are gone.Well its not running though, it has some basic mistakes, I guess. I may post here again if I get stuck.
Sorry John but here I am again…
I can’t find a solution.
The app crashes on start up even though there is not a single error.
Please post the crash data from logcat and I will try and point you in the right direction.
The log cat is too big. How do I just post the crash data??
Hi Anurag,
Try and identify the part which has the crash in it. You can filter the logcat window with various dropdown options at the top of the window.
A crash like this is often something like a null pointer exception, perhaps because you have used an uninitialized object.
Or as you are dealing with an array, perhaps your code accidentally writes or reads past the end of it causing a array out of bounds exception.
The cause might be in red I can’t remember off hand.
When you find it, post the parts of the message that look like they might be related.
I think I found the crash data. Here it is:
12-19 09:16:03.141 14493-14493/? E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.avalanchestudios.breakoutparadise/com.avalanchestudios.breakoutparadise.BreakoutParadise}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2343)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2395)
at android.app.ActivityThread.access$600(ActivityThread.java:162)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1364)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5371)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.avalanchestudios.breakoutparadise.Paddle.(Paddle.java:35)
at com.avalanchestudios.breakoutparadise.BreakoutParadiseView.prepareLevel(BreakoutParadiseView.java:67)
at com.avalanchestudios.breakoutparadise.BreakoutParadiseView.(BreakoutParadiseView.java:61)
at com.avalanchestudios.breakoutparadise.BreakoutParadise.onCreate(BreakoutParadise.java:20)
at android.app.Activity.performCreate(Activity.java:5122)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1081)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2307)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2395)Â
at android.app.ActivityThread.access$600(ActivityThread.java:162)Â
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1364)Â
at android.os.Handler.dispatchMessage(Handler.java:107)Â
at android.os.Looper.loop(Looper.java:194)Â
at android.app.ActivityThread.main(ActivityThread.java:5371)Â
at java.lang.reflect.Method.invokeNative(Native Method)Â
at java.lang.reflect.Method.invoke(Method.java:525)Â
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)Â
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)Â
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)Â
at dalvik.system.NativeStart.main(Native Method)Â
I removed all those variables that were not used but the app still crashes. It won’t look good if I just keep on posting the crash data in the comments. Any other way we could solve this. Help me please…
Hi Anurag. Other than discussing and seeing the errors/code I don’t know of another way to solve this. Once you solve this problem you will then be more aware of what caused it and less likely to do the same thing in the future. You will have learnt from experience.
I have looked at the output in your previous comment and it tells us that the problem is a null pointer exception.
Caused by: java.lang.NullPointerException
This means that you are attempting to use an object of a class that has not been initialized. I.e. you have declared an object perhaps something like this:
Paddle paddle;
But you haven’t initialized it, perhaps like this:
paddle = new Paddle(x, y, etc);
Please note the above paddle example is just a guess based on the errors you posted and is not definitely the solution.
The best places in your code to start looking for the error can also be determined from the output you posted.
at com.avalanchestudios.breakoutparadise.Paddle.(Paddle.java:35)
at com.avalanchestudios.breakoutparadise.BreakoutParadiseView.prepareLevel(BreakoutParadiseView.java:67)
This suggests looking for a problem like the one I describe at line 35 in the Paddle class and/or line 67 in the BreakoutParadiseView class.
Don’t be disheartened by setbacks like this, keep looking for a solution. The more frustration there is getting a game to work, the more satisfying it will be when it finally works.
If you can’t work out the problem from these tips then please post the Paddle class, the place you initialize any Paddle objects and a few lines of code around line 67 from BreakoutParadiseView class.
Good luck and have a good day.
John
I have initialized the paddle class already in the breakoutparadiseView class. Should I initialize it in the paddle class instead?
Thanks for the encouragement John. I was thinking of leaving this project and starting a new one. But well here I am pasting the code….
This is the paddle class constructor. And the first error at line 35 is where I assign the bitmap using bitmap factory.
public Paddle(Context context, int screenX, int screenY){
rect = new RectF();
length = screenX/10;
height = screenY/10;
x= screenX/2;
y = screenY – 20;
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.bat_orange);
bitmap = Bitmap.createScaledBitmap(bitmap,(int)(length),(int)(height),false);
Also it shows an error at one more place in the main activity class in the onCreate method:
breakoutParadiseView = new BreakoutParadiseView(this, size.x, size.y);
paddleSpeed = 350;
}
This is where I have initialized the paddle variable. The error points at the initialization of paddle.
private void prepareLevel() {
paddle = new Paddle(context, screenX, screenY);
ball = new Ball(context, screenX, screenY);
Thanks again!
This could be the problem. The only way I can see you getting a null pointer exception from that line of code is if context is not initialized.
You call the Paddle constructor from prepareLevel, so you must somehow have an initialized Context object available in prepare level? Your BreakoutParadiseView constructor does receive a context object but in that BreakoutParadiseView constructor, do you initialize the BreakoutParadiseView member Context? Perhaps like this:
this.context = context;
I am fairly sure this will be the problem, especially if you have used my breakout project as a kind of template. Take a look at the space invaders project again and you will see this happening.
In summary, Pass context from main activity to the class which extends SurfaceView, initialize a Context object of the SurfaceView class in the constructor:
BreakoutParadiseView extends SurfaceView etc…{
Context context;
…
public BreakoutParadiseView(Context context, int x, int y){ // Or simmilar
this.context = context;
…
Everything should now work.
Let me know if you don’t understand my explanation because I think it is the likely solution.
Good luck
Thanks John! It worked! The game is working!
YAY! The bigger the pain the more pleasant when it stops. Well done.
Well the game is running, but there are still some problems I’m facing like…
1. The ball is drawn a few pixels above the paddle and doesn’t move. I tried changing a few dimensions but to no avail. (By the way, I am using a portrait view in this app. I tried changing it to landscape yet nothing happens. The ball just hovers up there.)
2. It draws only one brick on the screen even if I have a declared a bitmap[]. Are there some other methods for bitmap arrays than our regular bitmap methods.
Are you using a Bitmap for the ball too? If so the answer for number 1 lies in studying the code for the player spaceship to see how we track and draw it in the right place.
The solution for number 2 would be to study way the invaders are drawn as they are contained in an array as well as using a Bitmap for each.
I am referring to the Space Invaders project in both possible solutions.
Hey John,
I followed and changed the code according to the Invaders class and the Bricks were a success. There’s just, it shows a gap in between the bricks but I think I can tweak it and make it work, no problem there.
But I am stuck on the ball. I tried tweaking the code according to the playership class. But well I don’t know where the problem arises…
The playership class demonstrates how to handle the moving bitmap but the ball class demonstrates the independent movement. So I guess the end result will be somewhere between the two. Make sure you are calling the ball.update as well, each frame.
Feel free to post some code if it doesn’t work out. And when you publish Breakout Paradise let me know and I will link to the play store listing.
Good luck.
Well I can’t seem to find why the ball isn’t moving…
Here is the code for the ball class:
public class Ball {
RectF rect;
private Bitmap bitmap;
float xVelocity;
float yVelocity;
float ballWidth = 10;
float ballHeight = 10;
float x;
float y;
public Ball(Context context, int screenX, int screenY){
rect = new RectF();
xVelocity = 200;
yVelocity = -400;
x = screenX/2;
y = screenY – 20;
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ball_blue);
bitmap = Bitmap.createScaledBitmap(bitmap, (int)(ballWidth), (int)(ballHeight), false);
}
public RectF getRect(){return rect;}
public Bitmap getBitmap(){return bitmap;}
public float getX(){return x;}
public float getBallWidth(){return ballWidth;}
public void update(long fps){
rect.left = rect.left + (xVelocity/fps);
rect.top = rect.top + (yVelocity/fps);
rect.right = rect.left + ballWidth;
rect.bottom = rect.top – ballHeight;
}
public void reverseYVelocity(){yVelocity = – yVelocity;}
public void reverseXVelocity(){xVelocity = – xVelocity;}
public void setRandomXVelocity(){
Random generator = new Random();
int answer = generator.nextInt(2);
if(answer == 0){
reverseXVelocity();
}
}
public void clearObstacleY(float y){
rect.bottom = y;
rect.top = y – ballHeight;
}
public void clearObstacleX(float x){
rect.left = x;
rect.right = x + ballWidth;
}
public void reset() {
rect.left = x/2;
rect.top = y – 20;
rect.right = x/2 + ballWidth;
rect.bottom = y – 20 – ballHeight;
}
}
Assuming you are calling ball.update each frame, please show me the line of code which draws the ball in the draw method.
I called the update method by passing the fps variable if that is what you mean.
And here is the draw method for the ball sprite:
//Draw the ball sprite
canvas.drawBitmap(ball.getBitmap(), ball.getX(), screenY – 50, paint);
I think I see.
The update method is updating the RectF but you are using getX and the static screenY – 50 to position the bitmap.
You can either change the update method to work on x and y then add a getY method as well.
Or you could try the slightly convoluted (but it will probably work):
//Draw the ball sprite
canvas.drawBitmap(ball.getBitmap(), ball.getRect().left, ball.getRect().top, paint);
The getRect.top and getRect.left method doesn’t work, it just places the ball more to the left. What should I change in the update method for the getX and getY method to work.
Here is the update method:
public void update(long fps){
rect.left = rect.left + (xVelocity/fps);
rect.top = rect.top + (yVelocity/fps);
rect.right = rect.left + ballWidth;
rect.bottom = rect.top – ballHeight;
}
Hi Anurag,
I can’t think why that doesn’t work. So changing the class might just make things worse. Try adding some debugging text to the screen to see what is going on with those coordinates. If they aren’t moving then either update isn’t being called or perhaps one of the velocities has been corrupted somehow.
Add this after the score is drawn
canvas.drawText(“x: ” + ball.getRect().left + ” y: ” + ball.getRect().top, 10,150, paint);
See what information you get from it and if it gives a clue.
So it prints x:120.0 and y:804.0 . What does it mean??
Do I have to print that statement while using the getRect().left and getRect().top method??
It still prints the same statement after the getRect methods and the ball is shifted more to the right…
Sorry Anurag. Can’t think what is happening. The static coordinates mean the ball.update method either isn’t updating them or isn’t being called at all. I would look into that.
I think instead of using a sprite I may just use a rect for a ball. I was going to try and include power ups for the ball and using a sprite would have made it easier.
I don’t think it is the sprite. Even after changing the ball to a rect, it still doesn’t move. That means I am going wrong somewhere else and its not the ball.
Hi Anurag,
Go back to the last working state you had, even if that is the original breakout project. Then change one thing at a time and test at each step. If you get yourself a github account and put the project there I will be more than happy to look at the code and be able to help troubleshoot better as you progress.
A complete beginner at this and find your teach by doing approach very inspiring. Have followed all classes without problem but the breakout game
I cant get the paddle to display. there are no errors and ball and bricks work just no paddle. Any help would be welcome.
Neil
Hi Neil,
Thanks for your comment. The first thing to check is that you have read and completed the section “Making the game full screen landscape”. If not the the paddle might be hidden just off-screen.
The next check would be to the draw() method to make make sure that is exactly as it should be.
If you still can’t see it after trying these things I would try changing the starting y position of the paddle. You can do this in the Paddle constructor at this line:
y = screenY – 20; // y = 100;
This would make sure the Paddle is not still being hidden off screen.
If you still can’t see the Paddle get back to me and I will discuss doing a bit of debugging by outputting some extra text to the screen.
Good luck.
The paddle for me is off screen as well with:
y = screenY – 20;
I’ve messed around with it and the only way I can get it to appear is by dividing or multiplying the screenY variable, adding or subtracting doesn’t seem to do anything at all. And when I multiply or divide the paddle ends up in roughly the middle of the screen or higher. I don’t know what I can do to fix this besides putting a constant number, but I feel like that would cause problems on different screen sizes.
Hmm. Try…
// play around with the value of divisor
int divisor = 8;
y = screenY - (screenY / divisor);
What resolution is your screen?
Decided to read and tinker a bit and it worked itself out. that solution worked, but i Wasn’t in full screen mode, took the instructions too literal and put android:theme=”@android:style/Theme.NoTitleBar.Fullscreen” directly underneath it and not inside of the .
thank you very much for these tutorials, gonna get back to it.
A pleasure Brian.
Thanks John for your prompt reply. Yes the paddle was too low so working now. I am only working with an emulator so having to change speeds of ball and paddle but a learning curve for me so please bear with me if some of my questions seem very basic. I’ll try not to bother you too often.
Neil
Your oldest follower
Hi Neil,
No bother at all. Glad it worked out.
public void update(long fps){
rect.left = rect.left + (xVelocity / fps);
rect.top = rect.top + (yVelocity / fps);
rect.right = rect.left + ballWidth;
rect.bottom = rect.top – ballHeight;
}
Thanks John for making this great tutorial. I have a doubt in Ball class. Won’t the above code lead to different speed of ball in different phones as our position is being updated by pixel/frame whic will make it fps dependent? If yes, than how can it be resolved?
Hi Nick,
Thanks for your comment. Hopefully dividing the target velocity (xVelocity) by the current fps will mean that faster phones will move more frequently by smaller amounts and slower phones less frequently but by larger amounts. Unless I have made a mistake somewhere.
The faster the phone is the bigger the value of fps and therefore the smaller the value in pixels that is moved each frame.
Let me know if you still think I have an error (it wouldn’t be the first time).
John
Thanks for replying,
You are right, but wouldn’t it be better to update the game objects as pixels per second instead of pixels per frame? Then the updates won’t depend on frame rate.
Also I have tried to add a few extra things to game but now I am getting errors when I am trying to run it on emulator. Can you help me with this? Should I post a link to my project?
PS. This is my first android and java based project.
Hi nick,
You can lock the framerate but then poor performing phones will lag. You can also use the delta time which is the time since the last frame. This allows you to multiply by the target pixels per second and is probably faster than doing the divide calculation.
I used this slight adaptation of delta time because I hoped it would be transparent and easier to undestand as well as flexible.
How fast in pixels per second do you want an object to go? Simply set xVelocity to this value at any time and regardless of the fps, even if it varies then the pixels per second remain the same.
Of course what you should also do is use the resolution to initialize the xVelocity (with some formula) so that different screen resolutions have a simmilar experience. In addition you should take into account pixel density as well because there are small screens with high resolutions and large screens with relatively low. Furthrtmore to be really exact you need to consider the ratio of width to height (pixels and inches).
But this tutorial series is targetted at people who might never have programmed before and is just a first step. In the new year I will add a few new tutorials with more fun and advanced features.
Yes feel free to add a github or simmilar link. Or post a code snippet with problems here.
Nice to talk with you.
Hi John,
Thanks for helping me out. I have attached the project link below. I have not yet added sounds and In-game menu.
Project – https://github.com/IshankGulati/Breakout
Hi Nick,
Sorry, I haven’t looked at this yet. How are you getting on?
Hi John
Game is working but there are a few problems I want to share. Ball fails to bounce off the surface of paddle most of the times but collision detection with wall, ceiling and bricks is working just fine. Also, sometimes even after removing finger from the screen, paddle keeps on moving in that direction. It would be great if you can have a look at the code and suggest me some corrections. I have updated the link above with the latest code and Collision detection code is in Ball.java.
Thanks
H Nick,
I can’t see why that wouldn’t work. Why not add some debugging text on screen for things like when the rectangles intersect and the number of times they intersect. This might make it plain if the collision is detected and is simply not responding or whether the ball is passing straight through.
Hi John
Except for a few small bugs, game is working just fine :). Waiting for next tutorials.
Thanks for helping out
Well done Nick,
I am planning 2016 right now and hope to provide some new stuff soon.
Hi Jhon, excellent tutorials, well done !!! the game works, perfecktly. I have only 2 questions.
First: When i run the game on a the AVD, it works fine, but when i run it on a real device, when the ball hits the first lines of bricks in front of the paddle, the ball just go throught them and impact the inner once. Really strange. And the second one is, that when someone loses or wins the games, doesnt appear the text. I tried comment the createBricksAndRestart() method and it shows me the text, but when I un-comment that line of code, I dont see any text if the gamer lost or won. Also I tried to put this line of code: Thread.sleep(3000); surrended by try-catch block, and doesnt show me the text. Thanks in advantage
Hi Roger,
Regarding the end of game situation. It is just a over simplified/bad bit of code. What is happening is that the pause condition ends as soon as a touch is detected which is almost always straight away. You could modify the code to only end the pause condition when the very top part of the screen is touched. I will probably improve this tutorial to incorporate this soon.
Does the ball go through every time or occasionally? Is the device very slow? It is possible that if the frame rate is low then the amount the ball moves each frame could cause the ball to jump through the test for a collision.
Thanks for your comment hope my reply helps.
I solved the text not showing problem adding a block of try-catch cointaingin this line of code: game.Thread.sleep(3000); I put this block of code when the game asks if the gamer won or lost the game in the update method, right after paused=true, and before, createBricksAndRestart(); So now it is showing me the text. Bur i cant yet solve the problem with the ball not hidding or braking the first and some lines of bricks. I dont know really where to modify the code. If yopu could give an example, please. Sorry for my bad english!
Hi Roger,
Well done for solving the text problem. I can’t think why the brick problem would happen. The problem is usually on the emulator not the phone. Have you made any modifications to the code or is it a very low resolution phone? If so try making the ball smaller and the bricks a little higher.
Hi John.
Have got game installed on phone and running well. Would love some tips on how to restart if won with ball moving faster.
Only if it’s not too difficult and you have time. It would help my understanding of where code is placed.
Neil
Hi Neal,
You can increase the speed of the ball by changing the xVelocity and yVelocity member variables in Ball.
As these variables are private we will need a public method to do the work for us. Add a method something like this (untested) to the Ball class.
// Call this method from the game loop
// when you want to increase the speed
public void increaseVelocity(){
// Increase speed by 10%
xVelocity = xVelocity * 1.1f;
yVelocity = yVelocity * 1.1f;
}
You can also consider shrinking the paddle a little in a similar way. Hope this helps.
Thanks John
I have been playing with ball and paddle speeds so no problem there.
I will try your suggestion for ball class ,but to call this method from game loop do I need something like if(score >=240){
increaseVelocity;}
Sorry but by beginner I mean beginner.Do your books explain this type of basic question, think I had better start there.
Thanks for your time and have a great new year
Neil }
Hi Neil,
Yes, that’s exactly how you could use it. And in the if block you would call the method like this ball.incraseVelocity();.
Yes my books do explain this. Learning Java Building Android Games assumes zero Java knowledge an will explain absolutely everything from the start, but as a result the games built are very basic (pong, snake and even simpler games). Android Game Programming by Example assumes you know Java so doesn’t explain objects and basic syntax etc. This doesn’t mean you won’t pick-up the basics if you are feeling daring and want to go for the more adventurous book. I don’t like shamlessley promoting my stuff in the comments but if you are thinking about buying they are $5 each in ebook format (from packt not Amazon) for a few more days.
All the best,
John
Hello John,
I wish u a happy new year
I hope my question is not off topic. I tried to implement the “boolean isVisible” to the TappyDefenderGame. I tried to get it like this. If the player gets hit by an enemy he gets invisible. But it doesnt work. After the player got hit he kind of gets “invincible” (no more shield reduction).
here is what i did in the TDView:
if (player.getVisibility() {
if (hitDetected) {
player.setInvisible;
soundPool.play(bump, 1, 1, 0, 0, 1);
player.reduceShieldStrength();
if (player.getShieldStrength() < 0) {
soundPool.play(destroyed, 1, 1, 0, 0, 1);
gameEnded = true;
}
}
and i copied the "private boolean isVisible", "visible = true" and the rest which belongs to this method in the playerShip class as u did it, for example in the Brick Class. I dunno what i did wrong.
Greetings
Niclas
I solved it. I forgot to declare get.Visibility on the draw method -.-
Nice one Niclas!
Hi John,
I’m running the game on the android emulator that comes with Android Studio. The bricks and ball seem to work fine, but when the game starts, I can’t see my paddle. Could you help me with this? Thanks
Oh wait, I finally made it work. Instead of setting the paddle’s y value to y – 20, I had to make it y – 80. For some reason, the display size given by getSize was transcending the actual one.
Hi Anoop,
Congrats for solving this. Also check if the screen was set to full screen otherwise y will be hiding slightly off-screen.
Hey,
I want to add images to the paddle, bricks and ball but Im really stuck here. I cant figure out the part where I have to add the canvas.getBitmap, paddle.getX part like in the Space invaders tutorial. Can you help me out a little please Thank you!
HI Henry,
Although the changes are possible they are reasonably extensive and in multiple places, making it tough to document in these comments.
What you need to do is add a getBitmap method to any class you want to draw as a bitmap as well as a Bitmap object. Then in the draw method you will then be able to use almost identical code to draw each object as in the Space Invaders project.
I would start by doing the Space Invaders project to get familiar with it and then revisit and improve (add bitmaps) to this project. You can also look further up in these comments to my discussion with Anurag where we discuss aspects of the same issue you are trying to solve.
I suppose the best solution is a more advanced tutorial that uses bitmaps and has some other more advanced features. I hope to do a scrolling shooter next and after that perhaps Breakout 2 would be a good idea.
Hope this helps,
John
Hey again!
I got the paddle and the ball working, and will try to put sprites on the blocks too, but now I have a different question. I want to add a background image, but when I change it in the .xml file, it still stays on the color and when i remove the paint, it starts glitching up. Any thoughts?
Hi Henry,
The game doesn’t use the XML layout it uses the BreakoutView class instead. If you look at the setContentView call in the onCreate method you can see this is so.
To draw a background create a Bitmap of the background image and draw it at coordinates 0,0 each and every frame in the draw() method. Draw the background first and everything else will be drawn on top of it.
canvas.drawBitmap(backgroundImage, 0, 0, null);
The image has to be the right size or it can be dynamically scaled using createScaledBitmap.
Hope this helps.
Hi John
Hope i’m not out of order asking this question here.
I have bought your book Learning java by building android games and have been working on the Snake game.
My problem is the home screen works fine but crashes as soon as touched. I first typed the game and then copied and pasted but same result
Don’t know what to try next any ideas would be welcome/
thanks
Neil
Hi Neil,
Thanks for your question.
In the logcat console window there will be a long description as to what is causing the crash. The text is called a trace, so it will refer to multiple lines of code which eventually lead back to one specific line and the cause. Have a go at deciphering it as it almost always holds the solution.
As a guess, I would say it’s a Null pointer exception. As you mention that you copy & pasted the Java, it is most likely the error is being caused by a problem in the related XML layout file. Perhaps a wrong id for a button or similar. Try copy and pasting the layout file as well to see if this fixes the problem.
Hope this helps,
John
Hi John
Thanks for your reply. Almost too embarrassed to tell you what I had missed but for the sake of other beginners…
I had not uncommented ….//i = new Intent(this, GameActivity.class); after running menu screen.
Hi score does not work but i’ll get back to you if I can’t work it out.
Thanks again
Neil
Thanks for letting me know Neil and congrats for solving it yourself.
Hi
I was wondering if you’re still active and could help me out.
I keep on getting the error that “You need to use a Theme.AppCompat theme (or descendant) with this activity.”
Thanks in advance!!!
Hi John,
Often this is caused by a conflict between the theme and activity class being used and can usually be solved by making sure you extend Activity and not whatever might have been auto-generated by the new project wizard. Thanks for the comment.
Hi John,
Firstly thank you for creating this great website! For anyone else who is interested, I’ve made a small adjustment to the code which makes the ball more controllable and the game a bit more enjoyable. This checks which end of the paddle the ball is hitting and only changes the direction if it hits the opposite half of the paddle to it’s direction of travel (ala classic breakout).
Update the if statement with checks for the ball colliding with the paddle as follows:
float paddleMiddle = (paddle.getRect().left + paddle.getRect().right) / 2;
float ballMiddle = (ball.getRect().left + ball.getRect().right) / 2;
ball.setXVelocity(paddleMiddle, ballMiddle);
And replace the setRandomXVelocity method in the ball.java file with the following:
public void setXVelocity(float paddleMiddle, float ballMiddle){
if((xVelocity > 0 && ballMiddle < paddleMiddle) || (xVelocity paddleMiddle)){
reverseXVelocity();
}
}
Secondly, it doesn’t appear that the Win or Lose parts of the draw method are ever called. I first tried adding a pause but when that didn’t work I added a logging line to the if(lives <= 0) check and noticed that it never writes anything to the logs before it resets. Any idea what is wrong here please?
Lastly, at least for me, your final code at the end of the tutorial is a bit jumbled with multiple lines of code appearing on one line in some spots. Not a huge deal just thought I'd mention it in case you'd missed it (it might just be me but I tried a few browsers and they all showed the same).
Cheers,
Bart
My bad, it looks like posting the comment trims the code for some reason – perhaps because the line is too long? Please feel free to delete my other post. Hopefully this one works but if not feel free to delete it as well!
public void setXVelocity(float paddleMiddle, float ballMiddle){
if((xVelocity > 0 && ballMiddle < paddleMiddle)
|| (xVelocity paddleMiddle)){
reverseXVelocity();
}
}
Thanks Bart that is really useful for people to use and improve on the tutorial code.
I am fixing the badly formatted text. Thanks for pointing it out to me!
Regarding the win and lose conditions I need to restructure the code a bit to make that viable. I hope to update things a bit soon.
Thanks very much for commenting.
No worries, I think my code is being messed up because the comments are posted as xml and it contains a less-than followed later by a greater-than symbol. I’m going to try it one more time using the escape strings then I give up!
if((xVelocity > 0 && ballMiddle < paddleMiddle) || (xVelocity < 0 && ballMiddle > paddleMiddle)){
reverseXVelocity();
}
looks ok to me. Thanks for the contribution
Oh also I tried the code to stop the paddle when it hits the edge of the screen.
if(motionEvent.getX() > screenX / 2){
// Only set state if not too far over already!
if(paddle.getRect().right < screenX){ paddle.setMovementState(paddle.RIGHT); } }
The reason this appears to not work as expected is because the initial motionEvent is still ongoing (if that makes sense) – if, when the paddle hits the edge of the screen, you lift your finger off the device and then try to move it again, it won't move, but if it's already moving it just continues off the screen. This is also the source of another small annoyance which I'm unsure how to fix – if you don't lift your finger off the right side of the screen before placing your finger on the left side of the screen (or vice-versa) the paddle will simply continue on in it's current direction. Is there a way to interrupt a motionEvent?
Thanks again,
Bart
hi. im having a problem with “Display.getSize(size)” its outlined in red. and i cant figure out how to fix it.
sorrry if i miss spelled something 😉
Hi Amandus,
Hover the mouse over the red error and it should tell you what exactly is wrong. If the error doesn’t help you solve it then post the error here and I will try and help.
Thanks for your comment.
when hovering over .getSize, it says “Cannot resolve symbole ‘.getSize'” and if i click the yellow bulb thingi, it says “insert App indexing API code” but when doing that it dosent even fix the problem, it just makes more errors. thanks for the fast reply.
i started i new project and found out that i had just placed it in the wrong place. thanks for the fast reply and keep up the good work.
Cannot resolve symbol is a round-about way of saying the method doesn’t exist. Have you copy & pasted the code or typed it?
I see from the last post you use Display.get…. This should be display.get…
Try copy and pasting it if not because the slightest error, for example the wrong capitalization will cause this error.
Good luck, keep at it, John.
Hi again, im having a problem with the paddle. i dont get a error, but when i run the game and press on on of the sides, it takes some time before it reacts. and when it does, it does not move, it just becomes longer. any idea what i have done wrong?
Sounds like the top left of the bat is getting updated when you move but the other coordinates are not being reassigned each frame. Try copy & pasting the Paddle class again, especially this line from the update method.
rect.right = x + length;
Hope that helps.
Hi, im sorry to informe that i did not work. i have retyed multiply times and just figure it out. but i noticed that in this tutorial you say that i should create the paddle class in the java folder, but not in the com.example.user.BreakoutGame subfolder. And i have put the paddle class in the subfolder because when i just had it in the java folder i had some problems in the BreakoutGame.java file. when i try to make the paddle object by writing “Paddle paddle;” i just says “can not resolve symbole ‘Paddle’. any ideas what im doing wrong. and thanks alot for the fast respond.
The other possibility I can think of that could cause this symptom is if the screen is not being cleared each frame. Try copy & pasting the draw() method again. Or check that it has this line
// Draw the background colorcanvas.drawColor(Color.argb(255, 26, 128, 182));
before anything else is drawn.
Another solution might be to copy & paste the entire project and get it working first. Then go back through the tutorial to find out how it all works.
Got it working somehow. thanks alot!
I’m programming this game for an old platform (Amiga with AMOS Basic).
The core of the code contains 2 joined loops, simplifying in metacode:
do
for k=1 to no_bricks
if spritecol(k,ball)
calculate ball direction
sprite off k
score=score+10
end if
next
draw ball
move ball
loop
this implementation needs too much resources of my poor Amiga because, for each main cycle time(for each step of movement of the ball,the “do loop”) there are no_bricks checks if collision is detected,which brick is involved,and, in case of collision,delete the brick.
In your opinion how I can optimize this code,using also any kind of trick.
Thank you
Regards
Hi Salvatore,
Fascinating question. It reminds me that even when we are programming so-called resource limited devices like phones, we have it so good today.
The honest answer to your question is that I don’t know. I would need to set myself up an amiga and get in the zone with it. I remember writing a text adventure on zx81 and even that had slow load time issues.
Sorry about that. Feel free to post an overview of your solution as a reply if you succeed. Good luck!
Thank you !
this tutorial is so good and so well made I would just like to congratulate you and say thank you again.
😀
Hey,
The games is working, everything is almost perfect, but I would like to fix two thngs:
1) When my lives run out, the YOU HAVE LOST text doesnt pop up,
2) When the game is over and I have won, the game just freezes on the YOU HAVE WON screen. I would like to restart it by pressing on the screen or making a restart button.
Any way to fix this?
Thanks,
Henry
Hi Henry,
Thanks for your question.
My code is flawed in this respect. I plan to modify it in a couple of months when I finish my current project. The solution lies in clearly defining the game states and wrapping parts of update, draw and the control handling to perform differently for each state. If you have learnt about enumerations you could use one of them. Otherwise you could declare some Booleans for paused and gameOver and then wrap the relevant parts of the game in blocks which only run when these various states are true.
Sorry I can’t give you the full solution right now but hopefully that gives you something to work with. Expect big improvements to existing content and new tutorials from June onwards.
Hi John: