Kilobolt
  • Home
  • Tutorials
    • Game Development Tutorial >
      • Unit 1: Beginning Java >
        • Before you begin...
        • Day 1: Setting Up
        • Day 2: Java Basics
        • Day 3: More Basics
        • Day 4: Java Math
        • Day 5: More Math
        • Day 6: If... else...
        • Day 7: More Control Flow
        • Day 8: Looping
        • Day 9: More on Looping
        • Day 10: Inheritance, Interface
        • Day 11: Threads and Graphics
      • Unit 2: Creating a Game I >
        • Day 1: Foundations
        • Day 2: Basic Framework
        • Day 3: Taking User Input
        • Day 4: Enter the Robot
        • Day 5: Background and Sprites
        • Day 6: Adding Enemies
        • Day 7: Shooting Bullets
        • Day 8: Animations
        • Day 9: 2D-Arrays
        • Day 10: Painting the Tilemap
      • Unit 3: Creating a Game II >
        • Day 1: Level Creation - Part 1
        • Day 2: Level Creation - Part 2
        • Day 3: Level Creation - Part 3
        • Collision Detection Basics
        • Day 4: Collision Detection Part 1
        • Day 5: Collision Detection Part 2
        • Day 6: Collision Detection Part 3
        • Day 7: Health System & Death
        • Day 8: Basic AI & Final Touches
      • Unit 4: Android Game Development >
        • Day 1: Introduction to Android
        • Day 2: Setting up for Development
        • Day 3: Creating our First Android Application
        • Day 4: Parts of an Android Application
        • Day 5: The Android Game Framework: Part I
        • Day 6: The Android Game Framework: Part II
        • Create an Android Game From Scratch (or port your existing game)
        • Day 7: Creating an Android Game (From Start to Finish)
      • Reference Sheet
    • Zombie Bird Tutorial (Flappy Bird Remake) >
      • Unit 1: Building the Game >
        • Introduction
        • Day 1: Flappy Bird - An In-depth Analysis
        • Day 2: Setting up libGDX
        • Day 3: Understanding the libGDX Framework
        • Day 4: GameWorld and GameRenderer and the Orthographic Camera
        • Day 5: The Flight of the Dead - Adding the Bird
        • Day 6: Adding Graphics - Welcome to the Necropolis
        • Day 7: The Grass, the Bird and the Skull Pipe
        • Day 8: Collision Detection and Sound Effects
        • Day 9: Finishing Gameplay and Basic UI
        • Day 10: GameStates and High Score
        • Day 11: Supporting iOS/Android + SplashScreen, Menus and Tweening
        • Day 12: Completed UI & Source Code
    • Android Application Development Tutorial >
      • Unit 1: Writing Basic Android Apps >
        • Before you begin...
        • Day 1: Android 101
        • Day 2: Getting to Know the Android Project
        • Day 3: The Development Machine
        • Day 4: Building a Music App - Part 1: Building Blocks
        • Day 5: Building a Music App - Part 2: Intents
        • Day 6: Building a Music App - Part 3: Activity Lifecycles
  • New Forum
  • About Us
    • Contact Us
  • Our Games
    • TUMBL: FallDown
  • Facebook
  • Twitter

GAME DEVELOPMENT TUTORIAL: DAY 2-7: Shooting Bullets

10/27/2012

80 Comments

 
Picture
Welcome to Day 7. Thank you to those of you who submitted ideas on the story of this game. We will be implementing some of them in the coming lessons.

This lesson will be dedicated to arming our character, so that next week, when we go over collision detection, we will have more to work with.

This is how we will approach today's task:
1. We will first create a Projectiles class, which we will use as a blueprint for our bullet objects.
2. Within the Robot class, we will create a method that handles shooting.
3. Finally, in the StartingClass, we will paint the bullets to the screen, and allow the user to shoot with the Control button.


Lesson #2-20: Creating the Projectile Class
The Projectile class, as mentioned, will be a blueprint for creating bullets!

As with many of the previous classes, we will do the following:

1. Create the class.
2. Declare variables
3. Create an update() method and create helper Getters and Setters methods

I. Creating the Projectile Class

1. Right click on the kiloboltgame package >> New >> Class
2. Name it "Projectile".
3. Check the box labeled "Constructors from superclass:"
4. Press OK!

You should now see the following:

package kiloboltgame;

public class Projectile {

public Projectile() {
// TODO Auto-generated constructor stub
}

}

II. Declaring Variables

Let's now declare the variables that we will be using.

private int x, y, speedX;
private boolean visible;


