Welcome to the Space Invaders coding project for Android. In this game project, we will step through everything you need to know to have a fully playable Space Invaders clone running on your Android phone or tablet. The wave of invaders is genuinely challenging yet achievable and it would be simple for you to extend this project to add extra features like increasingly difficult waves, high scores or perhaps add a flying saucer-like in the original arcade classic.
Getting started
The finished game will allow the player to move left and right by holding the corresponding side of the screen near the bottom. As the player also needs to shoot at the invaders we will respond when the screen is touched slightly higher than the lower part as well. The Invaders will slide across the screen flapping their arms and spitting bullets. If they hit a player he loses a life if they hit a shelter it will crumble until eventually the player has nowhere to hide. When the invaders reach the side of the screen they will drop down and scroll back the other way; a little bit faster. Eventually, they will be moving so fast the player is doomed. The space invaders must be taken out quickly and efficiently to survive.
To get started create a new project in Android Studio, call it Space Invaders, and name the Activity SpaceInvadersActivity then read on because we will do things slightly differently compared to the Breakout project.
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, locate the following line of code, android:name=".SpaceInvadersActivity">
- Place the cursor before the closing > shown above. Tap the enter key a couple of times to move the > a couple of lines below the rest of the line shown above.
- Immediately below SpaceInvadersActivity but BEFORE the newly positioned > 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" |
Let’s talk a bit about the assets we will use in Space Invaders.
The Graphics
In this project, we will use a mixture of bitmaps from external graphics files for the invaders and player ship and use the Canvas class’ drawRect method to represent the lasers and the shelters. Something worth mentioning at this point is that even the classes that use bitmaps will still have a RectF object because although we don’t need it for drawing we can still use it for collision detection. More on this later in the project.
Before we get coding we want to add the player ship graphic and two different graphics for the two frames of animation for our invader to our project files so we can use them in our code. The graphics are white so they are displayed below on a blue background. Here they are.
You can download them by right-clicking on the images and then selecting the Save image as… option. Just make sure the file names are kept the same. They are named playership.png, invader1.png, and invader2.png. Add the graphics to the drawable folder within your Android Studio folders.
The sound
We will have a menacing two-tone sound to represent the invader’s movement. This sound will speed up as the invaders speed up. I have called these two sounds “uh” and “oh” because if we were attacked by invaders we might say, “uh oh”. We also need sounds for shooting a laser, the player being hit, an invader being hit and a shelter being damaged.
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 each of the links.
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.
The class structure
For this project, we will vary slightly from the structure of the Breakout project. But far from adding complexity, we will see how by separating out further the code in the different files we will make our Space Invaders project simpler to write, manage and extend.
Each game object will be represented by its own class. So we will have one for the player’s ship, one for an invader, a bullet, and the brick of a defense shelter. Furthermore, we will also take the inner class which represents the view of the game, and make it a class in its own right. It will be called SpaceInvadersView. This changes nothing about how we code it internally but it does make the whole project more manageable.
We want to create classes to represent the view and the game objects we have just discussed. We will require the following classes. SpaceInvadersView, Invader, PlayerShip, DefenceBrick and Bullet. By creating empty implementations of all these classes we can then declare objects of them in SpaceInvadersView right away. This avoids constantly revisiting SpaceInvadersView to add new declarations. All we will need to do is implement each object, in turn, initialize it, update it, and draw it.
With this in mind let’s create those empty classes. Now, 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 SpaceInvadersView as the name for our new class and click OK. We have now created a new Java class in a separate file called SpaceInvadersView.java. As previously mentioned the class is not an inner class as the view was in the Breakout project.  This helps us to compartmentalize our code and keep it organized into logical areas to a greater extent than we did previously.
Now do the same and create new classes for PlayerShip, Bullet, DefenceBrick, and Invader classes. You should now have six classes in total including SpaceInvadersActivity. Just for clarity, the code for each of the five new classes is shown below (excluding the package declaration at the top of each class). We will then look at each of the classes, in turn, starting with SpaceInvadersActivity.
SpaceInvadersView
1 2 3 |
public class SpaceInvadersView{ } |
PlayerShip
1 2 3 |
public class PlayerShip { } |
Bullet
1 2 3 |
public class Bullet { } |
DefenceBrick
1 2 3 |
public class DefenceBrick { } |
Invader
1 2 3 |
public class Invader { } |
Coding the Space Invaders Activity class
There is nothing new here compared to the Activity class from the Breakout project. The only difference is that there is no inner class extending SurfaceView. Notice that we still create a new object of type SpaceInvadersView and set it as the view for the screen. We also get the screen resolution and pass this information into the SpaceInvadersView constructor method. The code below will show some errors until we implement the SpaceInvadersView class.
Tip: We will be using plenty of classes from the Android API in this project. You can use the Android Studio shortcut Alt + Enter while the mouse cursor hovers over any Android class which is showing an error. This will add the appropriate import… line at the top of the file.
Delete the default code that was auto-generated from SpaceInvadersActivity then add the code below.
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 |
import android.app.Activity; import android.graphics.Point; import android.os.Bundle; import android.view.Display; // SpaceInvadersActivity is the entry point to the game. // It will handle the lifecycle of the game by calling // methods of spaceInvadersView when prompted to so by the OS. public class SpaceInvadersActivity extends Activity { // spaceInvadersView will be the view of the game // It will also hold the logic of the game // and respond to screen touches as well SpaceInvadersView spaceInvadersView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 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); // Initialize gameView and set it as the view spaceInvadersView = new SpaceInvadersView(this, size.x, size.y); setContentView(spaceInvadersView); } // This method executes when the player starts the game @Override protected void onResume() { super.onResume(); // Tell the gameView resume method to execute spaceInvadersView.resume(); } // This method executes when the player quits the game @Override protected void onPause() { super.onPause(); // Tell the gameView pause method to execute spaceInvadersView.pause(); } } |
Now we have a working Activity class that is the entry point to our Space Invaders game. It will simply get the screen resolution, and pass it to SpaceInvadersView where all the game action will take place. SpaceInvadersActivity will not do anything unless it gets a message from the operating system to say it is being shut down or restarted; in which case it will call the pause and resume methods of SpaceInvadersView which will shut down or start the main game thread.
Coding the Space Invaders view class outline
As we have already created a bunch of empty classes we can flesh out our game engine along with a whole bunch of the key variable and object declarations right away. I have broken the starting code for this class into a number of sections as the code is quite lengthy. However, there is not much that we didn’t already see in the last project.
The SpaceInadersView declaration and member variables
First of all, in the next block of code, we see that the class declaration needs to be modified to extend SurfaceView and implement Runnable to provide our drawing and threading functionality. We then see a bunch of familiar member objects and variables for handling our thread, drawing, main game loop, frame rate, and screen resolution. The comments should act as a reminder to what does what.
Starting with the declaration of the playerShip object we see the Space Invaders-specific declarations. We have an object of PlayerShip and one of Bullet which will unsurprisingly represent the player’s ship and his solitary bullet. We then have an array of Bullet objects called invadersBullets along with a couple of variables nextBullet and maxInvaderBullets to help us manage this array.
After this, we then declare an array to hold a whole army of Invader objects and again, a variable to help us manage the array. Then we have an array of DefenceBrick objects. We will see how we construct and destroy the player’s shelters from this array later.
Following that we have the usual SoundPool object and a int to represent each of the sound FX we will want to play. Then we have an int to represent score and a int to represent lives. The last variables we declare are new and we will see near the end of the project how we use menaceInterval, uhOrOh and lastMenaceTime to time the flapping of the invader’s arms and the speed of the “uh oh” sound FX.
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 |
public class SpaceInvadersView extends SurfaceView implements Runnable{ Context context; // This is our thread private Thread gameThread = null; // Our SurfaceHolder to lock the surface before we draw our graphics private SurfaceHolder ourHolder; // A boolean which we will set and unset // when the game is running- or not. private volatile boolean playing; // Game is paused at the start private boolean paused = true; // A Canvas and a Paint object private Canvas canvas; private Paint paint; // This variable tracks the game frame rate private long fps; // This is used to help calculate the fps private private long timeThisFrame; // The size of the screen in pixels private int screenX; private int screenY; // The players ship private PlayerShip playerShip; // The player's bullet private Bullet bullet; // The invaders bullets private Bullet[] invadersBullets = new Bullet[200]; private int nextBullet; private int maxInvaderBullets = 10; // Up to 60 invaders Invader[] invaders = new Invader[60]; int numInvaders = 0; // The player's shelters are built from bricks private DefenceBrick[] bricks = new DefenceBrick[400]; private int numBricks; // For sound FX private SoundPool soundPool; private int playerExplodeID = -1; private int invaderExplodeID = -1; private int shootID = -1; private int damageShelterID = -1; private int uhID = -1; private int ohID = -1; // The score int score = 0; // Lives private int lives = 3; // How menacing should the sound be? private long menaceInterval = 1000; // Which menace sound should play next private boolean uhOrOh; // When did we last play a menacing sound private long lastMenaceTime = System.currentTimeMillis(); |
Declaring all the variables we just have will make progress through the rest of the project much faster.
The SpaceInvadersView constructor
The constructor is the first method we will implement. The constructor is the method called from SpaceInvadersActivity in the code spaceInvadersView = new SpaceInvadersView(this, screenX, screenY). So the first thing we notice is the signature of the method which receives the variables passed in.
As before we call the parent class ( SurfaceView) to help set up our object with the code super(context). The next line is new. this.context = context copies the Context object passed into the constructor to the SpaceInvadersView own context object. This makes it available throughout the class and not just in the constructor. The rest of the constructor we have seen in the last project. We simply initialize screenX and screenY then prepare our sound files ready to be played.
Finally, in the constructor, we call the prepareLevel method which is where we will initialize all our game objects and get ready to play the game. Notice in the implementation of prepareLevel there is a bunch of comments that indicate where code we have yet to write will eventually go. Add all the code in the constructor and prepareLevel immediately after the previous block of code. Be sure to include the comments in prepareLevel as reference points for the code we will soon write.
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 |
// When the we initialize (call new()) on gameView // This special constructor method runs public SpaceInvadersView(Context context, int x, int y) { // The next line of code asks the // SurfaceView class to set up our object. // How kind. super(context); // Make a globally available copy of the context so we can use it in another method this.context = context; // Initialize ourHolder and paint objects ourHolder = getHolder(); paint = new Paint(); screenX = x; screenY = y; // 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("shoot.ogg"); shootID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("invaderexplode.ogg"); invaderExplodeID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("damageshelter.ogg"); damageShelterID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("playerexplode.ogg"); playerExplodeID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("damageshelter.ogg"); damageShelterID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("uh.ogg"); uhID = soundPool.load(descriptor, 0); descriptor = assetManager.openFd("oh.ogg"); ohID = soundPool.load(descriptor, 0); }catch(IOException e){ // Print an error message to the console Log.e("error", "failed to load sound files"); } prepareLevel(); } private void prepareLevel(){ // Here we will initialize all the game objects // Make a new player space ship // Prepare the players bullet // Initialize the invadersBullets array // Build an army of invaders // Build the shelters } |
We are making good progress. We just need to add some of the usual suspects (methods) to the project and then we can get on with coding our first game object.
The usual game-loop methods: run, update, and draw
Next, we will add a whole bunch of methods that we have seen before when we looked at coding a basic game loop and coding a Breakout game. However, notice all placeholder comments that will be invaluable for locating where the code we will soon write needs to go. Add the methods below right after the prepareLevel method.
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 |
@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; } // We will do something new here towards the end of the project } private void update(){ // Did an invader bump into the side of the screen boolean bumped = false; // Has the player lost boolean lost = false; // Move the player's ship // Update the invaders if visible // Update all the invaders bullets if active // Did an invader bump into the edge of the screen if(lost){ prepareLevel(); } // Update the players bullet // Has the player's bullet hit the top of the screen // Has an invaders bullet hit the bottom of the screen // Has the player's bullet hit an invader // Has an alien bullet hit a shelter brick // Has a player bullet hit a shelter brick // Has an invader bullet hit the player ship } private 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 player spaceship // Draw the invaders // Draw the bricks if visible // Draw the players bullet if active // Draw the invaders bullets if active // Draw the score and remaining lives // Change the brush color paint.setColor(Color.argb(255, 249, 129, 0)); paint.setTextSize(40); canvas.drawText("Score: " + score + " Lives: " + lives, 10,50, paint); // Draw everything to the screen ourHolder.unlockCanvasAndPost(canvas); } } |
A few more methods that we have seen before follow next.
More of the usual suspects: pause, resume, and onTouchEvent
Add these methods which start and stop our thread and will eventually detect the player’s input.
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 |
// If SpaceInvadersActivity is paused/stopped // shutdown our thread. public void pause() { playing = false; try { gameThread.join(); } catch (InterruptedException e) { Log.e("Error:", "joining thread"); } } // If SpaceInvadersActivity 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: break; // Player has removed finger from screen case MotionEvent.ACTION_UP: break; } return true; } } |
Now we can run the Space Invaders game and see just the score and a plain background.
Now we have the outline for our SpaceInvadersView class let’s build the player’s spaceship.
Implementing the PlayerShip class
First of all, we have an RectF instance that will be used for collision detection, then we have an Bitmap object into which we will load the playership.png graphic, a float for each of the height and length,  a float for the x and y coordinates of the spaceship on the screen and another float, shipSpeed which is how many pixels per second the ship can move.
After that, we have three final int members STOPPED, LEFT and RIGHT which are public and can, therefore, be accessed from the SpaceInvadersView class to tell the spaceship which way to move. Then we have shipMoving which will be assigned one of the aforementioned final values and this is used internally in the update method of this class to determine which way to move if any.
Add all these member variables and objects just after the class declaration.
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 |
RectF rect; // The player ship will be represented by a Bitmap private Bitmap bitmap; // How long and high our ship will be private float length; private float height; // X is the far left of the rectangle which forms our ship private float x; // Y is the top coordinate private float y; // This will hold the pixels per second speed that the ship will move private float shipSpeed; // Which ways can the ship move public final int STOPPED = 0; public final int LEFT = 1; public final int RIGHT = 2; // Is the ship moving and in which direction private int shipMoving = STOPPED; |
Here is the PlayerShip constructor where we set up our PlayerShip class ready to defend the Earth. Notice the method parameters receive a Context and the screen’s horizontal and vertical resolution. We will see how we use these soon.
First, we initialize rect as a blank rectangle. It will become apparent how this object is useful soon when we implement the update method. We initialize length and height by dividing the screen resolution on the horizontal and vertical axes by ten. Ten is an arbitrary value but it works well. For a smaller ship, increase the number for a bigger ship decrease the number.
Next, we initialize x and y to the middle of the screen horizontally and just above the bottom vertically. The x and y variables actually refer to the top left pixel of the spaceship so dividing screenX by two is not exactly the middle but it is good enough.
Now we load bitmap with the .png file using BitmapFactory.decodeResource and after that, we scale the bitmap to the correct length and height using Bitmap.createScaledBitmap method.
Finally, for the constructor, we initialize the speed of our spaceship. Add this code just after the previous block of code.
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 |
// This the the constructor method // When we create an object from this class we will pass // in the screen width and height public PlayerShip(Context context, int screenX, int screenY){ // Initialize a blank RectF rect = new RectF(); length = screenX/10; height = screenY/10; // Start ship in roughly the screen centre x = screenX / 2; y = screenY - 20; // Initialize the bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.playership); // stretch the bitmap to a size appropriate for the screen resolution bitmap = Bitmap.createScaledBitmap(bitmap, (int) (length), (int) (height), false); // How fast is the spaceship in pixels per second shipSpeed = 350; } |
Here are some getters and setters so that SpaceInvadersView can grab a copy of rect for collision detection, bitmap for drawing the spaceship, x and length for firing bullets dead-center from the ship and the setter setMovementState gives onTouchEvent the ability to determine which way the ship should move each time update is called.
Add these methods below the last block of code then we can look at the update method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public RectF getRect(){ return rect; } // This is a getter method to make the rectangle that // defines our ship available in SpaceInvadersView class public Bitmap getBitmap(){ return bitmap; } public float getX(){ return x; } public float getLength(){ return length; } // This method will be used to change/set if the ship is going left, right or nowhere public void setMovementState(int state){ shipMoving = state; } |
And here is the last method of the PlayerShip class called update. It is very simple in the beginning and we have seen before how we update the x variable by shipSpeed divided by the current frame rate the game is running at and dependent upon the value of shipMoving. But what happens next is the key to how we detect collisions for our spaceship. We update the starting and ending horizontal and vertical positions of rect with the x and y locations of the spaceship. We know the ending locations simply by adding height to y and length to x. Now whenever SpaceInvadersActivity calls getRect it will get an RectF object which effectively wraps the player’s spaceship. This RectF can then be used in the RectF.intersects method in exactly the same way it was in the Breakout game. Add the update method to the PlayerShip class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// This update method will be called from update in SpaceInvadersView // It determines if the player ship needs to move and changes the coordinates // contained in x if necessary public void update(long fps){ if(shipMoving == LEFT){ x = x - shipSpeed / fps; } if(shipMoving == RIGHT){ x = x + shipSpeed / fps; } // Update rect which is used to detect hits rect.top = y; rect.bottom = y + height; rect.left = x; rect.right = x + length; } |
That’s it for the PlayerShip class. Now we can put it to work in three stages. First, we will initialize one in the prepareLevel method, then we will call its update method from update and then we will draw it in the draw method. We won’t be able to move the ship however until we fully implement the onTouchEvent method which we will do after we have implemented the Bullet class.
Enter this code in the prepareLevel method in the place indicated by the comment.
1 2 |
// Make a new player space ship playerShip = new PlayerShip(context, screenX, screenY); |
Enter this code in the update method in the place indicated by the comment.
1 2 |
// Move the player's ship playerShip.update(fps); |
Enter this code in the draw method in the place indicated by the comment.
// Now draw the player spaceship canvas.drawBitmap(playerShip.getBitmap(), playerShip.getX(), screenY - 50, paint);
If you run the game you will see the spaceship at the bottom of the screen.
Now we can implement the Bullet class
Shooting bullets
First, we add some member variables. An x and y to hold the bullet’s location on the screen. a RectF which will be used to both draw and detect collisions on a bullet. Two final int variables; UP and DOWN that SpaceInvadersView can use to control the direction of a bullet and heading which will hold one of those values; we initially initialize to -1 because it is going nowhere at the moment. The speed variable is initialized to 350. This is the pixels per second that the bullet will travel at. This is quite fast and presents a challenge even on a medium-resolution tablet. All bullets have a width and a height. The width is initialized right away to 1 pixel, height will be initialized in the constructor, and will be relative to the resolution of the screen. The last variable is a boolean isActive. We can set this to true and false as needed so we know when to draw and update each bullet and when we don’t need to bother.
Finally in the block of code below we have the constructor which initializes y as previously described, sets isActive to false and initializes a blank RectF object. Enter the code below in the Bullet 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 |
private float x; private float y; private RectF rect; // Which way is it shooting public final int UP = 0; public final int DOWN = 1; // Going nowhere int heading = -1; float speed = 350; private int width = 1; private int height; private boolean isActive; public Bullet(int screenY) { height = screenY / 20; isActive = false; rect = new RectF(); } |
Next, we have a bunch of getters and setters that pass rect back to SpaceInvadersView for collision detection and drawing, returns the status ( isActive true or false) which as we will see is useful for knowing when to draw and check for collisions and finally we have a getImpactPointY method which returns the tip pixel of the bullet. This will be different depending on whether the bullet is heading down (fired by an invader) or up (fired by a player). Enter the getters and setters we have just discussed below the previous block of code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public RectF getRect(){ return rect; } public boolean getStatus(){ return isActive; } public void setInactive(){ isActive = false; } public float getImpactPointY(){ if (heading == DOWN){ return y + height; }else{ return y; } } |
Next, we have the important shoot method which works by first confirming that the bullet is NOT already active. If it is already active, the launch of the bullet fails. Otherwise, a starting x and y location is initialized, the heading is set and the bullet is set to isActive = true. We return true to the calling code so further actions can be taken for a successful bullet launch; namely playing a sound and keeping track of the invadersBullets array. If the bullet was already active at the time this method was called the code returns false to let the calling code know that a new bullet launch was not possible.
Enter the shoot method below the previous block of code.
1 2 3 4 5 6 7 8 9 10 11 12 |
public boolean shoot(float startX, float startY, int direction) { if (!isActive) { x = startX; y = startY; heading = direction; isActive = true; return true; } // Bullet already active return false; } |
Of course, this class will also need a update method. Notice that we update x and y in the usual way and also update rect so it is up-to-date for drawing and collision detection when required. Enter the update method into the Bullet class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public void update(long fps){ // Just move up or down if(heading == UP){ y = y - speed / fps; }else{ y = y + speed / fps; } // Update rect rect.left = x; rect.right = x + width; rect.top = y; rect.bottom = y + height; } |
Now we just need to initialize, update and draw the bullets. Obviously, we won’t actually see any bullets until we implement a fire button for the player’s single bullet and the Invader class which will trigger the firing of the enemy bullets.
Notice in the next three blocks of code that we keep the single player’s bullet ( bullet) and the array of bullets ( invaderBullets) the invaders will use separately. We don’t want to waste time doing collision detection on the invader’s bullets against the invaders themselves so it is good to know which bullet belongs to which protagonist. Although we will detect the player damaging his own shelter as this feature was in the original arcade classic.
Enter this code in the prepareLevel method in the place indicated by the comment.
1 2 3 4 5 6 7 |
// Prepare the players bullet bullet = new Bullet(screenY); // Initialize the invadersBullets array for(int i = 0; i < invadersBullets.length; i++){ invadersBullets[i] = new Bullet(screenY); } |
Enter this code in the update method in the place indicated by the comments.
1 2 3 4 5 6 7 8 9 10 11 |
// Update the players bullet if(bullet.getStatus()){ bullet.update(fps); } // Update all the invaders bullets if active for(int i = 0; i < invadersBullets.length; i++){ if(invadersBullets[i].getStatus()) { invadersBullets[i].update(fps); } } |
Enter this code in the draw method in the place indicated by the comments.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Draw the players bullet if active if(bullet.getStatus()){ canvas.drawRect(bullet.getRect(), paint); } // Draw the invaders bullets // Update all the invader's bullets if active for(int i = 0; i < invadersBullets.length; i++){ if(invadersBullets[i].getStatus()) { canvas.drawRect(invadersBullets[i].getRect(), paint); } } |
Now we can implement the player controls to let him move and shoot.
Giving the player control
In the next block of code, I show the entire onTouchEvent method including the code we fleshed out near the start of the project. In it, you can see that we set paused to false in the ACTION_DOWN case. Also in ACTION_DOWN case we detect any touches in the bottom eighth of the screen ( if(motionEvent.getY() > screenY - screenY / 8)) then further test which side of the screen the touch was and call setMovementState with the appropriate public final int  to update which way the player’s spaceship will travel.
After this, still in ACTION_DOWN case we detect if a touch occurs ABOVE the bottom eighth of the screen ( if(motionEvent.getY() > screenY - screenY / 8)) and if so we call shoot on bullet passing in the coordinates of the top center of the player’s ship. If the shoot method returns true then a bullet is launched and a sound FX is played.
In the next case, ACTION_UP we simply stop the ship from moving by passing STOPPED into setMovementState.
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 |
@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.getY() > screenY - screenY / 8) { if (motionEvent.getX() > screenX / 2) { playerShip.setMovementState(playerShip.RIGHT); } else { playerShip.setMovementState(playerShip.LEFT); } } if(motionEvent.getY() < screenY - screenY / 8) { // Shots fired if(bullet.shoot(playerShip.getX()+ playerShip.getLength()/2,screenY,bullet.UP)){ soundPool.play(shootID, 1, 1, 0, 0, 1); } } break; // Player has removed finger from screen case MotionEvent.ACTION_UP: if(motionEvent.getY() > screenY - screenY / 10) { playerShip.setMovementState(playerShip.STOPPED); } break; } return true; } |
You can now run the game, and move the spaceship around by holding the screen on the bottom left and right. Furthermore, if you tap anywhere above the bottom eighth of the screen the player’s ship will fire a bullet. It will also play a laser-shooting sound effect.
Let’s give the player something to shoot at.
Implementing the Invader class
This class like the PlayerShip class will have an RectF object as well as an Bitmap object for collision detection and drawing respectively. We will implement these features in exactly the same way. However, the Invader class will have a Bitmap for each frame of animation (arms up and arms down). We will see in this class that we have a getBitmap and a getBitmap2 method. We will see later in the draw method of SpaceInvadersView how we choose which one to call each frame.
With this in mind enter this code to declare all the objects and variables the Invader class will need.
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 |
RectF rect; Random generator = new Random(); // The player ship will be represented by a Bitmap private Bitmap bitmap1; private Bitmap bitmap2; // How long and high our invader will be private float length; private float height; // X is the far left of the rectangle which forms our invader private float x; // Y is the top coordinate private float y; // This will hold the pixels per second speedthat the invader will move private float shipSpeed; public final int LEFT = 1; public final int RIGHT = 2; // Is the ship moving and in which direction private int shipMoving = RIGHT; boolean isVisible; |
Next, we have the Invader constructor that initializes rect as a blank rectangle, initializes length and width based on the screen resolution sets isVisible as true because we want to see the invader unless it is shot. Notice how the x and y location on the screen is determined by the invader’s position in the invader army. A row and column number is passed into the constructor and this is used, along with an padding of one twenty-fifth of the screens x resolution to determine the invader’s exact starting location.
Then in the constructor, we initialize and scale two Bitmap objects using the two graphics files. Finally, we set the speed to forty pixels per second. This will increase as the army of invaders make their way down to Earth.
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 |
public Invader(Context context, int row, int column, int screenX, int screenY) { // Initialize a blank RectF rect = new RectF(); length = screenX / 20; height = screenY / 20; isVisible = true; int padding = screenX / 25; x = column * (length + padding); y = row * (length + padding/4); // Initialize the bitmap bitmap1 = BitmapFactory.decodeResource(context.getResources(), R.drawable.invader1); bitmap2 = BitmapFactory.decodeResource(context.getResources(), R.drawable.invader2); // stretch the first bitmap to a size appropriate for the screen resolution bitmap1 = Bitmap.createScaledBitmap(bitmap1, (int) (length), (int) (height), false); // stretch the first bitmap to a size appropriate for the screen resolution bitmap2 = Bitmap.createScaledBitmap(bitmap2, (int) (length), (int) (height), false); // How fast is the invader in pixels per second shipSpeed = 40; } |
Next, we have a bunch of getters, setters, and helper methods. The first two below get and set the object as invisible and get the current state of visibility. The next two get the two bitmaps and return them to the code that called them. The next three, getX getY and getLength return the x, y and length values respectively. These are used, as they were with PlayerShip to get precise coordinates at which to fire a bullet. Enter these getter and setter methods.
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 |
public void setInvisible(){ isVisible = false; } public boolean getVisibility(){ return isVisible; } public RectF getRect(){ return rect; } public Bitmap getBitmap(){ return bitmap1; } public Bitmap getBitmap2(){ return bitmap2; } public float getX(){ return x; } public float getY(){ return y; } public float getLength(){ return length; } |
And of course, our Invader class needs a update method. This works in exactly the same way as it did for the PlayerShip class. Notice however that there is no code to handle the invader moving down. We will see this code next. Enter the code for the Invader class update method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public void update(long fps){ if(shipMoving == LEFT){ x = x - shipSpeed / fps; } if(shipMoving == RIGHT){ x = x + shipSpeed / fps; } // Update rect which is used to detect hits rect.top = y; rect.bottom = y + height; rect.left = x; rect.right = x + length; } |
The next method dropDownAndReverse does exactly as the name suggests. It swaps LEFT for RIGHT or vice versa then increases the invader’s y coordinate by height which has the effect of moving it down the screen. Finally, the speed is increased by 18% by multiplying by 1.18. Enter the dropDownAndReverse method.
1 2 3 4 5 6 7 8 9 10 11 |
public void dropDownAndReverse(){ if(shipMoving == LEFT){ shipMoving = RIGHT; }else{ shipMoving = LEFT; } y = y + height; shipSpeed = shipSpeed * 1.18f; } |
The takeAim method is kind of like our invader’s artificial intelligence. The first block of code in this method detects if the Invader object is approximately horizontally aligned with the player. If it is a random number is generated to produce a 1 in 150 chance of returning true to the calling code. As we will see shortly in the calling code, when true is returned an attempt to launch a bullet is made with a call to shoot.
If 1 in 150 doesn’t seem like very much chance that a shot will be fired just consider that this method will be called up to sixty times a second on one or maybe even two complete columns of invaders that return true to the initial if condition. So there will be loads of bullets flying when we run this code.
In the second block of code in this method, every invader is given a chance to unleash a shot no matter if they are aligned to the player or not. This is great for creating a hostile environment and taking out the shelters. As every single invader gets around sixty throws of the dice every second the odds have been changed to 1 in 2000. These are good variables to play with if you want to make the game harder or easier.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public boolean takeAim(float playerShipX, float playerShipLength){ int randomNumber = -1; // If near the player if((playerShipX + playerShipLength > x && playerShipX + playerShipLength < x + length) || (playerShipX > x && playerShipX < x + length)) { // A 1 in 500 chance to shoot randomNumber = generator.nextInt(150); if(randomNumber == 0) { return true; } } // If firing randomly (not near the player) a 1 in 5000 chance randomNumber = generator.nextInt(2000); if(randomNumber == 0){ return true; } return false; } |
Initializing, drawing, and updating the invaders
Now, as usual, we need to add code to the relevant places in SpaceInvadersView to bring our army of Invader objects to life.
Notice how we pass in a row, changing, and column numbers to each successive Invader object in our array. And we keep track of the overall number of Invader objects in our array by incrementing numIvaders. Enter this code in the prepareLevel method in the place indicated by the comments.
1 2 3 4 5 6 7 8 |
// Build an army of invaders numInvaders = 0; for(int column = 0; column < 6; column ++ ){ for(int row = 0; row < 5; row ++ ){ invaders[numInvaders] = new Invader(context, row, column, screenX, screenY); numInvaders ++; } } |
This next block of code which updates our array of invaders in each frame is quite lengthy but when examined closely it is not complicated. First, we loop through each and every invader and check if it is visible. If it is we call its update method and its coordinates will be updated. Next, we call takeAim on each and every invader in the array. Using the odds and aiming criteria specified in the takeAim method it might or might not return true. If it returns true we call shoot on the next bullet in the array as identified by nextBullet. If a bullet is successfully fired nextBullet is incremented ready for the next invader. We then check if nextBullet is equal to maxInvaderBullets and if it is we set nextBullet back to zero.
Back outside of the takeAim if block, we check if the invader has touched either the left or right side of the screen and if it has we set bumped to true.
Enter the code we have just discussed in the update method in the place indicated by the comment.
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 |
// Update all the invaders if visible for(int i = 0; i < numInvaders; i++){ if(invaders[i].getVisibility()) { // Move the next invader invaders[i].update(fps); // Does he want to take a shot? if(invaders[i].takeAim(playerShip.getX(), playerShip.getLength())){ // If so try and spawn a bullet if(invadersBullets[nextBullet].shoot(invaders[i].getX() + invaders[i].getLength() / 2, invaders[i].getY(), bullet.DOWN)) { // Shot fired // Prepare for the next shot nextBullet++; // Loop back to the first one if we have reached the last if (nextBullet == maxInvaderBullets) { // This stops the firing of another bullet until one completes its journey // Because if bullet 0 is still active shoot returns false. nextBullet = 0; } } } // If that move caused them to bump the screen change bumped to true if (invaders[i].getX() > screenX - invaders[i].getLength() || invaders[i].getX() < 0){ bumped = true; } } } |
This next code handles how the invaders are triggered to drop down and start heading the other way. It also decreases the value of menaceInterval making the invader arm waving and menacing sounds more frequent although we have a little more coding before this will take effect.
Enter this code in the update method immediately after the last block in the place indicated by the comment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// Did an invader bump into the edge of the screen if(bumped){ // Move all the invaders down and change direction for(int i = 0; i < numInvaders; i++){ invaders[i].dropDownAndReverse(); // Have the invaders landed if(invaders[i].getY() > screenY - screenY / 10){ lost = true; } } // Increase the menace level // By making the sounds more frequent menaceInterval = menaceInterval - 80; } |
Now we draw the invaders, notice the code we use to switch between the two different frames of animation. We will make this code fully functional in the section Timing the animation and the menacing sound.
Enter this code in the draw method in the place indicated by the comment.
1 2 3 4 5 6 7 8 9 10 |
// Draw the invaders for(int i = 0; i < numInvaders; i++){ if(invaders[i].getVisibility()) { if(uhOrOh) { canvas.drawBitmap(invaders[i].getBitmap(), invaders[i].getX(), invaders[i].getY(), paint); }else{ canvas.drawBitmap(invaders[i].getBitmap2(), invaders[i].getX(), invaders[i].getY(), paint); } } } |
Now we can run the game and see the invaders move from side to side getting lower all the time.
At the moment, however, they are not waving their arms or sounding very menacing. We will fix this now.
Timing the animation and the menacing sound
Implement playing the uh-oh sound by adding this code right at the very end (inside the closing curly brace) of the run method. This will also trigger the invaders to start waving their hands. The code simply alternates the value of uhOrOh based on an ever-decreasing (and therefore more frequent) value of menaceInterval.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// We will do something new here towards the end of the project // Play a sound based on the menace level if(!paused) { if ((startFrameTime - lastMenaceTime) > menaceInterval) { if (uhOrOh) { // Play Uh soundPool.play(uhID, 1, 1, 0, 0, 1); } else { // Play Oh soundPool.play(ohID, 1, 1, 0, 0, 1); } // Reset the last menace time lastMenaceTime = System.currentTimeMillis(); // Alter value of uhOrOh uhOrOh = !uhOrOh; } } } |
Initialize the menacing variable in the prepareLevel method
1 2 |
// Reset the menace level menaceInterval = 1000; |
You can now play the game and the menacing sound and invader arm waving will speed up with every trip across the screen. Notice that the invaders will only fire ten bullets and the player just one before no more can be shot. We will shortly do some collision detection and reset the bullets at appropriate events to fix this.
Before we do let’s build the player some destructible shelters.
Implementing the DefenceBrick class.
The DefenceBrick class is really simple. It has a RectF and a isVisible boolean variable. In the constructor the width and height are initialized based on the screen resolution as are all our other game objects. We also declare and initialize a brickPadding variable to 1, a shelterPadding variable to one-ninth of the screen width, and a startHeight for the first brick of each shelter.
When we then initialize rect we combine these values with the row, column and shelterNumber to create the perfectly positioned brick within one of four shelters. Of course, another key to this code is how we call the DefenceBrick constructor. We will see that in a minute. Add this code to the DefenceBrick 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 |
private RectF rect; private boolean isVisible; public DefenceBrick(int row, int column, int shelterNumber, int screenX, int screenY){ int width = screenX / 90; int height = screenY / 40; isVisible = true; // Sometimes a bullet slips through this padding. // Set padding to zero if this annoys you int brickPadding = 1; // The number of shelters int shelterPadding = screenX / 9; int startHeight = screenY - (screenY /8 * 2); rect = new RectF(column * width + brickPadding + (shelterPadding * shelterNumber) + shelterPadding + shelterPadding * shelterNumber, row * height + brickPadding + startHeight, column * width + width - brickPadding + (shelterPadding * shelterNumber) + shelterPadding + shelterPadding * shelterNumber, row * height + height - brickPadding + startHeight); } |
Here we have some simple getters and setters for DefenceBrick which get the rect object set the object as invisible (for when it is destroyed) and get its current state of visibility. Add these three methods to the DefenceBrick class.
1 2 3 4 5 6 7 8 9 10 11 |
public RectF getRect(){ return this.rect; } public void setInvisible(){ isVisible = false; } public boolean getVisibility(){ return isVisible; } |
Now, as usual, we will add code to SpaceInvadersView bring our shelters to life. Note that we do not need any code in update because they do not move or think. We will see how we destroy a brick in update later on.
In the code below we have a triple nested for loop to loop through four shelters made up of 10 columns and five rows of DefenceBrick objects each.
Enter this code in the prepareLevel method in the place indicated by the comment.
1 2 3 4 5 6 7 8 9 10 |
// Build the shelters numBricks = 0; for(int shelterNumber = 0; shelterNumber < 4; shelterNumber++){ for(int column = 0; column < 10; column ++ ) { for (int row = 0; row < 5; row++) { bricks[numBricks] = new DefenceBrick(row, column, shelterNumber, screenX, screenY); numBricks++; } } } |
Now we can just loop through the bricks array drawing any brick where getVisibility returns true.
Enter this code in the draw method in the place indicated by the comment.
1 2 3 4 5 6 |
// Draw the bricks if visible for(int i = 0; i < numBricks; i++){ if(bricks[i].getVisibility()) { canvas.drawRect(bricks[i].getRect(), paint); } } |
Run the game and we see that graphically we are finished.
We just need to handle all the different collisions.
Collision detection
There are five separate collision events that we need to detect and respond to. We will handle them each individually but each block of code can be entered straight into the update method in the locations indicated by the comments.
Here we check if the player’s bullet has hit the top of the screen. If it has we call
setInactive making it invisible and available for shooting again. The code then loops through all the bullets in
invadersBullets doing exactly the same.
Enter the code we have just discussed in the
update method at the place indicated by the comment.
1 2 3 4 5 6 7 8 9 10 11 |
// Has the player's bullet hit the top of the screen if(bullet.getImpactPointY() < 0){ bullet.setInactive(); } // Has an invaders bullet hit the bottom of the screen for(int i = 0; i < invadersBullets.length; i++){ if(invadersBullets[i].getImpactPointY() > screenY){ invadersBullets[i].setInactive(); } } |
In this next code, we check if the bullet is active, and if it is we loop through each of the invaders. For each invader that is visible, we use
RectF.intersects to check for a collision with the player’s bullet. When a collision is detected the invader is made invisible, we play an explosion sound, set the bullet to inactive, and add ten to the
score.
Enter the code we have just discussed in the
update method at the place indicated by the comment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// Has the player's bullet hit an invader if(bullet.getStatus()) { for (int i = 0; i < numInvaders; i++) { if (invaders[i].getVisibility()) { if (RectF.intersects(bullet.getRect(), invaders[i].getRect())) { invaders[i].setInvisible(); soundPool.play(invaderExplodeID, 1, 1, 0, 0, 1); bullet.setInactive(); score = score + 10; // Has the player won if(score == numInvaders * 10){ paused = true; score = 0; lives = 3; prepareLevel(); } } } } } |
Now we loop through every alien bullet in the
invadersBullets array. We check if it is active and if it is we loop through each and every brick in the
bricks array and for each visible brick we call
RectF.intersects to detect if they have collided. If they have the bullet set to inactive, the brick is set to invisible and the sound effect indicating a shelter has been damaged is played. Note that each and every active bullet is checked against each and every visible brick. This is a significant amount of checks. We will discuss ways of improving on this in the next project.
Enter the code we have just discussed in the
update method at the place indicated by the comment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// Has an alien bullet hit a shelter brick for(int i = 0; i < invadersBullets.length; i++){ if(invadersBullets[i].getStatus()){ for(int j = 0; j < numBricks; j++){ if(bricks[j].getVisibility()){ if(RectF.intersects(invadersBullets[i].getRect(), bricks[j].getRect())){ // A collision has occurred invadersBullets[i].setInactive(); bricks[j].setInvisible(); soundPool.play(damageShelterID, 1, 1, 0, 0, 1); } } } } } |
Here we do just the same as we did in the previous code block except we only check each brick against the player’s bullet. This is great for shooting a firing slit in the shelter.
Enter the code we have just discussed in the update method at the place indicated by the comment.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Has a player bullet hit a shelter brick if(bullet.getStatus()){ for(int i = 0; i < numBricks; i++){ if(bricks[i].getVisibility()){ if(RectF.intersects(bullet.getRect(), bricks[i].getRect())){ // A collision has occurred bullet.setInactive(); bricks[i].setInvisible(); soundPool.play(damageShelterID, 1, 1, 0, 0, 1); } } } } |
Now for the last block of code in the whole Space Invaders project. This code loops through each and every active bullet in the
invadersBullets array and checks to see if it has hit the player. If it has a life it is deducted, a sound is played and the bullet is made inactive. Finally, a check is made in case the player has lost all their
lives at which point the game is started again with a call to
prepareLevel.
Enter the code we have just discussed in the
update method at the place indicated by the comment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// Has an invader bullet hit the player ship for(int i = 0; i < invadersBullets.length; i++){ if(invadersBullets[i].getStatus()){ if(RectF.intersects(playerShip.getRect(), invadersBullets[i].getRect())){ invadersBullets[i].setInactive(); lives --; soundPool.play(playerExplodeID, 1, 1, 0, 0, 1); // Is it game over? if(lives == 0){ paused = true; lives = 3; score = 0; prepareLevel(); } } } } |
Congratulations we are done!
Space Invader’s final thoughts
The next project will have a scrolling world. That is the entire game area will not be drawn to the screen at one time. This will introduce the concept of a viewport which defines what the player can see at any given frame of play. We can also use the viewport to clip objects that don’t need updating or collision checking which in turn makes our code faster. Take a look a the Android 2D scrolling shooter project.
There is also a project you might be interested in to introduce a class to handle internal animations so we can have multiple objects all doing their own cool animations; like the Space Invaders arm waving but with an unlimited and dynamic number of frames.
Please leave any comments below. Thanks and happy coding.
Thank you so much for every tutorial you’ve done!
No problem Jose, loved every minute of it and thanks for the comment.
Thank you very much for tutorials….
A pleasure.
On my Galaxy Tab S, only the top (gun turret) of the ship was on screen, most was off the bottom edge of the screen.
It was due to a fixed value of 50 in draw (screenY â 50).
So I added a getHeight() to PlayerShip, and made line in draw use screenY â playerShip.getHeight().
Now the whole ship is on the screen.
Great tutorial set, Thanks
Terry
Thanks Terry,
Good improvement.
Student exercises:
*Limit ship to stay on screen
*Make bricks shorter then they are tall
*Stagger rows of bricks, like real masonry.
*Add some pin strips to the ship.
…
Great tutorial, fully playable but with plenty of things for the student to still figure out.
Thanks again.
How do I download the sound from the website. It only give me the option to play not download
Hi Mark,
Right click the text link (above the play button) and select Save link as…
Hope this helps.
hi
nice tutorial ,is there a complete source code for this
Hi there,
I will get round to preparing a download or putting it on github. All the code is on the page however. Hope this will do for now.
Thanks for the comment.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 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);
// Initialize gameView and set it as the view
spaceInvadersView = new SpaceInvadersView(this, size.x, size.y);
setContentView(spaceInvadersView);
}
// This method executes when the player starts the game
@Override
protected void onResume() {
super.onResume();
// Tell the gameView resume method to execute
spaceInvadersView.resume();
}
// This method executes when the player quits the game
@Override
protected void onPause() {
super.onPause();
// Tell the gameView pause method to execute
spaceInvadersView.pause();
}
errors are showing in this fragment. Red lines are highlighted on (onCreate method,getWindowManager,setContentView,onResume).
please help me
Thanks regards
That many errors seems odd. I could guess at missing imports or a closing curly brace } in the wrong place. If this doesn’t help then tell me what the errors are. In Android Studio you can hover the mouse pointer over the error to get more detail.
Thanks for the reply
Its not working. Showing same error. Can you connect with me by teamviewer ,so you can check my program once. Please help me.
Or connect with me by skype.
or provide me zip folder so i can import it directly in android studio.
Hi Deeps,
I don’t have the code to hand at the moment (other than the website). To test things out I just created a new project as described, created the six classes, pasted the code for SpaceInvadersActivity. I get errors in exactly the same places that you describe, but copy and pasting the code for SpaceInavdersView fixes this. Now however I have errors in SpaceInvadersView but adding the other classes, graphics and sound fixes this.
You will have errors throughout the project but if you follow the steps in order it should work out in the end.
If not, let me know the specific errors and I will try and help you troubleshoot.
Good luck,
Hi John,
Thank you so much for the guide.
Now its not showing any error. However at run time its not running and showing (Error:A problem occurred configuring project ‘:app’.
> failed to find Build Tools revision 23.0.0 rc3) Information:BUILD FAILED
Information:Total time: 3.993 secs
Information:1 error
Information:0 warnings
Information:See complete output in console
Please help me out.
Thanks regards,
Deeps
Hi Deeps,
Glad your making progress. I have tried to recreate this error but I can’t. Here is some things to try.
1) Select Tools | Android | Sync project with Gradle files.
Try and run it again.
2) Select File | Invalidate caches and restart. Confirm your selection and wait for Android Studio to restart.
Try and run it again
3)”See complete output in console” to see if it helps, if not, post the specific error in this thread.
Good luck.
Hi John,
Thanks again for your help, support and time. I followed the step as suggested by you. However, its not syncing and showing an error as follows.
Error:failed to find Build Tools revision 23.0.0 rc3
Install Build Tools 23.0.0 rc3 and sync project
Thanks,
Deeps
Hi Deeps,
It could be that in the project configuration there is a version where you don’t have the build tools (api etc.) installed.
But I would try this first:
1) Create a new project in Android Studio, call it Space Invaders and name the Activity SpaceInvadersActivity (as before) then make sure you leave all other settings at the default suggested by Android Studio especially the Android sdk versions.
2) Before you add/remove any code at all see if this”Hello world!” project will build and run.
3a) If it does run copy/paste all the java/image/sound files from your previous project and try to run again. Don’t copy paste the AndroidManifest file as this will contain configuration info which might be part of the problem.
3b) If it doesn’t run refer to the link below to try and fix the build version problem by following the info at this link as a rough guide. http://stackoverflow.com/questions/30665001/androidstudio-failed-to-sync-install-build-tools
Good luck Deeps.
Hi John,
Thanks for the reply.
I tried everything as suggested by you. Still , its not working. Will be possible for you to connect through skype or teamviewer and help me out.
Thanks,
Deeps
Hi Deeps, life is manic lately. I am on the go writing on a laptop much of the time. My father was taken ill on Monday, my partner is away at a conference for two weeks, the kids are due back at school tomorrow and I really can’t stop to do calls etc.
I do get a couple of minutes every now and then to reply to comments however and if you tell me what exactly didn’t work I might be able to suggest something else.
Did the new “Hello world!” project run? If it didn’t I would try making sure you have latest api installed. Tools | Android | SDK Manager.
Get the Hello world project to run and then add the Space Invaders code and assets to it.
Sorry I can’t chat at the moment. I really want you to be able to get this running I just can’t commit to face to face/chat at the moment.
All the best,
John
Super fantastic tutorials! I was about to give up on Java and go back to c# but your tutorials have won me over and I hope to start creating some awesome little games for Android soon. Thanks again Dude!!!
Hi Davey,
Thanks very much for your comment and good luck with your games!
hi , i have an error in SpaceInvadersActivity , in method onResume() , it seems it not override or implement a method from a supertype.
thanks regards
Hi There,
The error seems to suggest that a supertype with onResume doesn’t exist (which it does). So the possible solutions are that either the name or some other part of the signature is incorrect. Try pasting this code exactly and make sure it is inside the Activity. If it still doesn’t work perhaps you could post the error message.
// This method executes when the player starts the game
@Override
protected void onResume() {
super.onResume();
// Tell the gameView resume method to execute
spaceInvadersView.resume();
}
Thanks for your comment and good luck.
Thanks man , it was my mistake
Pleasure! Glad it worked.
hi again , i have another problem and i need help , i don’t have any error , but my ship is moving only at left .I checked the variables, and when i press right it change from 0 to 2 , and when i press left it change from 0 to 1 , but my ship is moving only at help. Do you have any idea how can i fix this problem ?
Thanks regards
Hi there a11n,
As the variables seem to be changing this is a bit odd. The only thing I can think of suggesting is first that the controls are very basic and if you hold down both sides of the screen simultaneously the code won’t handle it properly and you might get unexpected results.
The other thing which can make the input handling less responsive is if you haven’t implemented the “making the game full screen” near the start of the tutorial as this would leave hidden part of the control area at the bottom of the screen.
Let me know how you get on and if it still doesn’t work are you able to give any more details at all and I will try and help you solve this.
Good luck!
It is full screen.
i add after playerShip.setMovementState(playerShip.RIGHT); the code System.out.println(“1″ + motionEvent + “2 ” + (screenX / 2)); System.out.println(“2″); and after playerShip.setMovementState(playerShip.LEFT); yhe code System.out.println(“1″ + motionEvent + “2 ” + (screenX / 2)); System.out.println(“1″); to see if my program enter in the first case of the “if” and when i press in the right place of the screen in my console is diplayed “2” , same for the left place of the screen.This what i’ve done.
Hi a11n,
I have looked quite closely at your last message but I can’t work out quite what your doing.:-( I have just double checked the code, run it and it seems to be working. So I am not sure what is causing the problem. Try copy & pasting the entire onTouchEvent method again because it just worked for me.
hello john, can i ask for the whole sample code?
Hi and thanks for your comment. I don’t have the project to copy and paste the complete files from as I didn’t keep it :-(. I will get around to putting it on GitHub or something soon. Sorry. All the code is in the bonus download near the top of the article.
hehe thank you mister Horton.. i also want to read ur book xD..
There is often a BIG sale on https://www.packtpub.com/ in December. So if you can wait I would. I can’t guarantee it but you might save 80% + (depending on which title you want). If you want my soon to be released (non-gaming) “Android programming for beginners” you can currently get a free copy in exchange for an honest review. Thanks for checking out my tutorials and commenting!
Where i can find the SurfaceView class?
The complete listing for the class which extends SurfaceView is in the bonus download near the start of the article. Unless you meant which class do you need to import, in which case it is android.view.SurfaceView and you will also need android.view.SurfaceHolder. I hope I have understood your question correctly? Thanks for your comment.
Hey John!
Just completed this tutorial.I just wanted to ask how do I add other sprites than the one in your tutorial. And what methods steps etc.. are required to be changed..
Again, Thanks for this Tutorial…
Hi there!
If you mean to just change the image then you just need to replace the images with your own. You can either keep the names the same and it should work without code changes. Or take a look at this tutorial which looks more closely at the individual stages.
But won’t changing the sprite will change its dimensions and result in bugs…
Ok i did it and it works.
Hi there,
Take a look in the PlayerShip constructor for your answer. The size is dertmined by the createScaledBitmap method. The .png that you use needs to be an appropriate size to that which you scale it or it won’t look right but you can use almost any .png with any size.
Thanks for the tutorial it looks like a great project but i keep getting the following errors when i try to compile it in the latest android studio
Error:(51, 13) error: cannot find symbol class PlayerShip
i get that for each of the classes
Hi Adi,
The most likely solutions are either that the PlayerShip class is in a different folder to the other classes or the class itself has been misspelt. It is quite easy in Android Studio to create a new class in the Test module instead of the main package folder. 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.
moving the classes from the androidtest folder to the java one above seemed to fix those errors but not I get these
Error:(158, 22) error: constructor PlayerShip in class PlayerShip cannot be applied to given types;
required: no arguments
found: Context,int,int
reason: actual and formal argument lists differ in length
Hi Adi,
Have you got to the part in the tutorial where you implement(not just create the empty) the PlayerShip class? At this later stage in the tutorial you will create a constructor with the required arguments. You will get errors while implementing and adding the code at a few places. The thing to do would be to read it all through first to get a feel for it and then go back and implement it.
Hope this helps,
John
i am a beginner. but i understand your tutorial to 80 %. You are a good teacher.
I have one question:
When i fire a bullit, must wait till the bullit reached the top of the screen before i can fire the next bullit. I want to shoot faster. how can i change the code so that i can shoot ervery 1 second.
best regads
joachim
Hi Joachim,
Yes, the bullet can’t be refired until it reaches the top of the screen (as in the original). You can change this however. Look at how we handle the invaders bullets with an array and you will have your solution for super fast shooting. Remeber to change the collision detection code as well.
Hey John, shouldn’t the invader ships fall down after coming very near to the ship. But it doesn’t. When they come very close, the game just restarts…
Hi there, yes, and there should be ufo’s, high scores, 2 player games etc. It is just the simplest playable implementation. I am going to do a scrolling shooter with a few more features in the new year which will demonstrate a few more concepts.
Sorry for that, but the original game had that so I thought this would have it too.
Hi Anurag,
Thanks for your comments. I hope to make Space Invaders more authentic in the new year.
Hello John,
Thanks for this tutorial But the canon does not show on the screen!
When I change the colors
It seemed this was due to bad choice of color maybe alpha
Glad you sorted it. Thanks for the comment.
if i add the number of alliens to 12, they speed up toooooooooooooooooooo much!
How to downland ur entire android project code
Hi There,
I don’t have a download bundle yet but all the code is on the page. Sorry about that I am looking into it.
Thank you very much John for the tutorial. It was excellent. I have a couple of general questions.
1. With the finish product on a Nexus 7 tablet, the player moves around “jerkily”. I’m able to move and fire, etc. but the movement of the player is jerky. I realize this is a beginning demo, but could you give some general ideas on how you would make the action smoother? Is this where OpenGL comes in?
2. If I understand this demo fairly well, which of your books would you recommend? You have at least 3 dealing with Android and Games. Perhaps one is more up to date? And I believe I read somewhere on your blog a comment from you along the lines of when during the year the books are discounted or possibly a discount code. Then again, possibly it’s wishful thinking on my part! Any ideas? Thanks, Dave
Hi Andrew, thanks for the message. Space invaders should be reasonably smooth moving although the simplistic controls might make things a bit eratic. If the game runs slow try the version in my free android app to see if that has the same issues on your device. Anrdroid programming for beginners is non-games so not suitable if games is your thing. Learning java building android games is for complete java novices so not for you if you are comfortable with classees, threads, basic java. Android game programming by example has 3 projects in it. The first is about the same level as space invaders, the second is a platformer with an explorable scrolling world and the third an asteroids game using opengl es2. This one might be most appropriate. You can read about them on the books tab and the publishers site linked to from there and you can play the games that are built on the free android app. See the tab at the top of the page.
Packt do have discounts on and off thoughout the year but I am not sure when the next is. Hope this helps. Many thanks.
Thanks John. I’ll check out your app and the book. Looking forward to more tutorials on your site!
John,
I was reviewing the code with an aim to making minor modifications* I realized I have no idea what you are doing with:
private Thread gameThread = null;
As far as I can tell, youâre just starting the thread, and joining the thread. I come from a Windows background (C#/C++). I was expecting to see a thread procedure. That is a function that does work on this new thread. I donât see any of that. Itâs as if the thread is doing nothing. All the works seems to be on the main GUI thread. Is this some Android trick? Perhaps you could point me to somewhere on your site or elsewhere that explains it?
Thanks,
*If you play the game and click to the left of the player ship, the ship will go left. Thatâs correct. However, once the ship gets over to the left of the screen, if you click to the right of the ship, but still on the left hand side of the ship, the ship still goes left. I changed code to take into account whether the click is the left or right of the ship. It seems better (to me) now. Another improvement Iâll try and make is to âgrabâ the ship and drag it to the left or right. Iâm hoping you post a âscrolling gameâ soon. Perhaps Defender?
Hi Andrew,
Thanks very much for your comment. Your modifications sound neat. The control scheme mimics two big buttons. One for left and one for right regardless of the position of the ship. The run method is roughly equivalent to a C++ thread procedure. There is a little bit about Java threads and their relationship to the game loop in the article Managing simultaneous events with threads.
Thanks again!
Ahh. I see it now! You create the thread and pass in “this” in constructor.
“this” is SpaceInvadersView and SpaceInvadersView implements Runnable.
So the thread will run whatever is in SpaceInvadersView’s “public void run()” method.
It’s a little different than C++ but makes sense! Here is one particular link that goes into more depth
in case there are any other Java neophytes reading this:
http://examples.javacodegeeks.com/core-java/lang/runnable/java-runnable-example/
Thanks!
it works i forgot to remove my replaced error on main silly me xD TY FOR THE TUTORIAL I LEARNED A LOT LIKE HELL MY BRAIN CANT PROCESS IT ANYMORE
Is there any copiright on it©Ÿ? Can I youse the code and upload it. Maybe on Google Play Store ?
Thank you very much
Hi there,
Thanks for asking. Feel free to use the code in your apps. Please don’t reproduce the code, especially in tutorial form.
Many thanks.
Hello John Horton,
So if I understand correctly I may the app in the example Post in the Google Play Goals? And should the code not himself write a tutorial (What I do not hve playned). Do I have to point in Play Goals in this Turorial (Attribution)?
Many thanks for your response
Attribution would be nice. Good luck with your game.
Thanks I will Attribut you đ
Hello John Horton,
The Invaders Shoot too often. How can I patch the shoot not so often.The levels are usually too heavy đ
Thank you very much
Look in the takeAim method to adjust the rate at which the invaders shoot.
Thank you,
To all who want to have the game a bit easier
1. You must go to Invader.java file in your project.
2. Overwrite the this method:
public boolean takeAim(float playerShipX, float playerShipLength) {
int randomNumber = -1;
// If near the player
if ((playerShipX + playerShipLength > x && playerShipX + playerShipLength x && playerShipX < x + length)) {
// A 1 in 500 chance to shoot
randomNumber = generator.nextInt(2000);
if (randomNumber == 0) {
return true;
}
}
// If firing randomly (not near the player) a 1 in 5000 chance
randomNumber = generator.nextInt(4000);
if (randomNumber == 0) {
return true;
}
return false;
}
Great tutorial! I learned a lot.
However, there seems to be an error as the game won’t start. It crashes and I think its because of the manifest file showing an error.
<——————————–this part says there is no default constructor available in the view
Hi Janark, This sounds like an error you might get while coding but not finished yet. Try copy & pasting all the classes and see if it goes away. Let me know and I will try and help you get it working. Hope this helps.
firstly , thnx for the great tutorials!! i started from beginning and now i have a very good understanding of android game dev. although, i am getting a problem in my game. im stuck at the point after getting user input.my ship only fires once and then when i tap on top again, nothing happens again. any help would be appreciated.
Thanks for your message Sanilk. Have you got to the collision detection part near the end of the tutorial. This is the part of the code which prepares the player’s bullet after it has been shot and left the screen.
// Has the player's bullet hit the top of the screenif(bullet.getImpactPointY() < 0){ bullet.setInactive();}
Hey John thanks for the tutorial. What I want to ask is a few customization options:
1) how do I change the background to an image of my choice from the drawable folder?
2) how do I change the bullet’s and brick’s color?
Trying to learn from this tutorial for my project ^^
All you need to do is draw a bitmap the size of the whole screen and then draw all the other objects on top of it.
This code is untested, but it goes something like this:
// Create a bitmap outside the game loop
Bitmap background = BitmapFactory.decodeResource(getResources(),R.drawable.background);
// Each time, in the draw method of the game loop
// Draw the background first
canvas.drawBitmap(background, paint);
// Don’t fill the screen with color after or you will hide it
// Draw all the other objects
To change object colors just use the next line of code before the object you want to change the color of.
// Choose the brush color for drawing
// The numbers are 255 (full opacity) 255, 255, 255(full red, green and blue)
// The result is white
mPaint.setColor(Color.argb(255, 255, 255, 255));
Hope this helps.
Thanks John ! I really learned a lot from this tutorial and seeing you reply to each comment asking for help here really earns my respect. Thanks for teaching us !!
Hi there I’m a beginner for programming and all things related to technology.
I bought your book “ANDROID GAME Programming By Example” and it was very helpful, especially the game loop, pause and resume methods.
The thing that I need help with the most is that I want to add an static background image (drawable/mipmap) instead of an bitmap color scheme, how would I go about doing this?
Hi Lance, nice to hear from you.
All you need to do is draw a bitmap the size of the whole screen and then draw all the other objects on top of it.
This code is untested, but it goes something like this:
// Create a bitmap outside the game loop
Bitmap background = BitmapFactory.decodeResource(getResources(),R.drawable.background);
// Each time, in the draw method of the game loop
// Draw the background first
canvas.drawBitmap(background, paint);
// Don’t fill the screen with color after or you will hide it
// Draw all the other objects
Hope this helps.
I am very thankful! I did not imagine creating a background outside of the loop then use the draw method of the game loop to set canvas.drawBitmap(background,paint);
From the book I was creating another class object called background, as how you would have created a player ship class.
I shall try this out, thanks again!
I’ve tried following this tutorial but either I have very little understanding of what is going on or my software is faulty…
I followed the steps exactly, but I get a red line for:
setContentView(spaceInvadersView);
in SpaceInvadersActivity.java
also for:
bitmap1 = BitmapFactory.decodeResource(context.getResources(), R.drawable.invader1);
in Invader.java and PlayerShip.java
I get ” cannot resolve symbol ‘R’ ”
for SpaceInvadersView spaceInvadersView; in SpaceInvadersActivity.java it doesn’t seem to find SpaceInvadersView, no matter what I do…
Please help
Hi Mike,
Here are some suggestions of likely causes.
“I get a red line for: setContentView(spaceInvadersView);”. Most likely the class, is misnamed, has an error or is in a different folder (left hand side project explorer.), to the other classes.
â cannot resolve symbol âRâ â Is usually be fixed by syncining the project. Try Tools | Android | Sync project with Gradle files.
“it doesn’t seem to find SpaceInvadersView”. I am not sure what you mean here. Can you explain it to me another way.
I hope this helps. Let me know either way and I will try and help you get it working.
the red line was spelling.. silly me…
but syncing doesn’t seem to solve anything :/
I wish I could send you a screenshot. ‘R’ still says the same, the issue seems to persist in SpaceInvadersActivity.java I have
“cannot resolve symbol” for:
SpaceInvadersView spaceInvadersView;
spaceInvadersView = new SpaceInvadersView(this, size.x, size.y);
setContentView(SpaceInvadersView);
and “cannot resolve method” for:
spaceInvadersView.resume();
spaceInvadersView.pause();
Thanks for the reply
I just got it Working!
I really need to pay more attention…
Turns out, The packages were not declared in the classes for some reason.
I also needed to add some imports for RectF and Bitmap.
My bad xD
Thanks for the help!
I’d like to try further the content of this game some time ;D
Great news!
That happened to me as well. Can you explain how you fixed it?
Thanks
Hi again John,
I managed to code the previous code that I had trouble on. But I do have another question for you if you don’t mind.
I am having trouble with a GAME OVER screen. I know I have to call it to the surface view but no idea how to go about this. For instance a brand new view where the layout background is black, text is GAME OVER. I have no idea on how to add this to the Surface View.
Any tips on how I am able to do so? ( I made sure to /find this post, just in case someone had ask so already).
Hi Lance. There are a few ways to do this. The quickest, without changing the structure of the code, is to introduce some game states. This can be done with some simple Boolean variables perhaps ( homeScreen, hiScoreScreen, gameScreen) but could be more neatly done with an enumeration. You could then just wrap different parts of the drawing and input handling code in if statements to represent what screen should currently be shown. So when the player loses his last life you could set homeScreen = true. Then the draw and input handling parts of the code would respond differently. Hope this helps a bit.
It took me awhile to understand but from what I understand, since the draw handling part is image on top of image once my GAME_OVER screen is called it just covers the rest of the image by use of the if statement.in the draw method.
Hey John I’m stuck with another problem. I can’t seem to get the ship to appear. It’s as if it is below the screen. I tried changing a few things but nothing happened. Can you help me on how I could raise the ship so I can see it? Thanks.
Also I would like to return to an activity that I started with. I have a main activity and I was hoping to go back to it after the game ends. So if you could shed me some pointers on a game over screen and then a popup to go back to the main activity that would be much appreciated ^^
Hi Leon,
See if this helps.http://stackoverflow.com/questions/3591465/on-android-how-do-you-switch-activities-programatically.
Hi there,
Have you done the part near the start of the tutorial which makes the game fullscreen? If not, this is probably the problem.
Fantastic!
The way you lay out the tutorial is great.Learning to code in blocks of code as you show is a very easy and organized way to learn.
It makes it easier to understand each step and then see how it works, before even inserting into the different classes.
Great Job!
Thank you!
(Would like to see the Scrolling World Tutorial )
Hi Joe,
Thanks for your comment. Sorry about the scrolling world tutorial. I was overtaken by events back in January and haven’t caught up yet. I should be back working on new tutorials in about 4 weeks.
Very nice tutorial.
At the moment, the playership can’t shoot a new bullet before it out of screen. How could you make the change that allow playership to shoot a new bullet consecutively? Thanks a lot.
Hi Tuan, Thanks for the question.
To achieve this you would need more than one bullet object. Look at how the bullets for the invaders are handled, as an array of bullet objects and each time a new bullet is fired the next bullet object is used. You can use the invader bullet solution as a guide for the player’s bullet solution and you will get a rapid fire ship.
Hope this helps.
Hi John,
Thanks for the feedback. I think I manage to solve it by using: private List bulletList = new ArrayList();
Thanks again for the great tutorial.
Hello John!
I have a problem with the code.
I am 99% sure that i have copied the whole code as you intended it to be copied. I have an error in the SpaceInvadersActivity.java file. It won’t recognise the SpaceInvadersView.java file. I have to note that i don-t have the package line in the SpaceInvadersView.java file. When i put the same package line in the SpaceInvadersView.java file, the SpaceInvadersActivity.java works properly, but i get a lot of errors in SpaceInvadersView.java file.
package com.stipkeividda.spaceinvaders;
that is what my package line looks like. I would be grateful to you if you could help me as soon as possible
Hi David,
The likely solution would be to include the package name and deal with the errors in SpaceInvadersView. A quick thing to check. Are both files in the same folder in the project explorer window (left hand side of Android Studio)?
They are not, SpaceInvadersActivity is in the java/com.stipkeividda.spaceinvaders folder, while the rest of the classes are just in the java/ folder
Try moving them (dragging and dropping) all to the same folder as SpaceInvadersActivity. Worth a try.
Okay, i did that, and have imported the package line in the SpaceInvadersView.java file. Activity file is now okay, but the view file won’t recognise other classes
I have added the package line to every class. It works now, thank you! đ
Hey John,
Thanks for making this great tutorial series, it’s one of the better introductions to making games in Android Studio that I’ve found. However, my game has a peculiar issue with it. It appears that every game object will get drawn onto the canvas but after updating its previous drawn image won’t go away, so every object just ends up looking like it’s dragged across the screen (kinda like what happened to lagged windows on Windows 98). I have combed through your code to figure out if I missed something but I don’t see any or can’t catch it if I have. Here’s a link to the screen shot: https://goo.gl/photos/EjrkYFG9cgCV5tdR9
Thanks for the help!
Hi There,
Make sure that this line of code isn’t missing and is also the first thing you draw each frame.
// Draw the background colorcanvas.drawColor(Color.argb(255, 26, 128, 182));
See if that works. Good luck.
Hey mate, Just quickly. Love the tutorial, But i want to have a UI that enters into this game. Like a “PLAY” and a “Game Over” UI.
Any help would be awesome. I am new to android. Thank you.
Use the playing and paused variables, along with some mew ones, perhaps gameover, highscorescreen, etc to represent different states of the game. Then you can wrap the relevant parts of draw and update methods in if blocks to behave differently depending on the current state. That is the quick way but will eventually lead to quite a long sprawling code file. The better way would be to study a little more to devise a code structure/pattern that suits you specific game. I hope to add such tutorials soon.
Hell there,
First thanks for your Tutorial,
But well, i got my First Problem Right from the Start.
I ve Coded to the Point, when the Blue Screen and The score Board should appear, but when i run the program on my Phone, online for an Blink of an eye the screen Chance, and Them the App closes. I dont get any error Message…
Do you have any clue what happend there?
Thank you in advance
Nic
Hi Nik,
Are you using USB debugging via a USB cable. If not, you will need to, to get the error messages. If you are then check the logcat window for messages. If not you should do so or run the game on an emulator and then check the logcat window. Read the logcat and it should point you to the line that is causing the crash.
Hi John,
I am at the part where I have created my spaceship class and filled in all the methods.
And it says that if you run the application you should see your space ship in the middle, but it won’t show for me. I have no errors what so ever and the playership image is in the drawable folder. I tried copying the whole view, but it stull does not work..
should i go on with the bullets class or should this not happen?
thank in advance!
Hi Tim,
It is probably worth fixing it so far. If the background color IS drawn to the screen but the ship is not visible check if you have set the screen to full-screen (described near top of article). This could cause the ship to be drawn just out of sight.
Hi john,
Thanks for the reply!
i do have my screen on full screen..
so I still don’t know how it happens, I tried various full screen methods but they either just don’t work at all or there is still no spaceship
any more suggestions that could cause this?
Tim.
Hmm. Is the score,lives and blue background visible? If so try changing this line:
// Now draw the player spaceshipcanvas.drawBitmap(playerShip.getBitmap(), playerShip.getX(), screenY - 50, paint);
To this:
// Now draw the player spaceshipcanvas.drawBitmap(playerShip.getBitmap(), 500, 500, paint);
This draws the ship at 500, 500. If the ship still isn’t visible then either the graphic is in the wrong folder, has the wrong name or is not being loaded in the class constructor (for some other reason).
If the ship is drawn then the problem is that the ship was being drawn off-screen. I am guessing now, but try recreating the project from scratch using Empty Activity instead of Blank Activity. or change the line of code to draw it a little higher, perhaps:
canvas.drawBitmap(playerShip.getBitmap(), playerShip.getX(), screenY - <strong>250</strong>, paint);
Good luck!
it appears it is messing up the x and y somehow, it does show the ship when i put in the 500 x 500 but it is really stretched out. but when i put in any other code it disappears again. But when i hold my phone vertically it show the ship in roughly the middle..
I have now fixed it. It looks like it should on screen but something is still weird.. it mixes up the x and y axis i think.
this is what I have now :
canvas.drawBitmap(playerShip.getBitmap(), screenY/2, playerShip.getX()+550, paint);
Tim
Could be that it is not locked in landscape. If you are able to rotate the screen then it is not locked. Try studying the layout file and try and make sure it is locked in landscape.
Dear John,
I don’t know Java language, I tried to compile Space Invaders classes but found lots of errors, could you please send me Space Invaders classes to compile and run into Android Studio 2.1.2.
Thanks
Hi Ali,
I don’t have a copy of the files to hand, unfortunately. All the code can be copy-pasted from the page and the entire main class is shown in the bonus download near the start of the article. Hope this helps a bit.
Hi John,
Thanks for your prompt reply,
Ok I will try.
Thanks
Hi John,
First of all i wwant to say i love your tutorials. But at the object classes i can’t find any imports?
And without them my code is full of errors. So what do i have to import in the object classes?
and it also is not always clear for me where to paste the code(in which file).
The first block of code is SpaceInvadersActivity, everything from the long listing at the end of the article is SpaceInvadersView and each of the other classes should have a clear heading. Let me know if something is still unclear and I will hopefully get a chance to make some improvements in the next few days. Thanks for your message.
Hi Mees, I think Android Studio can solve this. Click the cursor onto an error then hold Alt andd tap Enter to get the auto-import options. I think that’s right.
If for anyone, the app is crashing, make sure you are extending Activity and not AppCompatActivity in the SpaceInvadersActivity class. Thought that might help someone.!
Hi John,
Would I be able to use this code in Eclipse? If not would changes would I need to make?
Kind Regards,
Ewan
Hi Ewan, the code should be the same in Eclipse.
Hi I just did the step where you include playership into the game but when I run the game on my smartphone I canÂŽt see it. There is just the blue background and the score and livestext. I have no errors in the text but it still wonÂŽt work. Can you please help me to figure out what to do, thanks!
Have you completed the section of the tutorial where you make the game full-screen? This has been said by others in the past and not making the game full-screen resulted in a hidden spaceship (just off the bottom of the screen). Hope this helps.
I did that step once again now just to see, and I saw that the “android:name” that was in my Manifest folder was named “.SpaceInvadersActivity” and not “.SpaceInvaders” like in the tutorial. Could this be a problem?
Hi Harald,
That shouldn’t be the cause. Try drawing the ship say 50 pixels higher and see if that helps.
// Start ship in roughly the screen centrex = screenX / 2;y = screenY - <strong>100</strong>;
See if you can see it now.
Umm I couldnÂŽt see the ship on my screen (which is samsung s4) but I could see it on another device (samsung ace 4). Could it be the phoneÂŽs fault? Anyway thank you for answering so quickly!
I am sure(fairly) it is something to do with the way the screen resolution is calculated. hard-coding a value for the y position of the spaceship to try and work out what is going on.
I tried to give pretty high numbers but nothing changed. Then I also deleted the code in AndroidManifest and nothing changed. Could IÂŽve written the code in the wrong place?
I copied the code from Manifest so that you can see if thereÂŽs anything wrong.
android:theme=”@android:style/Theme.NoTitleBar.Fullscreen”
android:screenOrientation=”landscape”
Sry here it is
android:theme=”@android:style/Theme.NoTitleBar.Fullscreen”
android:screenOrientation=”landscape”
Never mind i found the problem!
I had coded like this “”
android:theme=”@android:style/Theme.NoTitleBar.Fullscreen”
android:screenOrientation=”landscape””
But it shouldÂŽve been ” ”
Thanks alot for the help though I will continue this tutorial with eager!
That’s great Harald!
If you have started testing this game out, you may have noticed that once you shoot the bullet, it doesn’t appear to let you shoot it again. We need to program the bullet to return to the place in front of the rocket when we shoot it. We can do this using the Bullet.MoveTo block.
Hi Roland, The delayed firing is authentic to the original. Your idea would be good for a more modern rapid fire version. Thanks for commenting.
Hello! Thank you for the lovely tutorial! I was wondering if you’ve gotten the chance to place the code in github? I was also wondering if you could possibly show each java class’s code individually. I want to make sure I followed everything correctly in terms of placement.
Cheers!