Artillery

back

Notes

Click to fire an artillery shell. Hold to fire multiple shots.

These bullets are affected by gravity, so they make a parabolic arc to their target.

Source

/* @pjs preload="bullet.png, ground.png, explosion.png"; */

PImage bullet;
PImage ground;
PImage explosion;

int bullet_x;
int bullet_y;
float bullet_rotation;

// Define constants
int SHOT_DELAY = 100;
int BULLET_SPEED = 25;
int NUMBER_OF_BULLETS = 20;
int GRAVITY = 1;

int lastBulletShotAt = 0;

Bullet[] bullets;
ArrayList explosions = new ArrayList();

// Setup the example
void setup(){
 size(640, 480); 

 //Draw images from center
 imageMode(CENTER);

 // Load images
 bullet = loadImage("bullet.png");
 ground = loadImage("ground.png");
 explosion = loadImage("explosion.png");
 
 bullet_x = 50;
 bullet_y = height - 64;
 
 // Create an object pool of bullets
 bullets = new Bullet[NUMBER_OF_BULLETS];
 for(int i = 0; i < NUMBER_OF_BULLETS; i++){
   // Create each bullet and add it to the group.
   bullets[i] = new Bullet(bullet);
 }
 
}

// The draw() method is called every frame
void draw(){
  // Set stage background color
  background(#4488cc);
  
  // Create some ground, adjust because of imageMode(CENTER)
  for(int i = 0; i < width; i += ground.width){
     image(ground, i + 16, height - ground.height/2); 
  }
  
  // Detects if mousebutton is down
  if(mousePressed){
    // Shoot a bullet
    shootBullet(); 
  }
  
  // Aim the gun at the pointer.
  bullet_rotation = atan2(mouseY-bullet_y, mouseX-bullet_x);
  
  for(Bullet b : bullets){
    b.update();
    b.display();
    
    //Check collision with ground
    if(b.alive && rectangleCollision(b.x, b.y, b.img.width, b.img.height, 0, height - ground.height/2, width, ground.height) ){
      explosions.add(new Explosion(explosion, 4, b.x, b.y));
      b.kill();
    }
  }
  
  ArrayList deadExplosions = new ArrayList();
  for(Explosion s : explosions){
    s.display();
    if(s.isDead()){
      deadExplosions.add(s);
    }
  }
  for(Explosion s : deadExplosions){
    explosions.remove(s);
  }
  
  // Create an object representing our gun
  pushMatrix();
  translate(bullet_x, bullet_y);
  rotate(bullet_rotation);
  image(bullet, 0, 0);
  popMatrix();
  
}

void shootBullet(){
  // Enforce a short delay between shots by recording
  // the time that each bullet is shot and testing if
  // the amount of time since the last shot is more than
  // the required delay.
  if(millis() - lastBulletShotAt < SHOT_DELAY) return;
  lastBulletShotAt = millis();
  
  for(Bullet b : bullets){
    // Get a dead bullet from the pool
    if(!b.alive){
      
      // Revive the bullet
      // This makes the bullet "alive"
      b.revive();
      
      // Set the bullet position to the gun position.
      b.reset(bullet_x, bullet_y);
      
      b.rotation = bullet_rotation;
      b.x_velocity = cos(b.rotation) * BULLET_SPEED;
      b.y_velocity = sin(b.rotation) * BULLET_SPEED;
      break;
    }
  }
}

// Detects a single mouseclick
void mousePressed(){
  // Shoot a bullet
  //shootBullet(); 
}

//Detects collision between two rectangular objects
boolean rectangleCollision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2){
  return !(x1 > x2 + w2 || x1 + w1 < x2 || y1 > y2 + h2 || y1 + h1 < y2);
}

class Bullet{
  int x;
  int y;
  float x_velocity;
  float y_velocity;
  boolean alive;
  PImage img;
  float rotation;
  
  Bullet(PImage img){
   this.img = img; 
  }
  
  void display(){
    if(alive){
      pushMatrix();
      translate(x,y);
      rotate(rotation);
      image(img, 0, 0);
      popMatrix();
    } 
  }
  
  void update(){
    if(alive){
     x += x_velocity;
     y += y_velocity;
     
     y_velocity += GRAVITY;
     
     rotation = atan2(y_velocity, x_velocity);
     
     // Bullets should kill themselves when they leave the world.
     if(x > width || x < 0 || y > height || y < 0){
      kill(); 
     }
    }
  }
  
  void revive(){
   alive = true; 
  }
  
  void reset(int x, int y){
     this.x = x;
     this.y = y;
  }
  
  void kill(){
    alive = false;
  }
}

class Explosion{
 PImage[] frames;
 float currentFrame;
 int x;
 int y;
 
 Explosion(PImage img, int noFrames, int x, int y){
  int frameWidth = img.width / noFrames;
  frames = new PImage[noFrames];
  for(int i = 0; i < frames.length; i++){
    frames[i] = img.get(frameWidth * i, 0, frameWidth, img.height);  
  }
  
  this.x = x;
  this.y = y;
 }
 
 void display(){
   currentFrame = (currentFrame + 0.5);
   if(currentFrame < frames.length){
     image(frames[(int)currentFrame], x, y);
   }
 }
 
 boolean isDead(){
   return currentFrame >= frames.length;
 }
}

Warning: Cannot load module "http" because required module "raphf" is not loaded in Unknown on line 0