Code Monkey home page Code Monkey logo

javascript-rock-dodger's Introduction

JavaScript Rock Dodger

Objectives

  1. Use JavaScript to build a rock-dodging game
  2. Explain how window.requestAnimationFrame() is used to animate movement on a page
  3. Explain how to use setInterval()
  4. Show off your JavaScript know-how

Instructions

You did it — you've made it to the end of the introductory JavaScript curriculum. You've learned how to write JavaScript and how to use JavaScript to manipulate the DOM. Now, only this lab stands between you and freedom the end of this course!

So that we don't catch you off-guard, know that this project is meant to be difficult. We're really testing the limits of what we've learned so far. But know that we've solved the lab using only things that we've taught — well, mostly. There are two things (which we've partially implemented for you) that you should know about.

window.requestAnimationFrame()

This function tells the browser that we want to animate some change on the page. We'll use it in this lab for animating the movement of rocks and the dodger.

We can use window.requestAnimationFrame() by passing it a callback that contains our animation:

function move(el) {
  var top = 0

  function step() {
    el.style.top = `${top += 2}px`

    if (top < 200) {
      window.requestAnimationFrame(step)
    }
  }

  window.requestAnimationFrame(step)
}

If we call move(el) with a valid DOM element, window.requestAnimationFrame() will be called with the function step, which moves the el down the page in two-pixel increments until it's been moved 200 pixels. Pretty easy, right?

