diff --git a/projects/Classic Arcade Game Clone/css/style.css b/projects/Classic Arcade Game Clone/css/style.css new file mode 100644 index 00000000..c1ff6560 --- /dev/null +++ b/projects/Classic Arcade Game Clone/css/style.css @@ -0,0 +1,7 @@ +body { + text-align: center; +} + +div { + font-size: 30px; +} diff --git a/projects/Classic Arcade Game Clone/images/Gem Blue.png b/projects/Classic Arcade Game Clone/images/Gem Blue.png new file mode 100644 index 00000000..5808a7de Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/Gem Blue.png differ diff --git a/projects/Classic Arcade Game Clone/images/Gem Green.png b/projects/Classic Arcade Game Clone/images/Gem Green.png new file mode 100644 index 00000000..e971d14d Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/Gem Green.png differ diff --git a/projects/Classic Arcade Game Clone/images/Gem Orange.png b/projects/Classic Arcade Game Clone/images/Gem Orange.png new file mode 100644 index 00000000..f8faf7b5 Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/Gem Orange.png differ diff --git a/projects/Classic Arcade Game Clone/images/Heart.png b/projects/Classic Arcade Game Clone/images/Heart.png new file mode 100644 index 00000000..aa49b5c3 Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/Heart.png differ diff --git a/projects/Classic Arcade Game Clone/images/Key.png b/projects/Classic Arcade Game Clone/images/Key.png new file mode 100644 index 00000000..7602326a Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/Key.png differ diff --git a/projects/Classic Arcade Game Clone/images/Rock.png b/projects/Classic Arcade Game Clone/images/Rock.png new file mode 100644 index 00000000..29c4e200 Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/Rock.png differ diff --git a/projects/Classic Arcade Game Clone/images/Selector.png b/projects/Classic Arcade Game Clone/images/Selector.png new file mode 100644 index 00000000..e7c5475a Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/Selector.png differ diff --git a/projects/Classic Arcade Game Clone/images/Star.png b/projects/Classic Arcade Game Clone/images/Star.png new file mode 100644 index 00000000..17c0af58 Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/Star.png differ diff --git a/projects/Classic Arcade Game Clone/images/char-boy.png b/projects/Classic Arcade Game Clone/images/char-boy.png new file mode 100644 index 00000000..3dc7c298 Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/char-boy.png differ diff --git a/projects/Classic Arcade Game Clone/images/char-cat-girl.png b/projects/Classic Arcade Game Clone/images/char-cat-girl.png new file mode 100644 index 00000000..dc0538b1 Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/char-cat-girl.png differ diff --git a/projects/Classic Arcade Game Clone/images/char-horn-girl.png b/projects/Classic Arcade Game Clone/images/char-horn-girl.png new file mode 100644 index 00000000..90f22784 Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/char-horn-girl.png differ diff --git a/projects/Classic Arcade Game Clone/images/char-pink-girl.png b/projects/Classic Arcade Game Clone/images/char-pink-girl.png new file mode 100644 index 00000000..baef1772 Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/char-pink-girl.png differ diff --git a/projects/Classic Arcade Game Clone/images/char-princess-girl.png b/projects/Classic Arcade Game Clone/images/char-princess-girl.png new file mode 100644 index 00000000..9d9f958c Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/char-princess-girl.png differ diff --git a/projects/Classic Arcade Game Clone/images/enemy-bug.png b/projects/Classic Arcade Game Clone/images/enemy-bug.png new file mode 100644 index 00000000..191587b4 Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/enemy-bug.png differ diff --git a/projects/Classic Arcade Game Clone/images/grass-block.png b/projects/Classic Arcade Game Clone/images/grass-block.png new file mode 100644 index 00000000..eb04ba90 Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/grass-block.png differ diff --git a/projects/Classic Arcade Game Clone/images/stone-block.png b/projects/Classic Arcade Game Clone/images/stone-block.png new file mode 100644 index 00000000..01113cff Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/stone-block.png differ diff --git a/projects/Classic Arcade Game Clone/images/water-block.png b/projects/Classic Arcade Game Clone/images/water-block.png new file mode 100644 index 00000000..0383ed81 Binary files /dev/null and b/projects/Classic Arcade Game Clone/images/water-block.png differ diff --git a/projects/Classic Arcade Game Clone/index.html b/projects/Classic Arcade Game Clone/index.html new file mode 100644 index 00000000..fdad973f --- /dev/null +++ b/projects/Classic Arcade Game Clone/index.html @@ -0,0 +1,18 @@ + + + + + Effective JavaScript: Frogger + + + + +

