From 6bf4b90c90f15f4ab60833bddf5b5756d1a6b1f6 Mon Sep 17 00:00:00 2001 From: Elizabeth Alexander Hunt Date: Thu, 2 Jul 2026 11:55:17 -0700 Subject: Init --- Homework/cs5410/bbiy/README.md | 20 + Homework/cs5410/bbiy/assets/image/background.gif | Bin 0 -> 1468046 bytes Homework/cs5410/bbiy/assets/image/bigblue.png | Bin 0 -> 1489 bytes Homework/cs5410/bbiy/assets/image/flag.png | Bin 0 -> 985 bytes Homework/cs5410/bbiy/assets/image/floor.png | Bin 0 -> 1296 bytes Homework/cs5410/bbiy/assets/image/grass.png | Bin 0 -> 1090 bytes Homework/cs5410/bbiy/assets/image/hedge.png | Bin 0 -> 14592 bytes Homework/cs5410/bbiy/assets/image/lava.png | Bin 0 -> 409 bytes Homework/cs5410/bbiy/assets/image/rock.png | Bin 0 -> 1288 bytes Homework/cs5410/bbiy/assets/image/wall.png | Bin 0 -> 1283 bytes Homework/cs5410/bbiy/assets/image/water.png | Bin 0 -> 436 bytes Homework/cs5410/bbiy/assets/image/wordBigBlue.png | Bin 0 -> 1083 bytes Homework/cs5410/bbiy/assets/image/wordFlag.png | Bin 0 -> 509 bytes Homework/cs5410/bbiy/assets/image/wordIs.png | Bin 0 -> 490 bytes Homework/cs5410/bbiy/assets/image/wordKill.png | Bin 0 -> 1042 bytes Homework/cs5410/bbiy/assets/image/wordLava.png | Bin 0 -> 492 bytes Homework/cs5410/bbiy/assets/image/wordPush.png | Bin 0 -> 483 bytes Homework/cs5410/bbiy/assets/image/wordRock.png | Bin 0 -> 517 bytes Homework/cs5410/bbiy/assets/image/wordSink.png | Bin 0 -> 499 bytes Homework/cs5410/bbiy/assets/image/wordStop.png | Bin 0 -> 490 bytes Homework/cs5410/bbiy/assets/image/wordWall.png | Bin 0 -> 556 bytes Homework/cs5410/bbiy/assets/image/wordWater.png | Bin 0 -> 506 bytes Homework/cs5410/bbiy/assets/image/wordWin.png | Bin 0 -> 455 bytes Homework/cs5410/bbiy/assets/image/wordYou.png | Bin 0 -> 448 bytes Homework/cs5410/bbiy/assets/sound/death.mp3 | Bin 0 -> 7321 bytes Homework/cs5410/bbiy/assets/sound/move.mp3 | Bin 0 -> 1845 bytes Homework/cs5410/bbiy/assets/sound/music.mp3 | Bin 0 -> 2696840 bytes Homework/cs5410/bbiy/assets/sound/win.mp3 | Bin 0 -> 8678 bytes Homework/cs5410/bbiy/index.html | 47 ++ Homework/cs5410/bbiy/index.js | 55 ++ Homework/cs5410/bbiy/levels-all.bbiy | 252 ++++++ Homework/cs5410/bbiy/package-lock.json | 876 +++++++++++++++++++++ Homework/cs5410/bbiy/package.json | 15 + Homework/cs5410/bbiy/src/bootstrap.js | 117 +++ Homework/cs5410/bbiy/src/components/alive.js | 1 + Homework/cs5410/bbiy/src/components/appearence.js | 1 + Homework/cs5410/bbiy/src/components/burn.js | 1 + Homework/cs5410/bbiy/src/components/burnable.js | 1 + Homework/cs5410/bbiy/src/components/component.js | 8 + .../cs5410/bbiy/src/components/controllable.js | 1 + .../cs5410/bbiy/src/components/gridPosition.js | 1 + .../cs5410/bbiy/src/components/loadPriority.js | 1 + Homework/cs5410/bbiy/src/components/momentum.js | 1 + Homework/cs5410/bbiy/src/components/name.js | 1 + Homework/cs5410/bbiy/src/components/noun.js | 1 + Homework/cs5410/bbiy/src/components/particles.js | 1 + Homework/cs5410/bbiy/src/components/position.js | 1 + Homework/cs5410/bbiy/src/components/pushable.js | 1 + Homework/cs5410/bbiy/src/components/sink.js | 1 + Homework/cs5410/bbiy/src/components/sinkable.js | 1 + Homework/cs5410/bbiy/src/components/sprite.js | 1 + Homework/cs5410/bbiy/src/components/stop.js | 1 + Homework/cs5410/bbiy/src/components/verb.js | 1 + Homework/cs5410/bbiy/src/components/win.js | 1 + Homework/cs5410/bbiy/src/entities/bigblue.js | 13 + .../cs5410/bbiy/src/entities/borderParticles.js | 41 + Homework/cs5410/bbiy/src/entities/entity.js | 23 + Homework/cs5410/bbiy/src/entities/flag.js | 12 + Homework/cs5410/bbiy/src/entities/floor.js | 8 + Homework/cs5410/bbiy/src/entities/grass.js | 8 + Homework/cs5410/bbiy/src/entities/hedge.js | 9 + Homework/cs5410/bbiy/src/entities/lava.js | 9 + Homework/cs5410/bbiy/src/entities/rock.js | 14 + Homework/cs5410/bbiy/src/entities/wall.js | 13 + Homework/cs5410/bbiy/src/entities/water.js | 9 + Homework/cs5410/bbiy/src/entities/wordBigBlue.js | 10 + Homework/cs5410/bbiy/src/entities/wordFlag.js | 10 + Homework/cs5410/bbiy/src/entities/wordIs.js | 11 + Homework/cs5410/bbiy/src/entities/wordKill.js | 10 + Homework/cs5410/bbiy/src/entities/wordLava.js | 11 + Homework/cs5410/bbiy/src/entities/wordPush.js | 10 + Homework/cs5410/bbiy/src/entities/wordRock.js | 10 + Homework/cs5410/bbiy/src/entities/wordSink.js | 10 + Homework/cs5410/bbiy/src/entities/wordStop.js | 10 + Homework/cs5410/bbiy/src/entities/wordWall.js | 10 + Homework/cs5410/bbiy/src/entities/wordWater.js | 10 + Homework/cs5410/bbiy/src/entities/wordWin.js | 10 + Homework/cs5410/bbiy/src/entities/wordYou.js | 10 + Homework/cs5410/bbiy/src/game.js | 72 ++ Homework/cs5410/bbiy/src/render/graphics.js | 47 ++ Homework/cs5410/bbiy/src/render/sprites.js | 156 ++++ Homework/cs5410/bbiy/src/require.js | 5 + Homework/cs5410/bbiy/src/systems/collision.js | 93 +++ Homework/cs5410/bbiy/src/systems/grid.js | 71 ++ Homework/cs5410/bbiy/src/systems/keyboardInput.js | 46 ++ Homework/cs5410/bbiy/src/systems/logic.js | 149 ++++ Homework/cs5410/bbiy/src/systems/menu.js | 114 +++ Homework/cs5410/bbiy/src/systems/particle.js | 57 ++ Homework/cs5410/bbiy/src/systems/physics.js | 16 + Homework/cs5410/bbiy/src/systems/render.js | 26 + Homework/cs5410/bbiy/src/systems/system.js | 1 + Homework/cs5410/bbiy/src/systems/undo.js | 32 + Homework/cs5410/bbiy/src/utils/clamp.js | 6 + Homework/cs5410/bbiy/src/utils/loadLevel.js | 87 ++ .../cs5410/bbiy/src/utils/objectEquivalence.js | 14 + Homework/cs5410/bbiy/src/utils/randInRange.js | 4 + Homework/cs5410/bbiy/src/utils/unitizeVector.js | 11 + Homework/cs5410/bbiy/styles/style.css | 73 ++ .../centipede/assets/images/centipede-assets.png | Bin 0 -> 11555 bytes .../cs5410/centipede/assets/sounds/enemy_hit.wav | Bin 0 -> 125286 bytes Homework/cs5410/centipede/assets/sounds/laser.wav | Bin 0 -> 12402 bytes .../centipede/assets/sounds/mushroom_hit.wav | Bin 0 -> 9780 bytes Homework/cs5410/centipede/css/style.css | 63 ++ Homework/cs5410/centipede/index.html | 38 + Homework/cs5410/centipede/js/game/game.js | 39 + Homework/cs5410/centipede/js/game/graphics.js | 55 ++ Homework/cs5410/centipede/js/game/input.js | 32 + Homework/cs5410/centipede/js/game/menu.js | 143 ++++ Homework/cs5410/centipede/js/game/object.js | 51 ++ .../cs5410/centipede/js/game/objects/bullet.js | 11 + .../cs5410/centipede/js/game/objects/centipede.js | 105 +++ .../cs5410/centipede/js/game/objects/explosion.js | 14 + Homework/cs5410/centipede/js/game/objects/flea.js | 49 ++ .../cs5410/centipede/js/game/objects/mushroom.js | 43 + .../cs5410/centipede/js/game/objects/player.js | 63 ++ .../cs5410/centipede/js/game/objects/scorpion.js | 32 + .../cs5410/centipede/js/game/objects/spider.js | 45 ++ Homework/cs5410/centipede/js/game/sounds.js | 5 + Homework/cs5410/centipede/js/game/sprites.js | 120 +++ Homework/cs5410/centipede/js/main.js | 75 ++ Homework/cs5410/maize-maze/LICENSE.md | 21 + Homework/cs5410/maize-maze/README.md | 9 + Homework/cs5410/maize-maze/css/styles.css | 24 + Homework/cs5410/maize-maze/images/corn.png | Bin 0 -> 10272 bytes Homework/cs5410/maize-maze/images/fire.png | Bin 0 -> 8378 bytes Homework/cs5410/maize-maze/images/popcorn.jpg | Bin 0 -> 33339 bytes Homework/cs5410/maize-maze/index.html | 75 ++ Homework/cs5410/maize-maze/js/assets.js | 8 + Homework/cs5410/maize-maze/js/game.js | 249 ++++++ Homework/cs5410/maize-maze/js/helpers.js | 18 + Homework/cs5410/maize-maze/js/json-ds.js | 30 + Homework/cs5410/maize-maze/js/keyboard.js | 22 + Homework/cs5410/maize-maze/js/maze.js | 104 +++ Homework/cs5410/maize-maze/screenshot.png | Bin 0 -> 1295982 bytes 134 files changed, 4323 insertions(+) create mode 100644 Homework/cs5410/bbiy/README.md create mode 100644 Homework/cs5410/bbiy/assets/image/background.gif create mode 100644 Homework/cs5410/bbiy/assets/image/bigblue.png create mode 100644 Homework/cs5410/bbiy/assets/image/flag.png create mode 100644 Homework/cs5410/bbiy/assets/image/floor.png create mode 100644 Homework/cs5410/bbiy/assets/image/grass.png create mode 100644 Homework/cs5410/bbiy/assets/image/hedge.png create mode 100644 Homework/cs5410/bbiy/assets/image/lava.png create mode 100644 Homework/cs5410/bbiy/assets/image/rock.png create mode 100644 Homework/cs5410/bbiy/assets/image/wall.png create mode 100644 Homework/cs5410/bbiy/assets/image/water.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordBigBlue.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordFlag.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordIs.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordKill.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordLava.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordPush.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordRock.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordSink.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordStop.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordWall.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordWater.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordWin.png create mode 100644 Homework/cs5410/bbiy/assets/image/wordYou.png create mode 100644 Homework/cs5410/bbiy/assets/sound/death.mp3 create mode 100644 Homework/cs5410/bbiy/assets/sound/move.mp3 create mode 100644 Homework/cs5410/bbiy/assets/sound/music.mp3 create mode 100644 Homework/cs5410/bbiy/assets/sound/win.mp3 create mode 100644 Homework/cs5410/bbiy/index.html create mode 100644 Homework/cs5410/bbiy/index.js create mode 100644 Homework/cs5410/bbiy/levels-all.bbiy create mode 100644 Homework/cs5410/bbiy/package-lock.json create mode 100644 Homework/cs5410/bbiy/package.json create mode 100644 Homework/cs5410/bbiy/src/bootstrap.js create mode 100644 Homework/cs5410/bbiy/src/components/alive.js create mode 100644 Homework/cs5410/bbiy/src/components/appearence.js create mode 100644 Homework/cs5410/bbiy/src/components/burn.js create mode 100644 Homework/cs5410/bbiy/src/components/burnable.js create mode 100644 Homework/cs5410/bbiy/src/components/component.js create mode 100644 Homework/cs5410/bbiy/src/components/controllable.js create mode 100644 Homework/cs5410/bbiy/src/components/gridPosition.js create mode 100644 Homework/cs5410/bbiy/src/components/loadPriority.js create mode 100644 Homework/cs5410/bbiy/src/components/momentum.js create mode 100644 Homework/cs5410/bbiy/src/components/name.js create mode 100644 Homework/cs5410/bbiy/src/components/noun.js create mode 100644 Homework/cs5410/bbiy/src/components/particles.js create mode 100644 Homework/cs5410/bbiy/src/components/position.js create mode 100644 Homework/cs5410/bbiy/src/components/pushable.js create mode 100644 Homework/cs5410/bbiy/src/components/sink.js create mode 100644 Homework/cs5410/bbiy/src/components/sinkable.js create mode 100644 Homework/cs5410/bbiy/src/components/sprite.js create mode 100644 Homework/cs5410/bbiy/src/components/stop.js create mode 100644 Homework/cs5410/bbiy/src/components/verb.js create mode 100644 Homework/cs5410/bbiy/src/components/win.js create mode 100644 Homework/cs5410/bbiy/src/entities/bigblue.js create mode 100644 Homework/cs5410/bbiy/src/entities/borderParticles.js create mode 100644 Homework/cs5410/bbiy/src/entities/entity.js create mode 100644 Homework/cs5410/bbiy/src/entities/flag.js create mode 100644 Homework/cs5410/bbiy/src/entities/floor.js create mode 100644 Homework/cs5410/bbiy/src/entities/grass.js create mode 100644 Homework/cs5410/bbiy/src/entities/hedge.js create mode 100644 Homework/cs5410/bbiy/src/entities/lava.js create mode 100644 Homework/cs5410/bbiy/src/entities/rock.js create mode 100644 Homework/cs5410/bbiy/src/entities/wall.js create mode 100644 Homework/cs5410/bbiy/src/entities/water.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordBigBlue.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordFlag.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordIs.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordKill.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordLava.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordPush.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordRock.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordSink.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordStop.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordWall.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordWater.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordWin.js create mode 100644 Homework/cs5410/bbiy/src/entities/wordYou.js create mode 100644 Homework/cs5410/bbiy/src/game.js create mode 100644 Homework/cs5410/bbiy/src/render/graphics.js create mode 100644 Homework/cs5410/bbiy/src/render/sprites.js create mode 100644 Homework/cs5410/bbiy/src/require.js create mode 100644 Homework/cs5410/bbiy/src/systems/collision.js create mode 100644 Homework/cs5410/bbiy/src/systems/grid.js create mode 100644 Homework/cs5410/bbiy/src/systems/keyboardInput.js create mode 100644 Homework/cs5410/bbiy/src/systems/logic.js create mode 100644 Homework/cs5410/bbiy/src/systems/menu.js create mode 100644 Homework/cs5410/bbiy/src/systems/particle.js create mode 100644 Homework/cs5410/bbiy/src/systems/physics.js create mode 100644 Homework/cs5410/bbiy/src/systems/render.js create mode 100644 Homework/cs5410/bbiy/src/systems/system.js create mode 100644 Homework/cs5410/bbiy/src/systems/undo.js create mode 100644 Homework/cs5410/bbiy/src/utils/clamp.js create mode 100644 Homework/cs5410/bbiy/src/utils/loadLevel.js create mode 100644 Homework/cs5410/bbiy/src/utils/objectEquivalence.js create mode 100644 Homework/cs5410/bbiy/src/utils/randInRange.js create mode 100644 Homework/cs5410/bbiy/src/utils/unitizeVector.js create mode 100644 Homework/cs5410/bbiy/styles/style.css create mode 100644 Homework/cs5410/centipede/assets/images/centipede-assets.png create mode 100644 Homework/cs5410/centipede/assets/sounds/enemy_hit.wav create mode 100644 Homework/cs5410/centipede/assets/sounds/laser.wav create mode 100644 Homework/cs5410/centipede/assets/sounds/mushroom_hit.wav create mode 100644 Homework/cs5410/centipede/css/style.css create mode 100644 Homework/cs5410/centipede/index.html create mode 100644 Homework/cs5410/centipede/js/game/game.js create mode 100644 Homework/cs5410/centipede/js/game/graphics.js create mode 100644 Homework/cs5410/centipede/js/game/input.js create mode 100644 Homework/cs5410/centipede/js/game/menu.js create mode 100644 Homework/cs5410/centipede/js/game/object.js create mode 100644 Homework/cs5410/centipede/js/game/objects/bullet.js create mode 100644 Homework/cs5410/centipede/js/game/objects/centipede.js create mode 100644 Homework/cs5410/centipede/js/game/objects/explosion.js create mode 100644 Homework/cs5410/centipede/js/game/objects/flea.js create mode 100644 Homework/cs5410/centipede/js/game/objects/mushroom.js create mode 100644 Homework/cs5410/centipede/js/game/objects/player.js create mode 100644 Homework/cs5410/centipede/js/game/objects/scorpion.js create mode 100644 Homework/cs5410/centipede/js/game/objects/spider.js create mode 100644 Homework/cs5410/centipede/js/game/sounds.js create mode 100644 Homework/cs5410/centipede/js/game/sprites.js create mode 100644 Homework/cs5410/centipede/js/main.js create mode 100644 Homework/cs5410/maize-maze/LICENSE.md create mode 100644 Homework/cs5410/maize-maze/README.md create mode 100644 Homework/cs5410/maize-maze/css/styles.css create mode 100644 Homework/cs5410/maize-maze/images/corn.png create mode 100644 Homework/cs5410/maize-maze/images/fire.png create mode 100644 Homework/cs5410/maize-maze/images/popcorn.jpg create mode 100644 Homework/cs5410/maize-maze/index.html create mode 100644 Homework/cs5410/maize-maze/js/assets.js create mode 100644 Homework/cs5410/maize-maze/js/game.js create mode 100644 Homework/cs5410/maize-maze/js/helpers.js create mode 100644 Homework/cs5410/maize-maze/js/json-ds.js create mode 100644 Homework/cs5410/maize-maze/js/keyboard.js create mode 100644 Homework/cs5410/maize-maze/js/maze.js create mode 100644 Homework/cs5410/maize-maze/screenshot.png (limited to 'Homework/cs5410') diff --git a/Homework/cs5410/bbiy/README.md b/Homework/cs5410/bbiy/README.md new file mode 100644 index 0000000..da290c7 --- /dev/null +++ b/Homework/cs5410/bbiy/README.md @@ -0,0 +1,20 @@ +# BBIY (Big Blue Is You) + +It's like Baba is You, but Aggies (and not as good :P) + +Most artwork is from the initial game, as found [here](https://www.spriters-resource.com/pc_computer/babaisyou/sheet/115231/), besides an ugly AF custom "Big Blue" (I am no artist and I spent way too long on it). + +Music is "Fluffing a Duck" by Kevin Macleod, found [on YouTube](https://www.youtube.com/watch?v=yQjAF3frudY). + +Background image is stolen [from here](https://i.pinimg.com/originals/b2/2a/a2/b22aa22b2f3f55b6468361158d52e2e7.gif). +## Building and running + +It's as simple as: + +``` +npm install +npm run start +``` + +## Play online +[on my website](https://simponic.xyz/bbiy/) diff --git a/Homework/cs5410/bbiy/assets/image/background.gif b/Homework/cs5410/bbiy/assets/image/background.gif new file mode 100644 index 0000000..4188529 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/background.gif differ diff --git a/Homework/cs5410/bbiy/assets/image/bigblue.png b/Homework/cs5410/bbiy/assets/image/bigblue.png new file mode 100644 index 0000000..93f22ea Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/bigblue.png differ diff --git a/Homework/cs5410/bbiy/assets/image/flag.png b/Homework/cs5410/bbiy/assets/image/flag.png new file mode 100644 index 0000000..0a53d60 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/flag.png differ diff --git a/Homework/cs5410/bbiy/assets/image/floor.png b/Homework/cs5410/bbiy/assets/image/floor.png new file mode 100644 index 0000000..92ec9f7 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/floor.png differ diff --git a/Homework/cs5410/bbiy/assets/image/grass.png b/Homework/cs5410/bbiy/assets/image/grass.png new file mode 100644 index 0000000..1991e8c Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/grass.png differ diff --git a/Homework/cs5410/bbiy/assets/image/hedge.png b/Homework/cs5410/bbiy/assets/image/hedge.png new file mode 100644 index 0000000..9295e61 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/hedge.png differ diff --git a/Homework/cs5410/bbiy/assets/image/lava.png b/Homework/cs5410/bbiy/assets/image/lava.png new file mode 100644 index 0000000..bf95837 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/lava.png differ diff --git a/Homework/cs5410/bbiy/assets/image/rock.png b/Homework/cs5410/bbiy/assets/image/rock.png new file mode 100644 index 0000000..ce108b0 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/rock.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wall.png b/Homework/cs5410/bbiy/assets/image/wall.png new file mode 100644 index 0000000..6912323 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wall.png differ diff --git a/Homework/cs5410/bbiy/assets/image/water.png b/Homework/cs5410/bbiy/assets/image/water.png new file mode 100644 index 0000000..47703e0 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/water.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordBigBlue.png b/Homework/cs5410/bbiy/assets/image/wordBigBlue.png new file mode 100644 index 0000000..6fc767e Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordBigBlue.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordFlag.png b/Homework/cs5410/bbiy/assets/image/wordFlag.png new file mode 100644 index 0000000..d848902 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordFlag.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordIs.png b/Homework/cs5410/bbiy/assets/image/wordIs.png new file mode 100644 index 0000000..878e40c Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordIs.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordKill.png b/Homework/cs5410/bbiy/assets/image/wordKill.png new file mode 100644 index 0000000..e781260 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordKill.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordLava.png b/Homework/cs5410/bbiy/assets/image/wordLava.png new file mode 100644 index 0000000..be23819 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordLava.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordPush.png b/Homework/cs5410/bbiy/assets/image/wordPush.png new file mode 100644 index 0000000..bdf847e Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordPush.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordRock.png b/Homework/cs5410/bbiy/assets/image/wordRock.png new file mode 100644 index 0000000..6809956 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordRock.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordSink.png b/Homework/cs5410/bbiy/assets/image/wordSink.png new file mode 100644 index 0000000..8b06deb Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordSink.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordStop.png b/Homework/cs5410/bbiy/assets/image/wordStop.png new file mode 100644 index 0000000..e8dc434 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordStop.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordWall.png b/Homework/cs5410/bbiy/assets/image/wordWall.png new file mode 100644 index 0000000..24564a1 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordWall.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordWater.png b/Homework/cs5410/bbiy/assets/image/wordWater.png new file mode 100644 index 0000000..5141d08 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordWater.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordWin.png b/Homework/cs5410/bbiy/assets/image/wordWin.png new file mode 100644 index 0000000..0c018ea Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordWin.png differ diff --git a/Homework/cs5410/bbiy/assets/image/wordYou.png b/Homework/cs5410/bbiy/assets/image/wordYou.png new file mode 100644 index 0000000..a0613c5 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/image/wordYou.png differ diff --git a/Homework/cs5410/bbiy/assets/sound/death.mp3 b/Homework/cs5410/bbiy/assets/sound/death.mp3 new file mode 100644 index 0000000..b60a956 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/sound/death.mp3 differ diff --git a/Homework/cs5410/bbiy/assets/sound/move.mp3 b/Homework/cs5410/bbiy/assets/sound/move.mp3 new file mode 100644 index 0000000..59d2de5 Binary files /dev/null and b/Homework/cs5410/bbiy/assets/sound/move.mp3 differ diff --git a/Homework/cs5410/bbiy/assets/sound/music.mp3 b/Homework/cs5410/bbiy/assets/sound/music.mp3 new file mode 100644 index 0000000..0d879cc Binary files /dev/null and b/Homework/cs5410/bbiy/assets/sound/music.mp3 differ diff --git a/Homework/cs5410/bbiy/assets/sound/win.mp3 b/Homework/cs5410/bbiy/assets/sound/win.mp3 new file mode 100644 index 0000000..ad2887c Binary files /dev/null and b/Homework/cs5410/bbiy/assets/sound/win.mp3 differ diff --git a/Homework/cs5410/bbiy/index.html b/Homework/cs5410/bbiy/index.html new file mode 100644 index 0000000..d89a6b9 --- /dev/null +++ b/Homework/cs5410/bbiy/index.html @@ -0,0 +1,47 @@ + + + + Big Blue Is You! + + + + +
+
+ + + +
+
+ + + + + + diff --git a/Homework/cs5410/bbiy/index.js b/Homework/cs5410/bbiy/index.js new file mode 100644 index 0000000..8b046c1 --- /dev/null +++ b/Homework/cs5410/bbiy/index.js @@ -0,0 +1,55 @@ +const express = require('express'); +const path = require('path'); +const fs = require('fs'); + +const MAP_LAYERS=2; + +const app = express(); +app.route('/').get((req, res) => { + res.sendFile(path.join(__dirname, 'index.html')); +}); + +app.route('/levels').get((req, res) => { + fs.readFile(path.join(__dirname, 'levels-all.bbiy'), 'utf8', (err, data) => { + if (err) { + console.log(err); + return; + } + + const levels = []; + const lines = data.split('\r\n'); + do { + const levelName = lines.shift(); + if (!levelName) { + break; + } + const [xDim, yDim] = lines.shift().split(' x ').map((x) => parseInt(x)); + + let level = Array(yDim).fill(null).map(() => Array(xDim).fill(null).map(() => [])); + for (let i = 0; i < MAP_LAYERS; i++) { + for (let y = 0; y < yDim; y++) { + const line = lines.shift().split(''); + for (let x = 0; x < xDim; x++) { + if (line[x] !== ' ') { + level[y][x].push(line[x]); + } + } + } + } + levels.push({ + levelName, + gridSize: {xDim, yDim}, + level, + }); + } while (lines.length); + + // Send the array of objects + res.send(levels); + }); +}); + +app.use(express.static('.')); + +app.listen(3000, () => { + console.log('Listening on 3000'); +}); diff --git a/Homework/cs5410/bbiy/levels-all.bbiy b/Homework/cs5410/bbiy/levels-all.bbiy new file mode 100644 index 0000000..a098f30 --- /dev/null +++ b/Homework/cs5410/bbiy/levels-all.bbiy @@ -0,0 +1,252 @@ +(almost) No Rules +20 x 20 +hhhhhhhhhhhhhhhhhhhh +h h +h h +h h +h h +h h +h h +h wwwwwwwwwwww h +h r h +h b r f h +h r h +h aaaaa vvvvv h +h h +h h +h h +h h +h h +h h +h h +hhhhhhhhhhhhhhhhhhhh + + + V IK A IN + + W R + IS IP + + + + + + + + BIY IX + F + + + + + +Level-1 +20 x 20 +hhhhhhhhhhhhhhhhhhhh +h h +h h +h h +h h +h h +h h +h h +h llllllllllll h +h llllllllllll h +h llllllllllll h +h h +h h +h h +h h +h h +h h +h h +h h +hhhhhhhhhhhhhhhhhhhh + + + + + + WIS RIP + + wwwwwwwwwwww + r + b r f + r + wwwwwwwwwwww + + BIY FIX + + + + + + +Level-2 +20 x 20 +hhhhhhhhhhhhhhhhhhhh +h h +h g h +h h +h g g h +h g g h +h h +h h +h h +h h +h h +h h +h h +h h +h h +h g g h +h g h +h g gg h +h h +hhhhhhhhhhhhhhhhhhhh + + + + + wwwwwwww + w w + w I w + wwwww X w + w w + w F f b w + w w + wwwwwwwwwwww + + B W + I I + Y S + + + + +Level-3 +20 x 20 +hhhhhhhhhhhhhhhhhhhh +h h +h g g h +h g g h +h h +h g g gg h +h g g h +h g h +h h +h h +h g h +h h +h gh +h h +h gg h +h h +h g h +h gg h +h h +hhhhhhhhhhhhhhhhhhhh + + + + FIX + wwwww + w w + w f w + w w + wwwwwwwwwww + w w + w WIS w + w w + w w + w b w + w w + w w + wwwwwwwwwww + BIY + + +Level-4 +20 x 20 +hhhhhhhhhhhhhhhhhhhh +h h +h g h +h g gh +h h +h g g h +h h +h gg h +h h +h h +h h +h h +h h +h g h +h h +hg h +h h +h g ggg h +h g g h +hhhhhhhhhhhhhhhhhhhh + + BWw + IIw AIN + YSw wwwwwwww + www w w + w RIP w + w w + w b rr w + w w + wwwwwaaaawwwww + w w + w w + w w + waaa w + waaa FIX w + wfaa w + wwwwwwwwwwwwww + + + +Level-5 +20 x 20 +hhhhhhhhhhhhhhhhhhhh +h h +h g g h +h gg h +h g h +h h +h h +h ggg h +h g g h +h g ggg h +h g h +h h +h h +h gg g h +h h +h h +h g g h +h g h +h h +hhhhhhhhhhhhhhhhhhhh + + + r + r r + r W + I + wwwww vvvvv S + w w v v + w b r v f v + w w v v + wwwww vvvvv + + + wBIYw r + F + RIP I + X + + VIK + diff --git a/Homework/cs5410/bbiy/package-lock.json b/Homework/cs5410/bbiy/package-lock.json new file mode 100644 index 0000000..0a4e4d5 --- /dev/null +++ b/Homework/cs5410/bbiy/package-lock.json @@ -0,0 +1,876 @@ +{ + "name": "bigblueisyou", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "bigblueisyou", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "express": "^4.17.3" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + } + }, + "dependencies": { + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "requires": { + "bytes": "3.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + } + } +} diff --git a/Homework/cs5410/bbiy/package.json b/Homework/cs5410/bbiy/package.json new file mode 100644 index 0000000..e3dfbf8 --- /dev/null +++ b/Homework/cs5410/bbiy/package.json @@ -0,0 +1,15 @@ +{ + "name": "bigblueisyou", + "version": "1.0.0", + "description": "Big Blue Is You!", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node index.js" + }, + "author": "Logan Hunt", + "license": "ISC", + "dependencies": { + "express": "^4.17.3" + } +} diff --git a/Homework/cs5410/bbiy/src/bootstrap.js b/Homework/cs5410/bbiy/src/bootstrap.js new file mode 100644 index 0000000..09e7ec5 --- /dev/null +++ b/Homework/cs5410/bbiy/src/bootstrap.js @@ -0,0 +1,117 @@ +game.bootstrap = (() => { + const image_extensions = ["png", "jpeg", "jpg"]; + const audio_extensions = ["mp3"]; + const scripts = [ + { + src: [ + 'src/utils/objectEquivalence.js', 'src/utils/unitizeVector.js', 'src/utils/clamp.js', 'src/utils/loadLevel.js', + 'src/utils/randInRange.js' + ], + id: 'utils' + }, + { src: ['src/render/graphics.js'], id: 'graphics' }, + { src: ['src/render/sprites.js'], id: 'sprites' }, + { src: ['src/components/component.js'], id: 'component' }, + { + src: [ + 'src/components/position.js', 'src/components/momentum.js', 'src/components/gridPosition.js', + 'src/components/appearence.js', 'src/components/controllable.js', 'src/components/pushable.js', + 'src/components/loadPriority.js', 'src/components/stop.js', 'src/components/alive.js', + 'src/components/sprite.js', 'src/components/particles.js', 'src/components/noun.js', + 'src/components/name.js', 'src/components/verb.js', 'src/components/burn.js', + 'src/components/burnable.js', 'src/components/sink.js', 'src/components/sinkable.js', + 'src/components/win.js', + ], + id: 'components' + }, + { src: ['src/entities/entity.js'], id: 'entity' }, + { + src: [ + 'src/entities/bigblue.js', 'src/entities/flag.js', 'src/entities/floor.js', 'src/entities/grass.js', 'src/entities/hedge.js', + 'src/entities/lava.js', 'src/entities/rock.js', 'src/entities/wall.js', 'src/entities/wordBigBlue.js', + 'src/entities/wordFlag.js', 'src/entities/wordIs.js', 'src/entities/wordKill.js', 'src/entities/wordLava.js', + 'src/entities/wordPush.js', 'src/entities/wordRock.js', 'src/entities/wordSink.js', 'src/entities/wordStop.js', + 'src/entities/wordWall.js', 'src/entities/wordWater.js', 'src/entities/wordWin.js', 'src/entities/wordYou.js', + 'src/entities/borderParticles.js', 'src/entities/water.js' + ], + id: 'entities' + }, + { src: ['src/systems/system.js'], id: 'system' }, + { + src: [ + 'src/systems/render.js', 'src/systems/grid.js', 'src/systems/physics.js', 'src/systems/keyboardInput.js', + 'src/systems/collision.js', 'src/systems/undo.js', 'src/systems/particle.js', 'src/systems/menu.js', 'src/systems/logic.js', + ], + id: 'systems' }, + { src: ['src/game.js'], id: 'game' }, + ]; + const assets = {}; + [ + "bigblue", "flag", "floor", "grass", "hedge", "lava", "rock", + "wall", "wordBigBlue", "wordFlag", "wordIs", "wordKill", "wordLava", + "wordPush", "wordRock", "wordSink", "wordStop", "wordWall", "wordWater", + "wordWin", "wordYou", "water" + ].map((x) => assets[x] = `assets/image/${x}.png`); + [ + "music", "death", "move", "win" + ].map((x) => assets[x] = `assets/sound/${x}.mp3`); + + const loadScripts = function(onDone) { + if (scripts.length) { + let script = scripts.shift(); + require(script.src, () => { + loadScripts(onDone); + }); + } else { + onDone(); + } + } + + const loadAsset = (source) => { + let fileExtension = source.substr(source.lastIndexOf('.') + 1); + return fetch(source) + .then((r) => r.blob()) + .then((r) => { + let asset; + if (image_extensions.includes(fileExtension)) { + asset = new Image(); + } else if (audio_extensions.includes(fileExtension)) { + asset = new Audio(); + } + asset.src = URL.createObjectURL(r); + const ready = () => URL.revokeObjectURL(asset.src); + if (asset instanceof Image) { + asset.onload = ready; + } else if (asset instanceof Audio) { + asset.oncanplaythrough = ready; + } + return asset; + }) + } + + const loadAssets = function() { + game.assets = {}; + const promises = []; + for (let key in assets) { + promises.push(loadAsset(assets[key], (asset) => { + game.assets[key] = asset; + }, (error) => { + console.log(error) + })); + } + return Promise.all(Object.keys(assets).map((key) => { + return loadAsset(assets[key]).then((asset) => game.assets[key] = asset); + })); + } + + const loadLevels = function() { + game.levels = []; + fetch('/levels') + .then((r) => r.json()) + .then((r) => game.levels = r); + } + + Promise.all([loadAssets(), loadLevels()]).then(() => { + loadScripts(() => game.initialize()); + }) +})(); diff --git a/Homework/cs5410/bbiy/src/components/alive.js b/Homework/cs5410/bbiy/src/components/alive.js new file mode 100644 index 0000000..08b0890 --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/alive.js @@ -0,0 +1 @@ +game.components.Alive = () => game.Component('alive'); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/appearence.js b/Homework/cs5410/bbiy/src/components/appearence.js new file mode 100644 index 0000000..8c2130a --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/appearence.js @@ -0,0 +1 @@ +game.components.Appearance = ({rot, width, height}) => game.Component('appearance', {rot, width, height}); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/burn.js b/Homework/cs5410/bbiy/src/components/burn.js new file mode 100644 index 0000000..f138e9d --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/burn.js @@ -0,0 +1 @@ +game.components.Burn = () => game.Component('burn', {}); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/burnable.js b/Homework/cs5410/bbiy/src/components/burnable.js new file mode 100644 index 0000000..d5767e7 --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/burnable.js @@ -0,0 +1 @@ +game.components.Burnable = () => game.Component('burnable', {}); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/component.js b/Homework/cs5410/bbiy/src/components/component.js new file mode 100644 index 0000000..9b55a1f --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/component.js @@ -0,0 +1,8 @@ +game.components = {}; + +game.Component = (name, spec) => { + return { + name, + ...spec + }; +}; diff --git a/Homework/cs5410/bbiy/src/components/controllable.js b/Homework/cs5410/bbiy/src/components/controllable.js new file mode 100644 index 0000000..84b05ee --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/controllable.js @@ -0,0 +1 @@ +game.components.Controllable = ({ controls }) => game.Component('controllable', { controls }); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/gridPosition.js b/Homework/cs5410/bbiy/src/components/gridPosition.js new file mode 100644 index 0000000..ede4b23 --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/gridPosition.js @@ -0,0 +1 @@ +game.components.GridPosition = ({x, y}) => game.Component('gridPosition', {x, y}); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/loadPriority.js b/Homework/cs5410/bbiy/src/components/loadPriority.js new file mode 100644 index 0000000..35c3887 --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/loadPriority.js @@ -0,0 +1 @@ +game.components.LoadPriority = ({priority}) => game.Component('loadPriority', {priority}); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/momentum.js b/Homework/cs5410/bbiy/src/components/momentum.js new file mode 100644 index 0000000..b974aa7 --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/momentum.js @@ -0,0 +1 @@ +game.components.Momentum = ({dx, dy}) => game.Component('momentum', {dx, dy}); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/name.js b/Homework/cs5410/bbiy/src/components/name.js new file mode 100644 index 0000000..d3bf14a --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/name.js @@ -0,0 +1 @@ +game.components.Name = ({selector}) => game.Component('name', {selector}); diff --git a/Homework/cs5410/bbiy/src/components/noun.js b/Homework/cs5410/bbiy/src/components/noun.js new file mode 100644 index 0000000..4b01e06 --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/noun.js @@ -0,0 +1 @@ +game.components.Noun = ({select}) => game.Component('noun', {select}); diff --git a/Homework/cs5410/bbiy/src/components/particles.js b/Homework/cs5410/bbiy/src/components/particles.js new file mode 100644 index 0000000..8120ff1 --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/particles.js @@ -0,0 +1 @@ +game.components.Particles = (spec) => game.Component('particles', {spec}); diff --git a/Homework/cs5410/bbiy/src/components/position.js b/Homework/cs5410/bbiy/src/components/position.js new file mode 100644 index 0000000..072a1a6 --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/position.js @@ -0,0 +1 @@ +game.components.Position = ({x, y}) => game.Component('position', {x, y}) \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/pushable.js b/Homework/cs5410/bbiy/src/components/pushable.js new file mode 100644 index 0000000..85087ea --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/pushable.js @@ -0,0 +1 @@ +game.components.Pushable = () => game.Component('pushable'); diff --git a/Homework/cs5410/bbiy/src/components/sink.js b/Homework/cs5410/bbiy/src/components/sink.js new file mode 100644 index 0000000..3a4d9dc --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/sink.js @@ -0,0 +1 @@ +game.components.Sink = () => game.Component('sink', {}); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/sinkable.js b/Homework/cs5410/bbiy/src/components/sinkable.js new file mode 100644 index 0000000..1fcb132 --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/sinkable.js @@ -0,0 +1 @@ +game.components.Sinkable = () => game.Component('sinkable', {}); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/sprite.js b/Homework/cs5410/bbiy/src/components/sprite.js new file mode 100644 index 0000000..f45975d --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/sprite.js @@ -0,0 +1 @@ +game.components.Sprite = ({spriteName}) => game.Component('sprite', {spriteName}); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/components/stop.js b/Homework/cs5410/bbiy/src/components/stop.js new file mode 100644 index 0000000..17d4c38 --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/stop.js @@ -0,0 +1 @@ +game.components.Stop = () => game.Component("stop"); diff --git a/Homework/cs5410/bbiy/src/components/verb.js b/Homework/cs5410/bbiy/src/components/verb.js new file mode 100644 index 0000000..393e48c --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/verb.js @@ -0,0 +1 @@ +game.components.Verb = ({action}) => game.Component('verb', {action}); diff --git a/Homework/cs5410/bbiy/src/components/win.js b/Homework/cs5410/bbiy/src/components/win.js new file mode 100644 index 0000000..ea905fc --- /dev/null +++ b/Homework/cs5410/bbiy/src/components/win.js @@ -0,0 +1 @@ +game.components.Win = () => game.Component('win', {}); \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/entities/bigblue.js b/Homework/cs5410/bbiy/src/entities/bigblue.js new file mode 100644 index 0000000..45fbc90 --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/bigblue.js @@ -0,0 +1,13 @@ +game.createBigBlue = () => { + const bigBlue = game.Entity(); + bigBlue.addComponent(game.components.LoadPriority({priority: 1})); + bigBlue.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + bigBlue.addComponent(game.components.Alive()); + bigBlue.addComponent(game.components.Sprite({spriteName: "bigBlue"})); + +// bigBlue.addComponent(game.components.Controllable({controls: ['left', 'right', 'up', 'down']})); + bigBlue.addComponent(game.components.Name({selector: "bigblue"})); + bigBlue.addComponent(game.components.Burnable()); + bigBlue.addComponent(game.components.Sinkable()); + return bigBlue; +}; diff --git a/Homework/cs5410/bbiy/src/entities/borderParticles.js b/Homework/cs5410/bbiy/src/entities/borderParticles.js new file mode 100644 index 0000000..e1a7e98 --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/borderParticles.js @@ -0,0 +1,41 @@ +game.createBorderParticles = (spawnerSpec) => { + const particleSpawner = game.Entity(); + const spawnFunction = (particleSpec) => { + switch (Math.floor(Math.random() * 4)) { + case 0: + particleSpec.y = 0; + particleSpec.dy = -Math.abs(particleSpec.dy); + break; + case 1: + particleSpec.x = 1; + particleSpec.dx = Math.abs(particleSpec.dx); + break; + case 2: + particleSpec.y = 1; + particleSpec.dy = Math.abs(particleSpec.dy); + break; + case 3: + particleSpec.x = 0; + particleSpec.dx = -Math.abs(particleSpec.dx); + break; + } + return particleSpec; + }; + particleSpawner.addComponent(game.components.Particles({ + spec: { + spawnFunction, + colors: ["#666666", "#777777", "#888888", "#999999"], + maxSpeed: 0.20, + minRadius: 1, + maxRadius: 3, + minLife: 100, + maxLife: 300, + minAmount: 20, + maxAmount: 50, + ...spawnerSpec, + } + })); + particleSpawner.addComponent(game.components.LoadPriority({priority: 1})); + particleSpawner.addComponent(game.components.Alive()); + return particleSpawner; +} diff --git a/Homework/cs5410/bbiy/src/entities/entity.js b/Homework/cs5410/bbiy/src/entities/entity.js new file mode 100644 index 0000000..3da032c --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/entity.js @@ -0,0 +1,23 @@ +game.nextId = 0; + +game.Entity = (id=game.nextId++) => { + const components = {}; + + const addComponent = (component) => { + components[component.name] = component; + }; + const hasComponent = (componentName) => components[componentName] !== undefined; + const removeComponent = (componentName) => { + if (hasComponent(componentName)) { + delete components[componentName]; + } + }; + + return { + id, + components, + addComponent, + removeComponent, + hasComponent + }; +} \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/entities/flag.js b/Homework/cs5410/bbiy/src/entities/flag.js new file mode 100644 index 0000000..e8c662a --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/flag.js @@ -0,0 +1,12 @@ +game.createFlag = () => { + const flag = game.Entity(); + flag.addComponent(game.components.LoadPriority({priority: 5})); + flag.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + flag.addComponent(game.components.Alive()); + flag.addComponent(game.components.Sprite({spriteName: "flag"})) + flag.addComponent(game.components.Name({selector: "flag"})); + + flag.addComponent(game.components.Burnable()); + flag.addComponent(game.components.Sinkable()); + return flag; +} diff --git a/Homework/cs5410/bbiy/src/entities/floor.js b/Homework/cs5410/bbiy/src/entities/floor.js new file mode 100644 index 0000000..95cbcf2 --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/floor.js @@ -0,0 +1,8 @@ +game.createFloor = () => { + const floor = game.Entity(); + floor.addComponent(game.components.LoadPriority({priority: 6})); + floor.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + floor.addComponent(game.components.Alive()); + floor.addComponent(game.components.Sprite({spriteName: "floor"})) + return floor; +} diff --git a/Homework/cs5410/bbiy/src/entities/grass.js b/Homework/cs5410/bbiy/src/entities/grass.js new file mode 100644 index 0000000..7f26712 --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/grass.js @@ -0,0 +1,8 @@ +game.createGrass = () => { + const grass = game.Entity(); + grass.addComponent(game.components.LoadPriority({priority: 6})); + grass.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + grass.addComponent(game.components.Alive()); + grass.addComponent(game.components.Sprite({spriteName: "grass"})) + return grass; +} diff --git a/Homework/cs5410/bbiy/src/entities/hedge.js b/Homework/cs5410/bbiy/src/entities/hedge.js new file mode 100644 index 0000000..90d069b --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/hedge.js @@ -0,0 +1,9 @@ +game.createHedge = () => { + const hedge = game.Entity(); + hedge.addComponent(game.components.LoadPriority({priority: 6})); + hedge.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + hedge.addComponent(game.components.Stop({stop: true})); + hedge.addComponent(game.components.Alive()); + hedge.addComponent(game.components.Sprite({spriteName: "hedge"})) + return hedge; +} diff --git a/Homework/cs5410/bbiy/src/entities/lava.js b/Homework/cs5410/bbiy/src/entities/lava.js new file mode 100644 index 0000000..e529812 --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/lava.js @@ -0,0 +1,9 @@ +game.createLava = () => { + const lava = game.Entity(); + lava.addComponent(game.components.LoadPriority({priority: 6})); + lava.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + lava.addComponent(game.components.Alive()); + lava.addComponent(game.components.Sprite({spriteName: "lava"})) + lava.addComponent(game.components.Name({selector: "lava"})); + return lava; +} diff --git a/Homework/cs5410/bbiy/src/entities/rock.js b/Homework/cs5410/bbiy/src/entities/rock.js new file mode 100644 index 0000000..a87710a --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/rock.js @@ -0,0 +1,14 @@ +game.createRock = () => { + const rock = game.Entity(); + rock.addComponent(game.components.LoadPriority({priority: 2})); + rock.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + rock.addComponent(game.components.Alive()); + rock.addComponent(game.components.Sprite({spriteName: "rock"}));; + + +// rock.addComponent(game.components.Pushable()); + rock.addComponent(game.components.Name({selector: "rock"})); + rock.addComponent(game.components.Sinkable()); + + return rock; +}; diff --git a/Homework/cs5410/bbiy/src/entities/wall.js b/Homework/cs5410/bbiy/src/entities/wall.js new file mode 100644 index 0000000..e7549ca --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wall.js @@ -0,0 +1,13 @@ +game.createWall = () => { + const wall = game.Entity(); + wall.addComponent(game.components.LoadPriority({priority: 3})); + wall.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); +// wall.addComponent(game.components.Stop()); + wall.addComponent(game.components.Name({selector: "wall"})); + wall.addComponent(game.components.Alive()); + wall.addComponent(game.components.Sprite({spriteName: "wall"})); + + wall.addComponent(game.components.Burnable()); + wall.addComponent(game.components.Sinkable()); + return wall; +}; diff --git a/Homework/cs5410/bbiy/src/entities/water.js b/Homework/cs5410/bbiy/src/entities/water.js new file mode 100644 index 0000000..11522b1 --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/water.js @@ -0,0 +1,9 @@ +game.createWater = () => { + const water = game.Entity(); + water.addComponent(game.components.LoadPriority({priority: 5})); + water.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + water.addComponent(game.components.Alive()); + water.addComponent(game.components.Sprite({spriteName: "water"})) + water.addComponent(game.components.Name({selector: "water"})) + return water; +} diff --git a/Homework/cs5410/bbiy/src/entities/wordBigBlue.js b/Homework/cs5410/bbiy/src/entities/wordBigBlue.js new file mode 100644 index 0000000..15aaa0e --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordBigBlue.js @@ -0,0 +1,10 @@ +game.createWordBigBlue = () => { + const wordBigBlue = game.Entity(); + wordBigBlue.addComponent(game.components.LoadPriority({priority: 3})); + wordBigBlue.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordBigBlue.addComponent(game.components.Pushable({pushable: true})); + wordBigBlue.addComponent(game.components.Alive()); + wordBigBlue.addComponent(game.components.Sprite({spriteName: "wordBigBlue"})); + wordBigBlue.addComponent(game.components.Noun({select: "bigblue"})); + return wordBigBlue; +}; diff --git a/Homework/cs5410/bbiy/src/entities/wordFlag.js b/Homework/cs5410/bbiy/src/entities/wordFlag.js new file mode 100644 index 0000000..79617ea --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordFlag.js @@ -0,0 +1,10 @@ +game.createWordFlag = () => { + const wordFlag = game.Entity(); + wordFlag.addComponent(game.components.LoadPriority({priority: 3})); + wordFlag.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordFlag.addComponent(game.components.Pushable({pushable: true})); + wordFlag.addComponent(game.components.Alive()); + wordFlag.addComponent(game.components.Sprite({spriteName: "wordFlag"})); + wordFlag.addComponent(game.components.Noun({select: "flag"})); + return wordFlag; +} diff --git a/Homework/cs5410/bbiy/src/entities/wordIs.js b/Homework/cs5410/bbiy/src/entities/wordIs.js new file mode 100644 index 0000000..041f10c --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordIs.js @@ -0,0 +1,11 @@ +game.createWordIs = () => { + const wordIs = game.Entity(); + wordIs.addComponent(game.components.LoadPriority({priority: 3})); + wordIs.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + // wordIs.addComponent(game.components.Stop({stop: true})); + wordIs.addComponent(game.components.Pushable()); + wordIs.addComponent(game.components.Alive()); + wordIs.addComponent(game.components.Sprite({spriteName: "wordIs"})); + wordIs.addComponent(game.components.Verb({action: "Is"})); + return wordIs; +}; diff --git a/Homework/cs5410/bbiy/src/entities/wordKill.js b/Homework/cs5410/bbiy/src/entities/wordKill.js new file mode 100644 index 0000000..6906e9c --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordKill.js @@ -0,0 +1,10 @@ +game.createWordKill = () => { + const wordKill = game.Entity(); + wordKill.addComponent(game.components.LoadPriority({priority: 3})); + wordKill.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordKill.addComponent(game.components.Pushable({pushable: true})); + wordKill.addComponent(game.components.Alive()); + wordKill.addComponent(game.components.Sprite({spriteName: "wordKill"})) + wordKill.addComponent(game.components.Verb({action: "burn"})); + return wordKill; +} diff --git a/Homework/cs5410/bbiy/src/entities/wordLava.js b/Homework/cs5410/bbiy/src/entities/wordLava.js new file mode 100644 index 0000000..cf31286 --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordLava.js @@ -0,0 +1,11 @@ +game.createWordLava = () => { + const wordLava = game.Entity(); + wordLava.addComponent(game.components.LoadPriority({priority: 3})); + wordLava.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordLava.addComponent(game.components.Pushable({pushable: true})); + wordLava.addComponent(game.components.Alive()); + + wordLava.addComponent(game.components.Sprite({spriteName: "wordLava"})) + wordLava.addComponent(game.components.Noun({select: "lava"})); + return wordLava; +} diff --git a/Homework/cs5410/bbiy/src/entities/wordPush.js b/Homework/cs5410/bbiy/src/entities/wordPush.js new file mode 100644 index 0000000..5594e46 --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordPush.js @@ -0,0 +1,10 @@ +game.createWordPush = () => { + const wordPush = game.Entity(); + wordPush.addComponent(game.components.LoadPriority({priority: 3})); + wordPush.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordPush.addComponent(game.components.Pushable({pushable: true})); + wordPush.addComponent(game.components.Alive()); + wordPush.addComponent(game.components.Sprite({spriteName: "wordPush"})); + wordPush.addComponent(game.components.Verb({action: "push"})); + return wordPush; +}; diff --git a/Homework/cs5410/bbiy/src/entities/wordRock.js b/Homework/cs5410/bbiy/src/entities/wordRock.js new file mode 100644 index 0000000..648f6ba --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordRock.js @@ -0,0 +1,10 @@ +game.createWordRock = () => { + const wordRock = game.Entity(); + wordRock.addComponent(game.components.LoadPriority({priority: 3})); + wordRock.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordRock.addComponent(game.components.Pushable({pushable: true})); + wordRock.addComponent(game.components.Alive()); + wordRock.addComponent(game.components.Sprite({spriteName: "wordRock"})); + wordRock.addComponent(game.components.Noun({select: "rock"})); + return wordRock; +}; diff --git a/Homework/cs5410/bbiy/src/entities/wordSink.js b/Homework/cs5410/bbiy/src/entities/wordSink.js new file mode 100644 index 0000000..369f922 --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordSink.js @@ -0,0 +1,10 @@ +game.createWordSink = () => { + const wordSink = game.Entity(); + wordSink.addComponent(game.components.LoadPriority({priority: 3})); + wordSink.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordSink.addComponent(game.components.Pushable({pushable: true})); + wordSink.addComponent(game.components.Alive()); + wordSink.addComponent(game.components.Sprite({spriteName: "wordSink"})); + wordSink.addComponent(game.components.Verb({action: "sink"})); + return wordSink; +} diff --git a/Homework/cs5410/bbiy/src/entities/wordStop.js b/Homework/cs5410/bbiy/src/entities/wordStop.js new file mode 100644 index 0000000..e2ad45c --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordStop.js @@ -0,0 +1,10 @@ +game.createWordStop = () => { + const wordStop = game.Entity(); + wordStop.addComponent(game.components.LoadPriority({priority: 3})); + wordStop.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordStop.addComponent(game.components.Pushable({pushable: true})); + wordStop.addComponent(game.components.Alive()); + wordStop.addComponent(game.components.Sprite({spriteName: "wordStop"})); + wordStop.addComponent(game.components.Verb({action: "stop"})); + return wordStop; +}; diff --git a/Homework/cs5410/bbiy/src/entities/wordWall.js b/Homework/cs5410/bbiy/src/entities/wordWall.js new file mode 100644 index 0000000..277ab69 --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordWall.js @@ -0,0 +1,10 @@ +game.createWordWall = () => { + const wordWall = game.Entity(); + wordWall.addComponent(game.components.LoadPriority({priority: 3})); + wordWall.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordWall.addComponent(game.components.Pushable({pushable: true})); + wordWall.addComponent(game.components.Alive()); + wordWall.addComponent(game.components.Noun({select: "wall"})); + wordWall.addComponent(game.components.Sprite({spriteName: "wordWall"})); + return wordWall; +}; diff --git a/Homework/cs5410/bbiy/src/entities/wordWater.js b/Homework/cs5410/bbiy/src/entities/wordWater.js new file mode 100644 index 0000000..eb0c1be --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordWater.js @@ -0,0 +1,10 @@ +game.createWordWater = () => { + const wordWater = game.Entity(); + wordWater.addComponent(game.components.LoadPriority({priority: 3})); + wordWater.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordWater.addComponent(game.components.Pushable({pushable: true})); + wordWater.addComponent(game.components.Alive()); + wordWater.addComponent(game.components.Sprite({spriteName: "wordWater"})); + wordWater.addComponent(game.components.Noun({select: "water"})); + return wordWater; +} diff --git a/Homework/cs5410/bbiy/src/entities/wordWin.js b/Homework/cs5410/bbiy/src/entities/wordWin.js new file mode 100644 index 0000000..e8948ee --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordWin.js @@ -0,0 +1,10 @@ +game.createWordWin = () => { + const wordWin = game.Entity(); + wordWin.addComponent(game.components.LoadPriority({priority: 3})); + wordWin.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordWin.addComponent(game.components.Pushable({pushable: true})); + wordWin.addComponent(game.components.Alive()); + wordWin.addComponent(game.components.Sprite({spriteName: "wordWin"})); + wordWin.addComponent(game.components.Verb({action: "win"})); + return wordWin; +} diff --git a/Homework/cs5410/bbiy/src/entities/wordYou.js b/Homework/cs5410/bbiy/src/entities/wordYou.js new file mode 100644 index 0000000..1bf698f --- /dev/null +++ b/Homework/cs5410/bbiy/src/entities/wordYou.js @@ -0,0 +1,10 @@ +game.createWordYou = () => { + const wordYou = game.Entity(); + wordYou.addComponent(game.components.LoadPriority({priority: 3})); + wordYou.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); + wordYou.addComponent(game.components.Pushable({pushable: true})); + wordYou.addComponent(game.components.Alive()); + wordYou.addComponent(game.components.Sprite({spriteName: "wordYou"})); + wordYou.addComponent(game.components.Verb({action: "you"})); + return wordYou; +}; diff --git a/Homework/cs5410/bbiy/src/game.js b/Homework/cs5410/bbiy/src/game.js new file mode 100644 index 0000000..5a7e391 --- /dev/null +++ b/Homework/cs5410/bbiy/src/game.js @@ -0,0 +1,72 @@ +game.loop = (timeStamp) => { + if (!game.running) { + return; + } + + let elapsedTime = timeStamp - game.lastTimeStamp; + game.lastTimeStamp = timeStamp; + + const changedIds = new Set(); + game.systemOrder.map((i) => { + game.systems[i] + .update(elapsedTime, game.entities, changedIds) + .forEach((id) => changedIds.add(id)); + }); + + for (let id in game.entities) { + if (game.entities[id].hasComponent("particles") && !game.entities[id].hasComponent("alive")) { + delete game.entities[id]; + } + } + + requestAnimationFrame(game.loop); +}; + +game.toggleRunning = () => { + game.running = !game.running; +}; + +game.startLoop = () => { + game.running = true; + game.lastTimeStamp = performance.now(); + game.assets.music.play(); + if (game.assets.music.paused) { + alert("Failed to start background music; please allow autoplay in your browser settings."); + } + requestAnimationFrame(game.loop); +}; + +game.loadSystems = () => { + game.systemOrder = ["grid", "collision", "physics", "keyboardInput", "particle", "logic", "undo", "render"]; + game.systems = { }; + game.systems.physics = game.system.Physics(), + game.systems.grid = game.system.Grid(game.entitiesGrid); + game.systems.collision = game.system.Collision(game.entitiesGrid); + game.systems.render = game.system.Render(game.graphics); + game.systems.particle = game.system.Particle(game.canvas.context); + game.systems.keyboardInput = game.system.KeyboardInput(); + game.systems.logic = game.system.Logic(game.entitiesGrid); + game.systems.undo = game.system.Undo(game.entitiesGrid, game.systems.logic, game.systems.grid); + game.systems.menu = game.system.Menu(); +}; + +game.loadLevelIndex = (level) => { + game.win = false; + + game.level = level; + [game.entities, game.config] = game.loadLevel(game.levels[game.level]); + + // Maintained by grid system as a side-effect + game.entitiesGrid = Array(game.config.yDim).fill(null).map(() => Array(game.config.xDim).fill(null).map(() => new Map())); + game.loadSystems(); +}; + +game.initialize = () => { + game.assets.music.addEventListener('ended', function() { + this.currentTime = 0; + this.play(); + }, false); + + game.loadLevelIndex(0); + game.startLoop(); +}; diff --git a/Homework/cs5410/bbiy/src/render/graphics.js b/Homework/cs5410/bbiy/src/render/graphics.js new file mode 100644 index 0000000..aa4195e --- /dev/null +++ b/Homework/cs5410/bbiy/src/render/graphics.js @@ -0,0 +1,47 @@ +// Pretty much a copy of my centipede code +game.graphics = ( + (context) => { + context.imageSmoothingEnabled = false; + const clear = () => { + context.clearRect(0, 0, game.canvas.width, game.canvas.height); + }; + + const Sprite = ({image, spriteX, spriteY, spriteWidth, spriteHeight, timePerFrame, cols, rows, numFrames, color, drawFunction}) => { + timePerFrame = timePerFrame ?? 100; + numFrames = numFrames ?? 1; + cols = cols ?? numFrames; + rows = rows ?? 1; + spriteX = spriteX ?? 0; + spriteY = spriteY ?? 0; + + let currentFrame = 0; + let lastTime = performance.now(); + + let draw; + if (!drawFunction) { + draw = (_elapsedTime, {x, y, rot, width, height}) => { + if (numFrames > 1) { + if (performance.now()-lastTime > timePerFrame) { + lastTime = performance.now(); + currentFrame = (currentFrame + 1) % numFrames; + } + } + context.save(); + context.translate(x+width/2, y+height/2); + context.rotate(rot * Math.PI / 180); + context.translate(-x-width/2, -y-height/2); + const row = currentFrame % rows; + const col = Math.floor(currentFrame / rows); + context.drawImage(image, spriteX+col*spriteWidth, spriteY+row*spriteHeight, spriteWidth, spriteHeight, x, y, width, height); + + context.restore(); + }; + } else { + draw = (elapsedTime, drawSpec) => drawFunction(elapsedTime, drawSpec, context); + } + return { draw }; + } + + return { clear, Sprite }; + } +)(game.canvas.context); diff --git a/Homework/cs5410/bbiy/src/render/sprites.js b/Homework/cs5410/bbiy/src/render/sprites.js new file mode 100644 index 0000000..d8ae126 --- /dev/null +++ b/Homework/cs5410/bbiy/src/render/sprites.js @@ -0,0 +1,156 @@ +game.sprites = { + bigBlue: game.graphics.Sprite({ + image: game.assets.bigblue, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + flag: game.graphics.Sprite({ + image: game.assets.flag, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + floor: game.graphics.Sprite({ + image: game.assets.floor, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + hedge: game.graphics.Sprite({ + image: game.assets.hedge, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 250, + }), + grass: game.graphics.Sprite({ + image: game.assets.grass, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + lava: game.graphics.Sprite({ + image: game.assets.lava, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + rock: game.graphics.Sprite({ + image: game.assets.rock, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wall: game.graphics.Sprite({ + image: game.assets.wall, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + water: game.graphics.Sprite({ + image: game.assets.water, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordBigBlue: game.graphics.Sprite({ + image: game.assets.wordBigBlue, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordFlag: game.graphics.Sprite({ + image: game.assets.wordFlag, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordIs: game.graphics.Sprite({ + image: game.assets.wordIs, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordKill: game.graphics.Sprite({ + image: game.assets.wordKill, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordLava: game.graphics.Sprite({ + image: game.assets.wordLava, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordPush: game.graphics.Sprite({ + image: game.assets.wordPush, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordRock: game.graphics.Sprite({ + image: game.assets.wordRock, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordSink: game.graphics.Sprite({ + image: game.assets.wordSink, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordStop: game.graphics.Sprite({ + image: game.assets.wordStop, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordWall: game.graphics.Sprite({ + image: game.assets.wordWall, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordWater: game.graphics.Sprite({ + image: game.assets.wordWater, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordWin: game.graphics.Sprite({ + image: game.assets.wordWin, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), + wordYou: game.graphics.Sprite({ + image: game.assets.wordYou, + spriteHeight: 24, + spriteWidth: 24, + numFrames: 3, + timePerFrame: 100, + }), +}; diff --git a/Homework/cs5410/bbiy/src/require.js b/Homework/cs5410/bbiy/src/require.js new file mode 100644 index 0000000..a4203f0 --- /dev/null +++ b/Homework/cs5410/bbiy/src/require.js @@ -0,0 +1,5 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license RequireJS 2.3.6 Copyright jQuery Foundation and other contributors. + * Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE + */ +var requirejs,require,define;!function(global,setTimeout){var req,s,head,baseElement,dataMain,src,interactiveScript,currentlyAddingScript,mainScript,subPath,version="2.3.6",commentRegExp=/\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/gm,cjsRequireRegExp=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,jsSuffixRegExp=/\.js$/,currDirRegExp=/^\.\//,op=Object.prototype,ostring=op.toString,hasOwn=op.hasOwnProperty,isBrowser=!("undefined"==typeof window||"undefined"==typeof navigator||!window.document),isWebWorker=!isBrowser&&"undefined"!=typeof importScripts,readyRegExp=isBrowser&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,defContextName="_",isOpera="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),contexts={},cfg={},globalDefQueue=[],useInteractive=!1;function commentReplace(e,t){return t||""}function isFunction(e){return"[object Function]"===ostring.call(e)}function isArray(e){return"[object Array]"===ostring.call(e)}function each(e,t){var i;if(e)for(i=0;i { + const update = (elapsedTime, entities, changedIds) => { + const thisChangedIds = new Set(); + for (let entity of Object.keys(entities).map((id) => entities[id])) { + if (entity.hasComponent("position") && entity.hasComponent("gridPosition") && (entity.hasComponent("burnable") || entity.hasComponent("sinkable")) && entity.hasComponent("alive")) { + for (let collided of entitiesGrid[entity.components.gridPosition.y][entity.components.gridPosition.x].values()) { + if (!equivalence(entity, collided) && collided.hasComponent("alive")){ + if (entity.hasComponent("burnable") && collided.hasComponent("burn")) { + const burnedParticleSpawner = game.createBorderParticles({colors: ["#f58d42", "#d6600b", "#c7a312", "#f2b844"]}); + burnedParticleSpawner.addComponent(game.components.Position(collided.components.position)); + burnedParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim})); + game.entities[burnedParticleSpawner.id] = burnedParticleSpawner; + entity.removeComponent("alive"); + game.assets.death.play(); + break; + } else if (entity.hasComponent("sinkable") && collided.hasComponent("sink")) { + const sunkParticleSpawner = game.createBorderParticles({colors: ["#16f7c9", "#0d6e5a", "#2fa18a", "#48cfb4", "#58877d", "#178054", "#2cdb92"]}); + sunkParticleSpawner.addComponent(game.components.Position(collided.components.position)); + sunkParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim})); + game.entities[sunkParticleSpawner.id] = sunkParticleSpawner; + entity.removeComponent("alive"); + collided.removeComponent("alive"); + game.assets.death.play(); + break; + } + } + } + } + if (entity.hasComponent("controllable") && entity.hasComponent("gridPosition")) { + for (let collided of entitiesGrid[entity.components.gridPosition.y][entity.components.gridPosition.x].values()) { + if (collided.hasComponent("win")) { + game.assets.win.play(); + game.win = true; + game.systems.menu.bringUpMenu(); + game.systems.menu.setState("levelSelect"); + } + } + + if (entity.hasComponent("momentum")) { + const momentum = unitize(entity.components.momentum); + + let found; + const proposed = {x: entity.components.gridPosition.x + momentum.dx, y: entity.components.gridPosition.y + momentum.dy}; + const entitiesToPush = []; + let wall = false; + do { + const proposedClampedInBounds = clamp(proposed, game.config.xDim-1, game.config.yDim-1); + if (!equivalence(proposed, proposedClampedInBounds)) { + break; + } + + found = false; + + const entitiesInCell = entitiesGrid[proposed.y][proposed.x]; + + for (let next of entitiesInCell.values()) { + if (next.hasComponent("alive")) { + if (next.hasComponent("stop")) { + wall = next; + found = false; + break; + } + if (next.hasComponent("pushable")) { + entitiesToPush.push(next); + found = true; + } + } + } + + proposed.x += momentum.dx; + proposed.y += momentum.dy; + } while(found); + + if (wall) { + entity.removeComponent("momentum"); + } else { + game.assets.move.play(); + entitiesToPush.map((e) => { + const pushedParticleSpawner = game.createBorderParticles({maxSpeed: 0.1, minAmount: 10, maxAmount: 15}); + pushedParticleSpawner.addComponent(game.components.Position(e.components.position)); + pushedParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim})); + game.entities[pushedParticleSpawner.id] = pushedParticleSpawner; + + e.addComponent(game.components.Momentum({...momentum})); + }); + } + } + } + } + return thisChangedIds; + }; + return { update }; +}; diff --git a/Homework/cs5410/bbiy/src/systems/grid.js b/Homework/cs5410/bbiy/src/systems/grid.js new file mode 100644 index 0000000..6d4cf84 --- /dev/null +++ b/Homework/cs5410/bbiy/src/systems/grid.js @@ -0,0 +1,71 @@ +game.system.Grid = (entitiesGrid) => { + let gridWidth = game.canvas.width / game.config.xDim; + let gridHeight = game.canvas.height / game.config.yDim; + + const gameCoordsToGrid = ({ x, y }) => { + return { x: Math.floor((x+gridWidth/2) / game.canvas.width * game.config.yDim), y: Math.floor((y+gridHeight/2) / game.canvas.height * game.config.yDim) }; + }; + + const gridCoordsToGame = ({ x, y }) => { + return { x: x * gridWidth, y: y * gridHeight }; + }; + + const rebuildGrid = (entities) => { + let changedIds = new Set(); + entities.map(entity => { + const { x, y } = entity.components.gridPosition; + if (!entitiesGrid[y][x].has(entity.id)) { + changedIds.add(entity.id); + } + }); + entitiesGrid.forEach((row) => row.forEach((entitiesInCell) => { + for (let id of entitiesInCell.keys()) { + if (changedIds.has(id)) { + entitiesInCell.delete(id); + } + } + })); + changedIds.forEach(id => { + // TODO: Figure out why we HAVE to use game.entities rather than entities + // Hint: it breaks when changing a level in the menu + const entity = game.entities[id]; + const { x, y } = entity.components.gridPosition; + entitiesGrid[y][x].set(entity.id, entity); + }); + }; + + const update = (_elapsedTime, entities, changedIds) => { + gridEntities = Object.keys(entities).filter((x) => entities[x].hasComponent("gridPosition")).map((x) => entities[x]); + const thisChangedIds = new Set(); + gridEntities.map((entity) => { + if (entity.hasComponent("appearance")) { + entity.components.appearance.width = gridWidth; + entity.components.appearance.height = gridHeight; + } + if (entity.hasComponent("gridPosition")) { + const oldGridCoords = entity.components.gridPosition; + if (entity.hasComponent("position")) { + const gameCoords = gridCoordsToGame(entity.components.gridPosition); + if (Math.abs(entity.components.position.x - gameCoords.x) >= gridWidth/2 || Math.abs(entity.components.position.y - gameCoords.y) >= gridHeight/2) { + entity.components.gridPosition = gameCoordsToGrid(entity.components.position); + if (entity.hasComponent("momentum")) { + entity.removeComponent("momentum"); + } + } + } + if (!entity.hasComponent("position") || !equivalence(entity.components.gridPosition, oldGridCoords)) { + entity.components.position = { + ...entity.components.position, + ...gridCoordsToGame(entity.components.gridPosition) + }; + thisChangedIds.add(entity.id); + } + } + }); + rebuildGrid(gridEntities); + return thisChangedIds; + }; + + + return { gameCoordsToGrid, gridCoordsToGame, update, gridWidth, gridHeight }; +}; diff --git a/Homework/cs5410/bbiy/src/systems/keyboardInput.js b/Homework/cs5410/bbiy/src/systems/keyboardInput.js new file mode 100644 index 0000000..1b399ca --- /dev/null +++ b/Homework/cs5410/bbiy/src/systems/keyboardInput.js @@ -0,0 +1,46 @@ +game.system.KeyboardInput = () => { + "use strict"; + const keys = {}; + const keyPress = (event) => { + if (!event.repeat) { + keys[event.key] = true; + } + }; + const removeKey = (event) => { + delete keys[event.key]; + }; + const update = (elapsedTime, entities, changedIds) => { + for (let id in entities) { + const entity = entities[id]; + if (entity.hasComponent('controllable') && entity.hasComponent('alive')) { + const controls = entity.components.controllable.controls; + if (!changedIds.has(entity.id)) { + if (controls.includes('left') && keys[game.controls.left]) { + entity.addComponent(game.components.Momentum({ dx: -1, dy: 0 })); + } else if (controls.includes('right') && keys[game.controls.right]) { + entity.addComponent(game.components.Momentum({ dx: 1, dy: 0 })); + } else if (controls.includes('up') && keys[game.controls.up]) { + entity.addComponent(game.components.Momentum({ dx: 0, dy: -1 })); + } else if (controls.includes('down') && keys[game.controls.down]) { + entity.addComponent(game.components.Momentum({ dx: 0, dy: 1 })); + } + } + } + } + if (keys[game.controls.undo]) { + game.systems.undo.undo(entities); + } + if (keys[game.controls.reset]) { + game.loadLevelIndex(game.level); + } + if (keys["Escape"]) { + game.systems.menu.bringUpMenu(); + } + Object.keys(keys).map((key) => delete keys[key]); + + return new Set(); + }; + window.addEventListener("keydown", keyPress); + window.addEventListener("keyup", removeKey); + return { keys, update }; +} diff --git a/Homework/cs5410/bbiy/src/systems/logic.js b/Homework/cs5410/bbiy/src/systems/logic.js new file mode 100644 index 0000000..e8854c1 --- /dev/null +++ b/Homework/cs5410/bbiy/src/systems/logic.js @@ -0,0 +1,149 @@ +game.system.Logic = (entitiesGrid) => { + "use strict"; + let currentVerbRules = []; + let previousVerbState = { + controllable: new Set(), + win: new Set(), + }; + const isWord = (entity) => entity.hasComponent("gridPosition") && (entity.hasComponent("verb") || entity.hasComponent("noun")); + + const getFirstWordEntity = (gridPosition) => { + if (!equivalence(gridPosition, clamp(gridPosition, game.config.xDim, game.config.yDim))) { + return null; + } + for (let entity of entitiesGrid[gridPosition.y][gridPosition.x].values()) { + if (isWord(entity)) { + return entity; + } + } + return null; + }; + + const verbActionsToComponent = { + "stop": game.components.Stop(), + "push": game.components.Pushable(), + "you": game.components.Controllable({controls: ['left', 'right', 'up', 'down']}), + "burn": game.components.Burn(), + "sink": game.components.Sink(), + "win": game.components.Win(), + }; + + const nounsToEntityCreators = { + "rock": game.createRock, + "wall": game.createWall, + "bigblue": game.createBigBlue, + "flag": game.createFlag, + "lava": game.createLava, + "water": game.createWater, + }; + + const doOnRule = (rule, entities, direction) => { + const [applyee, application] = [entities[rule[0]], entities[rule[1]]]; + const changedEntityIds = []; + if (applyee.hasComponent("noun")) { + const entityName = applyee.components.noun.select; + if (application.hasComponent("verb")) { + const verb = application.components.verb.action; + if (direction == "apply") { + currentVerbRules.push(rule); + } + for (let id in entities) { + const entity = entities[id]; + if (entity.hasComponent("alive") && entity.hasComponent("name") && entity.components.name.selector == entityName) { + changedEntityIds.push(id); + const component = verbActionsToComponent[verb]; + if (component) { + if (direction == "apply") { + if (verb == "you") { + if (!previousVerbState.controllable.has(id)) { + const newYouParticleSpawner = game.createBorderParticles({colors: ["#ffc0cb", "#ffb6c1", "#ffc1cc", "#ffbcd9", "#ff1493"], minAmount: 80, maxAmount: 150, maxSpeed: 0.5}); + newYouParticleSpawner.addComponent(game.components.Position(entity.components.position)); + newYouParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim})); + game.entities[newYouParticleSpawner.id] = newYouParticleSpawner; + } + } + if (verb == "win") { + if (!previousVerbState.win.has(id)) { + game.assets.win.play(); + } + } + entity.addComponent(component); + } else if (direction == "deapply") { + if (entity.hasComponent("controllable")) { + previousVerbState.controllable.add(id); + } + if (entity.hasComponent("win")) { + previousVerbState.win.add(id); + } + entity.removeComponent(component.name); + } + } + } + } + if (direction == "apply") { + if (changedEntityIds.some((id) => previousVerbState.controllable.has(id))) { + previousVerbState.controllable = new Set(); + } + } + } + if (application.hasComponent("noun")) { + const applicationEntityName = application.components.noun.select; + for (let id in entities) { + const entity = entities[id]; + if (entity.hasComponent("name") && entity.components.name.selector == entityName) { + const e = nounsToEntityCreators[applicationEntityName](); + ["name", "sprite", "burnable", "sinkable"].map((name) => { + if (e.hasComponent(name)) { + entity.components[name] = e.components[name]; + } + }); + } + } + } + }; + return changedEntityIds; + }; + + const parseRules = (entities) => { + currentVerbRules.map((rule) => doOnRule(rule, entities, "deapply")); + currentVerbRules = []; + const isWordGridPositions = []; + const changedEntityIds = new Set(); + entitiesGrid.forEach((row) => row.forEach((entitiesInCell) => { + for (let entity of entitiesInCell.values()) { + if (isWord(entity) && entity.hasComponent("verb") && entity.components.verb.action == "Is") { + isWordGridPositions.push(entity.components.gridPosition); + } + } + })); + let newRules = []; + isWordGridPositions.forEach((gridPosition) => { + const east = getFirstWordEntity({y: gridPosition.y, x: gridPosition.x - 1}); + const west = getFirstWordEntity({y: gridPosition.y, x: gridPosition.x + 1}); + const north = getFirstWordEntity({x: gridPosition.x, y: gridPosition.y - 1}); + const south = getFirstWordEntity({x: gridPosition.x, y: gridPosition.y + 1}); + + if (east && west) { + newRules.push([east.id, west.id]); + } + if (north && south) { + newRules.push([north.id, south.id]); + } + }); + newRules = newRules.sort((a, b) => (entities[b[1]].hasComponent("noun") ? 1 : -1) - (entities[a[1]].hasComponent("noun") ? 1 : -1)); + newRules.map((rule) => doOnRule(rule, entities, "apply").map((id) => changedEntityIds.add(id))); + return changedEntityIds; + }; + + const update = (_elapsedTime, entities, changedIds) => { + for (let id of changedIds) { + const changed = entities[id]; + if (changed.hasComponent("verb") || changed.hasComponent("noun")) { + return parseRules(entities); + } + } + return new Set(); + }; + + return { update, parseRules }; +}; diff --git a/Homework/cs5410/bbiy/src/systems/menu.js b/Homework/cs5410/bbiy/src/systems/menu.js new file mode 100644 index 0000000..abd6748 --- /dev/null +++ b/Homework/cs5410/bbiy/src/systems/menu.js @@ -0,0 +1,114 @@ +game.system.Menu = () => { + let state; + + const menuElement = document.getElementById("menu"); + + const escapeEventListener = (e) => { + if (e.key == "Escape") { + setState('main'); + } + }; + + const setState = (newState) => { + state = newState; + draw(); + }; + + const bringUpMenu = () => { + game.running = false; + game.assets.music.pause(); + window.addEventListener("keydown", escapeEventListener); + setState("main"); + }; + + const hide = () => { + menuElement.style.display = "none"; + game.startLoop(); + }; + + const listenFor = (action, elementId) => { + const element = document.getElementById(elementId); + element.innerHTML = "Listening..."; + const handleKey = (event) => { + window.removeEventListener("keydown", handleKey); + if (event.key == "Escape") { + element.innerHTML = menu.controls[action]; + return; + } + game.controls[action] = event.key; + localStorage.setItem("controls", JSON.stringify(game.controls)); + element.innerHTML = event.key; + }; + window.addEventListener("keydown", handleKey); + }; + + const setLevel = (index) => { + game.loadLevelIndex(index); + hide(); + }; + + const draw = () => { + menuElement.style.display = "block"; + menuElement.innerHTML = `

Big Blue Is You

`; + if (state == "main") { + menuElement.innerHTML += ` + + + + `; + } + else if (state == "controls") { + menuElement.innerHTML += ` +
+

+ Move left: +
+ Move right: +
+ Move up: +
+ Move down: +
+ Undo: +
+ Reset: +

+
+ `; + } else if (state == "credits") { + menuElement.innerHTML += ` +
+

+ Sprites from Baba Is You, as hosted here, and a few custom ones. +
+ Background is from PinImg. +
+ Music is Fluffing A Duck by Kevin MacLeod. +
+ Other sound effects generated on SFXR. +
+ Developed by Logan Hunt, Ethan Payne +

+
+ `; + } else if (state == "levelSelect") { + menuElement.innerHTML += ` +
+

Select a level to play:

+ ${ + game.levels.map((level, index) => { + return ``; + }).join("") + } + `; + } + if (!game.win) { + menuElement.innerHTML += ""; + } + if (state !== "main") { + menuElement.innerHTML += ""; + } + }; + + return { bringUpMenu, setState, listenFor, hide, setLevel, state }; +}; diff --git a/Homework/cs5410/bbiy/src/systems/particle.js b/Homework/cs5410/bbiy/src/systems/particle.js new file mode 100644 index 0000000..56d8c47 --- /dev/null +++ b/Homework/cs5410/bbiy/src/systems/particle.js @@ -0,0 +1,57 @@ +game.system.Particle = () => { + "use strict"; + const particleSpawners = {}; + + const particleSpawner = ({colors, maxAmount, minAmount, minLife, maxLife, minRadius, maxRadius, maxSpeed, spawnFunction}) => { + return Array(randomInRange(minAmount, maxAmount)).fill(0).map(() => { + let particleSpec = { + x: Math.random(), + y: Math.random(), + dx: Math.random() * maxSpeed - maxSpeed / 2, + dy: Math.random() * maxSpeed - maxSpeed / 2, + radius: randomInRange(minRadius, maxRadius), + color: colors[randomInRange(0, colors.length-1)], + lifetime: randomInRange(minLife, maxLife), + elapsed: 0, + }; + if (spawnFunction) { + particleSpec = {...particleSpec, ...spawnFunction(particleSpec)}; + } + return particleSpec; + }); + }; + + const update = (elapsedTime, entities, _changedIds) => { + for (let id in entities) { + const entity = entities[id]; + if (entity.hasComponent("particles")) { + if (!particleSpawners[entity.id]) { + particleSpawners[entity.id] = particleSpawner(entity.components.particles.spec.spec); + entities[id].particleSprite = game.graphics.Sprite({ + drawFunction: (elapsedTime, {x, y, width, height}, context) => { + let particleSpawner = particleSpawners[entity.id]; + particleSpawner.map((particleSpec) => particleSpec.elapsed += elapsedTime); + particleSpawners[id] = particleSpawner.filter((particleSpec) => particleSpec.lifetime > particleSpec.elapsed); + particleSpawner = particleSpawners[id]; + if (particleSpawner.length === 0) { + entities[id].removeComponent("alive"); + } + particleSpawner.map((particleSpec) => { + const position = {x: (particleSpec.x * width) + x + particleSpec.dx * particleSpec.elapsed, y: (particleSpec.y * height) + y + particleSpec.dy * particleSpec.elapsed}; + const fill = context.fillStyle; + context.fillStyle = particleSpec.color; + context.beginPath(); + context.arc(position.x, position.y, particleSpec.radius, 0, 2 * Math.PI); + context.fill(); + context.fillStyle = fill; + }); + } + }); + } + } + } + return new Set(); + }; + + return { update }; +}; diff --git a/Homework/cs5410/bbiy/src/systems/physics.js b/Homework/cs5410/bbiy/src/systems/physics.js new file mode 100644 index 0000000..18c3cb3 --- /dev/null +++ b/Homework/cs5410/bbiy/src/systems/physics.js @@ -0,0 +1,16 @@ +game.system.Physics = () => { + const update = (elapsedTime, entities, changedIds) => { + for (let id in entities) { + const entity = entities[id]; + if (entity.hasComponent("momentum") && entity.hasComponent("appearance")) { + const {dx, dy} = entity.components.momentum; + entity.components.position.x += dx * elapsedTime; + entity.components.position.y += dy * elapsedTime; + entity.components.position = clamp(entity.components.position, game.canvas.width - entity.components.appearance.width, game.canvas.height - entity.components.appearance.height); + } + } + + return new Set(); + }; + return { update }; +}; diff --git a/Homework/cs5410/bbiy/src/systems/render.js b/Homework/cs5410/bbiy/src/systems/render.js new file mode 100644 index 0000000..e0db7e3 --- /dev/null +++ b/Homework/cs5410/bbiy/src/systems/render.js @@ -0,0 +1,26 @@ +game.system.Render = (graphics) => { + const update = (elapsedTime, entities, _changedIds) => { + graphics.clear(); + + const entitiesArray = Object.keys(entities).map(key => entities[key]); + const sortedEntities = entitiesArray.sort((a, b) => { + const aprior = a.hasComponent("loadPriority") ? a.components.loadPriority.priority : 0; + const bprior = b.hasComponent("loadPriority") ? b.components.loadPriority.priority : 0; + return bprior - aprior; + }); + + sortedEntities.forEach((entity) => { + if (entity.hasComponent("position") && entity.hasComponent("appearance") && entity.hasComponent("alive")) { + const drawSpec = {...entity.components.position, ...entity.components.appearance}; + if (entity.hasComponent("sprite")) { + game.sprites[entity.components.sprite.spriteName].draw(elapsedTime, drawSpec); + } else if (entity.hasComponent("particles") && entity.particleSprite) { + entity.particleSprite.draw(elapsedTime, drawSpec); + } + } + }); + + return new Set(); + }; + return { update }; +}; diff --git a/Homework/cs5410/bbiy/src/systems/system.js b/Homework/cs5410/bbiy/src/systems/system.js new file mode 100644 index 0000000..f331401 --- /dev/null +++ b/Homework/cs5410/bbiy/src/systems/system.js @@ -0,0 +1 @@ +game.system = {}; \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/systems/undo.js b/Homework/cs5410/bbiy/src/systems/undo.js new file mode 100644 index 0000000..086d6b4 --- /dev/null +++ b/Homework/cs5410/bbiy/src/systems/undo.js @@ -0,0 +1,32 @@ +game.system.Undo = (entitiesGrid, logicSystem, gridSystem) => { + const states = []; + + const update = (elapsedTime, entities, changedIds) => { + if (changedIds.size) { + const state = {}; + for (let id in entities) { + if (entities[id].hasComponent("gridPosition")) { + state[id] = JSON.parse(JSON.stringify(entities[id].components)); + } + } + states.push(state); + } + return new Set(); + }; + + const undo = (entities) => { + let state = states.slice(0, -1).pop(); + if (states.length > 1) { + states.pop(); + } + for (let id in state) { + for (let componentName in state[id]) { + entities[id].addComponent({name: componentName, ...state[id][componentName]}); + } + } + gridSystem.update(0, entities, new Set()); + logicSystem.parseRules(entities); + }; + + return { update, undo }; +}; diff --git a/Homework/cs5410/bbiy/src/utils/clamp.js b/Homework/cs5410/bbiy/src/utils/clamp.js new file mode 100644 index 0000000..b0da861 --- /dev/null +++ b/Homework/cs5410/bbiy/src/utils/clamp.js @@ -0,0 +1,6 @@ +const clamp = (vector, maxX, maxY) => { + const newVector = {...vector}; + newVector.x = Math.max(0, Math.min(maxX, vector.x)); + newVector.y = Math.max(0, Math.min(maxY, vector.y)); + return newVector; +}; diff --git a/Homework/cs5410/bbiy/src/utils/loadLevel.js b/Homework/cs5410/bbiy/src/utils/loadLevel.js new file mode 100644 index 0000000..3bd86d9 --- /dev/null +++ b/Homework/cs5410/bbiy/src/utils/loadLevel.js @@ -0,0 +1,87 @@ +game.loadLevel = (level) => { + const entities = {}; + const config = {...level.gridSize}; + for (let y = 0; y < level.gridSize.yDim; y++) { + for (let x = 0; x < level.gridSize.xDim; x++) { + const cell = level.level[y][x]; + cell.forEach((letter) => { + let entity; + switch (letter) { + case 'b': + entity = game.createBigBlue(); + break; + case 'h': + entity = game.createHedge(); + break; + case 'r': + entity = game.createRock(); + break; + case 'f': + entity = game.createFlag(); + break; + case 'g': + entity = game.createGrass(); + break; + case 'l': + entity = game.createFloor(); + break; + case 'w': + entity = game.createWall(); + break; + case 'a': + entity = game.createWater(); + break; + case 'A': + entity = game.createWordWater(); + break; + case 'N': + entity = game.createWordSink(); + break; + case 'V': + entity = game.createWordLava(); + break; + case 'v': + entity = game.createLava(); + break; + case 'K': + entity = game.createWordKill(); + break; + case 'W': + entity = game.createWordWall(); + break; + case 'I': + entity = game.createWordIs(); + break; + case 'S': + entity = game.createWordStop(); + break; + case 'R': + entity = game.createWordRock(); + break; + case 'P': + entity = game.createWordPush(); + break; + case 'B': + entity = game.createWordBigBlue(); + break; + case 'Y': + entity = game.createWordYou(); + break; + case 'F': + entity = game.createWordFlag(); + break; + case 'X': + entity = game.createWordWin(); + break; + default: + break; + } + if (entity) { + entity.addComponent(game.components.GridPosition({x, y})); + entities[entity.id] = entity; + } + }); + } + } + return [entities, config]; +}; \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/utils/objectEquivalence.js b/Homework/cs5410/bbiy/src/utils/objectEquivalence.js new file mode 100644 index 0000000..e33dd76 --- /dev/null +++ b/Homework/cs5410/bbiy/src/utils/objectEquivalence.js @@ -0,0 +1,14 @@ +const equivalence = (obj1, obj2) => { + if (obj1 === null) { + return obj1 === null; + } + return Object.keys(obj1).every(key => { + if (obj2[key] === undefined) { + return false; + } + if (typeof obj1[key] === 'object') { + return equivalence(obj1[key], obj2[key]); + } + return obj1[key] === obj2[key]; + }); +}; diff --git a/Homework/cs5410/bbiy/src/utils/randInRange.js b/Homework/cs5410/bbiy/src/utils/randInRange.js new file mode 100644 index 0000000..528221a --- /dev/null +++ b/Homework/cs5410/bbiy/src/utils/randInRange.js @@ -0,0 +1,4 @@ +const randomInRange = (min, max) => { + // min <= random number <= max + return Math.floor(Math.random() * (max - min + 1)) + min; +} \ No newline at end of file diff --git a/Homework/cs5410/bbiy/src/utils/unitizeVector.js b/Homework/cs5410/bbiy/src/utils/unitizeVector.js new file mode 100644 index 0000000..6297ca8 --- /dev/null +++ b/Homework/cs5410/bbiy/src/utils/unitizeVector.js @@ -0,0 +1,11 @@ +const unitize = (vector) => { + // Not *technically* a unit vector, but has x,y components of |magnitude| = 1 + Object.keys(vector).forEach((key) => { + if (typeof vector[key] === 'object') { + vector[key] = vector[key].unitize(); + } else if (typeof vector[key] === 'number') { + vector[key] = (vector[key] === 0 ? 0 : vector[key] / Math.abs(vector[key])); + } + }); + return vector; +} \ No newline at end of file diff --git a/Homework/cs5410/bbiy/styles/style.css b/Homework/cs5410/bbiy/styles/style.css new file mode 100644 index 0000000..9f0dc5c --- /dev/null +++ b/Homework/cs5410/bbiy/styles/style.css @@ -0,0 +1,73 @@ +body { + margin: 0; + font-family: Lucida Sans Typewriter,Lucida Console,monaco,Bitstream Vera Sans Mono,monospace; + background-image: url("/assets/image/background.gif"); + background-size: cover; + image-rendering: pixelated; +} + +.canvas-holder { + padding-top: 4vh; + padding-bottom: 4vh; +} +.canvas-holder canvas { + padding: 0; + margin: auto; + display: block; + height: 90vh; + width: auto; + border: 3px solid grey; + border-radius: 5px; + max-width: 100%; + background-color: rgba(0, 0, 25, 0.9); +} + +.game-hud { + position: absolute; + top: 0; + left: 50%; + transform: translate(-50%, -5px); + z-index: 1; + + background-color: rgba(255,255,255,0.5); + padding-left: 10px; + padding-right: 10px; + padding-top: 3px; + border: 1px solid white; + border-radius: 5px; +} + +.game-hud p { + margin: 0; + padding: 0; + font-size: 3vh; + text-align: center; +} + +.menu { + text-align:center; + max-width: 400px; + left: 50%; + top: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + position:absolute; + + background-color: rgba(200,200,255,0.90); + border: 1px solid #fff; + border-radius: 5px; + padding: 12px; + min-width: 400px; +} + +.menu-button { + background-color: #fff; + border-radius: 5px; + padding: 12px; + margin-bottom: 8px; + cursor: pointer; +} + +.menu-button:hover { + background-color: #d0d0d0; +} \ No newline at end of file diff --git a/Homework/cs5410/centipede/assets/images/centipede-assets.png b/Homework/cs5410/centipede/assets/images/centipede-assets.png new file mode 100644 index 0000000..20b9eac Binary files /dev/null and b/Homework/cs5410/centipede/assets/images/centipede-assets.png differ diff --git a/Homework/cs5410/centipede/assets/sounds/enemy_hit.wav b/Homework/cs5410/centipede/assets/sounds/enemy_hit.wav new file mode 100644 index 0000000..1b9c53f Binary files /dev/null and b/Homework/cs5410/centipede/assets/sounds/enemy_hit.wav differ diff --git a/Homework/cs5410/centipede/assets/sounds/laser.wav b/Homework/cs5410/centipede/assets/sounds/laser.wav new file mode 100644 index 0000000..16159a4 Binary files /dev/null and b/Homework/cs5410/centipede/assets/sounds/laser.wav differ diff --git a/Homework/cs5410/centipede/assets/sounds/mushroom_hit.wav b/Homework/cs5410/centipede/assets/sounds/mushroom_hit.wav new file mode 100644 index 0000000..ef26432 Binary files /dev/null and b/Homework/cs5410/centipede/assets/sounds/mushroom_hit.wav differ diff --git a/Homework/cs5410/centipede/css/style.css b/Homework/cs5410/centipede/css/style.css new file mode 100644 index 0000000..7142e28 --- /dev/null +++ b/Homework/cs5410/centipede/css/style.css @@ -0,0 +1,63 @@ +body { + margin: 0; + font-family: Lucida Sans Typewriter,Lucida Console,monaco,Bitstream Vera Sans Mono,monospace; +} + +.canvas-holder canvas { + padding: 0; + margin: auto; + display: block; + height: 100vh; + width: auto; + max-width: 100%; + background-color: black; +} + +.game-hud { + position: absolute; + top: 0; + left: 50%; + transform: translate(-50%, -5px); + z-index: 1; + + background-color: rgba(255,255,255,0.5); + padding-left: 10px; + padding-right: 10px; + padding-top: 3px; + border: 1px solid white; + border-radius: 5px; +} + +.game-hud p { + margin: 0; + padding: 0; + font-size: 3vh; + text-align: center; +} + +.menu { + text-align:center; + left: 50%; + top: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + position:absolute; + + background-color: rgba(255,255,255,0.75); + border: 1px solid #fff; + border-radius: 5px; + padding: 12px; + min-width: 400px; +} + +.menu-button { + background-color: #fff; + border-radius: 5px; + padding: 12px; + margin-bottom: 8px; + cursor: pointer; +} + +.menu-button:hover { + background-color: #d0d0d0; +} \ No newline at end of file diff --git a/Homework/cs5410/centipede/index.html b/Homework/cs5410/centipede/index.html new file mode 100644 index 0000000..3d73470 --- /dev/null +++ b/Homework/cs5410/centipede/index.html @@ -0,0 +1,38 @@ + + + + Centipede + + + + +
+
+ +
+

Hello, world!

+
+ +
+
+ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Homework/cs5410/centipede/js/game/game.js b/Homework/cs5410/centipede/js/game/game.js new file mode 100644 index 0000000..30454f9 --- /dev/null +++ b/Homework/cs5410/centipede/js/game/game.js @@ -0,0 +1,39 @@ +const game = { + stopped: false, + width: document.getElementById('game-canvas').width, + height: document.getElementById('game-canvas').height, + level: 1, +}; + +game.resume = () => { + game.stopped = false; + game.lastTimeStamp = performance.now(); + menu.reRegisterKeys(); + requestAnimationFrame(gameLoop); +} + +game.resetObjects = () => { + game.player.x = game.width/2; + game.player.y = game.height/2; + game.bullets = []; + game.explosions = []; + game.mushroomDims = {width: 40, height: 40}; + game.mushrooms = game.Mushroom.generateMushrooms(game.mushroomDims); + game.centipede = game.Centipede({segments: Math.min(game.level*5 + 5, 15), startX: game.width/2, startY: 0, rot: 180, width: 40, height: 40, dx: 0.2, dy: 0}); + game.spiders = []; + game.fleas = []; + game.scorpions = []; +} + +game.gameOver = () => { + menu.showMenu(); + menu.setState('game-over'); + menu.addScore(game.score); + + menu.onHide = initialize; +} + +game.getObjects = () => [game.player, ...game.bullets, ...game.mushrooms, ...game.spiders, ...game.fleas, ...game.scorpions, game.centipede, ...game.explosions]; +game.getBulletCollidableObjects = () => [...game.mushrooms, ...game.spiders, ...game.fleas, ...game.scorpions, game.centipede]; +game.getMushroomCollidableObjects = () => [game.player, ...game.scorpions, game.centipede]; +game.getPlayerCollidableObjects = () => [...game.spiders, ...game.fleas, ...game.scorpions, game.centipede] \ No newline at end of file diff --git a/Homework/cs5410/centipede/js/game/graphics.js b/Homework/cs5410/centipede/js/game/graphics.js new file mode 100644 index 0000000..3a0d7f9 --- /dev/null +++ b/Homework/cs5410/centipede/js/game/graphics.js @@ -0,0 +1,55 @@ +game.graphics = ( + (context) => { + context.imageSmoothingEnabled = false; + const clear = () => { + context.clearRect(0, 0, game.width, game.height); + }; + + const Sprite = ({sheetSrc, spriteX, spriteY, spriteWidth, spriteHeight, timePerFrame, cols, rows, numFrames, drawFunction}) => { + timePerFrame = timePerFrame ?? 100; + numFrames = numFrames ?? 1; + cols = cols ?? numFrames; + rows = rows ?? 1; + + let ready = false; + + let image; + if (sheetSrc) { + image = new Image(); + image.src = sheetSrc; + image.onload = () => { ready = true; }; + } + + let currentFrame = 0; + let lastTime = performance.now(); + + let draw; + if (!drawFunction) { + draw = (_elapsedTime, {x, y, rot, width, height}) => { + + if (ready) { + if (numFrames > 1) { + if (performance.now()-lastTime > timePerFrame) { + lastTime = performance.now(); + currentFrame = (currentFrame + 1) % numFrames; + } + } + context.save(); + context.translate(x+width/2, y+height/2); + context.rotate(rot * Math.PI / 180); + context.translate(-x-width/2, -y-height/2); + const row = currentFrame % rows; + const col = Math.floor(currentFrame / rows); + context.drawImage(image, spriteX+col*spriteWidth, spriteY+row*spriteHeight, spriteWidth, spriteHeight, x, y, width, height); + context.restore(); + } + }; + } else { + draw = (elapsedTime, drawSpec) => drawFunction(elapsedTime, drawSpec, context); + } + return { draw, timePerFrame, numFrames }; + } + + return { clear, Sprite }; + } +)(document.getElementById("game-canvas").getContext("2d")); \ No newline at end of file diff --git a/Homework/cs5410/centipede/js/game/input.js b/Homework/cs5410/centipede/js/game/input.js new file mode 100644 index 0000000..6ceff13 --- /dev/null +++ b/Homework/cs5410/centipede/js/game/input.js @@ -0,0 +1,32 @@ +game.input = (() => { + "use strict"; + const Keyboard = () => { + const keys = {}; + const handlers = {}; + const keyPress = (event) => { + keys[event.key] = event.timeStamp; + }; + const keyRelease = (event) => { + delete keys[event.key]; + }; + const registerCommand = (key, handler) => { + handlers[key] = handler; + }; + const unregisterCommand = (key) => { + delete handlers[key]; + } + const update = (elapsedTime) => { + for (let key in keys) { + if (keys.hasOwnProperty(key)) { + if (handlers[key]) { + handlers[key](elapsedTime); + } + } + } + }; + window.addEventListener("keydown", keyPress); + window.addEventListener("keyup", keyRelease); + return {keys, handlers, registerCommand, unregisterCommand, update}; + } + return { Keyboard }; +})(); \ No newline at end of file diff --git a/Homework/cs5410/centipede/js/game/menu.js b/Homework/cs5410/centipede/js/game/menu.js new file mode 100644 index 0000000..d4a7fe9 --- /dev/null +++ b/Homework/cs5410/centipede/js/game/menu.js @@ -0,0 +1,143 @@ +const menu = {}; +menu.initialize = () => { + menu.scores = localStorage.getItem("scores") ? JSON.parse(localStorage.getItem("scores")) : []; + menu.state = "main"; + + menu.controls = localStorage.getItem("controls") ? JSON.parse(localStorage.getItem("controls")) : { + "moveUp": "ArrowUp", + "moveDown": "ArrowDown", + "moveLeft": "ArrowLeft", + "moveRight": "ArrowRight", + "shoot": " ", + }; +} + +menu.setState = (state) => { + menu.state = state; + menu.draw(); +} + +menu.escapeEventListener = (e) => { + if (e.key == "Escape") { + menu.setState('main'); + menu.draw(); + } +} + +menu.showMenu = () => { + menu.draw(); + game.stopped = true; + window.addEventListener("keydown", menu.escapeEventListener); +} + +menu.reRegisterKeys = () => { + Object.keys(game.keyboard.handlers).map(key => game.keyboard.unregisterCommand(key)); + game.keyboard.registerCommand(menu.controls.moveUp, game.player.moveUp); + game.keyboard.registerCommand(menu.controls.moveDown, game.player.moveDown); + game.keyboard.registerCommand(menu.controls.moveLeft, game.player.moveLeft); + game.keyboard.registerCommand(menu.controls.moveRight, game.player.moveRight); + game.keyboard.registerCommand(menu.controls.shoot, game.player.shoot); + game.keyboard.registerCommand("Escape", menu.showMenu); + localStorage.setItem("controls", JSON.stringify(menu.controls)); +} + +menu.addScore = (score) => { + menu.scores.push(score); + menu.scores.sort((a, b) => b - a); + localStorage.setItem("scores", JSON.stringify(menu.scores)); +} + +menu.hide = () => { + const menuElement = document.getElementById("menu"); + menuElement.style.display = "none"; + menu.reRegisterKeys(); + window.removeEventListener("keydown", menu.escapeEventListener); + if (menu.onHide) { + menu.onHide(); + menu.onHide = null; + } + game.resume(); +} + +menu.listenFor = (action, elementId) => { + const element = document.getElementById(elementId); + element.innerHTML = "Listening..."; + const handleKey = (event) => { + window.removeEventListener("keydown", handleKey); + if (event.key == "Escape") { + element.innerHTML = menu.controls[action]; + return; + } + menu.controls[action] = event.key; + element.innerHTML = event.key; + } + window.addEventListener("keydown", handleKey); +} + +menu.draw = () => { + const menuElement = document.getElementById("menu"); + menuElement.style.display = "block"; + menuElement.innerHTML = `

Centipede

`; + if (menu.state == "main") { + menuElement.innerHTML += ` + + + + `; + } + else if (menu.state == "controls") { + menuElement.innerHTML += ` +
+

+ Move left: +
+ Move right: +
+ Move up: +
+ Move down: +
+ Shoot: +

+
+ ` + } else if (menu.state == "credits") { + menuElement.innerHTML += ` +
+

+ Sounds from dklon +
+ Sprites from PNGKit +
+ Some code from Dr. Mathias +
+ Developed by Logan Hunt +

+
+ ` + } else if (menu.state == "scores") { + menuElement.innerHTML += ` +
+

+ ${menu.scores.map((score, index) => `${index + 1}: ${score}
`).join("")} +

+
+ ` + } else if (menu.state == "game-over") { + menuElement.innerHTML += ` +
+

+ Game Over +
+ Your final score was: ${game.score} +

+ ` + } + + menuElement.innerHTML += "" + if (menu.state !== "main") { + menuElement.innerHTML += "" + } +} + +menu.initialize(); \ No newline at end of file diff --git a/Homework/cs5410/centipede/js/game/object.js b/Homework/cs5410/centipede/js/game/object.js new file mode 100644 index 0000000..1e22ec6 --- /dev/null +++ b/Homework/cs5410/centipede/js/game/object.js @@ -0,0 +1,51 @@ +game.Object = (object) => { + object.dx = object.dx ?? 0; + object.dy = object.dy ?? 0; + object.rot = object.rot ?? 0; + object.drot = object.drot ?? 0; + object.alive = object.alive ?? true; + + object.poisonedTimer = object.poisonedTimer ?? 4000; + object.poisoned = false; + object.elapsedPoisonedTimer = 0; + object.poison = () => { + object.poisoned = true; + object.elapsedPoisonedTimer = 0; + } + + object.intersects = (other) => { + if (object.x + object.width <= other.x) { + return false; + } + if (object.x >= other.x + other.width) { + return false; + } + if (object.y + object.height <= other.y) { + return false; + } + if (object.y >= other.y + other.height) { + return false; + } + return true; + } + + object.update = (elapsedTime) => { + if (object.poisoned && object.y >= game.height - object.height) { + object.elapsedPoisonedTimer += elapsedTime; + if (object.elapsedPoisonedTimer > object.poisonedTimer) { + object.poisoned = false; + object.elapsedPoisonedTimer = 0; + } + } + + object.x += (object.poisoned ? 0 : object.dx)*elapsedTime; + object.y += (object.poisoned ? 0.2 : object.dy)*elapsedTime; + object.rot += object.drot*elapsedTime; + }; + + object.draw = (elapsedTime) => { + object.sprite.draw(elapsedTime, object); + }; + + return object; +}; diff --git a/Homework/cs5410/centipede/js/game/objects/bullet.js b/Homework/cs5410/centipede/js/game/objects/bullet.js new file mode 100644 index 0000000..5791aca --- /dev/null +++ b/Homework/cs5410/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/Homework/cs5410/centipede/js/game/objects/centipede.js b/Homework/cs5410/centipede/js/game/objects/centipede.js new file mode 100644 index 0000000..7e4c8f6 --- /dev/null +++ b/Homework/cs5410/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/Homework/cs5410/centipede/js/game/objects/explosion.js b/Homework/cs5410/centipede/js/game/objects/explosion.js new file mode 100644 index 0000000..f38d820 --- /dev/null +++ b/Homework/cs5410/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/Homework/cs5410/centipede/js/game/objects/flea.js b/Homework/cs5410/centipede/js/game/objects/flea.js new file mode 100644 index 0000000..23479cc --- /dev/null +++ b/Homework/cs5410/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/Homework/cs5410/centipede/js/game/objects/mushroom.js b/Homework/cs5410/centipede/js/game/objects/mushroom.js new file mode 100644 index 0000000..b1f4787 --- /dev/null +++ b/Homework/cs5410/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/Homework/cs5410/centipede/js/game/objects/player.js b/Homework/cs5410/centipede/js/game/objects/player.js new file mode 100644 index 0000000..a1f6ea0 --- /dev/null +++ b/Homework/cs5410/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/Homework/cs5410/centipede/js/game/objects/scorpion.js b/Homework/cs5410/centipede/js/game/objects/scorpion.js new file mode 100644 index 0000000..036db14 --- /dev/null +++ b/Homework/cs5410/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/Homework/cs5410/centipede/js/game/objects/spider.js b/Homework/cs5410/centipede/js/game/objects/spider.js new file mode 100644 index 0000000..732c0a3 --- /dev/null +++ b/Homework/cs5410/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 diff --git a/Homework/cs5410/centipede/js/game/sounds.js b/Homework/cs5410/centipede/js/game/sounds.js new file mode 100644 index 0000000..584dbd3 --- /dev/null +++ b/Homework/cs5410/centipede/js/game/sounds.js @@ -0,0 +1,5 @@ +game.sounds = { + mushroom_hit: new Audio("assets/sounds/mushroom_hit.wav"), + enemy_hit: new Audio("assets/sounds/enemy_hit.wav"), + laser: new Audio("assets/sounds/laser.wav"), +} \ No newline at end of file diff --git a/Homework/cs5410/centipede/js/game/sprites.js b/Homework/cs5410/centipede/js/game/sprites.js new file mode 100644 index 0000000..3cdd77f --- /dev/null +++ b/Homework/cs5410/centipede/js/game/sprites.js @@ -0,0 +1,120 @@ +game.sprites = { + centipedeHead: game.graphics.Sprite({ + sheetSrc: "assets/images/centipede-assets.png", + spriteX: 0, + spriteY: 0, + spriteWidth: 40, + spriteHeight: 40, + numFrames: 4, + timePerFrame: 100, + }), + centipedeBody: game.graphics.Sprite({ + sheetSrc: "assets/images/centipede-assets.png", + spriteX: 0, + spriteY: 80, + spriteWidth: 40, + spriteHeight: 40, + numFrames: 4, + timePerFrame: 100, + }), + spider: game.graphics.Sprite({ + sheetSrc: "assets/images/centipede-assets.png", + spriteX: 0, + spriteY: 160, + spriteWidth: 80, + spriteHeight: 40, + numFrames: 8, + timePerFrame: 100, + cols: 4, + rows: 2, + }), + flea: game.graphics.Sprite({ + sheetSrc: "assets/images/centipede-assets.png", + spriteX: 320, + spriteY: 160, + spriteWidth: 45, + spriteHeight: 40, + numFrames: 4, + timePerFrame: 500, + cols: 2, + rows: 2, + }), + scorpion: game.graphics.Sprite({ + sheetSrc: "assets/images/centipede-assets.png", + spriteX: 0, + spriteY: 280, + spriteWidth: 80, + spriteHeight: 40, + numFrames: 4, + timePerFrame: 500, + cols: 4, + }), + ship: game.graphics.Sprite({ + sheetSrc: "assets/images/centipede-assets.png", + spriteX: 0, + spriteY: 400, + spriteWidth: 40, + spriteHeight: 40, + numFrames: 1, + timePerFrame: 0, + cols: 1, + rows: 1 + }), + bullet: game.graphics.Sprite({ + drawFunction: (_elapsedTime, {x, y, rot, width, height}, context) => { + context.save(); + context.translate(x+width/2, y+height/2); + context.rotate(rot * Math.PI / 180); + context.translate(-x-width/2, -y-height/2); + const fillStyle = context.fillStyle; + context.fillStyle = "#FF0000"; + context.fillRect(x, y, width, height); + context.fillStyle = fillStyle; + context.restore(); + } + }), + explosionBig: game.graphics.Sprite({ + sheetSrc: "assets/images/centipede-assets.png", + spriteX: 0, + spriteY: 320, + numFrames: 8, + spriteWidth: 80, + spriteHeight: 40, + cols: 4, + rows: 2, + timePerFrame: 30, + }), + explosionSmall: game.graphics.Sprite({ + sheetSrc: "assets/images/centipede-assets.png", + spriteX: 320, + spriteY: 320, + numFrames: 6, + spriteWidth: 40, + spriteHeight: 40, + cols: 3, + rows: 2, + timePerFrame: 30, + }), + regularMushrooms: [3,2,1,0].map(i => + game.graphics.Sprite({ + sheetSrc: "assets/images/centipede-assets.png", + spriteX: 320 + i*40, + spriteY: 0, + numFrames: 1, + spriteWidth: 40, + spriteHeight: 40, + timePerFrame: 0, + }) + ), + poisonMushrooms: [3,2,1,0].map(i => + game.graphics.Sprite({ + sheetSrc: "assets/images/centipede-assets.png", + spriteX: 320 + i*40, + spriteY: 40, + numFrames: 1, + spriteWidth: 40, + spriteHeight: 40, + timePerFrame: 0, + }) + ) +}; \ No newline at end of file diff --git a/Homework/cs5410/centipede/js/main.js b/Homework/cs5410/centipede/js/main.js new file mode 100644 index 0000000..f4c954d --- /dev/null +++ b/Homework/cs5410/centipede/js/main.js @@ -0,0 +1,75 @@ +let handleInput; +const initialize = () => { + game.level = 1; + game.score = 0; + game.totalTime = 0; + + game.keyboard = game.input.Keyboard(); + handleInput = game.keyboard.update; + + game.lastTimeStamp = performance.now(); + + game.player = game.Player({x: game.width/2 - 20, y: game.height-40, width: 40, height: 40, sprite: game.sprites.ship}); + + game.resetObjects(); +}; + +const update = (elapsedTime) => { + game.totalTime += elapsedTime; + + game.mushrooms.map((mushroom) => game.getMushroomCollidableObjects().filter((object) => object.intersects(mushroom))).map((objects, i) => { + objects.map((object => object.onMushroomCollision ? object.onMushroomCollision(game.mushrooms[i]) : null)); + }); + game.bullets.map((bullet) => game.getBulletCollidableObjects().filter((object) => object.intersects(bullet))).map((objects, i) => { + objects.map((object) => object.onBulletCollision ? object.onBulletCollision(game.bullets[i]) : null) + }) + game.getPlayerCollidableObjects().map((object) => object.intersects(game.player) ? object.onPlayerCollision(game.player) : null); + + game.bullets = game.bullets.filter((bullet) => bullet.alive); + game.spiders = game.spiders.filter((spider) => spider.alive); + game.explosions = game.explosions.filter((explosion) => explosion.alive); + game.mushrooms = game.mushrooms.filter((mushroom) => mushroom.state > 0); + game.scorpions = game.scorpions.filter((scorpion) => scorpion.x >= 0 && scorpion.x <= game.width - scorpion.width && scorpion.alive); + game.fleas = game.fleas.filter((flea) => flea.y < game.height - flea.height && flea.alive); + game.getObjects().map((object) => object.update(elapsedTime)); + + if (Math.random() < 0.002 * game.level && game.spiders.length < game.level) { + game.spiders.push(game.Spider({x: game.width/2, y: 0, width: 80, height: 40, rot: 0, dx: -0.2, dy: 0, sprite: game.sprites.spider})); + } + if (Math.random() < 0.001 * game.level && game.fleas.length < game.level) { + game.fleas.push(game.Flea({x: Math.floor(Math.random() * game.width / game.mushroomDims.width) * game.mushroomDims.width, y: 0, width: 40, height: 40, rot: 0, dx: 0, dy: 0.2, sprite: game.sprites.flea})); + } + if (Math.random() < 0.001 * game.level && game.scorpions.length < game.level) { + game.scorpions.push(game.Scorpion({y: Math.floor(Math.random() * game.height / game.mushroomDims.height) * game.mushroomDims.height, x: 0, width: 80, height: 40, rot: 0, dx: 0.2, dy: 0, sprite: game.sprites.scorpion})); + } + + if (!game.centipede.alive()) { + game.resetObjects(); + game.level++; + game.score += game.level*400; + } +}; + +const render = (elapsedTime) => { + game.graphics.clear(); + game.getObjects().map((object) => object.draw(elapsedTime)); + + document.getElementById("hud").innerHTML = `Level: ${game.level} Lives: ${game.player.lives} Score: ${game.score} ${game.player.poisoned ? "POISONED" : ""}`; +}; + +const gameLoop = (time) => { + const elapsedTime = time - game.lastTimeStamp; + game.lastTimeStamp = time; + + handleInput(elapsedTime); + update(elapsedTime); + render(elapsedTime); + + if (!game.stopped) { + requestAnimationFrame(gameLoop); + } +}; + +initialize(); +menu.reRegisterKeys(); +requestAnimationFrame(gameLoop); \ No newline at end of file diff --git a/Homework/cs5410/maize-maze/LICENSE.md b/Homework/cs5410/maize-maze/LICENSE.md new file mode 100644 index 0000000..47a36cd --- /dev/null +++ b/Homework/cs5410/maize-maze/LICENSE.md @@ -0,0 +1,21 @@ +Copyright (c) 2012-2022 Scott Chacon and others + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/Homework/cs5410/maize-maze/README.md b/Homework/cs5410/maize-maze/README.md new file mode 100644 index 0000000..d48c881 --- /dev/null +++ b/Homework/cs5410/maize-maze/README.md @@ -0,0 +1,9 @@ +# A Simple Maze Game + +Controls: ++ Arrow-keys / WASD / IJKL ++ h to toggle hint ++ p to toggle path ++ b to toggle breadcrumbs + +![Screenshot](./screenshot.png) diff --git a/Homework/cs5410/maize-maze/css/styles.css b/Homework/cs5410/maize-maze/css/styles.css new file mode 100644 index 0000000..4c8aac0 --- /dev/null +++ b/Homework/cs5410/maize-maze/css/styles.css @@ -0,0 +1,24 @@ +body { + margin: 0; + padding: 0; + overflow: scroll; + /* Font from https://www.cssfontstack.com/Lucida-Console */ + font-family: Lucida Console,Lucida Sans Typewriter,monaco,Bitstream Vera Sans Mono,monospace; + background: radial-gradient(circle, transparent 20%, black 80vw), white; +} + +.canvas-holder canvas { + padding: 0; + margin: auto; + display: block; + height: 70vh; + width: auto; + max-width: 100%; +} + +.button { + border: 1px solid black; + border-radius: 5px; + padding: 5px; + cursor: pointer; +} \ No newline at end of file diff --git a/Homework/cs5410/maize-maze/images/corn.png b/Homework/cs5410/maize-maze/images/corn.png new file mode 100644 index 0000000..f392216 Binary files /dev/null and b/Homework/cs5410/maize-maze/images/corn.png differ diff --git a/Homework/cs5410/maize-maze/images/fire.png b/Homework/cs5410/maize-maze/images/fire.png new file mode 100644 index 0000000..5e7b2ec Binary files /dev/null and b/Homework/cs5410/maize-maze/images/fire.png differ diff --git a/Homework/cs5410/maize-maze/images/popcorn.jpg b/Homework/cs5410/maize-maze/images/popcorn.jpg new file mode 100644 index 0000000..ad73e91 Binary files /dev/null and b/Homework/cs5410/maize-maze/images/popcorn.jpg differ diff --git a/Homework/cs5410/maize-maze/index.html b/Homework/cs5410/maize-maze/index.html new file mode 100644 index 0000000..36bae40 --- /dev/null +++ b/Homework/cs5410/maize-maze/index.html @@ -0,0 +1,75 @@ + + + + Amazeing Maize Maze + + + + + + + + + + +
+

The A-maze-ing Maize Maze!

+

Get to the fire to make popcorn! Current Time: seconds

+

+ +

+

+ 5x5 + 10x10 + 15x15 + 20x20 +

+
+
+ +
+
+
+ "Low" scores (player path length - shortest path length): +
+
+ + + + + + + + diff --git a/Homework/cs5410/maize-maze/js/assets.js b/Homework/cs5410/maize-maze/js/assets.js new file mode 100644 index 0000000..54ea6bb --- /dev/null +++ b/Homework/cs5410/maize-maze/js/assets.js @@ -0,0 +1,8 @@ +const GOAL = new Image(); +GOAL.src = "./images/fire.png"; + +const PLAYER = new Image(); +PLAYER.src = "./images/corn.png"; + +const BACKGROUND = new Image(); +BACKGROUND.src = "./images/popcorn.jpg"; diff --git a/Homework/cs5410/maize-maze/js/game.js b/Homework/cs5410/maize-maze/js/game.js new file mode 100644 index 0000000..1249a20 --- /dev/null +++ b/Homework/cs5410/maize-maze/js/game.js @@ -0,0 +1,249 @@ +let canvas,context; + +const HEIGHT = 1000; +const WIDTH = 1000; + +// Next assignment: don't use so much effing global data +let n = 10; +let maze; + +let total_time; + +let player_pos = []; +let goal_pos = []; + +let myInput = input.Keyboard(); + +let show_player_path = false; +let player_path = []; +let show_next_move = false; +let show_shortest_path = false; +let shortest_path = []; + +let do_score_update = false; +let scores = []; +let initial_shortest_path_length = 0; +let current_score; + +let do_time_update = false; +let dom_time; +let elapsed_time; +let last_time; + +function render_maze(maze, n, dx, dy) { + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + context.beginPath(); + if (maze[i][j].left) { + context.moveTo(j * dx, i * dy); + context.lineTo(j * dx, (i + 1) * dy); + } + if (maze[i][j].right) { + context.moveTo((j + 1) * dx, i * dy); + context.lineTo((j + 1) * dx, (i + 1) * dy); + } + if (maze[i][j].top) { + context.moveTo(j * dx, i * dy); + context.lineTo((j + 1) * dx, i * dy); + } + if (maze[i][j].bottom) { + context.moveTo(j * dx, (i + 1) * dy); + context.lineTo((j + 1) * dx, (i + 1) * dy); + } + context.stroke(); + } + } +} + +function render_player(x, y, dx, dy) { + context.drawImage(PLAYER, x*dx, y*dy, dx, dy); +} + +function render_scores(scores) { + let html = scores.sort((a,b) => a-b).map((x,i) => `${i+1}: ${x}`).join('
'); + document.getElementById('scores').innerHTML = html; +} + +function render_time(total_time) { + document.getElementById('elapsed-time').innerHTML = total_time; +} + +function render_goal(x, y, dx, dy) { + context.drawImage(GOAL, x*dx, y*dy, dx, dy); +} + +function render_background(n, dx, dy) { + for (let x = 0; x < WIDTH; x += WIDTH/n) { + for (let y = 0; y < HEIGHT; y += HEIGHT/n) { + context.drawImage(BACKGROUND, x, y, dx, dy); + } + } +} + +function render_circle(x,y,r,color) { + context.beginPath(); + context.fillStyle = color; + context.arc(x, y, r, 0, 2*Math.PI); + context.fill(); + context.stroke(); +} + +function render_path(path, dx, dy, color) { + path.map((coord) => { + render_circle(coord[0]*dx + dx/2, coord[1]*dy + dy/2, Math.min(dx/4, dy/4), color); + }); +} + +function render(elapsed) { + const dx = WIDTH / n; + const dy = HEIGHT / n; + + context.fillStyle = 'rgba(255,255,255,255)'; + context.fillRect(0, 0, canvas.width, canvas.height); + context.rect(0, 0, canvas.width, canvas.height); + context.stroke(); + + render_background(n, dx, dy); + render_maze(maze, n, dx, dy); + + if (show_player_path) { + render_path(player_path, dx, dy, 'rgba(255, 0, 0, 255)'); + } + + if (show_shortest_path) { + render_path(shortest_path, dx, dy, 'rgba(255, 255, 0, 255)'); + } + + if (show_next_move && shortest_path.length>1) { + render_path([shortest_path[1]], dx, dy, 'rgba(255, 255, 0, 255)'); + } + + if (do_score_update) { + render_scores(scores); + } + if (do_time_update) { + render_time(dom_time); + } + + render_player(Math.floor(player_pos[0]), Math.floor(player_pos[1]), dx, dy); + render_goal(goal_pos[0], goal_pos[1], dx, dy); +} + +let key_actions_down = {}; +let key_actions = { + "move_up": ['ArrowUp', 'i', 'w'], + "move_right": ['ArrowRight', 'l', 'd'], + "move_down": ['ArrowDown', 'k', 's'], + "move_left": ['ArrowLeft', 'j', 'a'], + "breadcrumbs": ['b'], + "shortest_path": ['p'], + "hint": ['h'] +}; +function handle_input(input) { + if (input) { + if (any(key_actions['move_up'].map((x) => input.keys[x])) && !key_actions_down['move_up'] && player_pos[1] > 0) { + key_actions_down['move_up'] = true; + if (!maze[player_pos[1]][player_pos[0]].top) { + player_pos[1] -= 1; + } + } + if (any(key_actions['move_right'].map((x) => input.keys[x])) && !key_actions_down['move_right'] && player_pos[0] < n-1) { + key_actions_down['move_right'] = true; + if (!maze[player_pos[1]][player_pos[0]].right) { + player_pos[0] += 1; + } + } + if (any(key_actions['move_down'].map((x) => input.keys[x])) && !key_actions_down['move_down'] && player_pos[1] < n-1) { + key_actions_down['move_down'] = true; + if (!maze[player_pos[1]][player_pos[0]].bottom) { + player_pos[1] += 1; + } + } + if (any(key_actions['move_left'].map((x) => input.keys[x])) && !key_actions_down['move_left'] && player_pos[0] > 0) { + key_actions_down['move_left'] = true; + if (!maze[player_pos[1]][player_pos[0]].left) { + player_pos[0] -= 1; + } + } + if (input.keys['b'] && !key_actions_down['breadcrumbs']) { + key_actions_down['breadcrumbs'] = true; + show_player_path = !show_player_path; + } + if (input.keys['p'] && !key_actions_down['shortest_path']) { + key_actions_down['shortest_path'] = true; + show_shortest_path = !show_shortest_path; + } + if (input.keys['h'] && !key_actions_down['hint']) { + key_actions_down['hint'] = true; + show_next_move = !show_next_move; + } + Object.keys(key_actions).map((x) => { + if (key_actions_down[x] && !any(key_actions[x].map((y) => input.keys[y]))) { + key_actions_down[x] = false; + } + }); + } +} + +function update(elapsed) { + total_time += elapsed; + + if (do_score_update) { + do_score_update = false; + } + if (do_time_update) { + do_time_update = false; + } + + if (JSON.stringify(player_pos) !== JSON.stringify(player_path[player_path.length-1])) { + player_path.push([player_pos[0], player_pos[1]]); + shortest_path = solve_maze(maze, player_pos[0], player_pos[1], goal_pos[0], goal_pos[1]); + } + + if (total_time / 1000 > dom_time) { + dom_time = Math.floor(total_time/1000); + } + do_time_update = true; + + if (player_pos[0] == goal_pos[0] && player_pos[1] == goal_pos[1]) { + current_score = player_path.length - initial_shortest_path_length; + scores.push(current_score); + initialize(); + do_score_update = true; + } +} + +function initialize(new_n) { + if (new_n) { + n = new_n; + } + maze = generate_maze(n); + player_pos = [random_in_range(0, 2), random_in_range(0, 2)]; + goal_pos = [random_in_range(n-2, n), random_in_range(n-2, n)]; + player_path = []; + shortest_path = solve_maze(maze, player_pos[0], player_pos[1], goal_pos[0], goal_pos[1]); + initial_shortest_path_length = shortest_path.length; + total_time = 0; + current_score = 0; + dom_time = 0; + last_time = performance.now(); +} + +function game_loop(time_stamp) { + elapsed_time = time_stamp - last_time; + last_time = time_stamp; + handle_input(myInput); + update(elapsed_time); + render(elapsed_time); + + // Wow! Tail call recursion! /sarcasm + requestAnimationFrame(game_loop); +} + +window.onload = function() { + initialize(); + canvas = document.getElementById('canvas'); + context = canvas.getContext('2d'); + + game_loop(performance.now()); +} diff --git a/Homework/cs5410/maize-maze/js/helpers.js b/Homework/cs5410/maize-maze/js/helpers.js new file mode 100644 index 0000000..1bc6579 --- /dev/null +++ b/Homework/cs5410/maize-maze/js/helpers.js @@ -0,0 +1,18 @@ +function random_in_range(a,z) { + return Math.floor(Math.random() * (z - a) + a); +} + +function shuffle_array(a) { + for (let i = 0; i < a.length; i++) { + let j = random_in_range(0, i+1); + temp = a[i]; a[i] = a[j]; a[j] = temp; + } +} + +function sub(p1, p2) { + return [p1[0] - p2[0], p1[1] - p2[1]]; +} + +function any(l) { + return l.filter((x) => x).length > 0; +} \ No newline at end of file diff --git a/Homework/cs5410/maize-maze/js/json-ds.js b/Homework/cs5410/maize-maze/js/json-ds.js new file mode 100644 index 0000000..feb0622 --- /dev/null +++ b/Homework/cs5410/maize-maze/js/json-ds.js @@ -0,0 +1,30 @@ +// If I were to rewrite this, I would use IEFE's - Dean was right about OO in JS +class JSONSet { + items = new Set(); + constructor(initial){ + if (initial) { + this.apply_set_function('add', initial); + } + } + apply_set_function(f_name, x) { + return this.items[f_name](JSON.stringify(x)); + } +} + +class JSONHash { + items = {}; + constructor(initial_key, initial_value){ + if (initial_key && initial_value) { + this.items[JSON.stringify(initial)] = initial_value; + } + } + set_value(key, value) { + this.items[JSON.stringify(key)] = value; + } + get_value(key) { + return this.items[JSON.stringify(key)]; + } + delete_value(key) { + delete this.items[JSON.stringify(key)]; + } +} \ No newline at end of file diff --git a/Homework/cs5410/maize-maze/js/keyboard.js b/Homework/cs5410/maize-maze/js/keyboard.js new file mode 100644 index 0000000..2196834 --- /dev/null +++ b/Homework/cs5410/maize-maze/js/keyboard.js @@ -0,0 +1,22 @@ +// Shameless stolen code from "Process the Input" presentation +let input = (function() { + function Keyboard() { + let that = { + keys : {} + }; + function keyPress(e) { + that.keys[e.key] = e.timeStamp; + } + function keyRelease(e) { + delete that.keys[e.key]; + } + window.addEventListener('keydown', keyPress); + window.addEventListener('keyup', keyRelease); + + return that; + } + + return { + Keyboard : Keyboard + }; +}()); \ No newline at end of file diff --git a/Homework/cs5410/maize-maze/js/maze.js b/Homework/cs5410/maize-maze/js/maze.js new file mode 100644 index 0000000..8bede6b --- /dev/null +++ b/Homework/cs5410/maize-maze/js/maze.js @@ -0,0 +1,104 @@ +function get_neighbors(maze, x, y) { + let neighbor_indices = []; + if (!maze[y][x].left && x > 0) { + neighbor_indices.push([x-1,y]); + } + if (!maze[y][x].right && x < maze[0].length-1) { + neighbor_indices.push([x+1,y]); + } + if (!maze[y][x].top && y > 0) { + neighbor_indices.push([x,y-1]); + } + if (!maze[y][x].bottom && y < maze.length-1) { + neighbor_indices.push([x,y+1]); + } + return neighbor_indices; +} + +function new_cell() { + return { + left: false, + right: false, + top: false, + bottom: false + } +} + +function generate_maze(n) { + let grid = new Array(n).fill().map((x) => (new Array(n).fill().map(new_cell))); + + let point_sets = []; + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + point_sets.push(new JSONSet([j,i])) + } + } + + let edges = []; + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (i !== n-1) { + edges.push([[i,j],[i+1,j]]) + } + if (j !== n-1) { + edges.push([[i,j],[i,j+1]]) + } + } + } + shuffle_array(edges); + + let maze_edges = edges.map((x) => x); + + while (edges.length) { + let edge = edges.pop(); + + let set_inds = edge.map((i) => point_sets.findIndex((x) => x.apply_set_function('has', i))); + if (set_inds[0] == -1 || set_inds[1] == -1) { + throw new Error("Could not find correct index"); + } + if (set_inds[0] == set_inds[1]) { + continue; + } + + // Perform the union of the sets + for (let i of point_sets[set_inds[1]].items) { + point_sets[set_inds[0]].items.add(i); + } + + point_sets.splice(set_inds[1], 1); + maze_edges = maze_edges.filter((x) => x !== edge); + } + maze_edges.forEach((edge) => { + let direction = sub(edge[0], edge[1]); + if (direction[0] == -1) { + grid[edge[0][1]][edge[0][0]].right = grid[edge[1][1]][edge[1][0]].left = true; + } + else if (direction[1] == -1) { + grid[edge[0][1]][edge[0][0]].bottom = grid[edge[1][1]][edge[1][0]].top = true; + } + }) + return grid; +} + +function solve_maze(maze, x, y, end_x, end_y) { + let path = new JSONHash(); + let visited = new JSONSet(); + let queue = [[x,y]]; + while (queue.length) { + let cell = queue.shift(); + visited.apply_set_function('add', cell); + if (cell[0] == end_x && cell[1] == end_y) { + let sol_path = [[end_x, end_y]]; + while (sol_path[0][0] != x || sol_path[0][1] != y) { + sol_path.unshift(path.get_value(sol_path[0])); + } + return sol_path; + } + for (let i of get_neighbors(maze, cell[0], cell[1])) { + if (!visited.apply_set_function('has', i)) { + queue.push(i); + path.set_value(i, cell); + } + } + } +} diff --git a/Homework/cs5410/maize-maze/screenshot.png b/Homework/cs5410/maize-maze/screenshot.png new file mode 100644 index 0000000..965eb61 Binary files /dev/null and b/Homework/cs5410/maize-maze/screenshot.png differ -- cgit v1.3