These are class-wide variables, so they should be below the class declaration:
public class Projectile{
   private int x, y, speedX;
   private boolean visible;


Now, we need to make some changes to the constructor:

public Projectile(){
}

As of now, it takes in no parameters. We want it to take in two values, a starting X coordinate and a starting Y coordinate, which will represent the top left corner of each painted bullet.

1. So we add the two parameters:

public Projectile(int startX, int startY){
}

2. To set these startX and startY variables into the class-wide x and y variables, and to set the speedX of the bullet and to initialize the visible boolean, we declare the following four statements inside the constructor:

x = startX;
y = startY;
speedX = 7;
visible = true;


Your constructor should now look like this:
 
public Projectile(int startX, int startY){
x = startX;
y = startY;
speedX = 7;
visible = true;
}

III. Creating the Update() and Helper Methods

The update() method in this class, as in the other classes, will be called with each update of the game.
Naturally, then, we should change the location of the bullet here with respect to speed, and react when the bullet collides or goes off the screen (we won't handle collision just yet).

1. So first create an update method:

public void update(){


}

2. Add the following statements:

x += speedX;
if (x > 800) {
   visible = false;
}

- The x += speedX; statement will continually update the x coordinate by adding to it the speed in the x direction.

- The if statement checks if the bullet is off the screen, and makes it invisible. In the other classes, we will remove these bullets so they do not take up unnecessary memory.

3. Now create Getters and Setters:

- Right click on the code, go to Source >> Generate Getters and Setters
- Select All
- Press OK

You should get the following:

   public int getX() {
return x;
}


public int getY() {
return y;
}


public int getSpeedX() {
return speedX;
}


public boolean isVisible() {
return visible;
}


public void setX(int x) {
this.x = x;
}


public void setY(int y) {
this.y = y;
}


public void setSpeedX(int speedX) {
this.speedX = speedX;
}


public void setVisible(boolean visible) {
this.visible = visible;
}


That should be it for the Projectile class for now. Here's the final code:

FIGURE 2-29: Projectile Class

package kiloboltgame;

public class Projectile {

private int x, y, speedX;
private boolean visible;

public Projectile(int startX, int startY){
x = startX;
y = startY;
speedX = 7;
visible = true;
}

public void update(){
x += speedX;
if (x > 800){
visible = false;
}

}

public int getX() {
return x;
}

public int getY() {
return y;
}

public int getSpeedX() {
return speedX;
}

public boolean isVisible() {
return visible;
}

public void setX(int x) {
this.x = x;
}

public void setY(int y) {
this.y = y;
}

public void setSpeedX(int speedX) {
this.speedX = speedX;
}

public void setVisible(boolean visible) {
this.visible = visible;
}

}

Lesson #2-21: Creating an ArrayList in the Robot Class
It would be extremely time consuming and inefficient if we were to manually create bullets each time that the player pressed "shoot." So we will be implementing a type of List called an ArrayList, which will allow us to store our Projectile objects in a "container" of increasing size.

1. To do so, we first declare (below all the other variable declarations):

private ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
(Make sure you import ArrayList, Ctrl+Shift+O).


Doing this creates an ArrayList (of Projectiles) called projectiles.

2. Now, below the jump() method, I will add the shoot() method:

  public void shoot() {
Projectile p = new Projectile(centerX + 50, centerY - 25);
projectiles.add(p);
}

This method simply creates a new Projectile, labels it p, and adds it to the projectiles ArrayList. We create this 50 pixels to the right and 25 pixels above the center of the robot, which is where the gun is.

3. Create a Getter method as follows:

  public ArrayList getProjectiles() {
return projectiles;
}

This will allow us to reference this newly created ArrayList from the other classes.

Your finished Robot class will look like this:

FIGURE 2-30: Robot Class (Changes in Bold)

package kiloboltgame;

import java.util.ArrayList;

public class Robot {

// Constants are Here
final int JUMPSPEED = -15;
final int MOVESPEED = 5;
final int GROUND = 382;

private int centerX = 100;
private int centerY = GROUND;
private boolean jumped = false;
private boolean movingLeft = false;
private boolean movingRight = false;
private boolean ducked = false;

private int speedX = 0;
private int speedY = 1;

private Background bg1 = StartingClass.getBg1();
private Background bg2 = StartingClass.getBg2();

private ArrayList<Projectile> projectiles = new ArrayList<Projectile>();

public void update() {

// Moves Character or Scrolls Background accordingly.

if (speedX < 0) {
centerX += speedX;
}
if (speedX == 0 || speedX < 0) {
bg1.setSpeedX(0);
bg2.setSpeedX(0);

}
if (centerX <= 200 && speedX > 0) {
centerX += speedX;
}
if (speedX > 0 && centerX > 200){
bg1.setSpeedX(-MOVESPEED);
bg2.setSpeedX(-MOVESPEED);
}

// Updates Y Position
centerY += speedY;
if (centerY + speedY >= GROUND) {
centerY = GROUND;
}

// Handles Jumping
if (jumped == true) {
speedY += 1;

if (centerY + speedY >= GROUND) {
centerY = GROUND;
speedY = 0;
jumped = false;
}
}
// Prevents going beyond X coordinate of 0
if (centerX + speedX <= 60) {
centerX = 61;
}
}
public void moveRight() {
if (ducked == false) {
speedX = MOVESPEED;
}
}

public void moveLeft() {
if (ducked == false) {
speedX = -MOVESPEED;
}
}

public void stopRight() {
setMovingRight(false);
stop();
}

public void stopLeft() {
setMovingLeft(false);
stop();
}

private void stop() {
if (isMovingRight() == false && isMovingLeft() == false) {
speedX = 0;
}


if (isMovingRight() == false && isMovingLeft() == true) {
moveLeft();
}


if (isMovingRight() == true && isMovingLeft() == false) {
moveRight();
}

}

public void jump() {
if (jumped == false) {
speedY = JUMPSPEED;
jumped = true;
}

}

public void shoot() {
Projectile p = new Projectile(centerX + 50, centerY - 25);
projectiles.add(p);
}



public int getCenterX() {
return centerX;
}

public int getCenterY() {
return centerY;
}


public boolean isJumped() {
return jumped;
}


public int getSpeedX() {
return speedX;
}


public int getSpeedY() {
return speedY;
}


public void setCenterX(int centerX) {
this.centerX = centerX;
}


public void setCenterY(int centerY) {
this.centerY = centerY;
}


public void setJumped(boolean jumped) {
this.jumped = jumped;
}


public void setSpeedX(int speedX) {
this.speedX = speedX;
}


public void setSpeedY(int speedY) {
this.speedY = speedY;
}


public boolean isDucked() {
return ducked;
}


public void setDucked(boolean ducked) {
this.ducked = ducked;
}


public boolean isMovingRight() {
return movingRight;
}


public void setMovingRight(boolean movingRight) {
this.movingRight = movingRight;
}


public boolean isMovingLeft() {
return movingLeft;
}


public void setMovingLeft(boolean movingLeft) {
this.movingLeft = movingLeft;
}


public ArrayList getProjectiles() {
return projectiles;
}


}

Lesson #2-22: Painting the Bullets in the StartingClass

I. Changing the Run() Method

Make the changes in bold to your run() method:

       @Override
public void run() {
while (true) {
robot.update();
if (robot.isJumped()) {
currentSprite = characterJumped;
} else if (robot.isJumped() == false && robot.isDucked() == false) {
currentSprite = character;
}

ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
if (p.isVisible() == true) {
p.update();
} else {
projectiles.remove(i);
}
}

hb.update();
hb2.update();
bg1.update();
bg2.update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(Make sure you import ArrayList: Ctrl+Shift+O)

Let's talk about what we did here:
We created a new ArrayList called projectiles and gave it the value of the projectiles ArrayList in robot.

We then created a for loop, which runs as long as the index i is lesser than the size of the projectiles ArrayList (which is the number of Projectile objects stored in it).

Then we check which Projectile object is in the i-th (4th, 5th, etc). place in the ArrayList (the Projectile object with an index of i).

To illustrate indexes, here's another example:
List = [1, 2, 3, 5, 7]
The indexes of each of these are: 0, 1, 2, 3, and 4. This means that the for loop will go through each object in the ArrayList of Projectiles and set it equal to p


After that, it checks if this p is on the screen (isVisible()). If true, it updates it. Else, it removes this p by removing the i-th index from the projectiles ArrayList.

To summarize all this, we create a for loop with an index called i which goes up by 1 each time. We set the i-th Projectile in the projectiles ArrayList, set it equal to p, and update it (if on screen) or remove it (if not on screen).

II. Changing the Paint() Method

Make the changes in bold in the paint() method:

       @Override
public void paint(Graphics g) {
g.drawImage(background, bg1.getBgX(), bg1.getBgY(), this);
g.drawImage(background, bg2.getBgX(), bg2.getBgY(), this);

ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
g.setColor(Color.YELLOW);
g.fillRect(p.getX(), p.getY(), 10, 5);
}

g.drawImage(currentSprite, robot.getCenterX() - 61,
robot.getCenterY() - 63, this);
g.drawImage(heliboy, hb.getCenterX() - 48, hb.getCenterY() - 48, this);
g.drawImage(heliboy, hb2.getCenterX() - 48, hb2.getCenterY() - 48, this);
}

The same concepts apply here.

We created an ArrayList called projectiles (the one from the update() method is only usable by the update() method, so this is a unique ArrayList) and give it the value of the projectiles ArrayList in the Robot class. 

We used a for loop and painted each Projectile object called p, which represents the i-th Projectile in the ArrayList at the current iteration of the for loop, and we draw a yellow rectangle with width 10 and height 5 at the X and Y coordinate of the p Projectile.
Lesson #2-23: Shooting on Keypress
We want to use the Ctrl button to shoot our bullets.
Navigate to the keyPressed() method in StartingClass, and make the following changes in bold:

  @Override
public void keyPressed(KeyEvent e) {

switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Move up");
break;

case KeyEvent.VK_DOWN:
currentSprite = characterDown;
if (robot.isJumped() == false) {
robot.setDucked(true);
robot.setSpeedX(0);
}
break;

case KeyEvent.VK_LEFT:
robot.moveLeft();
robot.setMovingLeft(true);
break;

case KeyEvent.VK_RIGHT:
robot.moveRight();
robot.setMovingRight(true);
break;

case KeyEvent.VK_SPACE:
robot.jump();
break;


case KeyEvent.VK_CONTROL:
if (robot.isDucked() == false && robot.isJumped() == false) {
robot.shoot();
}
break;

}

}

All we did was add another case to the switch, so that when CONTROL is pressed, the robot calls its shoot() method. We also check if the robot is ducking or jumping, and prevent shooting if it is doing either.

We can now run the game, and you should be able to shoot with the Control button!
The final StartingClass follows (changes in bold):

Figure 2-31: StartingClass, end of Day 7

package kiloboltgame;

import java.applet.Applet;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;
import java.util.ArrayList;

public class StartingClass extends Applet implements Runnable, KeyListener {

private Robot robot;
private Heliboy hb, hb2;
private Image image, currentSprite, character, characterDown,
characterJumped, background, heliboy;
private Graphics second;
private URL base;
private static Background bg1, bg2;

@Override
public void init() {

setSize(800, 480);
setBackground(Color.BLACK);
setFocusable(true);
addKeyListener(this);
Frame frame = (Frame) this.getParent().getParent();
frame.setTitle("Q-Bot Alpha");
try {
base = getDocumentBase();
} catch (Exception e) {
// TODO: handle exception
}

// Image Setups
character = getImage(base, "data/character.png");
characterDown = getImage(base, "data/down.png");
characterJumped = getImage(base, "data/jumped.png");
currentSprite = character;
heliboy = getImage(base, "data/heliboy.png");
background = getImage(base, "data/background.png");
}

@Override
public void start() {
bg1 = new Background(0, 0);
bg2 = new Background(2160, 0);
hb = new Heliboy(340, 360);
hb2 = new Heliboy(700, 360);
robot = new Robot();

Thread thread = new Thread(this);
thread.start();
}

@Override
public void stop() {
// TODO Auto-generated method stub
}

@Override
public void destroy() {
// TODO Auto-generated method stub
}

@Override
public void run() {
while (true) {
robot.update();
if (robot.isJumped()) {
currentSprite = characterJumped;
} else if (robot.isJumped() == false && robot.isDucked() == false) {
currentSprite = character;
}


ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
if (p.isVisible() == true) {
p.update();
} else {
projectiles.remove(i);
}
}

hb.update();
hb2.update();
bg1.update();
bg2.update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

@Override
public void update(Graphics g) {
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
second = image.getGraphics();
}

second.setColor(getBackground());
second.fillRect(0, 0, getWidth(), getHeight());
second.setColor(getForeground());
paint(second);

g.drawImage(image, 0, 0, this);

}

@Override
public void paint(Graphics g) {
g.drawImage(background, bg1.getBgX(), bg1.getBgY(), this);
g.drawImage(background, bg2.getBgX(), bg2.getBgY(), this);

ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
g.setColor(Color.YELLOW);
g.fillRect(p.getX(), p.getY(), 10, 5);
}

g.drawImage(currentSprite, robot.getCenterX() - 61,
robot.getCenterY() - 63, this);
g.drawImage(heliboy, hb.getCenterX() - 48, hb.getCenterY() - 48, this);
g.drawImage(heliboy, hb2.getCenterX() - 48, hb2.getCenterY() - 48, this);
}

@Override
public void keyPressed(KeyEvent e) {

switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Move up");
break;

case KeyEvent.VK_DOWN:
currentSprite = characterDown;
if (robot.isJumped() == false) {
robot.setDucked(true);
robot.setSpeedX(0);
}
break;

case KeyEvent.VK_LEFT:
robot.moveLeft();
robot.setMovingLeft(true);
break;

case KeyEvent.VK_RIGHT:
robot.moveRight();
robot.setMovingRight(true);
break;

case KeyEvent.VK_SPACE:
robot.jump();
break;

case KeyEvent.VK_CONTROL:
if (robot.isDucked() == false && robot.isJumped() == false) {
robot.shoot();
}
break;

}

}

@Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
System.out.println("Stop moving up");
break;

case KeyEvent.VK_DOWN:
currentSprite = character;
robot.setDucked(false);
break;

case KeyEvent.VK_LEFT:
robot.stopLeft();
break;

case KeyEvent.VK_RIGHT:
robot.stopRight();
break;

case KeyEvent.VK_SPACE:
break;

}

}

@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub

}

public static Background getBg1() {
return bg1;
}

public static Background getBg2() {
return bg2;
}

}
Thank you for reading this lesson! Things are starting to get a bit repetitive, so we will be mixing things up next time around.

As always, we appreciate your support, and we're extremely pleased that we broke 750 Facebook Likes!


Picture
kiloboltday7.zip
File Size: 714 kb
File Type: zip
Download File

Picture
Go to Day 6: Adding Enemies
Go to Day 8: Animations
80 Comments
nightmare6m
10/27/2012 10:41:06 am

Great tutorial as always. Thank you. I have a question of how to prevent the bullets from firing in a string if I hold the control key down? Would I put the fire event on key release rather than on key down? Or is there a way to fire on key down but only once per press?

Reply
James C
10/27/2012 10:49:05 am

I was going to cover this in a later lesson, but some ways to do that include checking the distance between the player and the previous bullet or shooting on release. We will do something complex later on. Don't worry too much about it for now.