Classic Arcade Game

+
+
Score:
+ + + + + + diff --git a/projects/Classic Arcade Game Clone/js/app.js b/projects/Classic Arcade Game Clone/js/app.js new file mode 100644 index 00000000..4aa58e8a --- /dev/null +++ b/projects/Classic Arcade Game Clone/js/app.js @@ -0,0 +1,132 @@ +// Declaring variables +var maximum_speed = 150; +var minimum_speed = 100; +var points = 0; + +// Printing zero for score +document.getElementById("score").innerHTML = points; + +// Enemies our player must avoid +var Enemy = function(x,y) { + // Variables applied to each of our instances go here, + // we've provided one for you to get started + this.x = x; + this.y = y; + this.speed = this.setspeed(); + // The image/sprite for our enemies, this uses + // a helper we've provided to easily load images + this.sprite = 'images/enemy-bug.png'; +}; + +// Function to randomize the speed of the enemies +Enemy.prototype.setspeed = function() { + return Math.floor(Math.random() * (maximum_speed - minimum_speed) + 500 * Math.random()); +}; + +// Update the enemy's position, required method for game +// Parameter: dt, a time delta between ticks +Enemy.prototype.update = function(dt) { + // You should multiply any movement by the dt parameter + // which will ensure the game runs at the same speed for + // all computers. + if(this.x < 550) + { + this.x += this.speed * dt; + } + else + { + this.x = -90; + this.speed = this.setspeed(); + } +}; + +// Draw the enemy on the screen, required method for game +Enemy.prototype.render = function() { + ctx.drawImage(Resources.get(this.sprite), this.x, this.y); +}; + +// Now write your own player class +var Player = function(x,y) +{ + this.x = x; + this.y = y; + this.sprite = 'images/char-boy.png'; +}; + +// Function to initialize the position of the player after every game +Player.prototype.start_position = function() { + this.x = 203; + this.y = 400; +}; + +// This class requires an update(), render() and +// a handleInput() method. +Player.prototype.update = function() { + for (var i = 0; i < allEnemies.length; i++) { + if ((this.x + 72 > allEnemies[i].x) && (this.x < allEnemies[i].x + 72) && (this.y + 72 > allEnemies[i].y) && (this.y < allEnemies[i].y + 72)) { + this.start_position(); + points = 0; + document.getElementById("score").innerHTML = points; + } + } +}; + +Player.prototype.handleInput = function(key) { + if (key == 'up') { + if (this.y > 40) + this.y -= 90; + else { + points++; + this.start_position(); + document.getElementById("score").innerHTML = points; + if(points == 10) { + alert("Your have won. Your score is " + points + ". Press OK to start a new game"); + //this.start_position(); + points = 0; + document.getElementById("score").innerHTML = points; + } + } + } else if (key == 'down') { + if (this.y < 470) { + this.y += 90; + } /*else { + this.start_position(); + }*/ + } else if (key == 'left') { + if (this.x > 50) + this.x -= 100; + } else if (key == 'right') { + if (this.x < 400) + this.x += 100; + } +}; + +Player.prototype.render = function() { + ctx.drawImage(Resources.get(this.sprite), this.x, this.y); +}; + +// Now instantiate your objects. + +// Place all enemy objects in an array called allEnemies +var allEnemies = [ + new Enemy(0,50), + new Enemy(0,145), + new Enemy(0,230), + new Enemy(0,310) +]; + +// Place the player object in a variable called player +var player = new Player(203,400); + +// This listens for key presses and sends the keys to your +// 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]); +}); \ No newline at end of file diff --git a/projects/Classic Arcade Game Clone/js/engine.js b/projects/Classic Arcade Game Clone/js/engine.js new file mode 100644 index 00000000..a8cb4e87 --- /dev/null +++ b/projects/Classic Arcade Game Clone/js/engine.js @@ -0,0 +1,185 @@ +/* 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). + * + * A game engine works by drawing the entire game screen over and over, kind of + * like a flipbook you may have created as a kid. When your player moves across + * the screen, it may look like just that image/character is moving or being + * drawn but that is not the case. What's really happening is the entire "scene" + * is being drawn over and over, presenting the illusion of animation. + * + * This engine is available globally via the Engine variable and it also makes + * the canvas' context (ctx) object globally available to make writing app.js + * a little simpler to work with. + */ + +var Engine = (function(global) { + /* Predefine the variables we'll be using within this scope, + * create the canvas element, grab the 2D context for that canvas + * set the canvas elements height/width and add it to the DOM. + */ + var doc = global.document, + win = global.window, + canvas = doc.createElement('canvas'), + ctx = canvas.getContext('2d'), + lastTime; + + canvas.width = 505; + canvas.height = 706; + 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. Because everyone's computer processes + * instructions at different speeds we need a constant value that + * would be the same for everyone (regardless of how fast their + * computer is) - hurray time! + */ + var now = Date.now(), + dt = (now - lastTime) / 1000.0; + + /* Call our update/render functions, pass along the time delta to + * our update function since it may be used for smooth animation. + */ + update(dt); + render(); + + /* Set our lastTime variable which is used to determine the time delta + * for the next time this function is called. + */ + lastTime = now; + + /* Use the browser's requestAnimationFrame function to call this + * function again as soon as the browser is able to draw another frame. + */ + 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() { + reset(); + 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. Based on how + * you implement your collision detection (when two entities occupy the + * same space, for instance when your character should die), you may find + * the need to add an additional function call here. For now, we've left + * it commented out - you may or may not want to implement this + * functionality this way (you could just implement collision detection + * on the entities themselves within your app.js file). + */ + function update(dt) { + updateEntities(dt); + // checkCollisions(); + } + + /* This is called by the update function and loops through all of the + * objects within your allEnemies array as defined in app.js and calls + * their update() methods. It will then call the update function for your + * player object. These update methods should focus purely on updating + * the data/properties related to the object. Do your drawing in your + * render methods. + */ + 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. Remember, this function is called every + * game tick (or loop of the game engine) because that's how games work - + * they are flipbooks creating the illusion of animation but in reality + * they are just drawing the entire screen over and over. + */ + 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/stone-block.png', + 'images/grass-block.png', // Row 1 of 2 of grass + 'images/grass-block.png' // Row 2 of 2 of grass + ], + numRows = 7, + numCols = 5, + row, col; + + /* 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() { + /* Loop through all of the objects within the allEnemies array and call + * the render function you have defined. + */ + allEnemies.forEach(function(enemy) { + enemy.render(); + }); + + player.render(); + } + + /* This function does nothing but it could have been a good place to + * handle game reset states - maybe a new game menu or a game over screen + * those sorts of things. It's only called once by the init() method. + */ + function reset() { + // noop + } + + /* Go ahead and load all of the images we know we're going to need to + * draw our game level. Then set init as the callback method, so that when + * all of these images are properly loaded our game will start. + */ + Resources.load([ + 'images/stone-block.png', + 'images/water-block.png', + 'images/grass-block.png', + 'images/enemy-bug.png', + 'images/char-boy.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/projects/Classic Arcade Game Clone/js/resources.js b/projects/Classic Arcade Game Clone/js/resources.js new file mode 100644 index 00000000..c49baff8 --- /dev/null +++ b/projects/Classic Arcade Game Clone/js/resources.js @@ -0,0 +1,111 @@ +/* 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 + }; +})();