Your task
You will be making a small, simple browser game, making use of JS, DOM manipulation, and event-driven programming.
- Click the GitHub link in the project 2 announcement, and clone your proj2 repo like before.
- Edit the JS and CSS files to make your game.
- You can also change the HTML file if you want to make it look nicer.
- Don’t forget to make commits while working.
- (And even push them to GitHub if you’re paranoid.)
The starting point
You have been given a few files:
index.html
has just enough HTML in it to show a very basic game interface.style.css
has a few important rules in it, and you are more than welcome to go crazy with it.mosquito.png
is a mosquito image.script.js
is where you’ll be doing most of your work.
What I’ve given you in script.js
-
Array.prototype.removeItem(item)
lets you remove a particular value from an array, like:let arr = [1, 2, 3, 4, 5] arr.removeItem(3) console.log(arr) // shows 1, 2, 4, 5
getRandomInt(min, max)
gives you a random integer in the range[min, max)
.- e.g.
getRandomInt(0, 10)
gives 0 as the smallest and 9 as the largest.
- e.g.
- Some named constants.
- USE NAMED CONSTANTS. Do NOT put “magical numbers” into your code.
- If a number “means something”, make a named constant for it!
- The
window.onload
function, which is sort of the starting point of your code. randomPointOnSide
andpickPointAndVector
will help you spawn mosquitoes.
The game
If you’re familiar with Mario Paint, and you know the fly-swatting game… yeah, that. Wait, most of you are way too young for that. 😅
It’s summer in Pittsburgh and that means MOSQUITOES. So, you have to slap them. There are so many. They are endless.
Game flow
The game will work like this:
Each round of the game goes like this:
- The player must click to begin the round.
- Mosquitoes randomly appear at the sides of the screen and move across it.
- If the player clicks a mosquito,
- The mosquito dies (is removed from the screen)
- They get 100 points
- If a mosquito moves off the edge of the screen,
- The mosquito “escapes” (and is removed from the screen)
- The player gets a miss
- If the player kills 10 mosquitoes,
- The current “round” is over
- They get a bonus according to how many misses they had:
(1000 - (250 * misses))
. So,- 0 misses = 1000 points
- 1 miss = 750 points
- 2 misses = 500 points, etc.
- Their misses are reset to 0, and the next round starts.
- If the player misses 5 mosquitoes,
- The game is over.
- They do not get any bonus points.
- Their final score may be entered into the high score table.
- They may start a new game by clicking the playfield. If so, the round is reset to 1 and the score is reset to 0.
Starting off
In your window.onload
function, set an onclick
handler on either the playfield
or the gameMessage
elements. It will be responsible for a few things:
- Hiding the message
- Resetting all the game variables (score, mosquitoes remaining, misses)
- Starting the main game loop (see below)
- Starting the mosquito spawning (also see below…)
Try to get the first two bullet points working first. Use the console, inspector, and debugger to help yourself.
The main game loop
You don’t get to write a “loop” in the typical sense. If you did, your browser would freeze.
Instead, you use the requestAnimationFrame()
function. It works like this:
// have to start it off somehow.
function startGame() {
// give it the name of the function to call.
requestAnimationFrame(gameLoop)
}
function gameLoop() {
// 1. update the position of the mosquitoes
// 2. update the score/misses/etc. displays
// 3. check if the user won or lost
// this is sort of the "loop condition."
// we call requestAnimationFrame again with gameLoop.
// this isn't recursive; the browser will call us again
// at some future point in time.
if(the game should continue) {
requestAnimationFrame(gameLoop)
}
}
You may use the above pseudocode in your project.
When you call requestAnimationFrame()
, you tell the browser “hey, call this function when you’re ready to update the display.” By having gameLoop
give itself to this function, it will be called repeatedly.
Mosquito spawning
To spawn the mosquitoes, you will use a timeout function. This is a way of having the browser call your code back after a set amount of time.
You use a similar pattern for this as for the main game loop:
function startSpawning() {
// 1000 ms (1 second) from now, spawnMosquito() will be called.
window.setTimeout(spawnMosquito, 1000)
}
function spawnMosquito() {
// this is a "destructuring assignment."
// it makes 4 local variables by extracting elements of the array that was returned.
let [x, y, vx, vy] = pickPointAndVector()
console.log("spawning a mosquito at " + x + ", " + y + " (remove this log statement)")
// now to actually make an object/DOM element
if(should continue spawning) {
// spawn another one a second from now
window.setTimeout(spawnMosquito, 1000)
}
}
You may use the above pseudocode in your project.
Representing the mosquitoes
Just do a little bit of code at a time. Test constantly. Put generous logging in at first, and remove it as you go. Use the debugger. You’re in a 1500 level class. Be smart about this.
The pickPointAndVector()
function I used in the example above returns 4 values representing a random position (x, y)
and direction (vx, vy)
of a mosquito. It’s like this:
Here are some tips on implementing the mosquitoes.
- Make a
Mosquito
object. (You need a constructor function and methods.)- Each mosquito needs to remember its position and velocity.
- Remember, you need to use
this.whatever
to access object properties.
- Each mosquito also needs a DOM element to represent it onscreen.
- Use
document.createElement('img')
to make an image element. - Set its
src
property to'mosquito.png'
. - You need to make it a child of something…
- To position it, you’ll have to use the element’s
style
property:// just to test. let x = 100 let y = 200 el.style.position = 'absolute' el.style.left = x + 'px' el.style.top = y + 'px'
- Use
- Have a global array of mosquito objects.
- The
push
andremoveItem
methods will be useful.
- The
- To move the mosquitoes,
- In your main game loop function, loop over that array of mosquitoes, and do something like this:
m.x += m.vx * speed m.y += m.vy * speed
Where
speed
is some value you pick. Something like 2 or 3 is pretty easy. - Don’t forget - you have to reposition the corresponding DOM element too.
- In your main game loop function, loop over that array of mosquitoes, and do something like this:
- When a mosquito goes offscreen, it needs to be destroyed…
- Which means removing it from that array and removing its DOM element.
- To remove a DOM element from its parent:
el.parentNode.removeChild(el)
-
To implement clicking on the mosquitoes, you’ll use their DOM elements’
onmousedown
event:el.onmousedown = function(event) { // event.button is 0 for the left mouse button. // event.target is the DOM element that was clicked. // how can you get the Mosquito object that represents this DOM element? // well, you can put *your own properties* on DOM elements too... // stops the event from bubbling up. event.stopPropagation() };
Other game aspects
- Get comfortable using the JS debugger in your browser’s inspector.
- it will be a lot more helpful than sprinkling
alert()
s andconsole.log()
s all over the place.
- it will be a lot more helpful than sprinkling
- The inspector’s HTML view also shows event handlers that are attached to elements.
- You’ll need to have some global variables… it’s okay.
- I like to put all my game-related variables inside an object, but you don’t have to.
- Look at the HTML and see how the “Round”, “Mosquitoes Left” etc. messages are structured.
- You can grab those
<span>
elements by ID and set theirinnerHTML
to change what they say.
- You can grab those
- You can hide the
gameMessage
element by setting itsstyle.display
to"none"
…- …and set it to
"flex"
to show it again. - Of course, you can use its
innerHTML
to change the message being displayed.
- …and set it to
- When the player gets a game over, their score needs to be entered into the high score list.
- You’ll use
window.localStorage
to store the high scores. - Since
Storage
expects the keys and values to be strings, you can encode your high score data usingJSON
.JSON.stringify(obj)
takes an object and turns it into a string.JSON.parse(str)
goes the other way - takes a string and gives you an object.
- How do you sort an array from biggest to smallest using the
.sort()
method? - Only keep the top 5 scores. Remember that
.length
can be changed. - Display the high scores in the
highScores
<ol>
(look at the HTML).
- You’ll use