Reply
L3xx
10/30/2012 05:33:46 am

As far as i tested this tut, u cant just hold the controlkey pressed and rapidfire. u got to click for every single bullet.
But i guess there is realy a need in the timings, a faster clicking player would allways be shooting more bullets than a slower clicking player. max Ammo, shooting distance, hopefully such things come in the next tuts :)

Reply
PJflo
10/31/2012 08:42:03 pm

I think that would be because the robot is (quite clearly) holding a pistol.
If they bring 'power ups' and enhancements into the game such as upgraded weapons then we may see an automatic_rifle object appear :)

Roshan Karki link
10/30/2012 01:51:59 am

Thank you.

Reply
Ben
10/31/2012 05:06:11 am

Thanks again James. Looking forward to the next day!

Reply
Gligor K
11/1/2012 11:29:10 am

Hi James,

Great tutorial so far. I am an android dev, but I've never thought of doing a game until now so this has been very helpful!

I have one question though, yesterday my game was running just fine and it was all good. Today I tried running again and the applet starts, but the screen is all BLACK! I can still see the console output when pressing the buttons and stuff, it's just that I can't see anything painted on the display. Any ideas what it might be?

Thanks heaps!!!

Reply
Devin C
11/2/2012 01:23:09 am

Usually this has to do with the character sprite not being located. Make sure it's in the right location.

Reply
Gligor
11/2/2012 08:08:55 am

Wouldn't that throw an exception though?

James C
11/4/2012 03:16:16 am

Actually, no. It will not throw an exception. It's not an error with the code itself.

Reply
Gligor
11/4/2012 06:35:34 am

Fixed it. The sprites were not included in the build path. Dumb me!

Thanks for the replies guys!!!

Shin link
11/1/2012 06:27:35 pm

Thank you for this tutorials, i got it all and its working, nice and clear.
Looking forward for the next lesson, and I would like to donate if the unit 4 tutorials is done... Your reward is waiting Sir James. Just hang on. its not much but a hundred bucks. You are cool man!

Reply
Devin C
11/2/2012 01:23:57 am

Exciting stuff, loving the tutorials so far! Any idea when step 8 will be published? I was sad when Tuesday came and went without an update :(

Reply
Eric
11/4/2012 04:27:27 pm

Hi James, I'm very impressed with your teaching skills! Just got through both sets of tutorials, and as a beginner android developer, I have found it useful. Thank you, and I will absolutely be donating.

Reply
Matthew
11/14/2012 09:18:06 pm

How could I add another weapon? For example, Say I also want to have missles.

Reply
Reece
11/19/2012 04:22:29 pm

Another great tutorial!

Thank you very much!

Reply
Paul
12/12/2012 07:03:53 am

Hi James,

as i´m currently waiting on the next part of your tutorial i´m experimenting with some of the stuff.

I tried to make my character shoot the position where i´d click with the mouse. How would i calculate the desired numbers for the speed of my projectile to let it fly diagonal correctly?
Currently i am doing this:(pseudo code)
x=targetX-startX
y=targetY-startY
factor=y/x //at this point both of the variables have been set positive
speedX=1 //if x has been negative this would be set negative
speedY=speedX*factor //if y has been negative this would be set negative

The problem with this is, of course the speed is varying depending on the angle the projectile is shot. Also its not very accurate.

If you could give me a solution or a hint on this i´d be happy :)