(Note that we can pass step to window.requestAnimationFrame() inside of step. This is a nifty feature of JavaScript (and other languages) called recursion. Don't worry if this concept makes your head spin a bit — that feeling is normal. For now, know that we can use window.requestAnimationFrame() as demonstrated above.)

setInterval()

setInterval() takes two arguments: a callback, and an interval in milliseconds. We can use it like so:

function sayHello() {
  console.log('hello')
}

const myInterval = setInterval(sayHello, 1000)

The above will print 'hello' to console once every second.

Note that setInterval() returns a reference to the interval. We can stop the interval from executing by calling clearInterval(myInterval).

Getting Started

Open up index.html in your browser. You should see a black 400-by-400px box with a white square at the bottom. That square is the dodger — it can only move left and right.

Well, it should be able to move only left and right — we'll need to implement that functionality!

Now open index.js. You'll see that we've defined a few functions for you, but we've left much of the file blank.

We've left enough comments to get you started, though, and we've defined all of the HTML and CSS that you'll need so that you can just focus on the JavaScript!

Remember to reload the page after updating and saving the file. You've got this!

Good luck!

Resources

View Rock Dodger on Learn.co and start learning to code for free.

javascript-rock-dodger's People

Contributors

annjohn avatar dakotalmartinez avatar devinburnette avatar gj avatar jkvyff avatar maxwellbenton avatar pletcher avatar rrcobb avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

javascript-rock-dodger's Issues

Game works, tests get stuck

My game works but the tests get stuck after 10 have run.
Here's me:
/home/tinaheiligers-29666/code/labs/javascript-rock-dodger-js-intro-000
Thanks!

KeyboardEvent.key should be used instead of KeyboardEvent.which as witch is Deprecated

as you can see on caniuse there is almost full support for KeyboardEvent.key. with an Edge fix coming soon.

a temporary workaround for Edge is as follows

if (e.key === 'ArrowLeft' || e.key === 'Left'){ 
 // code
}
if (e.key === 'ArrowRight' || e.key === 'Right'){ 
 // code
}

we should update the tests to reflect this
and update index.js to discard the following

8  const LEFT_ARROW = 37 // use e.which!
9  const RIGHT_ARROW = 39 // use e.which!

https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/which
https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
https://caniuse.com/#search=keyboardevent.key
https://www.w3.org/TR/uievents/#events-keyboardevents
https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/

Tests for rock-dodger stop not working properly.

I got the rock dodger game to work, but the tests won't pass.

I think maybe the tests are broken, but I don't know how to fix them. I spent hours trying to get the tests to pass, even though the program works fine. The test counts 10 passing tests, 0 failing, but can't run the rest so I controlC out of the tester.

At one point I found that if I changed some code in the createRock() function, I could get all 24 tests to pass. I initially learn submitted that copy of the program, having been so excited to finally get all tests to pass, but when the program is run, the rocks drop too fast to see.

After many more hours of headscratching as to why my program worked but the test runner couldnt complete, i checked the solution and compared it to mine. Turns out, even if I run the uploaded solution, the test runner still freezes after running the first 10 tests...

Any idea what's wrong?

rock dodger - the last lab

I got my rock dodger working and the game works, but my code still seems to have some sort of bug in it, when I do a "learn test" it goes to 10 and just hangs. When I do a "learn submit", the lab doesn't let me proceed. How can I get somebody to look over my code and help me?

Problem with test?

It seems that the solution given on GitHub does not pass the test in IDE.

In createRock function, 'top' and 'rock.style.top' are assigned the values below:
var top = 0
rock.style.top = top

I changed the code to below:
var top = rock.style.top

With this change, the code will pass the test. However, the variable top is now assigned a string value, which affects how the index.hml executes in a browser. It seems that whenever the variable 'top' is a number, the code cannot pass the test in IDE.

In short, the solution on GitHub executes correctly in a browser. But it does not pass the test in IDE.

Issue with the test file on this lab

So Zdrake tried to help me with the endGame function. So far all of my code was interpreted correctly, the issue I ran into was:
Rock Dodger endGame() removes the "keydown" event listener:
Error: spy was never called with [ 'keydown', [Function: moveDodger] ]
When my whole function looked like this:
function endGame() {
clearInterval(gameInterval);
ROCKS.forEach(function(rock)
{rock.remove();
});
document.removeEventListener('keydown', moveDodger);
//Zdrake tried to help on this one evidently the problem was with the test; please fix seriously
return alert('YOU LOSE!');
}

If there is any way a developer can look into this, it would save not only me but everyone working on this lab quite a bit of frustration.

Mocha blocks at test n°11

Hi,
I get all of the first 10 tests to pass then it pauses for a few minutes before raising an error.

> java-script-rock-dodger@0.1.0 test /home/brunoboehm-26262/code/labs/javascript-ro
ck-dodger-bootcamp-prep-000                                                        
> mocha -R mocha-multi --reporter-options nyan=-,json=.results.json                

 10  -_,------,                                                                    
 0   -_|   /\_/\                                                                   
 0   -^|__( ^ .^)                                                                  
     -  ""  ""

Killed_,------,                                                                    
npm ERR! Test failed.  See above for more details.                                 
/usr/local/rvm/gems/ruby-2.2.3/gems/learn-test-2.4.0/lib/learn_test/strategies/moch
a.rb:49:in `results': undefined method `[]' for nil:NilClass (NoMethodError)       
        from /usr/local/rvm/gems/ruby-2.2.3/gems/learn-test-2.4.0/lib/learn_test/ru
nner.rb:68:in `push_results'                                                       
        from /usr/local/rvm/gems/ruby-2.2.3/gems/learn-test-2.4.0/lib/learn_test/ru
nner.rb:19:in `run'                                                                
        from /usr/local/rvm/gems/ruby-2.2.3/gems/learn-test-2.4.0/bin/learn-test:60
:in `<top (required)>'                                                             
        from /usr/local/rvm/gems/ruby-2.2.3/bin/learn-test:23:in `load'            
        from /usr/local/rvm/gems/ruby-2.2.3/bin/learn-test:23:in `<main>'

Any idea of where this is coming from? Seems related to the endGame() part.

'checkCollision's comments and tests overcomplicate its function

'checkCollision's comments and tests overcomplicate its function:

only one evaluation is required to check for a collision, not three (or is that 2 instead of 6?)

The rock's right edge is > the DODGER's left edge,
and the rock's left edge is < the DODGER's right edge;
capture3

line 39 - 49

  if (false /**
               * Think about it -- what's happening here?
               * There's been a collision if one of three things is true:
               * 1. The rock's left edge is < the DODGER's left edge,
               *    and the rock's right edge is > the DODGER's left edge;
               * 2. The rock's left edge is > the DODGER's left edge,
               *    and the rock's right edge is < the DODGER's right edge;
               * 3. The rock's left edge is < the DODGER's right edge,
               *    and the rock's right edge is > the DODGER's right edge
               */) {
      return true

could be

  if (false /**
               * I thought about it this is all that's happening here
               * There's been a collision if
               * The rock's right edge is > the DODGER's left edge,
               * and the rock's left edge is < the DODGER's right edge;
               */) {
      return true

now in code:

if(rockRightEdge > dodgerLeftEdge && rockLeftEdge < dodgerRightEdge)

full function code:

function checkCollision(rock) {
  const top = positionToInteger(rock.style.top)

  if (top > 360) {
    const dodgerLeftEdge = positionToInteger(DODGER.style.left)
    const dodgerRightEdge = dodgerLeftEdge + 40
    const rockLeftEdge = positionToInteger(rock.style.left)
    const rockRightEdge = rockLeftEdge + 20

    if (rockRightEdge > dodgerLeftEdge &&
        rockLeftEdge < dodgerRightEdge
      /**
               * I thought about it this is all that's happening here
               * There's been a collision if
               * The rock's right edge is > the DODGER's left edge
               * and the rock's left edge is < the DODGER's right edge;
       */
    ) {
      return true
    }
  }
}

as you can see in the screenshot this code passes all test

capture2

Warning when opened locally

Just as an FYI - when I opened this index.html using httpserver in Chrome, I got the following warning:

"[Deprecation] Application Cache is deprecated in non-secure contexts, and will be restricted to secure contexts in M69, around September 2018. Please consider migrating your application to HTTPS, and eventually shifting over to Service Workers. See https://goo.gl/rStTGz for more details.
(anonymous) @ expect.min.js:7"

Ghost Rocks after endGame

I've tested this with my own code as well as the solution provided. After we remove the rock objects there is still some form of ghost rock that will re-trigger endGame() if it hits the dodger. It's most noticeable if you add the functionality to start a new game after you finish a run, but some other students and I observed this (or something similar) even when you are forced to refresh to start a new game. I've tried to come up with a solution myself for a while but I have thus far been unsuccessful. I will continue to see if I can come up with something.

Move Dodger function test script for right arrow: stopPropagation missing ()

file = index-test.js
row = 252

current:
expect(spy).toHaveBeenCalled

should be:
expect(spy).toHaveBeenCalled()

I changed on my forked copy and saved. Initially I failed the tests for preventDefault and stopPropagation as I didn't call them when I wrote my moveDodger function. However, only the left arrow test failed both and right arrow failed only preventDefault. Looked into the test and noticed that for the right arrow test on stopPropagation the parenthesis was missing. When I added the parenthesis the test results made sense as now I failed both preventDefault and stopPropagation on both the right and left arrow.

A fix for the 2 FIXMEs in checkCollision(rock)

There are 2 different places in checkCollision(rock) where there are comments indicating that we need to fix the code in place. These are:

// FIXME: The DODGER is 40 pixels wide -- how do we get the right edge? const dodgerRightEdge = 0;
and
// FIXME: The rock is 20 pixel's wide -- how do we get the right edge? const rockRightEdge = 0;

The problem here, ultimately, is that, since we can't get at the 'width' class elements from the CSS file from the JS file, we need constants to replicate them. Specifically, checking the CSS, we need the following 2, at least.

const DODGER_WIDTH = 40; const ROCK_WIDTH = 20;

These allow us to fix the issues by calculating the right edges.

const dodgerRightEdge = dodgerLeftEdge + DODGER_WIDTH; const rockRightEdge = rockLeftEdge + ROCK_WIDTH;

Rock Dodger contains test bug

Some other students and I have noticed that the Rock Dodger test contains a bug which makes the code pass in the Learn IDE, but which is fatal for the program in the browser.

// Hmmm, why would we have used 'var' here?
var top = 0;
rock.style.top = top;

If top is left with a var declaration, the Learn IDE freezes. However, if var is removed, the tests all pass.
However, without the var declaration, top gets global scoping and breaks the rest of the program when one attempts to run it in a browser such as Chrome such that the rocks do not fall as they should.

Official solution doesn't pass tests

Even the solution branch's index.js doesn't pass all the tests! It seems to get stuck while running lines 122-138 of index-test.js:

      it('removes the rock once it falls of the screen', done => {
        window.requestAnimationFrame = cb => {
          setInterval(cb, 0)
        }

        const rock = createRock(2)
        const spy = expect.spyOn(rock, 'remove')

        // Janky setTimeout to let the rock fall
        // off the screen
        setTimeout(() => {
          expect(spy).toHaveBeenCalled()
          done()
        }, 50)
      })

For next testing evaluation

Here is an example of code that is passing all tests, but has 2 flaws in it. Either of these render the game un-playable in a browser.

2 issues:
Removing a rock in the else

     if (top < 400) {
        window.requestAnimationFrame(moveRock)
        } else {
          rock.remove()
        }

Commenting out the call to rock.remove fixes this one.

Imperfect incrementing of top:

 top = `${top += 2}px`
rock.style.top = `${top}px`

Instead of the functional:

rock.style.top = `${top += 2}px`

CC: @gj @aturkewi

Test suite stopping after 10 tests; no rocks in browser

Track: BootCamp Prep (learn-co-students)

Branch: Solution

Issue Summary
When running the test suite and checking the game using the IDE (OSX) and httpserver, the test suite stops after running 10 tests, and no rocks are generated when playing the browser game. However, everything works totally fine on a local dev environment ( I tested it on my Mac).

According to one students a number of students have had similar issues.

@aturkewi

There is a bug in the tests for the endGame function.

Hello. For some reason, whenever I run mocha.run(), it triggers the alert in the endGame() function three times. If I am able to click out of each alert within two seconds after it appears, my code passes the test just fine.

However, if I wait more than two seconds before clicking the alert, it fails the test that triggers the alert, and it shows this error message: "Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test."

I tried just adding a call to done() in the tests, but then they fail because done() is not defined. I do not know where to put the call to done(), or if that is even what would solve the problem.

I should note that my code passes every test when it is run with the "learn test" command in the Learn IDE.

I also have two other minor issues. The first is that this lab requires knowledge of the logical operators && and | |. It also requires knowledge of the removeEventListener function. However, none of this is covered in any of the bootcamp prep lessons. My suggestion is to include && and | | in the Javascript Arithmetic Lab, and to include the removeEventListener function in the Listening to Nodes lab.

My other issue is about the hints for the "if" statement in the checkCollision function. They are a bit misleading as they suggest using < and > instead of <= and >=. Without the "=" sign, the "if" statement fails the tests for checkCollision.

I know that these are not the largest issues out there, but thank you for looking into this anyway.

GAME.removeChild(rock) VS rock.remove()

It might be worth offering a slight hint to remove the rocks by using their remove() method rather than using the removeChild method on the GAME element.

Using removeChild led to a REALLY confusing bug that caused me to spend 99% of my time getting the endGame() test to pass ; )

I'm thinking that's because the remove() method gets rid of all the bound events to the element, and removeChild does not. There is still a number of suggestions around the internet to avoid remove(), because it isn't well supported.

Test to remove keydown does not work with Node v 6.5.0

@AnnJohn

Solution branch works fine on v 6.3.0, but get the following error when running on 6.5.0:

(node:60203) fs: re-evaluating native module sources is not supported. If you are using the graceful-fs module, please update it to a more recent version.
npm WARN deprecated [email protected]: Jade has been renamed to pug, please install the latest version of pug instead of jade
npm WARN deprecated [email protected]: to-iso-string has been deprecated, use @segment/to-iso-string instead.
npm WARN deprecated [email protected]: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue

> [email protected] test /Users/avidor/Development/code/instructor/student_code/javascript-rock-dodger-bootcamp-prep-000
> mocha -R mocha-multi --reporter-options nyan=-,json=.results.json

 10  -_-_-_-_-_-_,------,
<--- Last few GCs --->\_/\ 
 0   -_-_-_-_-_-^|__( ^ .^) 
  442221 ms: Mark-sweep 1022.8 (1404.2) -> 1022.8 (1404.2) MB, 2240.4 / 0.0 ms [allocation failure] [GC in old space requested].
  444235 ms: Mark-sweep 1022.8 (1404.2) -> 1022.8 (1404.2) MB, 2013.8 / 0.0 ms [allocation failure] [GC in old space requested].
  446027 ms: Mark-sweep 1022.8 (1404.2) -> 1029.8 (1403.2) MB, 1791.0 / 0.0 ms [last resort gc].
  447799 ms: Mark-sweep 1029.8 (1403.2) -> 1036.7 (1403.2) MB, 1771.9 / 0.0 ms [last resort gc].


<--- JS stacktrace --->

==== JS stack trace =========================================

Security context: 0x1a1148dcfb51 <JS Object>
    1: _clearMemoizedQueries [/Users/avidor/Development/code/instructor/student_code/javascript-rock-dodger-bootcamp-prep-000/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:~252] [pc=0x3b5b6c5d8454] (this=0x3a1962f5a381 <an EventTargetImpl with map 0x20accce543d9>)
    2: _clearMemoizedQueries [/Users/avidor/Development/code/instructor/student_code/javascript-rock-dodger-bootcamp-prep-0...

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
 1: node::Abort() [/usr/local/bin/node]
 2: node::FatalException(v8::Isolate*, v8::Local<v8::Value>, v8::Local<v8::Message>) [/usr/local/bin/node]
 3: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [/usr/local/bin/node]
 4: v8::internal::Factory::NewByteArray(int, v8::internal::PretenureFlag) [/usr/local/bin/node]
 5: v8::internal::Factory::NewCode(v8::internal::CodeDesc const&, unsigned int, v8::internal::Handle<v8::internal::Object>, bool, bool, int, bool) [/usr/local/bin/node]
 6: v8::internal::PropertyAccessCompiler::GetCodeWithFlags(unsigned int, char const*) [/usr/local/bin/node]
 7: v8::internal::NamedLoadHandlerCompiler::CompileLoadConstant(v8::internal::Handle<v8::internal::Name>, int) [/usr/local/bin/node]
 8: v8::internal::LoadIC::CompileHandler(v8::internal::LookupIterator*, v8::internal::Handle<v8::internal::Object>, v8::internal::CacheHolderFlag) [/usr/local/bin/node]
 9: v8::internal::IC::ComputeHandler(v8::internal::LookupIterator*, v8::internal::Handle<v8::internal::Object>) [/usr/local/bin/node]
10: v8::internal::LoadIC::UpdateCaches(v8::internal::LookupIterator*) [/usr/local/bin/node]
11: v8::internal::LoadIC::Load(v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Name>) [/usr/local/bin/node]
12: v8::internal::Runtime_LoadIC_Miss(int, v8::internal::Object**, v8::internal::Isolate*) [/usr/local/bin/node]
13: 0x3b5b6bf092a7
/Users/avidor/.rvm/gems/ruby-2.3.0/gems/learn-test-2.4.0/lib/learn_test/strategies/mocha.rb:49:in `results': undefined method `[]' for nil:NilClass (NoMethodError)
    from /Users/avidor/.rvm/gems/ruby-2.3.0/gems/learn-test-2.4.0/lib/learn_test/runner.rb:68:in `push_results'
    from /Users/avidor/.rvm/gems/ruby-2.3.0/gems/learn-test-2.4.0/lib/learn_test/runner.rb:19:in `run'
    from /Users/avidor/.rvm/gems/ruby-2.3.0/gems/learn-test-2.4.0/bin/learn-test:60:in `<top (required)>'
    from /Users/avidor/.rvm/gems/ruby-2.3.0/bin/learn-test:22:in `load'
    from /Users/avidor/.rvm/gems/ruby-2.3.0/bin/learn-test:22:in `<main>'
    from /Users/avidor/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:in `eval'
    from /Users/avidor/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:in `<main>'

This is a problem as 6.5.0 is the node version that the Learn IDE is currently on.

It looks like this error is coming from the test 'removes the "keydown" event listener'.

`learn test` doesn't accurately test checkCollision(rock) for the case of the rock centered over the dodger.

To improve your test, I suggest changing your "180px" test case in the checkCollision(rock) function.

If the student's program fails to check for case 2 in the instructions ((rockLeftEdge >= dodgerLeftEdge) && (rockRightEdge <= dodgerRightEdge)), dropping a rock with a left edge of between 181 and 199, inclusive, will pass the tests and the rock will pass right through the dodger in the game.

To reproduce:

  1. Remove || ((rockLeftEdge >= dodgerLeftEdge) && (rockRightEdge <= dodgerRightEdge)) from your checkCollision(rock) function.
  2. Run the test and play the game.
    Result: The tests will pass and the rock will pass right through the dodger in the game.

I realized this because I originally misread the instructions and thought the rock had a width of 40, the same as the dodger. So case 2 in the instructions was redundant and I left it out. The game worked and I passed all the tests.

Before submitting, I went back through the original instructions - which I had been deleting as I implemented pieces - and realized that the rock was only supposed to be 20 wide. I changed that and observed the behavior above (I still passed the tests and the game doesn't stop).

If you change your "180px" check to something between 181-199, you'll catch the cases where the rock is wholly over the dodger with neither edge outside of the dodger's edges.

Directions should be more explicit that jQuery will not be used

@gj
The placement of this lab in the Bootcamp Prep track implies that jQuery should be used in this lab (since it comes after the jQuery section). I have had several students tell me that they were confused to find that jQuery could not be used to complete this lab. For the Bootcamp Prep course, I think it would help to explicitly state that jQuery will not be used.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.