• 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)>
      • 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
  • Forum
  • About Us
    • Contact Us
  • Our Games
    • TUMBL: FallDown
  • Donate
  • Facebook
  • Twitter

GAME DEVELOPMENT TUTORIAL: DAY 2-7: Shooting Bullets

10/27/2012

62 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
 


Comments

nightmare6m
10/27/2012 5:41pm

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 5:49pm

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 12:33pm

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
11/01/2012 3:42am

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 8:51am

Thank you.

Reply
Ben
10/31/2012 12:06pm

Thanks again James. Looking forward to the next day!

Reply
Gligor K
11/01/2012 6:29pm

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/02/2012 8:23am

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

Reply
Gligor
11/02/2012 3:08pm

Wouldn't that throw an exception though?

James C
11/04/2012 11:16am

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

Reply
Gligor
11/04/2012 2:35pm

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

Thanks for the replies guys!!!

Shin link
11/02/2012 1:27am

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/02/2012 8:23am

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/05/2012 12:27am

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/15/2012 5:18am

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

Reply
Reece
11/20/2012 12:22am

Another great tutorial!

Thank you very much!

Reply
Paul
12/12/2012 3:03pm

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 3:41pm

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/13/2012 6:49am

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 2:35pm

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/25/2012 12:48am

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
06/18/2013 2:35pm

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 10:36am

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
03/24/2014 12:52am

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/27/2012 1:04am

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
01/16/2013 2:55pm

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

Thanks!

Reply
James C.
01/20/2013 4:43pm

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
02/01/2013 5:01am

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
02/18/2013 7:42pm

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
03/02/2013 1:39pm

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
03/02/2013 1:41pm

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
03/16/2013 3:57pm

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
03/22/2013 11:41am

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
03/28/2013 5:18am

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
04/11/2013 2:34pm

Great!

Reply
Sorin
05/23/2013 12:45am

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
05/26/2013 9:36pm

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
06/15/2013 8:29am

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
06/15/2013 8:14pm

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
06/17/2013 7:42am

Thanks James, I understand it now.

volt107
06/29/2013 3:03pm

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
06/29/2013 3:09pm

Nevermind i figured it out

Reply
Imtiaz Ahmed
07/09/2013 11:02am

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
07/09/2013 11:22am

nevermind i found it

Reply
swapnil
07/22/2013 4:29am

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

Tiburssio
07/31/2013 10:58am

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
09/02/2013 12:06pm

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
09/28/2013 10:03am

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
09/28/2013 9:07pm

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 8:38am

Really Wonderfull Tutorial.

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

Thanks James !!!

Reply
Miki
11/11/2013 2:58am

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 11:18am

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
Miki
11/11/2013 11:18am

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 12:57pm

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 2:15pm

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/20/2013 3:41am

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
02/05/2014 5:07am

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
02/11/2014 10:56am

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
02/15/2014 11:50am

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
02/15/2014 11:54am

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

Reply
Branden
03/02/2014 11:45pm

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
03/23/2014 3:05am

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



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.