Thanks in advance

Paul

Reply
James C.
12/12/2012 07:41:45 am

Make sure you use floating points rather than integers for speed values.

Calculate the horizontal and vertical distance between the robot's arm and the target.

Use inverse tangent to calculate the angle of elevation, and then use speed cos theta, speed sin theta to calculate x and y velocities.

Reply
paul
12/12/2012 10:49:17 pm

Thank you i´ll check this out... I thought that this wouldnt happen to me but here is the moment i wish i had paid more attention to math in school :P Maybe atleast i could remember simple stuff like this...

regards

paul
12/13/2012 06:35:55 am

Hi James,

i found that your suggestion also does not seem to lead to 100% accurate results especially when one axis is zero :P
Here is a method i found that uses vectors and the theorem of Pythagoras. Accuracy = 100%


/*
* projectiles position on the vector
*/
double xnew= 0;
double ynew = 0;

/*
* factor for the vector
*/
double i = 0;

// spawn position
double OA[] = { 20, 25 };
// target position
double OB[] = { 15, 5 };

// vector from a to b
double vab[] = { OB[0] - OA[0], OB[1] - OA[1] };
// theorem of Pythagoras (square root(a² + b²) in this case a=x, b=y
double btr = Math.sqrt(Math.pow(vab[0], 2) + Math.pow(vab[1], 2));

double evab[] = { vab[0] / btr, vab[1] / btr };

/*
* while not colliding and i<btr calculate and set the current position
*/
while (!checkCollisions(OB[0], OB[1]) && (i <= btr))
{
xnew = OA[0] + evab[0] * i;
ynew = OA[1] + evab[1] * i;
i++;
}

This is a "standalone" version.
For the folks that want to implement this in their example, the calculation of the new points should not be done like here.
I calculate the vector at initialization of the projectile (so only once) and calculate the new position in my update() method.

Here´s it:
public void update() {
curPointX = x+evab[0]*i; //i is set =0 at initialization
curPointY = y+evab[1]*i;
i++;

x = curPointX;
y = curPointY;
}

regards Paul

pylon
12/24/2012 04:48:41 pm

Nice tutorial. It looks like there's a problem with the projectile updating loop in the run() method. While iterating through the projectile list, when we remove a non-visible projectile, the result would be that subsequent projectiles in the list would be shifted up by one. The following iteration would skip next projectile. An easy fix would be to use:

for (int i = projectiles.size() - 1; i >= 0; i--)


Thanks.

Reply
KaY
6/18/2013 07:35:19 am

Wouldn't it be easier to just place
i -= 1;
after
projectiles.remove(i);
to compensate for the shifting of the indices?
I'm not saying your way is wrong, but I think this is better.

Reply
Joel
11/27/2013 02:36:06 am

Actually, it is considered "dangerous" to modify the contents of an ArrayList while you're looping through it. You can iterate through it (and modify it) much safer with an iterator. The code to set up the basic loop is like this (writing this from memory in a coffee shop, so forgive any minor mistakes):

Iterator<Projectile> i = robot.getProjectiles().iterator();
while (i.hasNext()) {
Projectile p = i.next();
if (p.isVisible) {
p.update();
} else {
i.remove();
}

Reply
Rob
3/23/2014 05:52:59 pm

I hate Iterator's, Enumerators, etc. pylon has it right. Reversing through the array is a typical safe way to go about removing items from an array.

Ziff
12/26/2012 05:04:04 pm

Great job James!

The second line of this section of code really threw me:
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
// create a yellow square to be used as a bullet
g.setColor(Color.YELLOW);
g.fill3DRect(p.getX(), p.getY(), 50, 50, true);
}
But after some time I figured it out.

Reply
Jenton
1/16/2013 06:55:50 am

for that second line, how come you need 'Projectile' in parentheses (to the right of the equals sign?

Thanks!

Reply
James C.
1/20/2013 08:43:27 am

That is an example of casting.
You can change the type of objects by casting.

For example, given:

int a;

We can say

double b = (double) b;

Cyan
1/31/2013 09:01:21 pm

uhmm Mr. James i have a question(off-topic question)
i'm confused about the data/"filename".png .. where can i find data folder?
im sorry of this stupid question

Reply
David
2/18/2013 11:42:45 am

It's not really a dumb question. The data folder he's referring to is one you have to make. It's easily done by right clicking on src folder in your project, find new, go down to folder (it should be near the middle), and name it data.

Reply
S
3/2/2013 05:39:02 am

I'm sorry if this is dumb, but I got lost here.
Where does projectiles.size() come from? Where did projectils.add() come from? I don't know how these were pulled from thin air, or what they do, how they are interacting, or how I would know when using them again is ever appropriate.. could somebody please break this down for me?

Reply
S
3/2/2013 05:41:06 am

Nevermind, I read it over a few more times, I think I get it well enough to at least continue and maybe it'll click later.

Reply
Trey
3/16/2013 08:57:51 am

What's up with the warning that ArrayList is of raw type when you call something like ArrayList projectiles = robot.getProjectiles()? I think that java wants it as ArrayList<Object> projectiles or something like that but even more warnings pop up. How would you clean this up?

Reply
Kevin
3/22/2013 04:41:49 am

Hello, just a tiny suggestion to make one part a bit simpler and to teach people good programming style. For the shooting, you have it test if: if (robot.isDucked() == false && robot.isJumped() == false)

It would be better to check: if(!robot.isDucked() &&!robot.isJumped())
because not true is equal to false.

Reply
Liviu
3/27/2013 10:18:58 pm

Hi! First of all, thanks for the great tutorial!
I noticed that the projectiles.remove(i) from the run() method of StartingClass will make the FOR "jump" over the next member of the list because all the other elements will be shifted to the left by one position as a consequence of the remove(i).
Wouldn't it be safer to add a i = i -1 after the remove method?

Reply
Natanael Souza
4/11/2013 07:34:17 am

Great!

Reply
Sorin
5/22/2013 05:45:47 pm

Great tutorials, god job for all of them. Also, I have a question, how can I make the enemy shoot at the player?

Reply
James
5/26/2013 02:36:18 pm

Sorin,

Calculate the difference in x coordinates and y coordinates between the given enemy and the player, and create a bullet with an x and y velocity of the same ratio.

Reply
allister quinn
6/15/2013 01:29:30 am

Hi James, really enjoying your tutorials so big thanks for your creation.

However, there is something I just can't get my head around and hope you can explain.

In the StartingClass, both the run() and paint() methods interact with the robot.getProjectiles()

run()
ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
if (p.isVisible() == true) {
p.update();
} else {
projectiles.remove(i);
}
}

