summaryrefslogtreecommitdiff
path: root/centipede/js/game/objects
diff options
context:
space:
mode:
Diffstat (limited to 'centipede/js/game/objects')
-rw-r--r--centipede/js/game/objects/bullet.js11
-rw-r--r--centipede/js/game/objects/centipede.js105
-rw-r--r--centipede/js/game/objects/explosion.js14
-rw-r--r--centipede/js/game/objects/flea.js49
-rw-r--r--centipede/js/game/objects/mushroom.js43
-rw-r--r--centipede/js/game/objects/player.js63
-rw-r--r--centipede/js/game/objects/scorpion.js32
-rw-r--r--centipede/js/game/objects/spider.js45
8 files changed, 362 insertions, 0 deletions
diff --git a/centipede/js/game/objects/bullet.js b/centipede/js/game/objects/bullet.js
new file mode 100644
index 0000000..5791aca
--- /dev/null
+++ b/centipede/js/game/objects/bullet.js
@@ -0,0 +1,11 @@
+game.Bullet = (spec) => {
+ const object = game.Object(spec);
+ const parentUpdate = object.update;
+ object.update = (elapsedTime) => {
+ parentUpdate(elapsedTime);
+ if (object.y < 0) {
+ object.alive = false;
+ }
+ };
+ return object;
+} \ No newline at end of file
diff --git a/centipede/js/game/objects/centipede.js b/centipede/js/game/objects/centipede.js
new file mode 100644
index 0000000..7e4c8f6
--- /dev/null
+++ b/centipede/js/game/objects/centipede.js
@@ -0,0 +1,105 @@
+game.CentipedePiece = (spec) => {
+ const object = game.Object(spec);
+ object.poisonedTimer = 1000;
+ const parentUpdate = object.update;
+ object.turningState = {
+ turning: false,
+ turnDirectionY: 1,
+ objectStateBeforeTurn: null,
+ };
+ object.turn = () => {
+ object.turningState.objectStateBeforeTurn = {dx: object.dx, dy: object.dy, x: object.x, y: object.y};
+ object.turningState.turning = true;
+ if (object.y >= game.height - object.height) {
+ object.turningState.turnDirectionY = -1;
+ }
+ if (object.y <= 0) {
+ object.turningState.turnDirectionY = 1;
+ }
+ };
+ object.update = (elapsedTime) => {
+ if (object.poisoned) {
+ object.turningState.turning = false;
+ }
+ else if ((object.x+object.width > game.width || object.x < 0) && !object.turningState.turning) {
+ object.x = Math.min(Math.max(object.x, 0), game.width - object.width);
+ object.turn();
+ }
+ if (object.turningState.turning) {
+ object.dx = 0;
+ object.dy = Math.abs(object.turningState.objectStateBeforeTurn.dx) * object.turningState.turnDirectionY;
+ object.rot = object.dy > 0 ? -90 : 90;
+ if (Math.abs(object.turningState.objectStateBeforeTurn.y - object.y) >= object.height) {
+ object.y = object.turningState.objectStateBeforeTurn.y + object.height * object.turningState.turnDirectionY;
+ object.dx = -object.turningState.objectStateBeforeTurn.dx;
+ object.rot = object.dx > 0 ? 180 : 0;
+ object.dy = 0;
+ object.turningState.turning = false;
+ }
+ }
+ parentUpdate(elapsedTime);
+ object.y = Math.min(Math.max(object.y, 0), game.height - object.height);
+ };
+ object.onMushroomCollision = (mushroom) => {
+ if (mushroom.poisoned && object.dy === 0) {
+ object.poison();
+ return;
+ }
+ if (!object.turningState.turning) {
+ if (mushroom.x < object.x && object.dx > 0) {
+ return;
+ }
+ object.turn();
+ }
+ }
+ return object;
+}
+
+game.Centipede = (spec) => {
+ const segments = [
+ ...Array(spec.segments).fill(0).map((_, i) => game.CentipedePiece({...spec, x: spec.startX - spec.width*(i+1), y: spec.startY, sprite: game.sprites.centipedeBody})),
+ game.CentipedePiece({...spec, x: spec.startX, y: spec.startY, sprite: game.sprites.centipedeHead}),
+ ];
+
+ const update = (elapsedTime) => {
+ segments.map((segment) => segment.update(elapsedTime));
+ }
+
+ const draw = (elapsedTime) => {
+ segments.map((segment) => segment.draw(elapsedTime));
+ }
+
+ const intersects = (object) => {
+ return segments.filter((segment) => segment.intersects(object)).length;
+ }
+
+ const onBulletCollision = (bullet) => {
+ if (bullet.alive) {
+ const segment = segments.find((segment) => segment.intersects(bullet));
+ const segmentIndex = segments.indexOf(segment);
+
+ const {mushX, mushY} = game.Mushroom.toMushCoords(segment);
+ game.explosions.push(game.Explosion({...game.Mushroom.toGameCoords({mushX, mushY}), width: segment.width, height: segment.height, sprite: game.sprites.explosionSmall}));
+ if (!game.mushrooms.find((mushroom) => mushroom.mushX === mushX && mushroom.mushY === mushY)) {
+ game.mushrooms.push(game.Mushroom({mushX, mushY, ...game.mushroomDims}));
+ }
+ game.score += segment.sprite === game.sprites.centipedeHead ? 20 : 5;
+ game.sounds.enemy_hit.load();
+ game.sounds.enemy_hit.play();
+ segments.splice(segmentIndex, 1);
+ }
+ bullet.alive = false;
+ }
+
+ const onMushroomCollision = (mushroom) => {
+ segments.find((segment) => segment.intersects(mushroom)).onMushroomCollision(mushroom);
+ }
+
+ const onPlayerCollision = (player) => {
+ player.kill();
+ }
+
+ const alive = () => segments.length ? true : false;
+
+ return {update, draw, segments, intersects, onBulletCollision, onMushroomCollision, onPlayerCollision, alive};
+} \ No newline at end of file
diff --git a/centipede/js/game/objects/explosion.js b/centipede/js/game/objects/explosion.js
new file mode 100644
index 0000000..f38d820
--- /dev/null
+++ b/centipede/js/game/objects/explosion.js
@@ -0,0 +1,14 @@
+game.Explosion = (spec) => {
+ const object = game.Object(spec);
+ let explosionTime = 0;
+ const parentUpdate = object.update;
+ object.update = (elapsedTime) => {
+ parentUpdate(elapsedTime);
+ explosionTime += elapsedTime;
+
+ if (explosionTime > (object.sprite.numFrames * object.sprite.timePerFrame)) {
+ object.alive = false;
+ }
+ }
+ return object;
+} \ No newline at end of file
diff --git a/centipede/js/game/objects/flea.js b/centipede/js/game/objects/flea.js
new file mode 100644
index 0000000..23479cc
--- /dev/null
+++ b/centipede/js/game/objects/flea.js
@@ -0,0 +1,49 @@
+game.Flea = (spec) => {
+ const object = game.Object(spec);
+ const parentUpdate = object.update;
+ object.mushroomCoords = game.Mushroom.toMushCoords(object);
+ object.update = (elapsedTime) => {
+ const newMushroomCoords = game.Mushroom.toMushCoords(object);
+ if (newMushroomCoords.mushY !== object.mushroomCoords.mushY || newMushroomCoords.mushX !== object.mushroomCoords.mushX) {
+ if (Math.random() < Math.min(0.15 + 0.05*game.level, 0.7)) {
+ if (!game.mushrooms.find((mushroom) => mushroom.mushX === newMushroomCoords.mushX && mushroom.mushY === newMushroomCoords.mushY)) {
+ game.mushrooms.push(game.Mushroom({...newMushroomCoords, ...game.mushroomDims}));
+ }
+ }
+ object.mushroomCoords = newMushroomCoords;
+ }
+ parentUpdate(elapsedTime);
+ };
+
+ object.onMushroomCollision = (mushroom) => {
+ if (mushroom.poisoned) {
+ mushroom.state = 0;
+ object.poison();
+ }
+ }
+
+ object.explode = () => {
+ game.explosions.push(game.Explosion({x: object.x, y: object.y, width: object.width, height: object.height, sprite: game.sprites.explosionSmall}));
+ game.sounds.enemy_hit.load();
+ game.sounds.enemy_hit.play();
+ }
+
+ object.onBulletCollision = (bullet) => {
+ game.score += 20;
+ object.alive = false;
+ object.explode();
+ }
+
+ object.onPlayerCollision = (player) => {
+ object.alive = false;
+ player.kill();
+ object.explode();
+ }
+
+ object.onBulletCollision = (bullet) => {
+ object.explode();
+ object.alive = false;
+ }
+
+ return object;
+} \ No newline at end of file
diff --git a/centipede/js/game/objects/mushroom.js b/centipede/js/game/objects/mushroom.js
new file mode 100644
index 0000000..b1f4787
--- /dev/null
+++ b/centipede/js/game/objects/mushroom.js
@@ -0,0 +1,43 @@
+game.Mushroom = (spec) => {
+ spec.state = spec.state ?? 4;
+ const {mushX, mushY} = spec;
+ const objectSpec = {...spec};
+ objectSpec.x = mushX * objectSpec.width;
+ objectSpec.y = mushY * objectSpec.height;
+ const object = {...spec, ...game.Object(objectSpec)};
+ object.onBulletCollision = (bullet) => {
+ if (bullet.alive) {
+ object.state--;
+ game.score += 5;
+ game.sounds.mushroom_hit.load();
+ game.sounds.mushroom_hit.play();
+ }
+ bullet.alive = false;
+ };
+ object.draw = (elapsedTime) => {
+ if (object.state) {
+ object.sprite = object.poisoned ? game.sprites.poisonMushrooms[object.state-1] : game.sprites.regularMushrooms[object.state-1];
+ object.sprite.draw(elapsedTime, object);
+ }
+ }
+ return object;
+};
+
+game.Mushroom.toMushCoords = (coords) => {
+ return {mushX: Math.ceil(coords.x / game.mushroomDims.width), mushY: Math.ceil(coords.y / game.mushroomDims.height)};
+}
+
+game.Mushroom.toGameCoords = (mushCoords) => {
+ return {x: mushCoords.mushX * game.mushroomDims.width, y: mushCoords.mushY * game.mushroomDims.height};
+}
+
+game.Mushroom.generateMushrooms = (mushroomSpec) => {
+ const mushPositions = new Set();
+ for (let i = 0; i < Math.max(Math.random(), 0.05) * game.height / mushroomSpec.height * game.width / mushroomSpec.width * game.level * 0.5; i++) {
+ mushPositions.add(JSON.stringify([Math.floor(Math.random() * game.width / mushroomSpec.width), Math.max(1, Math.floor(Math.random() * (game.height / mushroomSpec.height - 3)))]));
+ }
+ return Array.from(mushPositions).map((pos) => {
+ const [mushX, mushY] = JSON.parse(pos);
+ return game.Mushroom({...mushroomSpec, mushX, mushY});
+ });
+}
diff --git a/centipede/js/game/objects/player.js b/centipede/js/game/objects/player.js
new file mode 100644
index 0000000..a1f6ea0
--- /dev/null
+++ b/centipede/js/game/objects/player.js
@@ -0,0 +1,63 @@
+game.Player = (spec) => {
+ const object = game.Object(spec);
+ object.poisonedTimer = 4000;
+ object.elapsedPoisonedTimer = 0;
+ object.poisoned = false;
+ object.bulletTimer = spec.bulletTimer ?? 150;
+ object.maxPlayerHeight = spec.maxPlayerHeight ?? game.height - object.height*6;
+ object.elapsedBulletTimer = 0;
+ object.lives = spec.lives ?? 3;
+
+ const parentUpdate = object.update;
+ object.update = (elapsedTime) => {
+ parentUpdate(elapsedTime);
+ object.x = Math.max(0, Math.min(object.x, game.width - object.width));
+ object.y = Math.max(object.maxPlayerHeight, Math.min(object.y, game.height - object.height));
+ object.dx = object.dy = 0;
+ object.elapsedBulletTimer += elapsedTime;
+ };
+ object.moveUp = () => {
+ object.dy = -0.75;
+ }
+ object.moveDown = () => {
+ object.dy = 0.75;
+ }
+ object.moveLeft = () => {
+ object.dx = -0.5;
+ }
+ object.moveRight = () => {
+ object.dx = 0.5;
+ }
+
+ object.shoot = () => {
+ if (object.elapsedBulletTimer > object.bulletTimer) {
+ object.elapsedBulletTimer = 0;
+ game.bullets.push(game.Bullet({x: object.x + object.width/2 - 5, y: object.y-object.height/2, dx: 0, dy: -1.5, width: 5, height: 50, sprite: game.sprites.bullet}));
+ game.sounds.laser.load();
+ game.sounds.laser.play();
+ }
+ }
+
+ object.onMushroomCollision = (mushroom) => {
+ if (mushroom.poisoned) {
+ mushroom.state = 0;
+ object.poison();
+ }
+ if (mushroom.x > object.x) {
+ object.x = mushroom.x - mushroom.width;
+ }
+ if (mushroom.x < object.x) {
+ object.x = mushroom.x + mushroom.width;
+ }
+ }
+
+ object.kill = () => {
+ object.lives--;
+ game.resetObjects();
+ if (object.lives == 0) {
+ game.gameOver();
+ }
+ }
+
+ return object;
+} \ No newline at end of file
diff --git a/centipede/js/game/objects/scorpion.js b/centipede/js/game/objects/scorpion.js
new file mode 100644
index 0000000..036db14
--- /dev/null
+++ b/centipede/js/game/objects/scorpion.js
@@ -0,0 +1,32 @@
+game.Scorpion = (spec) => {
+ const object = game.Object(spec);
+
+ const parentUpdate = object.update;
+ object.update = (elapsedTime) => {
+ parentUpdate(elapsedTime);
+ };
+
+ object.explode = () => {
+ game.explosions.push(game.Explosion({x: object.x, y: object.y, width: object.width, height: object.height, sprite: game.sprites.explosionBig}));
+ game.sounds.enemy_hit.load();
+ game.sounds.enemy_hit.play();
+ }
+
+ object.onBulletCollision = (bullet) => {
+ game.score += 100;
+ object.alive = false;
+ object.explode();
+ }
+
+ object.onPlayerCollision = (player) => {
+ object.alive = false;
+ player.kill();
+ object.explode();
+ }
+
+ object.onMushroomCollision = (mushroom) => {
+ mushroom.poisoned = true;
+ }
+
+ return object;
+} \ No newline at end of file
diff --git a/centipede/js/game/objects/spider.js b/centipede/js/game/objects/spider.js
new file mode 100644
index 0000000..732c0a3
--- /dev/null
+++ b/centipede/js/game/objects/spider.js
@@ -0,0 +1,45 @@
+game.Spider = (spec) => {
+ const object = game.Object(spec);
+
+ const parentUpdate = object.update;
+
+ object.randomizeVel = () => {
+ object.dx = Math.min(Math.random(), 0.25 + 0.05*game.level) * (Math.random() > 0.5 ? 1 : -1);
+ object.dy = Math.min(Math.random(), 0.25 + 0.05*game.level) * (Math.random() > 0.5 ? 1 : -1);
+ }
+
+ object.update = (elapsedTime) => {
+ if (Math.random() < 0.01*game.level) {
+ object.randomizeVel();
+ }
+ if (object.x < 0 || object.x > game.width - object.width) {
+ object.dx = -object.dx;
+ }
+ if (object.y < 0 || object.y > game.height - object.height) {
+ object.dy = -object.dy;
+ }
+ object.x = Math.max(0, Math.min(game.width - object.width, object.x));
+ object.y = Math.max(0, Math.min(game.height - object.height, object.y));
+ parentUpdate(elapsedTime);
+ };
+
+ object.explode = () => {
+ game.explosions.push(game.Explosion({x: object.x, y: object.y, width: object.width, height: object.height, sprite: game.sprites.explosionBig}));
+ game.sounds.enemy_hit.load();
+ game.sounds.enemy_hit.play();
+ }
+
+ object.onBulletCollision = (bullet) => {
+ game.score += 150;
+ object.alive = false;
+ object.explode();
+ }
+
+ object.onPlayerCollision = (player) => {
+ object.alive = false;
+ player.kill();
+ object.explode();
+ }
+
+ return object;
+} \ No newline at end of file