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.
/* @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; ArrayListexplosions = 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; } }