Compare commits
No commits in common. "f673efc1ddc2daec20435039fb5bdd71101ea71a" and "1e48f4a69e446beb500dd3cb2857cc383ad23ee1" have entirely different histories.
f673efc1dd
...
1e48f4a69e
87
src/Gun.js
87
src/Gun.js
|
@ -7,88 +7,33 @@ import bulletHole from '../data/bulletHole.png';
|
|||
import shot from '../data/shot.mp3';
|
||||
import empty from '../data/empty.mp3';
|
||||
|
||||
/*
|
||||
The Gun is the mouse. To draw it, hide the cursor with the noCursor function and then draw instead the image cursor.png at the location of the mouse. To load and play sounds with p5.js take a look at this example. The sound files are shot.mp3 and empty.mp3, depending on whether there are still shots available. Finally, when you shoot with the gun, add a random CURSOR_SIZE noise (or a similarly small amount) to alter the bullet's final hitting location.
|
||||
*/
|
||||
|
||||
class Gun extends Subject {
|
||||
constructor(totShots) {
|
||||
super();
|
||||
this.cursor = null;
|
||||
this.shotSound = null;
|
||||
this.emptySound = null;
|
||||
|
||||
this.totshots = totShots;
|
||||
this.remainingShots = totShots;
|
||||
this.bullets = []; // array of Bullet objects
|
||||
}
|
||||
|
||||
class Gun {
|
||||
noCursor() { }
|
||||
draw() { }
|
||||
setup() {
|
||||
this.cursor = loadImage(cursor);
|
||||
this.shotSound = loadSound(shot);
|
||||
this.emptySound = loadSound(empty);
|
||||
}
|
||||
draw() {
|
||||
noCursor();
|
||||
|
||||
if (this.cursor) {
|
||||
image(this.cursor, mouseX - CURSOR_SIZE / 2, mouseY - CURSOR_SIZE / 2, CURSOR_SIZE, CURSOR_SIZE);
|
||||
} // custom cursor
|
||||
|
||||
for (let bullet of this.bullets) {
|
||||
bullet.draw();
|
||||
} // draw bullet holes
|
||||
|
||||
this.bullets = this.bullets.filter(bullet => bullet.visible); // clean up bullet holes
|
||||
shot = loadSound('data/shot.mp3');
|
||||
empty = loadSound('data/empty.mp3');
|
||||
}
|
||||
|
||||
shoot() {
|
||||
if (this.remainingShots > 0) {
|
||||
this.remainingShots--;
|
||||
|
||||
if (this.shotSound) this.shotSound.play();
|
||||
|
||||
const x = mouseX;
|
||||
const y = mouseY;
|
||||
|
||||
const bullet = new Bullet(x, y);
|
||||
this.bullets.push(bullet);
|
||||
|
||||
this.notifySubscribers('gun', x, y, this.remainingShots);
|
||||
} else {
|
||||
if (this.emptySound) this.emptySound.play();
|
||||
}
|
||||
}
|
||||
|
||||
reload() {
|
||||
this.remainingShots = this.totShots;
|
||||
}
|
||||
|
||||
getRemainingShots() {
|
||||
return this.remainingShots;
|
||||
}
|
||||
// mousePressed() {
|
||||
// if () {
|
||||
// shot.play();
|
||||
// } else { // no bullets left
|
||||
// empty.play();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
// Bullet
|
||||
class Bullet {
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.visible = true;
|
||||
|
||||
this.img = null;
|
||||
loadImage(bulletHole, (img) => {
|
||||
this.img = img;
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.visible = false;
|
||||
}, BULLET_DURATION);
|
||||
}
|
||||
|
||||
draw() {
|
||||
if (this.visible && this.img) {
|
||||
image(this.img, this.x - BULLET_HOLE_SIZE / 2, this.y - BULLET_HOLE_SIZE / 2, BULLET_HOLE_SIZE, BULLET_HOLE_SIZE);
|
||||
}
|
||||
}
|
||||
// TO DO
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,28 +1,32 @@
|
|||
import { BULLET_SIZE, FONT_SIZE} from './Constants.js';
|
||||
import { BULLET_SIZE, FONT_SIZE, TOT_SHOTS } from './Constants.js';
|
||||
import { Gun } from './Gun.js';
|
||||
import { Target } from './Target';
|
||||
|
||||
import bullet from '../data/bullet.png';
|
||||
|
||||
|
||||
class ScoreDisplay {
|
||||
constructor(initialBullets) {
|
||||
this.img = null;
|
||||
this.bulletImg = null;
|
||||
this.shotLeft = initialBullets;
|
||||
this.score = 0;
|
||||
|
||||
loadImage(bullet, (PImage) => {
|
||||
this.img = PImage;
|
||||
loadImage(bullet, (img) => {
|
||||
this.bulletImg = img;
|
||||
});
|
||||
}
|
||||
|
||||
draw() {
|
||||
// score
|
||||
// Draw score on top-left
|
||||
textFont('Arial');
|
||||
textSize(FONT_SIZE);
|
||||
textSize(25);
|
||||
fill(255, 0, 0);
|
||||
textAlign(LEFT, TOP);
|
||||
text(`Score: ${this.score}`, 10, 10);
|
||||
|
||||
// bullets
|
||||
if (!this.img) return;
|
||||
if (!this.bulletImg) return;
|
||||
|
||||
// Draw remaining bullets on top-right
|
||||
const bulletSpacing = 20;
|
||||
const marginRight = 10;
|
||||
const bulletsWidth = this.shotLeft * bulletSpacing;
|
||||
|
@ -30,32 +34,10 @@ class ScoreDisplay {
|
|||
let y = 10;
|
||||
|
||||
for (let i = 0; i < this.shotLeft; i++) {
|
||||
image(this.img, startX + i * bulletSpacing, y, BULLET_SIZE, BULLET_SIZE);
|
||||
image(this.bulletImg, startX + i * bulletSpacing, y, BULLET_SIZE, BULLET_SIZE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
resetScore() {
|
||||
this.score = 0;
|
||||
}
|
||||
|
||||
addScore(scoreToAdd) {
|
||||
this.score += scoreToAdd;
|
||||
}
|
||||
|
||||
setBullets(numBullets) {
|
||||
this.shotLeft = numBullets;
|
||||
}
|
||||
|
||||
update(source, ...others) {
|
||||
if (source === 'gun') {
|
||||
const [, , remainingShots] = others;
|
||||
this.setBullets(remainingShots);
|
||||
} else if (source === 'target-hit') {
|
||||
const [points] = others;
|
||||
this.addScore(points);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { ScoreDisplay };
|
||||
|
|
|
@ -1,26 +1,5 @@
|
|||
class Subject {
|
||||
constructor() {
|
||||
this.observers = [];
|
||||
}
|
||||
|
||||
subscribe(observer) {
|
||||
if (!observer || typeof observer.update !== 'function') return;
|
||||
this.observers.push(observer);
|
||||
}
|
||||
|
||||
unsubscribe(observer) {
|
||||
this.observers = this.observers.filter(o => o !== observer);
|
||||
}
|
||||
|
||||
unsubscribeAll() {
|
||||
this.observers = [];
|
||||
}
|
||||
|
||||
notifySubscribers(source, ...others) {
|
||||
for (let observer of this.observers) {
|
||||
observer.update(source, ...others);
|
||||
}
|
||||
}
|
||||
// TO DO
|
||||
}
|
||||
|
||||
export { Subject };
|
||||
|
|
134
src/Target.js
134
src/Target.js
|
@ -1,135 +1,21 @@
|
|||
import { MAX_TARGETS, TARGET_WIDTH } from './Constants';
|
||||
import { Subject } from './Subject';
|
||||
import { Gun } from './Gun';
|
||||
|
||||
import teddy from '../data/teddy.png';
|
||||
import duck from '../data/duck.png';
|
||||
import squirrel from '../data/squirrel.png';
|
||||
|
||||
class Target extends Subject {
|
||||
constructor(x, y, width) {
|
||||
super();
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = width;
|
||||
this.visible = true;
|
||||
this.img = null;
|
||||
}
|
||||
|
||||
draw() {
|
||||
if (this.visible && this.img) {
|
||||
image(this.img, this.x, this.y, this.width, this.height);
|
||||
}
|
||||
}
|
||||
|
||||
getPoints() {
|
||||
return 0; // to be overridden
|
||||
}
|
||||
|
||||
isHit(x, y) {
|
||||
return (
|
||||
this.visible &&
|
||||
x >= this.x &&
|
||||
x <= this.x + this.width &&
|
||||
y >= this.y &&
|
||||
y <= this.y + this.height
|
||||
);
|
||||
}
|
||||
|
||||
shoot(x, y) {
|
||||
if (this.isHit(x, y)) {
|
||||
this.visible = false;
|
||||
this.notifySubscribers('target-hit', this.getPoints());
|
||||
}
|
||||
}
|
||||
|
||||
update(source, ...others) {
|
||||
if (source === 'gun') {
|
||||
const [x, y] = others;
|
||||
this.shoot(x, y);
|
||||
}
|
||||
}
|
||||
class Target {
|
||||
// TO DO
|
||||
}
|
||||
|
||||
class TeddyTarget extends Target {
|
||||
constructor(x, y) {
|
||||
super(x, y, TARGET_WIDTH);
|
||||
this.img = loadImage(teddy);
|
||||
}
|
||||
|
||||
getPoints() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
class DuckTarget extends Target {
|
||||
constructor(x, y) {
|
||||
super(x, y, TARGET_WIDTH);
|
||||
this.img = loadImage(duck);
|
||||
}
|
||||
|
||||
getPoints() {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
class SquirrelTarget extends Target {
|
||||
constructor(x, y) {
|
||||
super(x, y, TARGET_WIDTH);
|
||||
this.img = loadImage(squirrel);
|
||||
}
|
||||
|
||||
getPoints() {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
// TO DO
|
||||
// class TeddyTarget ...
|
||||
// class DuckTarget ...
|
||||
// class SquirrelTarget ...
|
||||
|
||||
class TargetFactory {
|
||||
static instance;
|
||||
|
||||
static getInstance() {
|
||||
if (!TargetFactory.instance) {
|
||||
TargetFactory.instance = new TargetFactory();
|
||||
}
|
||||
return TargetFactory.instance;
|
||||
}
|
||||
|
||||
getTargetsByName(targetNames, targetWidth, y) {
|
||||
const targets = [];
|
||||
|
||||
for (let i = 0; i < targetNames.length && i < MAX_TARGETS; i += 1) {
|
||||
const name = targetNames[i];
|
||||
const x = 100 + i * targetWidth;
|
||||
|
||||
switch (name) {
|
||||
case 'teddy':
|
||||
targets.push(new TeddyTarget(x, y));
|
||||
break;
|
||||
case 'duck':
|
||||
targets.push(new DuckTarget(x, y));
|
||||
break;
|
||||
case 'squirrel':
|
||||
targets.push(new SquirrelTarget(x, y));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
getRandomTargets(numTargets, targetWidth, y) {
|
||||
const names = ['teddy', 'duck', 'squirrel'];
|
||||
const targetNames = [];
|
||||
|
||||
for (let i = 0; i < numTargets; i++) {
|
||||
targetNames.push(random(names));
|
||||
}
|
||||
|
||||
return this.getTargetsByName(targetNames, targetWidth, y);
|
||||
} // create random targets
|
||||
// TO DO
|
||||
}
|
||||
|
||||
export {
|
||||
Target, TeddyTarget,
|
||||
DuckTarget,
|
||||
SquirrelTarget, TargetFactory
|
||||
};
|
||||
export { Target, TargetFactory };
|
||||
|
|
33
src/main.js
33
src/main.js
|
@ -14,36 +14,21 @@ function setup() {
|
|||
createCanvas(800, 600);
|
||||
|
||||
// 1. Init gun and score display
|
||||
gun = new Gun(TOT_SHOTS);
|
||||
gun.setup();
|
||||
score = new ScoreDisplay(TOT_SHOTS);
|
||||
// 2. Init the targets
|
||||
initTargets();
|
||||
|
||||
// 3. Subscribe gun
|
||||
gun.subscribe(score);
|
||||
|
||||
// Subscribe each target to gun
|
||||
for (let target of targets) {
|
||||
gun.subscribe(target);
|
||||
target.subscribe(score);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function draw() {
|
||||
background('#eeeeee');
|
||||
for (let target of targets) {
|
||||
target.draw();
|
||||
}
|
||||
gun.draw();
|
||||
score.draw();
|
||||
// draw targets, gun, bullets, score
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Shoot
|
||||
function mousePressed() {
|
||||
gun.shoot();
|
||||
// shoot
|
||||
}
|
||||
|
||||
|
@ -51,27 +36,13 @@ function mousePressed() {
|
|||
function keyPressed() {
|
||||
if (key === ' ') {
|
||||
// reset score and targets
|
||||
gun.remainingShots = TOT_SHOTS;
|
||||
score.shotLeft = TOT_SHOTS;
|
||||
score.score = 0;
|
||||
|
||||
initTargets();
|
||||
}
|
||||
}
|
||||
|
||||
// init the targets
|
||||
function initTargets() {
|
||||
// Create new targets from the factory
|
||||
const factory = TargetFactory.getInstance();
|
||||
// Remember to unsubscribe the previous targets and to subscribe the new ones
|
||||
gun.unsubscribeAll();
|
||||
|
||||
targets = factory.getRandomTargets(MAX_TARGETS, TARGET_WIDTH, 200);
|
||||
gun.subscribe(score);
|
||||
for (let target of targets) {
|
||||
gun.subscribe(target);
|
||||
target.subscribe(score);
|
||||
}
|
||||
}
|
||||
|
||||
// Do not touch these
|
||||
|
|
Loading…
Reference in New Issue
Block a user