paint()
ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
g.setColor(Color.YELLOW);
g.fillRect(p.getX(), p.getY(), 10, 5);
}

What I don't understand is, two new seperate ArrayList projectiles are created in each method. They don't appear to modify the original robot.projectiles class, they appear to only modify themselves, and they don't interact with each other. Yet, if a projectile is removed in the run() method ArrayList projectiles, the paint() method does not paint it, so they must be communicating or changing robot.projectiles somehow.

What I`m saying is, if A = C and B = C (represented here by the two projectiles = robot.getProjectiles() in run and paint), and I modify A or B, it doesn't change the value of C. Yet here, it appears as though it does.

I understand this may seem very confusing, obviously somewhere my understanding is flawed, but I really hope you can help explain.

Reply
James
6/15/2013 01:14:28 pm

This is a very good question.

With primitives such as ints, when we say:

int a = 5;
int b = a;

We get two different primitives that are stored in two different places in memory. When we modify a, b is not changed (and vice versa).

With memory-intensive Objects such as ArrayLists, we simply create new pointers to the SAME Object. This means that whenever we modify a "copy" of the Object, the original is also modified in the same way.

In our case, both the run and paint method are modifying the same object. robot.getProjectiles() retrieves the projectiles ArrayList to be modified, rather than making a full copy of it.

Hope that answers your question!

Reply
allister quinn
6/17/2013 12:42:11 am

Thanks James, I understand it now.

volt107
6/29/2013 08:03:53 am

Hi, I am getting an error with this part:

public void shoot() {
Projectile p = new Projectile(centerX + 50, centerY - 25);
projectiles.add(p);
}

It says "The constructor Projectile(int, int) is undefined".

Please help!

Reply
volt107
6/29/2013 08:09:26 am

Nevermind i figured it out

Reply
Imtiaz Ahmed
7/9/2013 04:02:57 am

Hi,

great lessons, I'm learning alot and brushing up on java.

I have a question, I may have missed something small.

The line public void shoot() {
Projectile p = new Projectile(centerX + 50, centerY - 25);
projectiles.add(p);
}

basically adds a projectile to the array everytime you press CTRL. My interpretation of this is the size of the array would simply grow larger and larger everytime a projectile is shot. I missed any parts in the code that discard part of the array for a bullet that has gone off screen. I know you set visible to false, but that is just a flag within the constructor so I don't see how that affects it.

Much to my surprise, I made an output to the console for the size of the array when the bullet was shot and it would discard the projectile of the screen and decrease the size by 1.

Now this is great! I was concerned that in a really long level you could potentially have this array get bigger and bigger and it may lead to problems, so what I really want to know is how does the code know to decrease the size of the array once the bullet has gone off screen, can you point this out in the code incase I missed something or is java's garbage collector simply really smart?

thanks,
Imtiaz

Reply
Imtiaz
7/9/2013 04:22:48 am

nevermind i found it

Reply
swapnil
7/21/2013 09:29:35 pm

i want enemy to fire bullet what changes i do please tell me

Tiburssio
7/31/2013 03:58:12 am

Why when I hold the CONTROL key the robot does not fire all the time, I changed the button to shoot with the arrow up key and so with this work, he was shooting while the key was pressed, but with the CONTROL it reads command only once.

Reply
Sandy
9/2/2013 05:06:40 am

Really a gud job Jame...
It would have been much help full if u hd gone detail on the purpose of arrylist here... expecting it via cmnd...

Reply
Masha
9/28/2013 03:03:44 am

hey , i have been following this tutorial , im understanding it 90%. and i don't think i can make such a game by myself.what do you advise me to do?

Reply
Kristijan
9/28/2013 02:07:18 pm

Hi, I've been following your tutorials and I've understood pretty much of it.
But, I can't get this. When I hold CONTROL, the character shoots rapidly. And when i do it while moving, and suddenly stop moving, it stops the shooting. In the stop methods, only speedX is affected and I don't get it how does it affect the shooting.

I'm really confused right now.

Reply
Mohamed
10/25/2013 01:38:37 am

Really Wonderfull Tutorial.

As a newbie in game developpemnt , It is really helpfull for me.

Thanks James !!!

Reply
Miki
11/10/2013 06:58:17 pm

Hello!
I'm creating a game based on this tutorial.

This is my question; what is needed if I want a image for this projectile? I mean that in this tutorial you use a yellow rectangle to paint it on the screen. And I want my image to replace that rectangle.

I'v been trying for some time without any luck. I'v added a image variable and added line for the image setups section.

Reply
Miki
11/11/2013 03:18:42 am

Never mind. I found the problem :)


I noticed that if I paint a image by my self I have to save the image somewhere in the hard drive, not in the data folder already. Eclipse doesn't recognize image from the data folder by itself. I use drag and drop to import image inside eclipse.

Reply
never mind link
4/21/2015 03:19:36 am

never mind

Miki
11/11/2013 03:18:58 am

Never mind. I found the problem :)


I noticed that if I paint a image by my self I have to save the image somewhere in the hard drive, not in the data folder already. Eclipse doesn't recognize image from the data folder by itself. I use drag and drop to import image inside eclipse.

Reply
Ethan
11/13/2013 04:57:25 am

There is a syntax bug in the posted code on this page (at least as far as Eclipse 4.3.1 is concerned).

Everywhere this line is:
ArrayList projectiles = robot.getProjectiles();

should be:
ArrayList<Projectile> projectiles = robot.getProjectiles();

Otherwise Eclipse says that there is an error (ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized.).


Reply
Ethan
11/21/2013 06:15:37 am

Just had a chance to go onto the lesson after this. It is also using an Arraylist which Eclipse is throwing the same type of warning/error (will not run) unless the Arraylist is parameterized. Basically, an Arraylist needs to be parameterized with whatever the name of the class it is in is.

Reply
Adriano
12/19/2013 07:41:39 pm

Hello James.
Great tutorial.
Just one question to you.
This line of code
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
if (p.isVisible() == true) {
//call update to update the bullet on the screen
p.update();
} else {
//
projectiles.remove(i);
}
}
You are looping through the projectiles but there is only one at the time in the ArrayList.
Are you planning to add more on later tutorials.
Thanks Adriano

Reply
Mohamed Nasr
2/4/2014 09:07:09 pm

Thanks A lot man. I need you help to understand something:

1- Lets say we will click CTRL key once:

Now the Keypressed switch case will invoke robot.shoot(); which will make a new projectile and add it to ArrayList projectiles.
right now we have only one projectile so the ArrayList size is 1

2- Then the Run thread will get this ArrayListand check the it's size at the for loop for(int i=0 ; i<1 ; i++) and this will invoke
p.update(); which ultimately will make X of the projectile = X+7 and by that the first iteration is done.

3- now for the 2nd iteration for(int i=1; i<1 ; 1++) which will lead that loop to break and it won't call p.update(); again which means X position of the projectile won't change....
so how come i can see the projectile keeps painting all across the screen at the X direction?

i know something wrong with my logic and i hope you can point it for me .

Thanks A lot

Reply
Sheo
2/11/2014 02:56:41 am

Hello, thanks a lot for this amazing tutorial :). i've a question,

Is that possible to change this :


ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
g.setColor(Color.YELLOW);
g.fillRect(p.getX(), p.getY(), 10, 5);
}

to fire a bullet.png for exemple ?

Regards,
Maxime

Reply
James Kotel
2/15/2014 03:50:35 am

Hey James I love these tutorials and will certainly be donating. This site taught me more about java than my university class did. Anywho I wanted to say that I cannot figure out why the bullets are not firing. they appear and move with the robot when I scroll the background but they do not shoot out and away from him. I have even copied and pasted your code line for line and added in the ArrayList<Projectiles> piece to compensate for the error I was receiving in the newest version of eclipse. Please any insight would be very helpful

Reply
James
2/15/2014 03:54:22 am

I lied thank you. I set the speedX in the projectile class to 0 in the constructor out of habit. Fixed!

Reply
Branden
3/2/2014 03:45:58 pm

Hi there I did the tutorial "creating an Android Game" at Kilibolt.com and I completed the whole game... and changed some stuff around. Unfortunately in the tutorial they only showed how to make the main character shoot.

I have three robots that are painted, created, and are contained in an array list. I want to make them shoot randomly every few seconds or so. I tried following all of the same techniques and procedures that were shown making the MAIN CHARACTER shoot.

1) creating an arraylist of projectiles class in the MAIN CHARACTER CLASS (however for my enemies... I did it in their class) 2) Made Getters and Setters 3) Painted the array JUST as they had with the MAIN CHARACTER in my "main-startingclass" 4) and either removed or updated items in array

None of this worked for some reason. I even tried setting COMMA as a key press... then running shoot() in my enemy class... as they had with the MAIN CHARACTER. That didnt help.

I keep getting "Null Pointer Exception".... I dont know what this means or how to fix it nor am I very experienced with Java, Android, or Eclipse. Please help if you have anything that might help my situation it would be greatly appreciated.

SOME OF THE ERRORS`enter code here`:
"Exception in thread "Thread-3" java.lang.NullPointerException
at kiloboltgame.StartingClass.run(StartingC...
at java.lang.Thread.run(Unknown Source)
Exception in thread "AWT-EventQueue-1" java.lang.NullPointerException
at kiloboltgame.StartingClass.paint(Startin...
at sun.awt.RepaintArea.paintComponent(Unkno... Source)
at sun.awt.RepaintArea.paint(Unknown Source)
at sun.awt.windows.WComponentPeer.handleEve... Source)
at java.awt.Component.dispatchEventImpl(Unk... Source)
at java.awt.Container.dispatchEventImpl(Unk... Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Un... Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)"



http://pastebin.com/iaiSCqtQ

Reply
mudit
3/22/2014 08:05:24 pm

hey james. i am loving your tutorials here :)
but i am facing a problem... at 2 places i am getting a red underlined error... one in run method where we defined arraylist projectiles..
the code "p.update();" update is getting underlined and error saying that "The method update() from the type Projectile is not visible"
and kind of same error at keyPressedEvents. under case keyEvent.VK_control. under code "robot.shoot();" shoot is underlined with the same error "The method shoot() from the type Robot is not visible".
any kind of help will be appreciated.

Reply
JayT
4/26/2014 03:20:34 pm

All I'm seeing is the bullets...I've replaced the code I typed with the code in the zip file and I still get only the bullets. The .png files are all loaded and accurate.

Reply
JayT
4/26/2014 03:50:43 pm

I had to right-click all my .png files and refresh them. Also I made a new folder. I right clicked src and made a general folder called BotData. I then changed the code at the appropriate places and ta-da everything worked. I must have created my data folder wrong. Hope this helps. Preciate everything James!!!

Reply
FartBombs
6/20/2014 12:56:21 pm

Hey guys, so I decided to go on a limb and add my own customization such as being able to shoot constantly while jumping and ducking without interrupting the bullet flow. I got that fixed but now I was wondering how would you limit the amount of bullets coming out? You know like maybe 1 every so amount of x millisecond instead of a big burst when you pressed down control (keep in mind i have mine set to allow constant bullet flow when i hold down control). Any help be appreciated and yes this is offtopic but I feel I may need this later on when creating my own game :).

Reply
FartBombs
6/20/2014 12:58:50 pm

Tried using Thread.sleep() but I don't want the game to slow down while I'm waiting. Feels like i need to do multithreading but I'm not sure where to start.

Reply
Tom A.
8/24/2014 07:26:14 am

'Bomb,

Wouldn't you put in some sort of timer object (probably in Run() ) and access it from the robot.shoot(). The robot would keep a variable of the time of the last bullet, check the current time variable, and decide if it was allowed to shoot again.

Similarly, if you wanted to limit the number of bullets out at a time, check how big the projectiles array is, and only allow a new bullet if it is less than the maximum number.

DeadZero
6/26/2014 05:39:09 am

Hey Enjoying the Tutorials :), I'm very new to java, can you help explain one line, I understand how the code works I just don't understand the syntax?

Projectile p = (Projectile) projectiles.get(i);


for Projectile p is this creating a new Projectile and calling it p , why is it not Projectile p = new Projectile, or am I am way off?

also

(Projectile) projectiles.get(i);

projectiles.get(i); get the current count? in the array list?
and the first part (Projectiles), I have no idea, sorry :/.

Thanks for any help.

Reply
Tom A
8/24/2014 01:20:27 pm

Java is a strongly typed language; however with inheritance, you can get around some of that typing. It used to be that ArrayList x was an array list of Objects (and since all classes have Object as their ultimate ancestor you could do this. Implementation wise, it would just store the pointer to the object in the array list, but the goal of a high level language is to protect you from such low level details.) But if you did put your specific type of object into an array list, you had to tell it what king of object you were pulling out, thus the "cast", (Projectile) that is set before the array list retrieval of the i-th entry in the array list.

Projectile p = (Projectile) projectiles.get(i);
^ cast ^ array ^retrieval method

Now-a-days (I think with Java 6 or so) you don't define objects as ArrayLists anymore, you define them as
ArrayList<e> where c is a class name for the type of object that will go into it. So in the game
ArrayList<Projectile>
This should eliminate the need for casting the retrieval from the array list, so
Projectile p = projectiles.get(i);
should work (since the compiler will only allow the code to put Projectile objects into the array-list, so that's all that can come out).

Hope this helps.

Reply
Ryan link
12/14/2014 12:53:59 pm

Just a quick question, I'm building this in netbeans and I don't know how to run an applet directly from the IDE. Do I need to create an HTML file first?

Thanks

Reply
SmartAss Zombie
5/2/2015 06:17:55 pm

Hello, very nice tutorial i am really thankful.
Today while i was progressing deeply into your tutorial i asked my self why dont i try to replace the robot with a stick man made of my own, so i went out and opened paint and drew a stickman (i adjusted the pxs as 122*126) but yet when i entered stickman to the game, the white color (background of paint that is also found in your robot picture) appeared in game and it was like a white box who had a stickman in it jumping around, how does the robot's white background didnt appear, how can i manage to do that? pls help

Reply
TheGunner
10/4/2016 03:07:12 am

you need the background to be transperent

Reply
ProgrammerE
5/19/2015 12:34:02 am

Hi James,
Are you still monitoring the comments here? I'm wondering why the robot can't shoot and walk at the same time. Which lines are responsible for that?

Kind regards,
ProgrammerE

Reply
JJ
9/6/2015 06:17:12 pm

This might a dumb question, but why exactly do we need to store our bullets into an array? Can't we just make a function that creates a bullet then deletes them? Or is it that this way just recycles bullet objects?

Reply
Justine
11/3/2015 11:19:10 am

Hey James, this was a great tutorial.
I'm making my own game based on this tutorial but it isn't a shooter, it's a platform game more like Mario, so I was wondering if I could bypass this entire section without errors later on.

Reply
Cem
1/18/2016 05:53:38 am

Hey James, thanks for tutorial. I have a little question.

If we want to use left and right control buttons for different purposes. How do we do that?

Reply
Rishabh Gupta
6/28/2016 10:54:33 pm

I found this : http://stackoverflow.com/questions/991765/how-to-tell-which-shift-key-was-pressed

Reply
TheGunner
10/4/2016 03:11:05 am

if i hold control it creates a line of bullets, is there a way to prevent that?
great tutorial by the way

Reply
Eemil
10/14/2016 08:18:04 am

Hi James. I have this problem. The picture freezes when i run the game and only refreshes to a point where the robot ducks and nothing else changes when I press VK_DOWN and simultaneously make the window either big or small. Any advices how to fix this?

Reply



Leave a Reply.

    Author

    James Cho is the lead developer at Kilobolt Studios. He is a college student at Duke University and loves soccer, music, and sharing knowledge. 


© 2014 Kilobolt, LLC. All rights reserved.