From 9128aa0a3780d2c97bf0f83e8aa9fe7eaaf22190 Mon Sep 17 00:00:00 2001 From: testerUse21 <106081205+testerUse21@users.noreply.github.com> Date: Fri, 24 Feb 2023 16:27:42 +0530 Subject: [PATCH] Add files via upload --- app - Copy (2).js | 454 +++++++++++++++++++++++++++++++++++++++ app - Copy (3).js | 454 +++++++++++++++++++++++++++++++++++++++ app - Copy (4).js | 454 +++++++++++++++++++++++++++++++++++++++ app - Copy.js | 454 +++++++++++++++++++++++++++++++++++++++ app.js | 454 +++++++++++++++++++++++++++++++++++++++ background - Copy (2).js | 4 + background - Copy (3).js | 4 + background - Copy (4).js | 4 + background - Copy.js | 4 + background.js | 4 + index - Copy (2).js | 34 +++ index - Copy (3).js | 34 +++ index - Copy (4).js | 34 +++ index - Copy.js | 34 +++ index.js | 34 +++ script - Copy (2).js | 64 ++++++ script - Copy (3).js | 64 ++++++ script - Copy (4).js | 64 ++++++ script - Copy.js | 64 ++++++ script.js | 64 ++++++ 20 files changed, 2780 insertions(+) create mode 100644 app - Copy (2).js create mode 100644 app - Copy (3).js create mode 100644 app - Copy (4).js create mode 100644 app - Copy.js create mode 100644 app.js create mode 100644 background - Copy (2).js create mode 100644 background - Copy (3).js create mode 100644 background - Copy (4).js create mode 100644 background - Copy.js create mode 100644 background.js create mode 100644 index - Copy (2).js create mode 100644 index - Copy (3).js create mode 100644 index - Copy (4).js create mode 100644 index - Copy.js create mode 100644 index.js create mode 100644 script - Copy (2).js create mode 100644 script - Copy (3).js create mode 100644 script - Copy (4).js create mode 100644 script - Copy.js create mode 100644 script.js diff --git a/app - Copy (2).js b/app - Copy (2).js new file mode 100644 index 00000000..05fe7d47 --- /dev/null +++ b/app - Copy (2).js @@ -0,0 +1,454 @@ +// @ts-check +class EventEmitter { + constructor() { + this.listeners = {}; + } + + on(message, listener) { + if (!this.listeners[message]) { + this.listeners[message] = []; + } + this.listeners[message].push(listener); + } + + emit(message, payload = null) { + if (this.listeners[message]) { + this.listeners[message].forEach((l) => l(message, payload)); + } + } +} + +class GameObject { + constructor(x, y) { + this.x = x; + this.y = y; + this.dead = false; + this.type = ''; + this.width = 0; + this.height = 0; + this.img = undefined; + } + + draw(ctx) { + ctx.drawImage(this.img, this.x, this.y, this.width, this.height); + } + + rectFromGameObject() { + return { + top: this.y, + left: this.x, + bottom: this.y + this.height, + right: this.x + this.width, + }; + } +} + +class Hero extends GameObject { + constructor(x, y) { + super(x, y); + (this.width = 99), (this.height = 75); + this.type = 'Hero'; + this.speed = { x: 0, y: 0 }; + } +} + +class Laser extends GameObject { + constructor(x, y) { + super(x, y); + this.width = 9; + this.height = 33; + this.type = 'Laser'; + let id = setInterval(() => { + if (!this.dead) { + this.y = this.y > 0 ? this.y - 20 : this.y; + if (this.y <= 0) { + this.dead = true; + } + } else { + clearInterval(id); + } + }, 100); + } +} + +class Explosion extends GameObject { + constructor(x, y, img) { + super(x, y); + this.img = img; + this.type = 'Explosion'; + (this.width = 56 * 2), (this.height = 54 * 2); + setTimeout(() => { + this.dead = true; + }, 300); + } +} + +class Monster extends GameObject { + constructor(x, y) { + super(x, y); + this.type = 'Monster'; + (this.width = 98), (this.height = 50); + let id = setInterval(() => { + if (!this.dead) { + this.y = this.y < HEIGHT ? this.y + 30 : this.y; + if (this.y >= HEIGHT - this.height) { + this.dead = true; + eventEmitter.emit('MONSTER_OUT_OF_BOUNDS'); + } + } else { + clearInterval(id); + } + }, 1500); + } +} + +const Messages = { + MONSTER_OUT_OF_BOUNDS: 'MONSTER_OUT_OF_BOUNDS', + HERO_SPEED_LEFT: 'HERO_MOVING_LEFT', + HERO_SPEED_RIGHT: 'HERO_MOVING_RIGHT', + HERO_SPEED_ZERO: 'HERO_SPEED_ZERO', + HERO_FIRE: 'HERO_FIRE', + GAME_END_LOSS: 'GAME_END_LOSS', + GAME_END_WIN: 'GAME_END_WIN', + COLLISION_MONSTER_LASER: 'COLLISION_MONSTER_LASER', + COLLISION_MONSTER_HERO: 'COLLISION_MONSTER_HERO', + KEY_EVENT_UP: 'KEY_EVENT_UP', + KEY_EVENT_DOWN: 'KEY_EVENT_DOWN', + KEY_EVENT_LEFT: 'KEY_EVENT_LEFT', + KEY_EVENT_RIGHT: 'KEY_EVENT_RIGHT', + GAME_START: 'GAME_START', +}; + +class Game { + constructor() { + this.points = 0; + this.life = 3; + this.end = false; + this.ready = false; + + eventEmitter.on(Messages.MONSTER_OUT_OF_BOUNDS, () => { + hero.dead = true; + }); + eventEmitter.on(Messages.HERO_SPEED_LEFT, () => { + hero.speed.x = -10; + hero.img = heroImgLeft; + }); + eventEmitter.on(Messages.HERO_SPEED_RIGHT, () => { + hero.speed.x = 10; + hero.img = heroImgRight; + }); + eventEmitter.on(Messages.HERO_SPEED_ZERO, () => { + hero.speed = { x: 0, y: 0 }; + if (game.life === 3) { + hero.img = heroImg; + } else { + hero.img = heroImgDamaged; + } + }); + eventEmitter.on(Messages.HERO_FIRE, () => { + if (coolDown === 0) { + let l = new Laser(hero.x + 45, hero.y - 30); + l.img = laserRedImg; + gameObjects.push(l); + cooling(); + } + }); + eventEmitter.on(Messages.GAME_END_LOSS, (_, gameLoopId) => { + game.end = true; + displayMessage('You died... - Press [Enter] to start the game Captain Pew Pew'); + clearInterval(gameLoopId); + }); + + eventEmitter.on(Messages.GAME_END_WIN, (_, gameLoopId) => { + game.end = true; + displayMessage('Victory!!! Pew Pew... - Press [Enter] to start a new game Captain Pew Pew', 'green'); + clearInterval(gameLoopId); + }); + eventEmitter.on(Messages.COLLISION_MONSTER_LASER, (_, { first: laser, second: monster }) => { + laser.dead = true; + monster.dead = true; + this.points += 100; + + gameObjects.push(new Explosion(monster.x, monster.y, laserRedShot)); + }); + eventEmitter.on(Messages.COLLISION_MONSTER_HERO, (_, { monster: m, id }) => { + game.life--; + if (game.life === 0) { + hero.dead = true; + eventEmitter.emit(Messages.GAME_END_LOSS, id); + gameObjects.push(new Explosion(hero.x, hero.y, laserGreenShot)); + } + hero.img = heroImgDamaged; + m.dead = true; + gameObjects.push(new Explosion(m.x, m.y, laserRedShot)); + }); + eventEmitter.on(Messages.KEY_EVENT_UP, () => { + hero.y = hero.y > 0 ? hero.y - 5 : hero.y; + }); + eventEmitter.on(Messages.KEY_EVENT_DOWN, () => { + hero.y = hero.y < HEIGHT ? hero.y + 5 : hero.y; + }); + eventEmitter.on(Messages.KEY_EVENT_LEFT, () => { + hero.x = hero.x > 0 ? hero.x - 10 : hero.x; + }); + eventEmitter.on(Messages.KEY_EVENT_RIGHT, () => { + hero.x = hero.x < WIDTH ? hero.x + 10 : hero.x; + }); + eventEmitter.on(Messages.GAME_START, () => { + if (game.ready && game.end) { + // assets loaded + runGame(); + } + }); + } +} + +const eventEmitter = new EventEmitter(); +const hero = new Hero(0, 0); +const WIDTH = 1024; +const HEIGHT = 768; +let gameObjects = []; +let laserRedImg; +let laserRedShot; +let laserGreenShot; +let canvas; +let ctx; +let heroImg; +let heroImgLeft; +let heroImgRight; +let heroImgDamaged; +let lifeImg; +let monsterImg; + +let coolDown = 0; + +const game = new Game(); + +function loadTexture(path) { + return new Promise((resolve) => { + const img = new Image(); + img.src = path; + img.onload = () => { + resolve(img); + }; + }); +} + +function rectFromGameObject(go) { + return { + top: go.y, + left: go.x, + bottom: go.y + go.height, + right: go.x + go.width, + }; +} + +function intersectRect(r1, r2) { + return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top); +} + +function draw(ctx, objects) { + objects.forEach((obj) => { + obj.draw(ctx); + }); +} + +let onKeyDown = function (e) { + console.log(e.keyCode); + switch (e.keyCode) { + case 37: + case 39: + case 38: + case 40: // Arrow keys + case 32: + e.preventDefault(); + break; // Space + default: + break; // do not block other keys + } +}; + +window.addEventListener('keydown', onKeyDown); +window.addEventListener('keydown', (e) => { + switch (e.keyCode) { + case 37: + // if left + eventEmitter.emit(Messages.HERO_SPEED_LEFT); + break; + case 39: + eventEmitter.emit(Messages.HERO_SPEED_RIGHT); + break; + } +}); + +// TODO make message driven +window.addEventListener('keyup', (evt) => { + eventEmitter.emit(Messages.HERO_SPEED_ZERO); + if (evt.key === 'ArrowUp') { + eventEmitter.emit(Messages.KEY_EVENT_UP); + } else if (evt.key === 'ArrowDown') { + eventEmitter.emit(Messages.KEY_EVENT_DOWN); + } else if (evt.key === 'ArrowLeft') { + eventEmitter.emit(Messages.KEY_EVENT_LEFT); + } else if (evt.key === 'ArrowRight') { + eventEmitter.emit(Messages.KEY_EVENT_RIGHT); + } else if (evt.keyCode === 32) { + // space + eventEmitter.emit(Messages.HERO_FIRE); + } else if (evt.key === 'Enter') { + eventEmitter.emit(Messages.GAME_START); + } +}); + +function cooling() { + coolDown = 500; + let id = setInterval(() => { + coolDown -= 100; + if (coolDown === 0) { + clearInterval(id); + } + }, 100); +} + +function displayGameScore(message) { + ctx.font = '30px Arial'; + ctx.fillStyle = 'red'; + ctx.textAlign = 'right'; + ctx.fillText(message, canvas.width - 90, canvas.height - 30); +} + +function displayLife() { + // should show tree ships.. 94 * 3 + const START_X = canvas.width - 150 - 30; + for (let i = 0; i < game.life; i++) { + ctx.drawImage(lifeImg, START_X + (i + 1) * 35, canvas.height - 90); + } +} + +function displayMessage(message, color = 'red') { + ctx.font = '30px Arial'; + ctx.fillStyle = color; + ctx.textAlign = 'center'; + ctx.fillText(message, canvas.width / 2, canvas.height / 2); +} + +function createMonsters(monsterImg) { + // 98 * 5 canvas.width - (98*5 /2) + const MONSTER_TOTAL = 5; + const MONSTER_WIDTH = MONSTER_TOTAL * 98; + const START_X = (canvas.width - MONSTER_WIDTH) / 2; + const STOP_X = START_X + MONSTER_WIDTH; + + for (let x = START_X; x < STOP_X; x += 98) { + for (let y = 0; y < 50 * 5; y += 50) { + gameObjects.push(new Monster(x, y)); + } + } + + gameObjects.forEach((go) => { + go.img = monsterImg; + }); +} + +function createHero(heroImg) { + hero.dead = false; + hero.img = heroImg; + hero.y = (canvas.height / 4) * 3; + hero.x = canvas.width / 2; + gameObjects.push(hero); +} + +function checkGameState(gameLoopId) { + const monsters = gameObjects.filter((go) => go.type === 'Monster'); + if (hero.dead) { + eventEmitter.emit(Messages.GAME_END_LOSS, gameLoopId); + } else if (monsters.length === 0) { + eventEmitter.emit(Messages.GAME_END_WIN); + } + + // update hero position + if (hero.speed.x !== 0) { + hero.x += hero.speed.x; + } + + const lasers = gameObjects.filter((go) => go.type === 'Laser'); + // laser hit something + lasers.forEach((l) => { + monsters.forEach((m) => { + if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) { + eventEmitter.emit(Messages.COLLISION_MONSTER_LASER, { + first: l, + second: m, + }); + } + }); + }); + + // hero hit monster + monsters.forEach((m) => { + if (intersectRect(m.rectFromGameObject(), hero.rectFromGameObject())) { + eventEmitter.emit(Messages.COLLISION_MONSTER_HERO, { monster: m, id: gameLoopId }); + } + }); + + gameObjects = gameObjects.filter((go) => !go.dead); +} + +function runGame() { + gameObjects = []; + game.life = 3; + game.points = 0; + game.end = false; + + createMonsters(monsterImg); + createHero(heroImg); + + let gameLoopId = setInterval(() => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + displayGameScore('Score: ' + game.points); + displayLife(); + checkGameState(gameLoopId); + draw(ctx, gameObjects); + }, 100); +} + +window.onload = async () => { + canvas = document.getElementById('myCanvas'); + ctx = canvas.getContext('2d'); + + heroImg = await loadTexture('spaceArt/png/player.png'); + heroImgLeft = await loadTexture('spaceArt/png/playerLeft.png'); + heroImgRight = await loadTexture('spaceArt/png/playerRight.png'); + heroImgDamaged = await loadTexture('spaceArt/png/playerDamaged.png'); + monsterImg = await loadTexture('spaceArt/png/enemyShip.png'); + laserRedImg = await loadTexture('spaceArt/png/laserRed.png'); + laserRedShot = await loadTexture('spaceArt/png/laserRedShot.png'); + laserGreenShot = await loadTexture('spaceArt/png/laserGreenShot.png'); + lifeImg = await loadTexture('spaceArt/png/life.png'); + + game.ready = true; + game.end = true; + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + displayMessage('Press [Enter] to start the game Captain Pew Pew', 'blue'); + + // CHECK draw 5 * 5 monsters + // CHECK move monsters down 1 step per 0.5 second + // CHECK if monster collide with hero, destroy both, display loose text + // CHECK if monster reach MAX, destroy hero, loose text + // TODO add explosion when laser hits monster, should render for <=300ms + // TODO add specific texture when moving left or right + // TODO take damage when a meteor moves into you + // TODO add meteor, meteors can damage ships + // TODO add UFO after all monsters are down, UFO can fire back + // TODO start random green laser from an enemy and have it go to HEIGHT, if collide with hero then deduct point + + // CHECK draw bullet + // CHECK , bullet should be destroyed at top + // CHECK space should produce bullet, bullet should move 2 step per second + // CHECK if bullet collide with monster, destroy both + // CHECK if bullet rect intersect with monster rect then it is colliding.. +}; diff --git a/app - Copy (3).js b/app - Copy (3).js new file mode 100644 index 00000000..05fe7d47 --- /dev/null +++ b/app - Copy (3).js @@ -0,0 +1,454 @@ +// @ts-check +class EventEmitter { + constructor() { + this.listeners = {}; + } + + on(message, listener) { + if (!this.listeners[message]) { + this.listeners[message] = []; + } + this.listeners[message].push(listener); + } + + emit(message, payload = null) { + if (this.listeners[message]) { + this.listeners[message].forEach((l) => l(message, payload)); + } + } +} + +class GameObject { + constructor(x, y) { + this.x = x; + this.y = y; + this.dead = false; + this.type = ''; + this.width = 0; + this.height = 0; + this.img = undefined; + } + + draw(ctx) { + ctx.drawImage(this.img, this.x, this.y, this.width, this.height); + } + + rectFromGameObject() { + return { + top: this.y, + left: this.x, + bottom: this.y + this.height, + right: this.x + this.width, + }; + } +} + +class Hero extends GameObject { + constructor(x, y) { + super(x, y); + (this.width = 99), (this.height = 75); + this.type = 'Hero'; + this.speed = { x: 0, y: 0 }; + } +} + +class Laser extends GameObject { + constructor(x, y) { + super(x, y); + this.width = 9; + this.height = 33; + this.type = 'Laser'; + let id = setInterval(() => { + if (!this.dead) { + this.y = this.y > 0 ? this.y - 20 : this.y; + if (this.y <= 0) { + this.dead = true; + } + } else { + clearInterval(id); + } + }, 100); + } +} + +class Explosion extends GameObject { + constructor(x, y, img) { + super(x, y); + this.img = img; + this.type = 'Explosion'; + (this.width = 56 * 2), (this.height = 54 * 2); + setTimeout(() => { + this.dead = true; + }, 300); + } +} + +class Monster extends GameObject { + constructor(x, y) { + super(x, y); + this.type = 'Monster'; + (this.width = 98), (this.height = 50); + let id = setInterval(() => { + if (!this.dead) { + this.y = this.y < HEIGHT ? this.y + 30 : this.y; + if (this.y >= HEIGHT - this.height) { + this.dead = true; + eventEmitter.emit('MONSTER_OUT_OF_BOUNDS'); + } + } else { + clearInterval(id); + } + }, 1500); + } +} + +const Messages = { + MONSTER_OUT_OF_BOUNDS: 'MONSTER_OUT_OF_BOUNDS', + HERO_SPEED_LEFT: 'HERO_MOVING_LEFT', + HERO_SPEED_RIGHT: 'HERO_MOVING_RIGHT', + HERO_SPEED_ZERO: 'HERO_SPEED_ZERO', + HERO_FIRE: 'HERO_FIRE', + GAME_END_LOSS: 'GAME_END_LOSS', + GAME_END_WIN: 'GAME_END_WIN', + COLLISION_MONSTER_LASER: 'COLLISION_MONSTER_LASER', + COLLISION_MONSTER_HERO: 'COLLISION_MONSTER_HERO', + KEY_EVENT_UP: 'KEY_EVENT_UP', + KEY_EVENT_DOWN: 'KEY_EVENT_DOWN', + KEY_EVENT_LEFT: 'KEY_EVENT_LEFT', + KEY_EVENT_RIGHT: 'KEY_EVENT_RIGHT', + GAME_START: 'GAME_START', +}; + +class Game { + constructor() { + this.points = 0; + this.life = 3; + this.end = false; + this.ready = false; + + eventEmitter.on(Messages.MONSTER_OUT_OF_BOUNDS, () => { + hero.dead = true; + }); + eventEmitter.on(Messages.HERO_SPEED_LEFT, () => { + hero.speed.x = -10; + hero.img = heroImgLeft; + }); + eventEmitter.on(Messages.HERO_SPEED_RIGHT, () => { + hero.speed.x = 10; + hero.img = heroImgRight; + }); + eventEmitter.on(Messages.HERO_SPEED_ZERO, () => { + hero.speed = { x: 0, y: 0 }; + if (game.life === 3) { + hero.img = heroImg; + } else { + hero.img = heroImgDamaged; + } + }); + eventEmitter.on(Messages.HERO_FIRE, () => { + if (coolDown === 0) { + let l = new Laser(hero.x + 45, hero.y - 30); + l.img = laserRedImg; + gameObjects.push(l); + cooling(); + } + }); + eventEmitter.on(Messages.GAME_END_LOSS, (_, gameLoopId) => { + game.end = true; + displayMessage('You died... - Press [Enter] to start the game Captain Pew Pew'); + clearInterval(gameLoopId); + }); + + eventEmitter.on(Messages.GAME_END_WIN, (_, gameLoopId) => { + game.end = true; + displayMessage('Victory!!! Pew Pew... - Press [Enter] to start a new game Captain Pew Pew', 'green'); + clearInterval(gameLoopId); + }); + eventEmitter.on(Messages.COLLISION_MONSTER_LASER, (_, { first: laser, second: monster }) => { + laser.dead = true; + monster.dead = true; + this.points += 100; + + gameObjects.push(new Explosion(monster.x, monster.y, laserRedShot)); + }); + eventEmitter.on(Messages.COLLISION_MONSTER_HERO, (_, { monster: m, id }) => { + game.life--; + if (game.life === 0) { + hero.dead = true; + eventEmitter.emit(Messages.GAME_END_LOSS, id); + gameObjects.push(new Explosion(hero.x, hero.y, laserGreenShot)); + } + hero.img = heroImgDamaged; + m.dead = true; + gameObjects.push(new Explosion(m.x, m.y, laserRedShot)); + }); + eventEmitter.on(Messages.KEY_EVENT_UP, () => { + hero.y = hero.y > 0 ? hero.y - 5 : hero.y; + }); + eventEmitter.on(Messages.KEY_EVENT_DOWN, () => { + hero.y = hero.y < HEIGHT ? hero.y + 5 : hero.y; + }); + eventEmitter.on(Messages.KEY_EVENT_LEFT, () => { + hero.x = hero.x > 0 ? hero.x - 10 : hero.x; + }); + eventEmitter.on(Messages.KEY_EVENT_RIGHT, () => { + hero.x = hero.x < WIDTH ? hero.x + 10 : hero.x; + }); + eventEmitter.on(Messages.GAME_START, () => { + if (game.ready && game.end) { + // assets loaded + runGame(); + } + }); + } +} + +const eventEmitter = new EventEmitter(); +const hero = new Hero(0, 0); +const WIDTH = 1024; +const HEIGHT = 768; +let gameObjects = []; +let laserRedImg; +let laserRedShot; +let laserGreenShot; +let canvas; +let ctx; +let heroImg; +let heroImgLeft; +let heroImgRight; +let heroImgDamaged; +let lifeImg; +let monsterImg; + +let coolDown = 0; + +const game = new Game(); + +function loadTexture(path) { + return new Promise((resolve) => { + const img = new Image(); + img.src = path; + img.onload = () => { + resolve(img); + }; + }); +} + +function rectFromGameObject(go) { + return { + top: go.y, + left: go.x, + bottom: go.y + go.height, + right: go.x + go.width, + }; +} + +function intersectRect(r1, r2) { + return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top); +} + +function draw(ctx, objects) { + objects.forEach((obj) => { + obj.draw(ctx); + }); +} + +let onKeyDown = function (e) { + console.log(e.keyCode); + switch (e.keyCode) { + case 37: + case 39: + case 38: + case 40: // Arrow keys + case 32: + e.preventDefault(); + break; // Space + default: + break; // do not block other keys + } +}; + +window.addEventListener('keydown', onKeyDown); +window.addEventListener('keydown', (e) => { + switch (e.keyCode) { + case 37: + // if left + eventEmitter.emit(Messages.HERO_SPEED_LEFT); + break; + case 39: + eventEmitter.emit(Messages.HERO_SPEED_RIGHT); + break; + } +}); + +// TODO make message driven +window.addEventListener('keyup', (evt) => { + eventEmitter.emit(Messages.HERO_SPEED_ZERO); + if (evt.key === 'ArrowUp') { + eventEmitter.emit(Messages.KEY_EVENT_UP); + } else if (evt.key === 'ArrowDown') { + eventEmitter.emit(Messages.KEY_EVENT_DOWN); + } else if (evt.key === 'ArrowLeft') { + eventEmitter.emit(Messages.KEY_EVENT_LEFT); + } else if (evt.key === 'ArrowRight') { + eventEmitter.emit(Messages.KEY_EVENT_RIGHT); + } else if (evt.keyCode === 32) { + // space + eventEmitter.emit(Messages.HERO_FIRE); + } else if (evt.key === 'Enter') { + eventEmitter.emit(Messages.GAME_START); + } +}); + +function cooling() { + coolDown = 500; + let id = setInterval(() => { + coolDown -= 100; + if (coolDown === 0) { + clearInterval(id); + } + }, 100); +} + +function displayGameScore(message) { + ctx.font = '30px Arial'; + ctx.fillStyle = 'red'; + ctx.textAlign = 'right'; + ctx.fillText(message, canvas.width - 90, canvas.height - 30); +} + +function displayLife() { + // should show tree ships.. 94 * 3 + const START_X = canvas.width - 150 - 30; + for (let i = 0; i < game.life; i++) { + ctx.drawImage(lifeImg, START_X + (i + 1) * 35, canvas.height - 90); + } +} + +function displayMessage(message, color = 'red') { + ctx.font = '30px Arial'; + ctx.fillStyle = color; + ctx.textAlign = 'center'; + ctx.fillText(message, canvas.width / 2, canvas.height / 2); +} + +function createMonsters(monsterImg) { + // 98 * 5 canvas.width - (98*5 /2) + const MONSTER_TOTAL = 5; + const MONSTER_WIDTH = MONSTER_TOTAL * 98; + const START_X = (canvas.width - MONSTER_WIDTH) / 2; + const STOP_X = START_X + MONSTER_WIDTH; + + for (let x = START_X; x < STOP_X; x += 98) { + for (let y = 0; y < 50 * 5; y += 50) { + gameObjects.push(new Monster(x, y)); + } + } + + gameObjects.forEach((go) => { + go.img = monsterImg; + }); +} + +function createHero(heroImg) { + hero.dead = false; + hero.img = heroImg; + hero.y = (canvas.height / 4) * 3; + hero.x = canvas.width / 2; + gameObjects.push(hero); +} + +function checkGameState(gameLoopId) { + const monsters = gameObjects.filter((go) => go.type === 'Monster'); + if (hero.dead) { + eventEmitter.emit(Messages.GAME_END_LOSS, gameLoopId); + } else if (monsters.length === 0) { + eventEmitter.emit(Messages.GAME_END_WIN); + } + + // update hero position + if (hero.speed.x !== 0) { + hero.x += hero.speed.x; + } + + const lasers = gameObjects.filter((go) => go.type === 'Laser'); + // laser hit something + lasers.forEach((l) => { + monsters.forEach((m) => { + if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) { + eventEmitter.emit(Messages.COLLISION_MONSTER_LASER, { + first: l, + second: m, + }); + } + }); + }); + + // hero hit monster + monsters.forEach((m) => { + if (intersectRect(m.rectFromGameObject(), hero.rectFromGameObject())) { + eventEmitter.emit(Messages.COLLISION_MONSTER_HERO, { monster: m, id: gameLoopId }); + } + }); + + gameObjects = gameObjects.filter((go) => !go.dead); +} + +function runGame() { + gameObjects = []; + game.life = 3; + game.points = 0; + game.end = false; + + createMonsters(monsterImg); + createHero(heroImg); + + let gameLoopId = setInterval(() => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + displayGameScore('Score: ' + game.points); + displayLife(); + checkGameState(gameLoopId); + draw(ctx, gameObjects); + }, 100); +} + +window.onload = async () => { + canvas = document.getElementById('myCanvas'); + ctx = canvas.getContext('2d'); + + heroImg = await loadTexture('spaceArt/png/player.png'); + heroImgLeft = await loadTexture('spaceArt/png/playerLeft.png'); + heroImgRight = await loadTexture('spaceArt/png/playerRight.png'); + heroImgDamaged = await loadTexture('spaceArt/png/playerDamaged.png'); + monsterImg = await loadTexture('spaceArt/png/enemyShip.png'); + laserRedImg = await loadTexture('spaceArt/png/laserRed.png'); + laserRedShot = await loadTexture('spaceArt/png/laserRedShot.png'); + laserGreenShot = await loadTexture('spaceArt/png/laserGreenShot.png'); + lifeImg = await loadTexture('spaceArt/png/life.png'); + + game.ready = true; + game.end = true; + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + displayMessage('Press [Enter] to start the game Captain Pew Pew', 'blue'); + + // CHECK draw 5 * 5 monsters + // CHECK move monsters down 1 step per 0.5 second + // CHECK if monster collide with hero, destroy both, display loose text + // CHECK if monster reach MAX, destroy hero, loose text + // TODO add explosion when laser hits monster, should render for <=300ms + // TODO add specific texture when moving left or right + // TODO take damage when a meteor moves into you + // TODO add meteor, meteors can damage ships + // TODO add UFO after all monsters are down, UFO can fire back + // TODO start random green laser from an enemy and have it go to HEIGHT, if collide with hero then deduct point + + // CHECK draw bullet + // CHECK , bullet should be destroyed at top + // CHECK space should produce bullet, bullet should move 2 step per second + // CHECK if bullet collide with monster, destroy both + // CHECK if bullet rect intersect with monster rect then it is colliding.. +}; diff --git a/app - Copy (4).js b/app - Copy (4).js new file mode 100644 index 00000000..05fe7d47 --- /dev/null +++ b/app - Copy (4).js @@ -0,0 +1,454 @@ +// @ts-check +class EventEmitter { + constructor() { + this.listeners = {}; + } + + on(message, listener) { + if (!this.listeners[message]) { + this.listeners[message] = []; + } + this.listeners[message].push(listener); + } + + emit(message, payload = null) { + if (this.listeners[message]) { + this.listeners[message].forEach((l) => l(message, payload)); + } + } +} + +class GameObject { + constructor(x, y) { + this.x = x; + this.y = y; + this.dead = false; + this.type = ''; + this.width = 0; + this.height = 0; + this.img = undefined; + } + + draw(ctx) { + ctx.drawImage(this.img, this.x, this.y, this.width, this.height); + } + + rectFromGameObject() { + return { + top: this.y, + left: this.x, + bottom: this.y + this.height, + right: this.x + this.width, + }; + } +} + +class Hero extends GameObject { + constructor(x, y) { + super(x, y); + (this.width = 99), (this.height = 75); + this.type = 'Hero'; + this.speed = { x: 0, y: 0 }; + } +} + +class Laser extends GameObject { + constructor(x, y) { + super(x, y); + this.width = 9; + this.height = 33; + this.type = 'Laser'; + let id = setInterval(() => { + if (!this.dead) { + this.y = this.y > 0 ? this.y - 20 : this.y; + if (this.y <= 0) { + this.dead = true; + } + } else { + clearInterval(id); + } + }, 100); + } +} + +class Explosion extends GameObject { + constructor(x, y, img) { + super(x, y); + this.img = img; + this.type = 'Explosion'; + (this.width = 56 * 2), (this.height = 54 * 2); + setTimeout(() => { + this.dead = true; + }, 300); + } +} + +class Monster extends GameObject { + constructor(x, y) { + super(x, y); + this.type = 'Monster'; + (this.width = 98), (this.height = 50); + let id = setInterval(() => { + if (!this.dead) { + this.y = this.y < HEIGHT ? this.y + 30 : this.y; + if (this.y >= HEIGHT - this.height) { + this.dead = true; + eventEmitter.emit('MONSTER_OUT_OF_BOUNDS'); + } + } else { + clearInterval(id); + } + }, 1500); + } +} + +const Messages = { + MONSTER_OUT_OF_BOUNDS: 'MONSTER_OUT_OF_BOUNDS', + HERO_SPEED_LEFT: 'HERO_MOVING_LEFT', + HERO_SPEED_RIGHT: 'HERO_MOVING_RIGHT', + HERO_SPEED_ZERO: 'HERO_SPEED_ZERO', + HERO_FIRE: 'HERO_FIRE', + GAME_END_LOSS: 'GAME_END_LOSS', + GAME_END_WIN: 'GAME_END_WIN', + COLLISION_MONSTER_LASER: 'COLLISION_MONSTER_LASER', + COLLISION_MONSTER_HERO: 'COLLISION_MONSTER_HERO', + KEY_EVENT_UP: 'KEY_EVENT_UP', + KEY_EVENT_DOWN: 'KEY_EVENT_DOWN', + KEY_EVENT_LEFT: 'KEY_EVENT_LEFT', + KEY_EVENT_RIGHT: 'KEY_EVENT_RIGHT', + GAME_START: 'GAME_START', +}; + +class Game { + constructor() { + this.points = 0; + this.life = 3; + this.end = false; + this.ready = false; + + eventEmitter.on(Messages.MONSTER_OUT_OF_BOUNDS, () => { + hero.dead = true; + }); + eventEmitter.on(Messages.HERO_SPEED_LEFT, () => { + hero.speed.x = -10; + hero.img = heroImgLeft; + }); + eventEmitter.on(Messages.HERO_SPEED_RIGHT, () => { + hero.speed.x = 10; + hero.img = heroImgRight; + }); + eventEmitter.on(Messages.HERO_SPEED_ZERO, () => { + hero.speed = { x: 0, y: 0 }; + if (game.life === 3) { + hero.img = heroImg; + } else { + hero.img = heroImgDamaged; + } + }); + eventEmitter.on(Messages.HERO_FIRE, () => { + if (coolDown === 0) { + let l = new Laser(hero.x + 45, hero.y - 30); + l.img = laserRedImg; + gameObjects.push(l); + cooling(); + } + }); + eventEmitter.on(Messages.GAME_END_LOSS, (_, gameLoopId) => { + game.end = true; + displayMessage('You died... - Press [Enter] to start the game Captain Pew Pew'); + clearInterval(gameLoopId); + }); + + eventEmitter.on(Messages.GAME_END_WIN, (_, gameLoopId) => { + game.end = true; + displayMessage('Victory!!! Pew Pew... - Press [Enter] to start a new game Captain Pew Pew', 'green'); + clearInterval(gameLoopId); + }); + eventEmitter.on(Messages.COLLISION_MONSTER_LASER, (_, { first: laser, second: monster }) => { + laser.dead = true; + monster.dead = true; + this.points += 100; + + gameObjects.push(new Explosion(monster.x, monster.y, laserRedShot)); + }); + eventEmitter.on(Messages.COLLISION_MONSTER_HERO, (_, { monster: m, id }) => { + game.life--; + if (game.life === 0) { + hero.dead = true; + eventEmitter.emit(Messages.GAME_END_LOSS, id); + gameObjects.push(new Explosion(hero.x, hero.y, laserGreenShot)); + } + hero.img = heroImgDamaged; + m.dead = true; + gameObjects.push(new Explosion(m.x, m.y, laserRedShot)); + }); + eventEmitter.on(Messages.KEY_EVENT_UP, () => { + hero.y = hero.y > 0 ? hero.y - 5 : hero.y; + }); + eventEmitter.on(Messages.KEY_EVENT_DOWN, () => { + hero.y = hero.y < HEIGHT ? hero.y + 5 : hero.y; + }); + eventEmitter.on(Messages.KEY_EVENT_LEFT, () => { + hero.x = hero.x > 0 ? hero.x - 10 : hero.x; + }); + eventEmitter.on(Messages.KEY_EVENT_RIGHT, () => { + hero.x = hero.x < WIDTH ? hero.x + 10 : hero.x; + }); + eventEmitter.on(Messages.GAME_START, () => { + if (game.ready && game.end) { + // assets loaded + runGame(); + } + }); + } +} + +const eventEmitter = new EventEmitter(); +const hero = new Hero(0, 0); +const WIDTH = 1024; +const HEIGHT = 768; +let gameObjects = []; +let laserRedImg; +let laserRedShot; +let laserGreenShot; +let canvas; +let ctx; +let heroImg; +let heroImgLeft; +let heroImgRight; +let heroImgDamaged; +let lifeImg; +let monsterImg; + +let coolDown = 0; + +const game = new Game(); + +function loadTexture(path) { + return new Promise((resolve) => { + const img = new Image(); + img.src = path; + img.onload = () => { + resolve(img); + }; + }); +} + +function rectFromGameObject(go) { + return { + top: go.y, + left: go.x, + bottom: go.y + go.height, + right: go.x + go.width, + }; +} + +function intersectRect(r1, r2) { + return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top); +} + +function draw(ctx, objects) { + objects.forEach((obj) => { + obj.draw(ctx); + }); +} + +let onKeyDown = function (e) { + console.log(e.keyCode); + switch (e.keyCode) { + case 37: + case 39: + case 38: + case 40: // Arrow keys + case 32: + e.preventDefault(); + break; // Space + default: + break; // do not block other keys + } +}; + +window.addEventListener('keydown', onKeyDown); +window.addEventListener('keydown', (e) => { + switch (e.keyCode) { + case 37: + // if left + eventEmitter.emit(Messages.HERO_SPEED_LEFT); + break; + case 39: + eventEmitter.emit(Messages.HERO_SPEED_RIGHT); + break; + } +}); + +// TODO make message driven +window.addEventListener('keyup', (evt) => { + eventEmitter.emit(Messages.HERO_SPEED_ZERO); + if (evt.key === 'ArrowUp') { + eventEmitter.emit(Messages.KEY_EVENT_UP); + } else if (evt.key === 'ArrowDown') { + eventEmitter.emit(Messages.KEY_EVENT_DOWN); + } else if (evt.key === 'ArrowLeft') { + eventEmitter.emit(Messages.KEY_EVENT_LEFT); + } else if (evt.key === 'ArrowRight') { + eventEmitter.emit(Messages.KEY_EVENT_RIGHT); + } else if (evt.keyCode === 32) { + // space + eventEmitter.emit(Messages.HERO_FIRE); + } else if (evt.key === 'Enter') { + eventEmitter.emit(Messages.GAME_START); + } +}); + +function cooling() { + coolDown = 500; + let id = setInterval(() => { + coolDown -= 100; + if (coolDown === 0) { + clearInterval(id); + } + }, 100); +} + +function displayGameScore(message) { + ctx.font = '30px Arial'; + ctx.fillStyle = 'red'; + ctx.textAlign = 'right'; + ctx.fillText(message, canvas.width - 90, canvas.height - 30); +} + +function displayLife() { + // should show tree ships.. 94 * 3 + const START_X = canvas.width - 150 - 30; + for (let i = 0; i < game.life; i++) { + ctx.drawImage(lifeImg, START_X + (i + 1) * 35, canvas.height - 90); + } +} + +function displayMessage(message, color = 'red') { + ctx.font = '30px Arial'; + ctx.fillStyle = color; + ctx.textAlign = 'center'; + ctx.fillText(message, canvas.width / 2, canvas.height / 2); +} + +function createMonsters(monsterImg) { + // 98 * 5 canvas.width - (98*5 /2) + const MONSTER_TOTAL = 5; + const MONSTER_WIDTH = MONSTER_TOTAL * 98; + const START_X = (canvas.width - MONSTER_WIDTH) / 2; + const STOP_X = START_X + MONSTER_WIDTH; + + for (let x = START_X; x < STOP_X; x += 98) { + for (let y = 0; y < 50 * 5; y += 50) { + gameObjects.push(new Monster(x, y)); + } + } + + gameObjects.forEach((go) => { + go.img = monsterImg; + }); +} + +function createHero(heroImg) { + hero.dead = false; + hero.img = heroImg; + hero.y = (canvas.height / 4) * 3; + hero.x = canvas.width / 2; + gameObjects.push(hero); +} + +function checkGameState(gameLoopId) { + const monsters = gameObjects.filter((go) => go.type === 'Monster'); + if (hero.dead) { + eventEmitter.emit(Messages.GAME_END_LOSS, gameLoopId); + } else if (monsters.length === 0) { + eventEmitter.emit(Messages.GAME_END_WIN); + } + + // update hero position + if (hero.speed.x !== 0) { + hero.x += hero.speed.x; + } + + const lasers = gameObjects.filter((go) => go.type === 'Laser'); + // laser hit something + lasers.forEach((l) => { + monsters.forEach((m) => { + if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) { + eventEmitter.emit(Messages.COLLISION_MONSTER_LASER, { + first: l, + second: m, + }); + } + }); + }); + + // hero hit monster + monsters.forEach((m) => { + if (intersectRect(m.rectFromGameObject(), hero.rectFromGameObject())) { + eventEmitter.emit(Messages.COLLISION_MONSTER_HERO, { monster: m, id: gameLoopId }); + } + }); + + gameObjects = gameObjects.filter((go) => !go.dead); +} + +function runGame() { + gameObjects = []; + game.life = 3; + game.points = 0; + game.end = false; + + createMonsters(monsterImg); + createHero(heroImg); + + let gameLoopId = setInterval(() => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + displayGameScore('Score: ' + game.points); + displayLife(); + checkGameState(gameLoopId); + draw(ctx, gameObjects); + }, 100); +} + +window.onload = async () => { + canvas = document.getElementById('myCanvas'); + ctx = canvas.getContext('2d'); + + heroImg = await loadTexture('spaceArt/png/player.png'); + heroImgLeft = await loadTexture('spaceArt/png/playerLeft.png'); + heroImgRight = await loadTexture('spaceArt/png/playerRight.png'); + heroImgDamaged = await loadTexture('spaceArt/png/playerDamaged.png'); + monsterImg = await loadTexture('spaceArt/png/enemyShip.png'); + laserRedImg = await loadTexture('spaceArt/png/laserRed.png'); + laserRedShot = await loadTexture('spaceArt/png/laserRedShot.png'); + laserGreenShot = await loadTexture('spaceArt/png/laserGreenShot.png'); + lifeImg = await loadTexture('spaceArt/png/life.png'); + + game.ready = true; + game.end = true; + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + displayMessage('Press [Enter] to start the game Captain Pew Pew', 'blue'); + + // CHECK draw 5 * 5 monsters + // CHECK move monsters down 1 step per 0.5 second + // CHECK if monster collide with hero, destroy both, display loose text + // CHECK if monster reach MAX, destroy hero, loose text + // TODO add explosion when laser hits monster, should render for <=300ms + // TODO add specific texture when moving left or right + // TODO take damage when a meteor moves into you + // TODO add meteor, meteors can damage ships + // TODO add UFO after all monsters are down, UFO can fire back + // TODO start random green laser from an enemy and have it go to HEIGHT, if collide with hero then deduct point + + // CHECK draw bullet + // CHECK , bullet should be destroyed at top + // CHECK space should produce bullet, bullet should move 2 step per second + // CHECK if bullet collide with monster, destroy both + // CHECK if bullet rect intersect with monster rect then it is colliding.. +}; diff --git a/app - Copy.js b/app - Copy.js new file mode 100644 index 00000000..05fe7d47 --- /dev/null +++ b/app - Copy.js @@ -0,0 +1,454 @@ +// @ts-check +class EventEmitter { + constructor() { + this.listeners = {}; + } + + on(message, listener) { + if (!this.listeners[message]) { + this.listeners[message] = []; + } + this.listeners[message].push(listener); + } + + emit(message, payload = null) { + if (this.listeners[message]) { + this.listeners[message].forEach((l) => l(message, payload)); + } + } +} + +class GameObject { + constructor(x, y) { + this.x = x; + this.y = y; + this.dead = false; + this.type = ''; + this.width = 0; + this.height = 0; + this.img = undefined; + } + + draw(ctx) { + ctx.drawImage(this.img, this.x, this.y, this.width, this.height); + } + + rectFromGameObject() { + return { + top: this.y, + left: this.x, + bottom: this.y + this.height, + right: this.x + this.width, + }; + } +} + +class Hero extends GameObject { + constructor(x, y) { + super(x, y); + (this.width = 99), (this.height = 75); + this.type = 'Hero'; + this.speed = { x: 0, y: 0 }; + } +} + +class Laser extends GameObject { + constructor(x, y) { + super(x, y); + this.width = 9; + this.height = 33; + this.type = 'Laser'; + let id = setInterval(() => { + if (!this.dead) { + this.y = this.y > 0 ? this.y - 20 : this.y; + if (this.y <= 0) { + this.dead = true; + } + } else { + clearInterval(id); + } + }, 100); + } +} + +class Explosion extends GameObject { + constructor(x, y, img) { + super(x, y); + this.img = img; + this.type = 'Explosion'; + (this.width = 56 * 2), (this.height = 54 * 2); + setTimeout(() => { + this.dead = true; + }, 300); + } +} + +class Monster extends GameObject { + constructor(x, y) { + super(x, y); + this.type = 'Monster'; + (this.width = 98), (this.height = 50); + let id = setInterval(() => { + if (!this.dead) { + this.y = this.y < HEIGHT ? this.y + 30 : this.y; + if (this.y >= HEIGHT - this.height) { + this.dead = true; + eventEmitter.emit('MONSTER_OUT_OF_BOUNDS'); + } + } else { + clearInterval(id); + } + }, 1500); + } +} + +const Messages = { + MONSTER_OUT_OF_BOUNDS: 'MONSTER_OUT_OF_BOUNDS', + HERO_SPEED_LEFT: 'HERO_MOVING_LEFT', + HERO_SPEED_RIGHT: 'HERO_MOVING_RIGHT', + HERO_SPEED_ZERO: 'HERO_SPEED_ZERO', + HERO_FIRE: 'HERO_FIRE', + GAME_END_LOSS: 'GAME_END_LOSS', + GAME_END_WIN: 'GAME_END_WIN', + COLLISION_MONSTER_LASER: 'COLLISION_MONSTER_LASER', + COLLISION_MONSTER_HERO: 'COLLISION_MONSTER_HERO', + KEY_EVENT_UP: 'KEY_EVENT_UP', + KEY_EVENT_DOWN: 'KEY_EVENT_DOWN', + KEY_EVENT_LEFT: 'KEY_EVENT_LEFT', + KEY_EVENT_RIGHT: 'KEY_EVENT_RIGHT', + GAME_START: 'GAME_START', +}; + +class Game { + constructor() { + this.points = 0; + this.life = 3; + this.end = false; + this.ready = false; + + eventEmitter.on(Messages.MONSTER_OUT_OF_BOUNDS, () => { + hero.dead = true; + }); + eventEmitter.on(Messages.HERO_SPEED_LEFT, () => { + hero.speed.x = -10; + hero.img = heroImgLeft; + }); + eventEmitter.on(Messages.HERO_SPEED_RIGHT, () => { + hero.speed.x = 10; + hero.img = heroImgRight; + }); + eventEmitter.on(Messages.HERO_SPEED_ZERO, () => { + hero.speed = { x: 0, y: 0 }; + if (game.life === 3) { + hero.img = heroImg; + } else { + hero.img = heroImgDamaged; + } + }); + eventEmitter.on(Messages.HERO_FIRE, () => { + if (coolDown === 0) { + let l = new Laser(hero.x + 45, hero.y - 30); + l.img = laserRedImg; + gameObjects.push(l); + cooling(); + } + }); + eventEmitter.on(Messages.GAME_END_LOSS, (_, gameLoopId) => { + game.end = true; + displayMessage('You died... - Press [Enter] to start the game Captain Pew Pew'); + clearInterval(gameLoopId); + }); + + eventEmitter.on(Messages.GAME_END_WIN, (_, gameLoopId) => { + game.end = true; + displayMessage('Victory!!! Pew Pew... - Press [Enter] to start a new game Captain Pew Pew', 'green'); + clearInterval(gameLoopId); + }); + eventEmitter.on(Messages.COLLISION_MONSTER_LASER, (_, { first: laser, second: monster }) => { + laser.dead = true; + monster.dead = true; + this.points += 100; + + gameObjects.push(new Explosion(monster.x, monster.y, laserRedShot)); + }); + eventEmitter.on(Messages.COLLISION_MONSTER_HERO, (_, { monster: m, id }) => { + game.life--; + if (game.life === 0) { + hero.dead = true; + eventEmitter.emit(Messages.GAME_END_LOSS, id); + gameObjects.push(new Explosion(hero.x, hero.y, laserGreenShot)); + } + hero.img = heroImgDamaged; + m.dead = true; + gameObjects.push(new Explosion(m.x, m.y, laserRedShot)); + }); + eventEmitter.on(Messages.KEY_EVENT_UP, () => { + hero.y = hero.y > 0 ? hero.y - 5 : hero.y; + }); + eventEmitter.on(Messages.KEY_EVENT_DOWN, () => { + hero.y = hero.y < HEIGHT ? hero.y + 5 : hero.y; + }); + eventEmitter.on(Messages.KEY_EVENT_LEFT, () => { + hero.x = hero.x > 0 ? hero.x - 10 : hero.x; + }); + eventEmitter.on(Messages.KEY_EVENT_RIGHT, () => { + hero.x = hero.x < WIDTH ? hero.x + 10 : hero.x; + }); + eventEmitter.on(Messages.GAME_START, () => { + if (game.ready && game.end) { + // assets loaded + runGame(); + } + }); + } +} + +const eventEmitter = new EventEmitter(); +const hero = new Hero(0, 0); +const WIDTH = 1024; +const HEIGHT = 768; +let gameObjects = []; +let laserRedImg; +let laserRedShot; +let laserGreenShot; +let canvas; +let ctx; +let heroImg; +let heroImgLeft; +let heroImgRight; +let heroImgDamaged; +let lifeImg; +let monsterImg; + +let coolDown = 0; + +const game = new Game(); + +function loadTexture(path) { + return new Promise((resolve) => { + const img = new Image(); + img.src = path; + img.onload = () => { + resolve(img); + }; + }); +} + +function rectFromGameObject(go) { + return { + top: go.y, + left: go.x, + bottom: go.y + go.height, + right: go.x + go.width, + }; +} + +function intersectRect(r1, r2) { + return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top); +} + +function draw(ctx, objects) { + objects.forEach((obj) => { + obj.draw(ctx); + }); +} + +let onKeyDown = function (e) { + console.log(e.keyCode); + switch (e.keyCode) { + case 37: + case 39: + case 38: + case 40: // Arrow keys + case 32: + e.preventDefault(); + break; // Space + default: + break; // do not block other keys + } +}; + +window.addEventListener('keydown', onKeyDown); +window.addEventListener('keydown', (e) => { + switch (e.keyCode) { + case 37: + // if left + eventEmitter.emit(Messages.HERO_SPEED_LEFT); + break; + case 39: + eventEmitter.emit(Messages.HERO_SPEED_RIGHT); + break; + } +}); + +// TODO make message driven +window.addEventListener('keyup', (evt) => { + eventEmitter.emit(Messages.HERO_SPEED_ZERO); + if (evt.key === 'ArrowUp') { + eventEmitter.emit(Messages.KEY_EVENT_UP); + } else if (evt.key === 'ArrowDown') { + eventEmitter.emit(Messages.KEY_EVENT_DOWN); + } else if (evt.key === 'ArrowLeft') { + eventEmitter.emit(Messages.KEY_EVENT_LEFT); + } else if (evt.key === 'ArrowRight') { + eventEmitter.emit(Messages.KEY_EVENT_RIGHT); + } else if (evt.keyCode === 32) { + // space + eventEmitter.emit(Messages.HERO_FIRE); + } else if (evt.key === 'Enter') { + eventEmitter.emit(Messages.GAME_START); + } +}); + +function cooling() { + coolDown = 500; + let id = setInterval(() => { + coolDown -= 100; + if (coolDown === 0) { + clearInterval(id); + } + }, 100); +} + +function displayGameScore(message) { + ctx.font = '30px Arial'; + ctx.fillStyle = 'red'; + ctx.textAlign = 'right'; + ctx.fillText(message, canvas.width - 90, canvas.height - 30); +} + +function displayLife() { + // should show tree ships.. 94 * 3 + const START_X = canvas.width - 150 - 30; + for (let i = 0; i < game.life; i++) { + ctx.drawImage(lifeImg, START_X + (i + 1) * 35, canvas.height - 90); + } +} + +function displayMessage(message, color = 'red') { + ctx.font = '30px Arial'; + ctx.fillStyle = color; + ctx.textAlign = 'center'; + ctx.fillText(message, canvas.width / 2, canvas.height / 2); +} + +function createMonsters(monsterImg) { + // 98 * 5 canvas.width - (98*5 /2) + const MONSTER_TOTAL = 5; + const MONSTER_WIDTH = MONSTER_TOTAL * 98; + const START_X = (canvas.width - MONSTER_WIDTH) / 2; + const STOP_X = START_X + MONSTER_WIDTH; + + for (let x = START_X; x < STOP_X; x += 98) { + for (let y = 0; y < 50 * 5; y += 50) { + gameObjects.push(new Monster(x, y)); + } + } + + gameObjects.forEach((go) => { + go.img = monsterImg; + }); +} + +function createHero(heroImg) { + hero.dead = false; + hero.img = heroImg; + hero.y = (canvas.height / 4) * 3; + hero.x = canvas.width / 2; + gameObjects.push(hero); +} + +function checkGameState(gameLoopId) { + const monsters = gameObjects.filter((go) => go.type === 'Monster'); + if (hero.dead) { + eventEmitter.emit(Messages.GAME_END_LOSS, gameLoopId); + } else if (monsters.length === 0) { + eventEmitter.emit(Messages.GAME_END_WIN); + } + + // update hero position + if (hero.speed.x !== 0) { + hero.x += hero.speed.x; + } + + const lasers = gameObjects.filter((go) => go.type === 'Laser'); + // laser hit something + lasers.forEach((l) => { + monsters.forEach((m) => { + if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) { + eventEmitter.emit(Messages.COLLISION_MONSTER_LASER, { + first: l, + second: m, + }); + } + }); + }); + + // hero hit monster + monsters.forEach((m) => { + if (intersectRect(m.rectFromGameObject(), hero.rectFromGameObject())) { + eventEmitter.emit(Messages.COLLISION_MONSTER_HERO, { monster: m, id: gameLoopId }); + } + }); + + gameObjects = gameObjects.filter((go) => !go.dead); +} + +function runGame() { + gameObjects = []; + game.life = 3; + game.points = 0; + game.end = false; + + createMonsters(monsterImg); + createHero(heroImg); + + let gameLoopId = setInterval(() => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + displayGameScore('Score: ' + game.points); + displayLife(); + checkGameState(gameLoopId); + draw(ctx, gameObjects); + }, 100); +} + +window.onload = async () => { + canvas = document.getElementById('myCanvas'); + ctx = canvas.getContext('2d'); + + heroImg = await loadTexture('spaceArt/png/player.png'); + heroImgLeft = await loadTexture('spaceArt/png/playerLeft.png'); + heroImgRight = await loadTexture('spaceArt/png/playerRight.png'); + heroImgDamaged = await loadTexture('spaceArt/png/playerDamaged.png'); + monsterImg = await loadTexture('spaceArt/png/enemyShip.png'); + laserRedImg = await loadTexture('spaceArt/png/laserRed.png'); + laserRedShot = await loadTexture('spaceArt/png/laserRedShot.png'); + laserGreenShot = await loadTexture('spaceArt/png/laserGreenShot.png'); + lifeImg = await loadTexture('spaceArt/png/life.png'); + + game.ready = true; + game.end = true; + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + displayMessage('Press [Enter] to start the game Captain Pew Pew', 'blue'); + + // CHECK draw 5 * 5 monsters + // CHECK move monsters down 1 step per 0.5 second + // CHECK if monster collide with hero, destroy both, display loose text + // CHECK if monster reach MAX, destroy hero, loose text + // TODO add explosion when laser hits monster, should render for <=300ms + // TODO add specific texture when moving left or right + // TODO take damage when a meteor moves into you + // TODO add meteor, meteors can damage ships + // TODO add UFO after all monsters are down, UFO can fire back + // TODO start random green laser from an enemy and have it go to HEIGHT, if collide with hero then deduct point + + // CHECK draw bullet + // CHECK , bullet should be destroyed at top + // CHECK space should produce bullet, bullet should move 2 step per second + // CHECK if bullet collide with monster, destroy both + // CHECK if bullet rect intersect with monster rect then it is colliding.. +}; diff --git a/app.js b/app.js new file mode 100644 index 00000000..05fe7d47 --- /dev/null +++ b/app.js @@ -0,0 +1,454 @@ +// @ts-check +class EventEmitter { + constructor() { + this.listeners = {}; + } + + on(message, listener) { + if (!this.listeners[message]) { + this.listeners[message] = []; + } + this.listeners[message].push(listener); + } + + emit(message, payload = null) { + if (this.listeners[message]) { + this.listeners[message].forEach((l) => l(message, payload)); + } + } +} + +class GameObject { + constructor(x, y) { + this.x = x; + this.y = y; + this.dead = false; + this.type = ''; + this.width = 0; + this.height = 0; + this.img = undefined; + } + + draw(ctx) { + ctx.drawImage(this.img, this.x, this.y, this.width, this.height); + } + + rectFromGameObject() { + return { + top: this.y, + left: this.x, + bottom: this.y + this.height, + right: this.x + this.width, + }; + } +} + +class Hero extends GameObject { + constructor(x, y) { + super(x, y); + (this.width = 99), (this.height = 75); + this.type = 'Hero'; + this.speed = { x: 0, y: 0 }; + } +} + +class Laser extends GameObject { + constructor(x, y) { + super(x, y); + this.width = 9; + this.height = 33; + this.type = 'Laser'; + let id = setInterval(() => { + if (!this.dead) { + this.y = this.y > 0 ? this.y - 20 : this.y; + if (this.y <= 0) { + this.dead = true; + } + } else { + clearInterval(id); + } + }, 100); + } +} + +class Explosion extends GameObject { + constructor(x, y, img) { + super(x, y); + this.img = img; + this.type = 'Explosion'; + (this.width = 56 * 2), (this.height = 54 * 2); + setTimeout(() => { + this.dead = true; + }, 300); + } +} + +class Monster extends GameObject { + constructor(x, y) { + super(x, y); + this.type = 'Monster'; + (this.width = 98), (this.height = 50); + let id = setInterval(() => { + if (!this.dead) { + this.y = this.y < HEIGHT ? this.y + 30 : this.y; + if (this.y >= HEIGHT - this.height) { + this.dead = true; + eventEmitter.emit('MONSTER_OUT_OF_BOUNDS'); + } + } else { + clearInterval(id); + } + }, 1500); + } +} + +const Messages = { + MONSTER_OUT_OF_BOUNDS: 'MONSTER_OUT_OF_BOUNDS', + HERO_SPEED_LEFT: 'HERO_MOVING_LEFT', + HERO_SPEED_RIGHT: 'HERO_MOVING_RIGHT', + HERO_SPEED_ZERO: 'HERO_SPEED_ZERO', + HERO_FIRE: 'HERO_FIRE', + GAME_END_LOSS: 'GAME_END_LOSS', + GAME_END_WIN: 'GAME_END_WIN', + COLLISION_MONSTER_LASER: 'COLLISION_MONSTER_LASER', + COLLISION_MONSTER_HERO: 'COLLISION_MONSTER_HERO', + KEY_EVENT_UP: 'KEY_EVENT_UP', + KEY_EVENT_DOWN: 'KEY_EVENT_DOWN', + KEY_EVENT_LEFT: 'KEY_EVENT_LEFT', + KEY_EVENT_RIGHT: 'KEY_EVENT_RIGHT', + GAME_START: 'GAME_START', +}; + +class Game { + constructor() { + this.points = 0; + this.life = 3; + this.end = false; + this.ready = false; + + eventEmitter.on(Messages.MONSTER_OUT_OF_BOUNDS, () => { + hero.dead = true; + }); + eventEmitter.on(Messages.HERO_SPEED_LEFT, () => { + hero.speed.x = -10; + hero.img = heroImgLeft; + }); + eventEmitter.on(Messages.HERO_SPEED_RIGHT, () => { + hero.speed.x = 10; + hero.img = heroImgRight; + }); + eventEmitter.on(Messages.HERO_SPEED_ZERO, () => { + hero.speed = { x: 0, y: 0 }; + if (game.life === 3) { + hero.img = heroImg; + } else { + hero.img = heroImgDamaged; + } + }); + eventEmitter.on(Messages.HERO_FIRE, () => { + if (coolDown === 0) { + let l = new Laser(hero.x + 45, hero.y - 30); + l.img = laserRedImg; + gameObjects.push(l); + cooling(); + } + }); + eventEmitter.on(Messages.GAME_END_LOSS, (_, gameLoopId) => { + game.end = true; + displayMessage('You died... - Press [Enter] to start the game Captain Pew Pew'); + clearInterval(gameLoopId); + }); + + eventEmitter.on(Messages.GAME_END_WIN, (_, gameLoopId) => { + game.end = true; + displayMessage('Victory!!! Pew Pew... - Press [Enter] to start a new game Captain Pew Pew', 'green'); + clearInterval(gameLoopId); + }); + eventEmitter.on(Messages.COLLISION_MONSTER_LASER, (_, { first: laser, second: monster }) => { + laser.dead = true; + monster.dead = true; + this.points += 100; + + gameObjects.push(new Explosion(monster.x, monster.y, laserRedShot)); + }); + eventEmitter.on(Messages.COLLISION_MONSTER_HERO, (_, { monster: m, id }) => { + game.life--; + if (game.life === 0) { + hero.dead = true; + eventEmitter.emit(Messages.GAME_END_LOSS, id); + gameObjects.push(new Explosion(hero.x, hero.y, laserGreenShot)); + } + hero.img = heroImgDamaged; + m.dead = true; + gameObjects.push(new Explosion(m.x, m.y, laserRedShot)); + }); + eventEmitter.on(Messages.KEY_EVENT_UP, () => { + hero.y = hero.y > 0 ? hero.y - 5 : hero.y; + }); + eventEmitter.on(Messages.KEY_EVENT_DOWN, () => { + hero.y = hero.y < HEIGHT ? hero.y + 5 : hero.y; + }); + eventEmitter.on(Messages.KEY_EVENT_LEFT, () => { + hero.x = hero.x > 0 ? hero.x - 10 : hero.x; + }); + eventEmitter.on(Messages.KEY_EVENT_RIGHT, () => { + hero.x = hero.x < WIDTH ? hero.x + 10 : hero.x; + }); + eventEmitter.on(Messages.GAME_START, () => { + if (game.ready && game.end) { + // assets loaded + runGame(); + } + }); + } +} + +const eventEmitter = new EventEmitter(); +const hero = new Hero(0, 0); +const WIDTH = 1024; +const HEIGHT = 768; +let gameObjects = []; +let laserRedImg; +let laserRedShot; +let laserGreenShot; +let canvas; +let ctx; +let heroImg; +let heroImgLeft; +let heroImgRight; +let heroImgDamaged; +let lifeImg; +let monsterImg; + +let coolDown = 0; + +const game = new Game(); + +function loadTexture(path) { + return new Promise((resolve) => { + const img = new Image(); + img.src = path; + img.onload = () => { + resolve(img); + }; + }); +} + +function rectFromGameObject(go) { + return { + top: go.y, + left: go.x, + bottom: go.y + go.height, + right: go.x + go.width, + }; +} + +function intersectRect(r1, r2) { + return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top); +} + +function draw(ctx, objects) { + objects.forEach((obj) => { + obj.draw(ctx); + }); +} + +let onKeyDown = function (e) { + console.log(e.keyCode); + switch (e.keyCode) { + case 37: + case 39: + case 38: + case 40: // Arrow keys + case 32: + e.preventDefault(); + break; // Space + default: + break; // do not block other keys + } +}; + +window.addEventListener('keydown', onKeyDown); +window.addEventListener('keydown', (e) => { + switch (e.keyCode) { + case 37: + // if left + eventEmitter.emit(Messages.HERO_SPEED_LEFT); + break; + case 39: + eventEmitter.emit(Messages.HERO_SPEED_RIGHT); + break; + } +}); + +// TODO make message driven +window.addEventListener('keyup', (evt) => { + eventEmitter.emit(Messages.HERO_SPEED_ZERO); + if (evt.key === 'ArrowUp') { + eventEmitter.emit(Messages.KEY_EVENT_UP); + } else if (evt.key === 'ArrowDown') { + eventEmitter.emit(Messages.KEY_EVENT_DOWN); + } else if (evt.key === 'ArrowLeft') { + eventEmitter.emit(Messages.KEY_EVENT_LEFT); + } else if (evt.key === 'ArrowRight') { + eventEmitter.emit(Messages.KEY_EVENT_RIGHT); + } else if (evt.keyCode === 32) { + // space + eventEmitter.emit(Messages.HERO_FIRE); + } else if (evt.key === 'Enter') { + eventEmitter.emit(Messages.GAME_START); + } +}); + +function cooling() { + coolDown = 500; + let id = setInterval(() => { + coolDown -= 100; + if (coolDown === 0) { + clearInterval(id); + } + }, 100); +} + +function displayGameScore(message) { + ctx.font = '30px Arial'; + ctx.fillStyle = 'red'; + ctx.textAlign = 'right'; + ctx.fillText(message, canvas.width - 90, canvas.height - 30); +} + +function displayLife() { + // should show tree ships.. 94 * 3 + const START_X = canvas.width - 150 - 30; + for (let i = 0; i < game.life; i++) { + ctx.drawImage(lifeImg, START_X + (i + 1) * 35, canvas.height - 90); + } +} + +function displayMessage(message, color = 'red') { + ctx.font = '30px Arial'; + ctx.fillStyle = color; + ctx.textAlign = 'center'; + ctx.fillText(message, canvas.width / 2, canvas.height / 2); +} + +function createMonsters(monsterImg) { + // 98 * 5 canvas.width - (98*5 /2) + const MONSTER_TOTAL = 5; + const MONSTER_WIDTH = MONSTER_TOTAL * 98; + const START_X = (canvas.width - MONSTER_WIDTH) / 2; + const STOP_X = START_X + MONSTER_WIDTH; + + for (let x = START_X; x < STOP_X; x += 98) { + for (let y = 0; y < 50 * 5; y += 50) { + gameObjects.push(new Monster(x, y)); + } + } + + gameObjects.forEach((go) => { + go.img = monsterImg; + }); +} + +function createHero(heroImg) { + hero.dead = false; + hero.img = heroImg; + hero.y = (canvas.height / 4) * 3; + hero.x = canvas.width / 2; + gameObjects.push(hero); +} + +function checkGameState(gameLoopId) { + const monsters = gameObjects.filter((go) => go.type === 'Monster'); + if (hero.dead) { + eventEmitter.emit(Messages.GAME_END_LOSS, gameLoopId); + } else if (monsters.length === 0) { + eventEmitter.emit(Messages.GAME_END_WIN); + } + + // update hero position + if (hero.speed.x !== 0) { + hero.x += hero.speed.x; + } + + const lasers = gameObjects.filter((go) => go.type === 'Laser'); + // laser hit something + lasers.forEach((l) => { + monsters.forEach((m) => { + if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) { + eventEmitter.emit(Messages.COLLISION_MONSTER_LASER, { + first: l, + second: m, + }); + } + }); + }); + + // hero hit monster + monsters.forEach((m) => { + if (intersectRect(m.rectFromGameObject(), hero.rectFromGameObject())) { + eventEmitter.emit(Messages.COLLISION_MONSTER_HERO, { monster: m, id: gameLoopId }); + } + }); + + gameObjects = gameObjects.filter((go) => !go.dead); +} + +function runGame() { + gameObjects = []; + game.life = 3; + game.points = 0; + game.end = false; + + createMonsters(monsterImg); + createHero(heroImg); + + let gameLoopId = setInterval(() => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + displayGameScore('Score: ' + game.points); + displayLife(); + checkGameState(gameLoopId); + draw(ctx, gameObjects); + }, 100); +} + +window.onload = async () => { + canvas = document.getElementById('myCanvas'); + ctx = canvas.getContext('2d'); + + heroImg = await loadTexture('spaceArt/png/player.png'); + heroImgLeft = await loadTexture('spaceArt/png/playerLeft.png'); + heroImgRight = await loadTexture('spaceArt/png/playerRight.png'); + heroImgDamaged = await loadTexture('spaceArt/png/playerDamaged.png'); + monsterImg = await loadTexture('spaceArt/png/enemyShip.png'); + laserRedImg = await loadTexture('spaceArt/png/laserRed.png'); + laserRedShot = await loadTexture('spaceArt/png/laserRedShot.png'); + laserGreenShot = await loadTexture('spaceArt/png/laserGreenShot.png'); + lifeImg = await loadTexture('spaceArt/png/life.png'); + + game.ready = true; + game.end = true; + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + displayMessage('Press [Enter] to start the game Captain Pew Pew', 'blue'); + + // CHECK draw 5 * 5 monsters + // CHECK move monsters down 1 step per 0.5 second + // CHECK if monster collide with hero, destroy both, display loose text + // CHECK if monster reach MAX, destroy hero, loose text + // TODO add explosion when laser hits monster, should render for <=300ms + // TODO add specific texture when moving left or right + // TODO take damage when a meteor moves into you + // TODO add meteor, meteors can damage ships + // TODO add UFO after all monsters are down, UFO can fire back + // TODO start random green laser from an enemy and have it go to HEIGHT, if collide with hero then deduct point + + // CHECK draw bullet + // CHECK , bullet should be destroyed at top + // CHECK space should produce bullet, bullet should move 2 step per second + // CHECK if bullet collide with monster, destroy both + // CHECK if bullet rect intersect with monster rect then it is colliding.. +}; diff --git a/background - Copy (2).js b/background - Copy (2).js new file mode 100644 index 00000000..ef6ddb57 --- /dev/null +++ b/background - Copy (2).js @@ -0,0 +1,4 @@ +//add listener here + +//borrowed from energy lollipop extension +//draw the icon here diff --git a/background - Copy (3).js b/background - Copy (3).js new file mode 100644 index 00000000..ef6ddb57 --- /dev/null +++ b/background - Copy (3).js @@ -0,0 +1,4 @@ +//add listener here + +//borrowed from energy lollipop extension +//draw the icon here diff --git a/background - Copy (4).js b/background - Copy (4).js new file mode 100644 index 00000000..ef6ddb57 --- /dev/null +++ b/background - Copy (4).js @@ -0,0 +1,4 @@ +//add listener here + +//borrowed from energy lollipop extension +//draw the icon here diff --git a/background - Copy.js b/background - Copy.js new file mode 100644 index 00000000..ef6ddb57 --- /dev/null +++ b/background - Copy.js @@ -0,0 +1,4 @@ +//add listener here + +//borrowed from energy lollipop extension +//draw the icon here diff --git a/background.js b/background.js new file mode 100644 index 00000000..ef6ddb57 --- /dev/null +++ b/background.js @@ -0,0 +1,4 @@ +//add listener here + +//borrowed from energy lollipop extension +//draw the icon here diff --git a/index - Copy (2).js b/index - Copy (2).js new file mode 100644 index 00000000..562a80f3 --- /dev/null +++ b/index - Copy (2).js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import Router from 'vue-router'; +import Home from '@/views/Home.vue'; +import Quiz from '@/components/Quiz.vue'; +import NotFound from '@/views/NotFound.vue'; +Vue.use(Router); + +const router = new Router({ + mode: 'history', + base: process.env.BASE_URL, + routes: [ + { + path: '/', + name: 'home', + component: Home, + }, + { + path: '/quiz/:id', + name: 'Quiz', + component: Quiz, + }, + { + path: '/:pathMatch(.*)*', + name: 'NotFound', + component: NotFound, + meta: { title: 'Not Found' }, + }, + ], +}); + +router.beforeEach((to, from, next) => { + next(); +}); +export default router; diff --git a/index - Copy (3).js b/index - Copy (3).js new file mode 100644 index 00000000..562a80f3 --- /dev/null +++ b/index - Copy (3).js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import Router from 'vue-router'; +import Home from '@/views/Home.vue'; +import Quiz from '@/components/Quiz.vue'; +import NotFound from '@/views/NotFound.vue'; +Vue.use(Router); + +const router = new Router({ + mode: 'history', + base: process.env.BASE_URL, + routes: [ + { + path: '/', + name: 'home', + component: Home, + }, + { + path: '/quiz/:id', + name: 'Quiz', + component: Quiz, + }, + { + path: '/:pathMatch(.*)*', + name: 'NotFound', + component: NotFound, + meta: { title: 'Not Found' }, + }, + ], +}); + +router.beforeEach((to, from, next) => { + next(); +}); +export default router; diff --git a/index - Copy (4).js b/index - Copy (4).js new file mode 100644 index 00000000..562a80f3 --- /dev/null +++ b/index - Copy (4).js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import Router from 'vue-router'; +import Home from '@/views/Home.vue'; +import Quiz from '@/components/Quiz.vue'; +import NotFound from '@/views/NotFound.vue'; +Vue.use(Router); + +const router = new Router({ + mode: 'history', + base: process.env.BASE_URL, + routes: [ + { + path: '/', + name: 'home', + component: Home, + }, + { + path: '/quiz/:id', + name: 'Quiz', + component: Quiz, + }, + { + path: '/:pathMatch(.*)*', + name: 'NotFound', + component: NotFound, + meta: { title: 'Not Found' }, + }, + ], +}); + +router.beforeEach((to, from, next) => { + next(); +}); +export default router; diff --git a/index - Copy.js b/index - Copy.js new file mode 100644 index 00000000..562a80f3 --- /dev/null +++ b/index - Copy.js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import Router from 'vue-router'; +import Home from '@/views/Home.vue'; +import Quiz from '@/components/Quiz.vue'; +import NotFound from '@/views/NotFound.vue'; +Vue.use(Router); + +const router = new Router({ + mode: 'history', + base: process.env.BASE_URL, + routes: [ + { + path: '/', + name: 'home', + component: Home, + }, + { + path: '/quiz/:id', + name: 'Quiz', + component: Quiz, + }, + { + path: '/:pathMatch(.*)*', + name: 'NotFound', + component: NotFound, + meta: { title: 'Not Found' }, + }, + ], +}); + +router.beforeEach((to, from, next) => { + next(); +}); +export default router; diff --git a/index.js b/index.js new file mode 100644 index 00000000..562a80f3 --- /dev/null +++ b/index.js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import Router from 'vue-router'; +import Home from '@/views/Home.vue'; +import Quiz from '@/components/Quiz.vue'; +import NotFound from '@/views/NotFound.vue'; +Vue.use(Router); + +const router = new Router({ + mode: 'history', + base: process.env.BASE_URL, + routes: [ + { + path: '/', + name: 'home', + component: Home, + }, + { + path: '/quiz/:id', + name: 'Quiz', + component: Quiz, + }, + { + path: '/:pathMatch(.*)*', + name: 'NotFound', + component: NotFound, + meta: { title: 'Not Found' }, + }, + ], +}); + +router.beforeEach((to, from, next) => { + next(); +}); +export default router; diff --git a/script - Copy (2).js b/script - Copy (2).js new file mode 100644 index 00000000..cc3950b0 --- /dev/null +++ b/script - Copy (2).js @@ -0,0 +1,64 @@ +/*The solution to draggable elements was inspired by w3schools solution on creating a [Draggable HTML Element](https://www.w3schools.com/howto/howto_js_draggable.asp).*/ + +dragElement(document.getElementById('plant1')); +dragElement(document.getElementById('plant2')); +dragElement(document.getElementById('plant3')); +dragElement(document.getElementById('plant4')); +dragElement(document.getElementById('plant5')); +dragElement(document.getElementById('plant6')); +dragElement(document.getElementById('plant7')); +dragElement(document.getElementById('plant8')); +dragElement(document.getElementById('plant9')); +dragElement(document.getElementById('plant10')); +dragElement(document.getElementById('plant11')); +dragElement(document.getElementById('plant12')); +dragElement(document.getElementById('plant13')); +dragElement(document.getElementById('plant14')); + +/*"A closure is the combination of a function bundled together (enclosed) +with references to its surrounding state (the lexical environment). +In other words, a closure gives you access to an outer function’s scope +from an inner function." Create a closure so that you can track the dragged element*/ + +function dragElement(terrariumElement) { + //set 4 positions for positioning on the screen + let pos1 = 0, + pos2 = 0, + pos3 = 0, + pos4 = 0; + terrariumElement.onpointerdown = pointerDrag; + + function pointerDrag(e) { + e.preventDefault(); + console.log(e); + // get the initial mouse cursor position for pos3 and pos4 + pos3 = e.clientX; + pos4 = e.clientY; + // when the mouse moves, start the drag + document.onpointermove = elementDrag; + // when the mouse is lifted, stop the drag + document.onpointerup = stopElementDrag; + } + + function elementDrag(e) { + // calculate the new cursor position + // pos1 = where the Xmouse WAS - where it IS + pos1 = pos3 - e.clientX; + // pos2 = where the Ymouse WAS - where it IS + pos2 = pos4 - e.clientY; + //reset pos3 to current location of Xmouse + pos3 = e.clientX; + //reset pos4 to current location of Ymouse + pos4 = e.clientY; + console.log(pos1, pos2, pos3, pos4); + // set the element's new position: + terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px'; + terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px'; + } + + function stopElementDrag() { + // stop calculating when mouse is released + document.onpointerup = null; + document.onpointermove = null; + } +} diff --git a/script - Copy (3).js b/script - Copy (3).js new file mode 100644 index 00000000..cc3950b0 --- /dev/null +++ b/script - Copy (3).js @@ -0,0 +1,64 @@ +/*The solution to draggable elements was inspired by w3schools solution on creating a [Draggable HTML Element](https://www.w3schools.com/howto/howto_js_draggable.asp).*/ + +dragElement(document.getElementById('plant1')); +dragElement(document.getElementById('plant2')); +dragElement(document.getElementById('plant3')); +dragElement(document.getElementById('plant4')); +dragElement(document.getElementById('plant5')); +dragElement(document.getElementById('plant6')); +dragElement(document.getElementById('plant7')); +dragElement(document.getElementById('plant8')); +dragElement(document.getElementById('plant9')); +dragElement(document.getElementById('plant10')); +dragElement(document.getElementById('plant11')); +dragElement(document.getElementById('plant12')); +dragElement(document.getElementById('plant13')); +dragElement(document.getElementById('plant14')); + +/*"A closure is the combination of a function bundled together (enclosed) +with references to its surrounding state (the lexical environment). +In other words, a closure gives you access to an outer function’s scope +from an inner function." Create a closure so that you can track the dragged element*/ + +function dragElement(terrariumElement) { + //set 4 positions for positioning on the screen + let pos1 = 0, + pos2 = 0, + pos3 = 0, + pos4 = 0; + terrariumElement.onpointerdown = pointerDrag; + + function pointerDrag(e) { + e.preventDefault(); + console.log(e); + // get the initial mouse cursor position for pos3 and pos4 + pos3 = e.clientX; + pos4 = e.clientY; + // when the mouse moves, start the drag + document.onpointermove = elementDrag; + // when the mouse is lifted, stop the drag + document.onpointerup = stopElementDrag; + } + + function elementDrag(e) { + // calculate the new cursor position + // pos1 = where the Xmouse WAS - where it IS + pos1 = pos3 - e.clientX; + // pos2 = where the Ymouse WAS - where it IS + pos2 = pos4 - e.clientY; + //reset pos3 to current location of Xmouse + pos3 = e.clientX; + //reset pos4 to current location of Ymouse + pos4 = e.clientY; + console.log(pos1, pos2, pos3, pos4); + // set the element's new position: + terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px'; + terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px'; + } + + function stopElementDrag() { + // stop calculating when mouse is released + document.onpointerup = null; + document.onpointermove = null; + } +} diff --git a/script - Copy (4).js b/script - Copy (4).js new file mode 100644 index 00000000..cc3950b0 --- /dev/null +++ b/script - Copy (4).js @@ -0,0 +1,64 @@ +/*The solution to draggable elements was inspired by w3schools solution on creating a [Draggable HTML Element](https://www.w3schools.com/howto/howto_js_draggable.asp).*/ + +dragElement(document.getElementById('plant1')); +dragElement(document.getElementById('plant2')); +dragElement(document.getElementById('plant3')); +dragElement(document.getElementById('plant4')); +dragElement(document.getElementById('plant5')); +dragElement(document.getElementById('plant6')); +dragElement(document.getElementById('plant7')); +dragElement(document.getElementById('plant8')); +dragElement(document.getElementById('plant9')); +dragElement(document.getElementById('plant10')); +dragElement(document.getElementById('plant11')); +dragElement(document.getElementById('plant12')); +dragElement(document.getElementById('plant13')); +dragElement(document.getElementById('plant14')); + +/*"A closure is the combination of a function bundled together (enclosed) +with references to its surrounding state (the lexical environment). +In other words, a closure gives you access to an outer function’s scope +from an inner function." Create a closure so that you can track the dragged element*/ + +function dragElement(terrariumElement) { + //set 4 positions for positioning on the screen + let pos1 = 0, + pos2 = 0, + pos3 = 0, + pos4 = 0; + terrariumElement.onpointerdown = pointerDrag; + + function pointerDrag(e) { + e.preventDefault(); + console.log(e); + // get the initial mouse cursor position for pos3 and pos4 + pos3 = e.clientX; + pos4 = e.clientY; + // when the mouse moves, start the drag + document.onpointermove = elementDrag; + // when the mouse is lifted, stop the drag + document.onpointerup = stopElementDrag; + } + + function elementDrag(e) { + // calculate the new cursor position + // pos1 = where the Xmouse WAS - where it IS + pos1 = pos3 - e.clientX; + // pos2 = where the Ymouse WAS - where it IS + pos2 = pos4 - e.clientY; + //reset pos3 to current location of Xmouse + pos3 = e.clientX; + //reset pos4 to current location of Ymouse + pos4 = e.clientY; + console.log(pos1, pos2, pos3, pos4); + // set the element's new position: + terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px'; + terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px'; + } + + function stopElementDrag() { + // stop calculating when mouse is released + document.onpointerup = null; + document.onpointermove = null; + } +} diff --git a/script - Copy.js b/script - Copy.js new file mode 100644 index 00000000..cc3950b0 --- /dev/null +++ b/script - Copy.js @@ -0,0 +1,64 @@ +/*The solution to draggable elements was inspired by w3schools solution on creating a [Draggable HTML Element](https://www.w3schools.com/howto/howto_js_draggable.asp).*/ + +dragElement(document.getElementById('plant1')); +dragElement(document.getElementById('plant2')); +dragElement(document.getElementById('plant3')); +dragElement(document.getElementById('plant4')); +dragElement(document.getElementById('plant5')); +dragElement(document.getElementById('plant6')); +dragElement(document.getElementById('plant7')); +dragElement(document.getElementById('plant8')); +dragElement(document.getElementById('plant9')); +dragElement(document.getElementById('plant10')); +dragElement(document.getElementById('plant11')); +dragElement(document.getElementById('plant12')); +dragElement(document.getElementById('plant13')); +dragElement(document.getElementById('plant14')); + +/*"A closure is the combination of a function bundled together (enclosed) +with references to its surrounding state (the lexical environment). +In other words, a closure gives you access to an outer function’s scope +from an inner function." Create a closure so that you can track the dragged element*/ + +function dragElement(terrariumElement) { + //set 4 positions for positioning on the screen + let pos1 = 0, + pos2 = 0, + pos3 = 0, + pos4 = 0; + terrariumElement.onpointerdown = pointerDrag; + + function pointerDrag(e) { + e.preventDefault(); + console.log(e); + // get the initial mouse cursor position for pos3 and pos4 + pos3 = e.clientX; + pos4 = e.clientY; + // when the mouse moves, start the drag + document.onpointermove = elementDrag; + // when the mouse is lifted, stop the drag + document.onpointerup = stopElementDrag; + } + + function elementDrag(e) { + // calculate the new cursor position + // pos1 = where the Xmouse WAS - where it IS + pos1 = pos3 - e.clientX; + // pos2 = where the Ymouse WAS - where it IS + pos2 = pos4 - e.clientY; + //reset pos3 to current location of Xmouse + pos3 = e.clientX; + //reset pos4 to current location of Ymouse + pos4 = e.clientY; + console.log(pos1, pos2, pos3, pos4); + // set the element's new position: + terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px'; + terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px'; + } + + function stopElementDrag() { + // stop calculating when mouse is released + document.onpointerup = null; + document.onpointermove = null; + } +} diff --git a/script.js b/script.js new file mode 100644 index 00000000..cc3950b0 --- /dev/null +++ b/script.js @@ -0,0 +1,64 @@ +/*The solution to draggable elements was inspired by w3schools solution on creating a [Draggable HTML Element](https://www.w3schools.com/howto/howto_js_draggable.asp).*/ + +dragElement(document.getElementById('plant1')); +dragElement(document.getElementById('plant2')); +dragElement(document.getElementById('plant3')); +dragElement(document.getElementById('plant4')); +dragElement(document.getElementById('plant5')); +dragElement(document.getElementById('plant6')); +dragElement(document.getElementById('plant7')); +dragElement(document.getElementById('plant8')); +dragElement(document.getElementById('plant9')); +dragElement(document.getElementById('plant10')); +dragElement(document.getElementById('plant11')); +dragElement(document.getElementById('plant12')); +dragElement(document.getElementById('plant13')); +dragElement(document.getElementById('plant14')); + +/*"A closure is the combination of a function bundled together (enclosed) +with references to its surrounding state (the lexical environment). +In other words, a closure gives you access to an outer function’s scope +from an inner function." Create a closure so that you can track the dragged element*/ + +function dragElement(terrariumElement) { + //set 4 positions for positioning on the screen + let pos1 = 0, + pos2 = 0, + pos3 = 0, + pos4 = 0; + terrariumElement.onpointerdown = pointerDrag; + + function pointerDrag(e) { + e.preventDefault(); + console.log(e); + // get the initial mouse cursor position for pos3 and pos4 + pos3 = e.clientX; + pos4 = e.clientY; + // when the mouse moves, start the drag + document.onpointermove = elementDrag; + // when the mouse is lifted, stop the drag + document.onpointerup = stopElementDrag; + } + + function elementDrag(e) { + // calculate the new cursor position + // pos1 = where the Xmouse WAS - where it IS + pos1 = pos3 - e.clientX; + // pos2 = where the Ymouse WAS - where it IS + pos2 = pos4 - e.clientY; + //reset pos3 to current location of Xmouse + pos3 = e.clientX; + //reset pos4 to current location of Ymouse + pos4 = e.clientY; + console.log(pos1, pos2, pos3, pos4); + // set the element's new position: + terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px'; + terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px'; + } + + function stopElementDrag() { + // stop calculating when mouse is released + document.onpointerup = null; + document.onpointermove = null; + } +}