- Welcome to the official repository for the IESD Hack Day event.
+ August 2019 IESD Hack Day event.
## **Getting Started**
-Look under branches and find the appropriate month and year for the Hack Day you're participating in. Each branch has its own documentation for getting started.
+This repository has the resources to get you prepared for the Hack Day event.
+
+```Starter code has been update - 8/31/19 @ 1:55 PM.```
If you have any questions, please ask on our [Slack](https://ie-sd.slack.com). We welcome everyone to our Slack, so don't be afraid to join! Have fun coding!
**Join our Slack!**
+
+## **Concepts to Review**
+Resources section below has links for these concepts.
+- Canvas
+- RequestAnimationFrame (JS Method)
+- Object Oriented JavaScript
+- Prototypal Inheritance
+- Sprites
+- Keyboard Events
+
+## **Resources**
+List will be updated up until the day of the Hack Day event.
+- Making Sprite Based Games with Canvas (2013 article - still relevant)
+- HTML5 Canvas Game: 2D Collision Detection
+- Adding collision detection to images drawn on canvas on StackOverflow
+- Modals in Pure ES6 JavaScript
+- KeyboardEvent Value (keyCodes, metaKey, etc) via CSS-Tricks
+
+### **RequestAnimationFrame**
+
+The `window.requestAnimationFrame()` method tells the browser that you wish to perform an animation and requests that the browser call a specified function to update an animation before the next repaint. The method takes a callback as an argument to be invoked before the repaint. Read more about this here.
+
+### **Object-Oriented JavaScript**
+Make sure you are comfortable with Object-Oriented JavaScript:
+
+- What is an object?
+- How is an object different from a primitive in JavaScript (e.g., can a primitive have methods?)
+- What are some ways to create or instantiate a new object?
+- How do you modify properties, or add/remove properties from an object?
+- What is a constructor function (or class)?
+- What is `this`? What does it refer to and how is it used in different contexts (i.e., in a constructor function, a method, etc.)?
+- How do you add a property or method to a constructor's prototype?
+- What is prototypal inheritance and how is it implemented?
diff --git a/css/style.css b/css/style.css
new file mode 100644
index 0000000..e28c912
--- /dev/null
+++ b/css/style.css
@@ -0,0 +1,3 @@
+body {
+ text-align: center;
+}
diff --git a/images/Heart.png b/images/Heart.png
new file mode 100644
index 0000000..aa49b5c
Binary files /dev/null and b/images/Heart.png differ
diff --git a/images/Key.png b/images/Key.png
new file mode 100644
index 0000000..7602326
Binary files /dev/null and b/images/Key.png differ
diff --git a/images/Rock.png b/images/Rock.png
new file mode 100644
index 0000000..29c4e20
Binary files /dev/null and b/images/Rock.png differ
diff --git a/images/Selector.png b/images/Selector.png
new file mode 100644
index 0000000..e7c5475
Binary files /dev/null and b/images/Selector.png differ
diff --git a/images/Star.png b/images/Star.png
new file mode 100644
index 0000000..17c0af5
Binary files /dev/null and b/images/Star.png differ
diff --git a/images/char-boy.png b/images/char-boy.png
new file mode 100644
index 0000000..3dc7c29
Binary files /dev/null and b/images/char-boy.png differ
diff --git a/images/char-cat-girl.png b/images/char-cat-girl.png
new file mode 100644
index 0000000..dc0538b
Binary files /dev/null and b/images/char-cat-girl.png differ
diff --git a/images/char-horn-girl.png b/images/char-horn-girl.png
new file mode 100644
index 0000000..90f2278
Binary files /dev/null and b/images/char-horn-girl.png differ
diff --git a/images/char-pink-girl.png b/images/char-pink-girl.png
new file mode 100644
index 0000000..baef177
Binary files /dev/null and b/images/char-pink-girl.png differ
diff --git a/images/char-princess-girl.png b/images/char-princess-girl.png
new file mode 100644
index 0000000..9d9f958
Binary files /dev/null and b/images/char-princess-girl.png differ
diff --git a/images/enemy-bug.png b/images/enemy-bug.png
new file mode 100644
index 0000000..191587b
Binary files /dev/null and b/images/enemy-bug.png differ
diff --git a/images/gem-blue.png b/images/gem-blue.png
new file mode 100644
index 0000000..48c677c
Binary files /dev/null and b/images/gem-blue.png differ
diff --git a/images/gem-green.png b/images/gem-green.png
new file mode 100644
index 0000000..ad3da84
Binary files /dev/null and b/images/gem-green.png differ
diff --git a/images/gem-orange.png b/images/gem-orange.png
new file mode 100644
index 0000000..1f3cd46
Binary files /dev/null and b/images/gem-orange.png differ
diff --git a/images/grass-block.png b/images/grass-block.png
new file mode 100644
index 0000000..eb04ba9
Binary files /dev/null and b/images/grass-block.png differ
diff --git a/images/stone-block.png b/images/stone-block.png
new file mode 100644
index 0000000..01113cf
Binary files /dev/null and b/images/stone-block.png differ
diff --git a/images/water-block.png b/images/water-block.png
new file mode 100644
index 0000000..0383ed8
Binary files /dev/null and b/images/water-block.png differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..a8a564f
--- /dev/null
+++ b/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ Hack Day - Frogger Clone Starter Code
+
+
+
+
+
+
+
+
diff --git a/js/app.js b/js/app.js
new file mode 100644
index 0000000..736378e
--- /dev/null
+++ b/js/app.js
@@ -0,0 +1,183 @@
+//Parent object for sprites
+class Populate {
+ constructor () {
+ this.x = 0;
+ this.y = 0;
+ this.speed = 0;
+ this.sprite = "";
+ this.sideways = 101;
+ this.upDown = 83;
+ }
+
+ render () {
+ ctx.drawImage(Resources.get(this.sprite), this.x, this.y);
+ }
+
+ reset () {
+ this.x = 0;
+ this.y = 415;
+ }
+}
+
+//Player class
+class Player extends Populate {
+ constructor () {
+ super();
+ this.x = 0;
+ this.y = 415;
+ this.sprite = "images/char-boy.png";
+ this.blueGemsCollected = 0;
+ this.greenGemsCollected = 0;
+ this.orangeGemsCollected = 0;
+ this.gemsLeft = 0;
+ this.score = 0;
+ }
+
+//key input for Player
+ handleInput (input) {
+ switch (input) {
+ case "left":
+ if (this.x >= this.sideways) {
+ this.x -= this.sideways;
+ }
+ break;
+ case "right":
+ if (this.x <= this.sideways * 3) {
+ this.x += this.sideways;
+ }
+ break;
+ case "up":
+ if (this.y >= 83) {
+ this.y -= this.upDown;
+ }
+ break;
+ case "down":
+ if (this.y <= this.upDown * 4) {
+ this.y += this.upDown;
+ }
+ break;
+ }
+ }
+
+ //updates player and sets condition for collision & win
+ update () {
+ for (let enemy of allEnemies) {
+ if (this.y === enemy.y && (enemy.x + enemy.sideways / 2 > this.x && enemy.x < this.x + this.sideways / 2)) {
+ this.reset();
+ }
+ }
+
+ for (let gem of allGems) {
+ if ((gem.x + gem.sideways / 2 > this.x && gem.x < this.x + this.sideways / 2) &&
+ (gem.y - gem.upDown / 2 < this.y && gem.y > this.y - this.upDown / 2)) {
+ console.log(gemsLeft);
+ gem.x = -10000;
+ gem.y = -10000;
+ gemsLeft--;
+
+ switch (gem.color) {
+ case "blue":
+ this.blueGemsCollected++;
+ this.score += 100;
+ break;
+ case "green":
+ this.greenGemsCollected++;
+ this.score += 250;
+ break;
+ case "orange":
+ this.orangeGemsCollected++;
+ this.score += 500;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ if (gemsLeft === 0 && this.score > 0) {
+ resetGems();
+ }
+
+ }
+ }
+}
+
+const player = new Player();
+
+//Array to hold Enemy objects
+const allEnemies = [];
+
+//Array to hold gems for points
+let allGems = [];
+
+//Enemy class
+class Enemy extends Populate {
+ constructor (x, y, speed) {
+ super();
+ this.x = x;
+ this.y = y;
+ this.speed = speed;
+ this.sprite = "images/enemy-bug.png";
+ this.enemySprite = this.sprite;
+ }
+
+ //Smooth movement of Enemy objects across gameboard
+ update (dt) {
+ if (this.x < this.sideways * 5) {
+ this.x += this.speed * dt;
+ } else {
+ this.x = -100;
+ }
+ }
+}
+
+class Gem extends Populate {
+ constructor (color) {
+ super();
+ this.x = Math.floor(Math.random() * 5) * 101 + 25;
+ this.y = Math.floor(Math.random() * 5) * 83 + 35;
+ this.color = color;
+ this.speed = 0;
+ this.sprite = "images/gem-"+color+".png";
+ this.sideways = 50;
+ this.upDown = 85;
+ }
+}
+
+const enemy1 = new Enemy(101, 83, 150);
+const enemy2 = new Enemy(404, 166, 350);
+const enemy3 = new Enemy(0, 249, 375);
+const enemy4 = new Enemy(0, 83, 100);
+let gemsLeft = 0;
+resetGems();
+
+function resetGems() {
+ allGems = [];
+
+ for (i = 0; i < Math.random() * 3 + 1; i++)
+ {allGems.push(new Gem("blue"));
+ gemsLeft++;
+console.log(gemsLeft);}
+
+ for (i = 0; i < Math.random() * 3 + 1; i++)
+ {allGems.push(new Gem("green"));
+ gemsLeft++;}
+
+ for (i = 0; i < Math.random() * 3 + 1; i++)
+ {allGems.push(new Gem("orange"));
+ gemsLeft++;}
+}
+
+allEnemies.push(enemy1, enemy2, enemy3, enemy4);
+
+// Player.handleInput() method. You don't need to modify this.
+document.addEventListener("keyup", function (e) {
+ var allowedKeys = {
+ 37: "left",
+ 38: "up",
+ 39: "right",
+ 40: "down"
+ };
+
+ player.handleInput(allowedKeys[e.keyCode]);
+});
diff --git a/js/engine.js b/js/engine.js
new file mode 100644
index 0000000..752fec8
--- /dev/null
+++ b/js/engine.js
@@ -0,0 +1,156 @@
+/* Engine.js
+ * This file provides the game loop functionality (update entities and render),
+ * draws the initial game board on the screen, and then calls the update and
+ * render methods on your player and enemy objects (defined in your app.js).
+ * This engine makes the canvas' context (ctx) object globally available to make
+ * writing app.js a little simpler to work with.
+ */
+
+var Engine = (function (global) {
+ var doc = global.document,
+ win = global.window,
+ canvas = doc.createElement("canvas"),
+ ctx = canvas.getContext("2d"),
+ lastTime;
+
+ canvas.width = 505;
+ canvas.height = 606;
+ doc.body.appendChild(canvas);
+
+ /* This function serves as the kickoff point for the game loop itself
+ * and handles properly calling the update and render methods.
+ */
+ function main () {
+ /* Get our time delta information which is required if your game
+ * requires smooth animation.
+ */
+ var now = Date.now(),
+ dt = (now - lastTime) / 1000.0;
+
+ /* Call our update/render functions, pass along the time delta to
+ * our update function
+ */
+ update(dt);
+ render();
+
+ /* Set our lastTime variable which is used to determine the time delta
+ */
+ lastTime = now;
+
+ /* Use the browser's requestAnimationFrame function to call this
+ * function again as soon as the browser is able to draw another frame.
+ */
+ if (player.winAStar === true) {
+ modal.style.display = "block";
+ win.cancelAnimationFrame;
+
+ } else {
+ win.requestAnimationFrame(main);
+
+ }
+ }
+
+ /* This function does some initial setup that should only occur once,
+ * particularly setting the lastTime variable that is required for the
+ * game loop.
+ */
+ function init () {
+ lastTime = Date.now();
+ main();
+ }
+
+ /* This function is called by main (our game loop) and itself calls all
+ * of the functions which may need to update entity's data. */
+
+ function update (dt) {
+ updateEntities(dt);
+ }
+
+ /* This is called by the update function and loops through all of the
+ * objects within your allEnemies array as defined in app.js
+ */
+ function updateEntities (dt) {
+ allEnemies.forEach(function (enemy) {
+ enemy.update(dt);
+ });
+ player.update();
+ }
+
+ /* This function initially draws the "game level", it will then call
+ * the renderEntities function.
+ */
+ function render () {
+ /* This array holds the relative URL to the image used
+ * for that particular row of the game level.
+ */
+ var rowImages = [
+ "images/water-block.png", // Top row is water
+ "images/stone-block.png", // Row 1 of 3 of stone
+ "images/stone-block.png", // Row 2 of 3 of stone
+ "images/stone-block.png", // Row 3 of 3 of stone
+ "images/grass-block.png", // Row 1 of 2 of grass
+ "images/grass-block.png" // Row 2 of 2 of grass
+ ],
+ numRows = 6,
+ numCols = 5,
+ row, col;
+
+ // Before drawing, clear existing canvas
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ /* Loop through the number of rows and columns we've defined above
+ * and, using the rowImages array, draw the correct image for that
+ * portion of the "grid"
+ */
+ for (row = 0; row < numRows; row++) {
+ for (col = 0; col < numCols; col++) {
+ /* The drawImage function of the canvas' context element
+ * requires 3 parameters: the image to draw, the x coordinate
+ * to start drawing and the y coordinate to start drawing.
+ * We're using our Resources helpers to refer to our images
+ * so that we get the benefits of caching these images, since
+ * we're using them over and over.
+ */
+ ctx.drawImage(Resources.get(rowImages[row]), col * 101, row * 83);
+ }
+ }
+
+ renderEntities();
+ }
+
+ /* This function is called by the render function and is called on each game
+ * tick. Its purpose is to then call the render functions you have defined
+ * on your enemy and player entities within app.js
+ */
+ function renderEntities () {
+ allGems.forEach(function (gem) {
+ gem.render();
+ });
+
+ allEnemies.forEach(function (enemy) {
+ enemy.render();
+ });
+
+ player.render();
+ }
+
+ //Images used in game
+ Resources.load([
+ "images/stone-block.png",
+ "images/water-block.png",
+ "images/grass-block.png",
+ "images/enemy-bug.png",
+ "images/char-boy.png",
+ "images/gem-blue.png",
+ "images/gem-green.png",
+ "images/gem-orange.png",
+ "images/Star.png"
+ ]);
+ Resources.onReady(init);
+
+ /* Assign the canvas' context object to the global variable (the window
+ * object when run in a browser) so that developers can use it more easily
+ * from within their app.js files.
+ */
+ global.ctx = ctx;
+})(this);
diff --git a/js/resources.js b/js/resources.js
new file mode 100644
index 0000000..cd267b5
--- /dev/null
+++ b/js/resources.js
@@ -0,0 +1,112 @@
+/* Resources.js
+ * This is simply an image loading utility. It eases the process of loading
+ * image files so that they can be used within your game. It also includes
+ * a simple "caching" layer so it will reuse cached images if you attempt
+ * to load the same image multiple times.
+ */
+(function() {
+ var resourceCache = {};
+ // var loading = [];
+ var readyCallbacks = [];
+
+ /* This is the publicly accessible image loading function. It accepts
+ * an array of strings pointing to image files or a string for a single
+ * image. It will then call our private image loading function accordingly.
+ */
+ function load(urlOrArr) {
+ if(urlOrArr instanceof Array) {
+ /* If the developer passed in an array of images
+ * loop through each value and call our image
+ * loader on that image file
+ */
+ urlOrArr.forEach(function(url) {
+ _load(url);
+ });
+ } else {
+ /* The developer did not pass an array to this function,
+ * assume the value is a string and call our image loader
+ * directly.
+ */
+ _load(urlOrArr);
+ }
+ }
+
+ /* This is our private image loader function, it is
+ * called by the public image loader function.
+ */
+ function _load(url) {
+ if(resourceCache[url]) {
+ /* If this URL has been previously loaded it will exist within
+ * our resourceCache array. Just return that image rather
+ * re-loading the image.
+ */
+ return resourceCache[url];
+ } else {
+ /* This URL has not been previously loaded and is not present
+ * within our cache; we'll need to load this image.
+ */
+ var img = new Image();
+ img.onload = function() {
+ /* Once our image has properly loaded, add it to our cache
+ * so that we can simply return this image if the developer
+ * attempts to load this file in the future.
+ */
+ resourceCache[url] = img;
+
+ /* Once the image is actually loaded and properly cached,
+ * call all of the onReady() callbacks we have defined.
+ */
+ if(isReady()) {
+ readyCallbacks.forEach(function(func) { func(); });
+ }
+ };
+
+ /* Set the initial cache value to false, this will change when
+ * the image's onload event handler is called. Finally, point
+ * the image's src attribute to the passed in URL.
+ */
+
+ resourceCache[url] = false;
+ img.src = url;
+ }
+ }
+
+ /* This is used by developers to grab references to images they know
+ * have been previously loaded. If an image is cached, this functions
+ * the same as calling load() on that URL.
+ */
+ function get(url) {
+ return resourceCache[url];
+ }
+
+ /* This function determines if all of the images that have been requested
+ * for loading have in fact been properly loaded.
+ */
+ function isReady() {
+ var ready = true;
+ for(var k in resourceCache) {
+ if(resourceCache.hasOwnProperty(k) &&
+ !resourceCache[k]) {
+ ready = false;
+ }
+ }
+ return ready;
+ }
+
+ /* This function will add a function to the callback stack that is called
+ * when all requested images are properly loaded.
+ */
+ function onReady(func) {
+ readyCallbacks.push(func);
+ }
+
+ /* This object defines the publicly accessible functions available to
+ * developers by creating a global Resources object.
+ */
+ window.Resources = {
+ load: load,
+ get: get,
+ onReady: onReady,
+ isReady: isReady
+ };
+})();