diff --git a/README.md b/README.md index 4439e34..68b513b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# CoderSchool FTW - * Nam, the Monster Hunter * +# CoderSchool FTW - _ Nam, the Monster Hunter _ Created with love by: Charles Lee - -This is a simple Canvas-based game that requires a solid understanding of the principles of JavaScript programming to customize. + +This is a simple Canvas-based game that requires a solid understanding of the principles of JavaScript programming to customize. ## Video Walkthrough @@ -12,39 +12,38 @@ Here's a walkthrough of implemented user stories. ## Code Reviews -This code was reviewed by @username and @otherusername. - -* [Link to PR #X](#) - reviewed by @username. -* [Link to PR #Y](#) - reviewed by @otherusername. +This code was reviewed by @username and @otherusername. +- [Link to PR #X](https://github.com/vanmitG/canvas_game_starter/pull/1) - reviewed by @username. +- [Link to PR #Y](#) - reviewed by @otherusername. ## Required User Stories + - [ ] I have at least three code reviews from others. -- [x] The user can move their character with the arrow keys. +- [x] The user can move their character with the arrow keys. - [x] The user can see a monster. -- [ ] The monster is placed at a random location within the game boundaries. +- [x] The monster is placed at a random location within the game boundaries. - [x] The user can catch a monster by moving their character to the same location as a monster. -- [ ] When the user catches a monster, a new monster is placed randomly upon the screen. -- [ ] The user can see the numbers of monsters she has caught. Every time she catches a monster, the number should increment by one. -- [ ] The game ends when the user has caught 20 monsters. The total time elapsed is displayed upon game completion, in seconds. -- [ ] The user can access this game from the internet (e.g. using Netlify). -- [ ] The code has been reviewed by at least one other person, using Pull Requests on GitHub. +- [x] When the user catches a monster, a new monster is placed randomly upon the screen. +- [x] The user can see the numbers of monsters she has caught. Every time she catches a monster, the number should increment by one. +- [x] The game ends when the user has caught 20 monsters. The total time elapsed is displayed upon game completion, in seconds. +- [x] The user can access this game from the internet (e.g. using Netlify). +- [x] The code has been reviewed by at least one other person, using Pull Requests on GitHub. ## Optional User Stories -- [ ] Custom styling: the developer has replaced the images for the main character, monster, and background with something of her choice. -- [ ] The user cannot move her character off the screen. -- [ ] The user sees a few different types of monster each time a new monster is spawned. -- [ ] The monster moves around on its own each frame, and the user must chase it. -- [ ] The map has "obstacles", such as trees, which block the user from moving through the space occupied by the obstacle. -- [ ] The user can hear sound effects upon movement and upon catching a monster. -- [ ] The user hears background music during the game. -- [ ] The user can see their high score. - +- [x] Custom styling: the developer has replaced the images for the main character, monster, and background with something of her choice. +- [x] The user cannot move her character off the screen. +- [] The user sees a few different types of monster each time a new monster is spawned. +- [ ] The monster moves around on its own each frame, and the user must chase it. +- [ ] The map has "obstacles", such as trees, which block the user from moving through the space occupied by the obstacle. +- [ ] The user can hear sound effects upon movement and upon catching a monster. +- [ ] The user hears background music during the game. +- [x] The user can see their high score. The following **additional** features are implemented: -* [x] List anything else that you can get done to improve the page! +- [x] List anything else that you can get done to improve the page! ## Time Spent and Lessons Learned @@ -66,4 +65,4 @@ Describe any challenges encountered while building the app. distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file + limitations under the License. diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..82e8c1c --- /dev/null +++ b/css/style.css @@ -0,0 +1,11 @@ +#gameContainer { + width: 980; + height: 680; + display: flex; + justify-content: flex-end; + align-items: center; +} +.noScroll { + max-width: 100vw; + overflow-x: hidden; +} diff --git a/game.js b/game.js index 0fd9496..cb76b7f 100644 --- a/game.js +++ b/game.js @@ -9,134 +9,367 @@ Here, we create and add our "canvas" to the page. We also load all of our images. */ - let canvas; let ctx; canvas = document.createElement("canvas"); ctx = canvas.getContext("2d"); -canvas.width = 512; -canvas.height = 480; -document.body.appendChild(canvas); +canvas.width = 1110; +canvas.height = 512; +// document.body.appendChild(canvas); +document.getElementById("gameContainer").appendChild(canvas); let bgReady, heroReady, monsterReady; let bgImage, heroImage, monsterImage; +let stoneReady, poolReady, bushReady, fireReady; +let stoneImage, poolImage, bushImage, fireImage; let startTime = Date.now(); const SECONDS_PER_ROUND = 30; +const endGameScore = 20; let elapsedTime = 0; +let timePerGame = 0; +let score = 0; +let playerHighScore = 0; +//get high score from local storage +let highScore = localStorage.getItem("highScore"); +document.getElementById("highScore").innerHTML = highScore; +// console.log("highScorehighScore", highScore); +let gameNumber = 1; function loadImages() { bgImage = new Image(); - bgImage.onload = function () { + bgImage.onload = function() { // show the background image bgReady = true; }; - bgImage.src = "images/background.png"; + bgImage.src = "images/backgroundN2.png"; + //hero heroImage = new Image(); - heroImage.onload = function () { + heroImage.onload = function() { // show the hero image heroReady = true; }; - heroImage.src = "images/hero.png"; - + heroImage.src = "images/shrekSmall.png"; + //monster monsterImage = new Image(); - monsterImage.onload = function () { + monsterImage.onload = function() { // show the monster image monsterReady = true; }; - monsterImage.src = "images/monster.png"; + monsterImage.src = "images/blackGhost2.png"; + //stone + stoneImage = new Image(); + stoneImage.onload = function() { + // show the stone image + stoneReady = true; + }; + stoneImage.src = "images/stoneSmall.png"; + //pool + poolImage = new Image(); + poolImage.onload = function() { + // show the pool image + poolReady = true; + }; + poolImage.src = "images/pondFrog2.png"; + //bush + bushImage = new Image(); + bushImage.onload = function() { + // show the push image + bushReady = true; + }; + bushImage.src = "images/stoneSmall2.png"; + //fire + fireImage = new Image(); + fireImage.onload = function() { + // show the fire image + fireReady = true; + }; + fireImage.src = "images/fireSmall.png"; +} + +class gameObject { + constructor(locationX, locationY, sizeX, sizeY) { + this.X = locationX; + this.Y = locationY; + this.sizeX = sizeX; + this.sizeY = sizeY; + } +} +class objectRange { + constructor(minX, minY, maxX, maxY) { + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } +} + +// let hero.X = canvas.width / 2; +// let hero.Y = canvas.height / 2; + +// let monster.X = Math.floor(Math.random() * (canvas.width - 10)) + 1; +// let monster.Y = Math.floor(Math.random() * (canvas.height - 10)) + 1; + +function getRandomIntInclusive(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive } -/** +function moveObjectRandomly(object, objectRange) { + const moveX = getRandomIntInclusive(objectRange.minX, objectRange.maxX); + const moveY = getRandomIntInclusive(objectRange.minY, objectRange.maxY); + object.X = moveX; + object.Y = moveY; + return object; +} + +/** * Setting up our characters. - * - * Note that heroX represents the X position of our hero. - * heroY represents the Y position. + * + * Note that hero.X represents the X position of our hero. + * hero.Y represents the Y position. * We'll need these values to know where to "draw" the hero. - * + * * The same applies to the monster. */ +let hero = new gameObject(canvas.width / 2, canvas.height / 2, 65, 78); +const heroRange = new objectRange( + 10, + 10, + canvas.width - 65, + canvas.height - 78 +); +let monster = new gameObject(100, 100, 50, 57); +console.log("monterere142", monster); -let heroX = canvas.width / 2; -let heroY = canvas.height / 2; +const monsterRange = new objectRange( + 10, + 10, + canvas.width - monster.sizeX, + canvas.height - monster.sizeY +); +console.log("monsterRange150", monsterRange); +// console.log(`hero.X: ${hero.X} and hero.Y: ${hero.Y}`); +let stone = new gameObject(canvas.width / 7, canvas.height / 4, 100, 67); +let pool = new gameObject(canvas.width - 480, 70, 150, 150); +let bush = new gameObject(canvas.width - 750, canvas.height - 150, 120, 78); +let fire = new gameObject(canvas.width - 100, canvas.height - 200, 60, 60); -let monsterX = 100; -let monsterY = 100; +let obstacle = [stone, pool, bush]; +// let hero.X = canvas.width / 2; +// let hero.Y = canvas.height / 2; +// let monster.X = 100; +// let monster.Y = 100; -/** +/** * Keyboard Listeners - * You can safely ignore this part, for now. - * + * You can safely ignore this part, for now. + * * This is just to let JavaScript know when the user has pressed a key. -*/ + */ let keysDown = {}; function setupKeyboardListeners() { // Check for keys pressed where key represents the keycode captured - // For now, do not worry too much about what's happening here. - addEventListener("keydown", function (key) { - keysDown[key.keyCode] = true; - }, false); - - addEventListener("keyup", function (key) { - delete keysDown[key.keyCode]; - }, false); + // For now, do not worry too much about what's happening here. + addEventListener( + "keydown", + function(key) { + keysDown[key.keyCode] = true; + }, + false + ); + + addEventListener( + "keyup", + function(key) { + delete keysDown[key.keyCode]; + }, + false + ); } +function isObjectOneColideObjectTwo(objectOne, ObjectTwo) { + const isObj1CollideObj2 = + objectOne.X <= ObjectTwo.X + ObjectTwo.sizeX && + ObjectTwo.X <= objectOne.X + objectOne.sizeX && + objectOne.Y <= ObjectTwo.Y + ObjectTwo.sizeY && + ObjectTwo.Y <= objectOne.Y + objectOne.sizeY; + if (isObj1CollideObj2) { + return true; + } else { + return false; + } +} + +/**Restart Game */ +function playAgain() { + //reset + startTime = Date.now(); + score = 0; + gameNumber = gameNumber + 1; + + document.getElementById("scoreNumber").innerHTML = score; + document.getElementById("gameNumber").innerHTML = gameNumber; + // document.getElementById("timePlay").innerHTML = elapsedTime; +} + +function isObjectNotColideObstacle(object, obstacle) { + const isObjColideObs = + isObjectOneColideObjectTwo(object, obstacle[0]) || + isObjectOneColideObjectTwo(object, obstacle[1]) || + isObjectOneColideObjectTwo(object, obstacle[2]); + if (isObjColideObs) { + return false; + } else { + return true; + } +} /** * Update game objects - change player position based on key pressed * and check to see if the monster has been caught! - * + * * If you change the value of 5, the player will move at a different rate. */ -let update = function () { +monster = moveObjectRandomly(monster, monsterRange); + +if (isObjectNotColideObstacle(monster, obstacle)) { + monster = moveObjectRandomly(monster, monsterRange); +} + +let update = function() { // Update the time. elapsedTime = Math.floor((Date.now() - startTime) / 1000); + const isStillTimeAndScoreNotMax = + elapsedTime <= SECONDS_PER_ROUND && score <= endGameScore; + if (isStillTimeAndScoreNotMax) { + document.getElementById("timePlay").innerHTML = elapsedTime; + document.getElementById("scoreNumber").innerHTML = score; + } else { + // GAME OVER + return; + } - - if (38 in keysDown) { // Player is holding up key - heroY -= 5; + if (38 in keysDown) { + // Player is holding up key + hero.Y -= 5; } - if (40 in keysDown) { // Player is holding down key - heroY += 5; + if (40 in keysDown) { + // Player is holding down key + hero.Y += 5; } - if (37 in keysDown) { // Player is holding left key - heroX -= 5; + if (37 in keysDown) { + // Player is holding left key + hero.X -= 5; } - if (39 in keysDown) { // Player is holding right key - heroX += 5; + if (39 in keysDown) { + // Player is holding right key + hero.X += 5; } + if (hero.X <= 10) { + hero.X = 10; + } + if (hero.X >= canvas.width - 20) { + hero.X = canvas.width - 20; + } + if (hero.Y <= 10) { + hero.Y = 10; + } + if (hero.Y >= canvas.height - 20) { + hero.Y = canvas.height - 20; + } + // console.log("hero.Xhero.X", hero.X); + // console.log("hero.Yhero.Y", hero.Y); // Check if player and monster collided. Our images // are about 32 pixels big. - if ( - heroX <= (monsterX + 32) - && monsterX <= (heroX + 32) - && heroY <= (monsterY + 32) - && monsterY <= (heroY + 32) - ) { + + // const isHeroCollideMonster = + // hero.X <= monster.X + 32 && + // monster.X <= hero.X + 32 && + // hero.Y <= monster.Y + 32 && + // monster.Y <= hero.Y + 32; + // if (isObjectOneColideObjectTwo(hero, stone)) { + // } + if (isObjectOneColideObjectTwo(hero, monster)) { // Pick a new location for the monster. // Note: Change this to place the monster at a new, random location. - monsterX = monsterX + 50; - monsterY = monsterY + 70; + + score = score + 1; + // console.log("scorescore", score); + // console.log("hero.Xhero.X", hero.X); + // console.log("hero.Yhero.Y", hero.Y); + // document.getElementById("scoreNumber").innerHTML = score; + + if (score > playerHighScore) { + playerHighScore = score; + document.getElementById("playerHighScore").innerHTML = playerHighScore; + } + if (playerHighScore > highScore) { + highScore = playerHighScore; + document.getElementById("highScore").innerHTML = highScore; + localStorage.setItem("highScore", highScore); + } + + // monster.X = monster.X + 50; + // monster.Y = monster.Y + 70; + // monster.X = Math.floor(Math.random() * (canvas.width - 25)) + 1; + // monster.Y = Math.floor(Math.random() * (canvas.height - 25)) + 1; + // objectsMoveRandomly(monster.X, monster.Y); + monster = moveObjectRandomly(monster, monsterRange); + console.log(`monster(x,y)L307= (${monster.X},${monster.Y})`); } }; /** * This function, render, runs as often as possible. */ -var render = function () { - if (bgReady) { - ctx.drawImage(bgImage, 0, 0); - } - if (heroReady) { - ctx.drawImage(heroImage, heroX, heroY); - } - if (monsterReady) { - ctx.drawImage(monsterImage, monsterX, monsterY); +var render = function() { + let remainTime = SECONDS_PER_ROUND - elapsedTime; + const isStillTimeAndScoreNotMax = + elapsedTime <= SECONDS_PER_ROUND && score <= endGameScore; + if (isStillTimeAndScoreNotMax) { + if (bgReady) { + ctx.drawImage(bgImage, 0, 0); + } + if (heroReady) { + ctx.drawImage(heroImage, hero.X, hero.Y); + } + if (monsterReady) { + // ctx.clearRect(monster.X, monster.Y, 65, 74); + // ctx.save(); + // ctx.globalAlpha = 0.5; + ctx.drawImage(monsterImage, monster.X, monster.Y); + // ctx.restore(); + } + + if (stoneReady) { + ctx.drawImage(stoneImage, stone.X, stone.Y); + } + if (poolReady) { + ctx.drawImage(poolImage, pool.X, pool.Y); + } + if (bushReady) { + ctx.drawImage(bushImage, bush.X, bush.Y); + } + if (fireReady) { + ctx.drawImage(fireImage, fire.X, fire.Y); + } + + ctx.fillStyle = "black"; + ctx.font = "12px Arial"; + ctx.textAlign = "left"; + ctx.fillText(`Seconds Remaining: ${remainTime}`, 20, 50); + } else { + ctx.fillStyle = "red"; + ctx.font = "50px Arial"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", canvas.width / 2, canvas.height / 2); + // GAME OVER + return; } - ctx.fillText(`Seconds Remaining: ${SECONDS_PER_ROUND - elapsedTime}`, 20, 100); }; /** @@ -144,20 +377,24 @@ var render = function () { * update (updates the state of the game, in this case our hero and monster) * render (based on the state of our game, draw the right things) */ -var main = function () { - update(); +var main = function() { + update(); render(); // Request to do this again ASAP. This is a special method - // for web browsers. + // for web browsers. requestAnimationFrame(main); }; // Cross-browser support for requestAnimationFrame. // Safely ignore this line. It's mostly here for people with old web browsers. var w = window; -requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame; +requestAnimationFrame = + w.requestAnimationFrame || + w.webkitRequestAnimationFrame || + w.msRequestAnimationFrame || + w.mozRequestAnimationFrame; // Let's play this game! loadImages(); setupKeyboardListeners(); -main(); \ No newline at end of file +main(); diff --git a/images/0756dd46e11b3ce.jpg b/images/0756dd46e11b3ce.jpg new file mode 100644 index 0000000..0a72a48 Binary files /dev/null and b/images/0756dd46e11b3ce.jpg differ diff --git a/images/6d3de9e6b437cedf71d3468aa8cc8297_pond-clip-art-free-clipart-panda-free-clipart-images_1249-1249.svg b/images/6d3de9e6b437cedf71d3468aa8cc8297_pond-clip-art-free-clipart-panda-free-clipart-images_1249-1249.svg new file mode 100644 index 0000000..1eaf4c0 --- /dev/null +++ b/images/6d3de9e6b437cedf71d3468aa8cc8297_pond-clip-art-free-clipart-panda-free-clipart-images_1249-1249.svg @@ -0,0 +1,157 @@ + + + diff --git a/images/assetList.png b/images/assetList.png new file mode 100644 index 0000000..fb5c206 Binary files /dev/null and b/images/assetList.png differ diff --git a/images/backgroundN1.png b/images/backgroundN1.png new file mode 100644 index 0000000..93f0fe7 Binary files /dev/null and b/images/backgroundN1.png differ diff --git a/images/backgroundN2 - Copy.png b/images/backgroundN2 - Copy.png new file mode 100644 index 0000000..991f43c Binary files /dev/null and b/images/backgroundN2 - Copy.png differ diff --git a/images/backgroundN2.png b/images/backgroundN2.png new file mode 100644 index 0000000..114b30b Binary files /dev/null and b/images/backgroundN2.png differ diff --git a/images/blackGhost2.png b/images/blackGhost2.png new file mode 100644 index 0000000..aac3cae Binary files /dev/null and b/images/blackGhost2.png differ diff --git a/images/blackGhostSmall.png b/images/blackGhostSmall.png new file mode 100644 index 0000000..a6317dc Binary files /dev/null and b/images/blackGhostSmall.png differ diff --git a/images/bonfire_PNG44.png b/images/bonfire_PNG44.png new file mode 100644 index 0000000..474f429 Binary files /dev/null and b/images/bonfire_PNG44.png differ diff --git a/images/bush1.png b/images/bush1.png new file mode 100644 index 0000000..61eb875 Binary files /dev/null and b/images/bush1.png differ diff --git a/images/fireSmall.png b/images/fireSmall.png new file mode 100644 index 0000000..680e18c Binary files /dev/null and b/images/fireSmall.png differ diff --git a/images/ghost_PNG85.png b/images/ghost_PNG85.png new file mode 100644 index 0000000..1e5bf31 Binary files /dev/null and b/images/ghost_PNG85.png differ diff --git a/images/hero2.png b/images/hero2.png new file mode 100644 index 0000000..fbd32ee Binary files /dev/null and b/images/hero2.png differ diff --git a/images/pondFrog.png b/images/pondFrog.png new file mode 100644 index 0000000..3bbb661 Binary files /dev/null and b/images/pondFrog.png differ diff --git a/images/pondFrog2.png b/images/pondFrog2.png new file mode 100644 index 0000000..68f24bd Binary files /dev/null and b/images/pondFrog2.png differ diff --git a/images/pool.png b/images/pool.png new file mode 100644 index 0000000..8fe8bf6 Binary files /dev/null and b/images/pool.png differ diff --git a/images/shrekSmall.png b/images/shrekSmall.png new file mode 100644 index 0000000..134e411 Binary files /dev/null and b/images/shrekSmall.png differ diff --git a/images/shrek_PNG5.png b/images/shrek_PNG5.png new file mode 100644 index 0000000..e34a91e Binary files /dev/null and b/images/shrek_PNG5.png differ diff --git a/images/stone-bush.png b/images/stone-bush.png new file mode 100644 index 0000000..a0ceacc Binary files /dev/null and b/images/stone-bush.png differ diff --git a/images/stone1.png b/images/stone1.png new file mode 100644 index 0000000..922d5e0 Binary files /dev/null and b/images/stone1.png differ diff --git a/images/stoneSmall.png b/images/stoneSmall.png new file mode 100644 index 0000000..9ad2919 Binary files /dev/null and b/images/stoneSmall.png differ diff --git a/images/stoneSmall2.png b/images/stoneSmall2.png new file mode 100644 index 0000000..c4e2eb2 Binary files /dev/null and b/images/stoneSmall2.png differ diff --git a/images/stone_PNG13589.png b/images/stone_PNG13589.png new file mode 100644 index 0000000..e4c2ca3 Binary files /dev/null and b/images/stone_PNG13589.png differ diff --git a/images/stone_PNG13590.png b/images/stone_PNG13590.png new file mode 100644 index 0000000..d7575bf Binary files /dev/null and b/images/stone_PNG13590.png differ diff --git a/images/water-2748638_960_720.png b/images/water-2748638_960_720.png new file mode 100644 index 0000000..d55f783 Binary files /dev/null and b/images/water-2748638_960_720.png differ diff --git a/images/waterSmall.png b/images/waterSmall.png new file mode 100644 index 0000000..16402ea Binary files /dev/null and b/images/waterSmall.png differ diff --git a/index.html b/index.html index f780ee0..285986b 100644 --- a/index.html +++ b/index.html @@ -1,10 +1,70 @@
- +