diff --git a/.eslintignore b/.eslintignore index c3651b8..c6a4e07 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,5 @@ dist/ node_modules/ lib/jquery/ +lib/threadify coverage/ \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index ccf2ddf..37b9414 100644 --- a/.eslintrc +++ b/.eslintrc @@ -8,6 +8,7 @@ "no-trailing-spaces": ["error", { "skipBlankLines": true }], "padded-blocks": ["error", "always"], "no-unused-vars": 0, + "new-cap": 0, "no-console": "error", "no-only-tests/no-only-tests": 2 }, diff --git a/lib/canvas/canvas.js b/lib/canvas/canvas.js index dea3289..1ee8d53 100644 --- a/lib/canvas/canvas.js +++ b/lib/canvas/canvas.js @@ -220,63 +220,6 @@ class Canvas { } - /** - * checks collision between obstacles and bird object - */ - collisionDetection () { - - let birdShape = this.bird.shape; - let obstacles = this.obstacles; - let birdWidth = birdShape.x + birdShape.width; - - const _hitAction = () => { - - if (typeof this.onClear === 'function') { - - this.onClear(); - - } - - }; - - obstacles.forEach(obstacle => { - - let obstacleShape = obstacle.shape; - let obstacleHeight = obstacleShape.y + obstacleShape.height; - let obstacleWidth = obstacleShape.x + obstacleShape.width; - - if ( - (birdShape.x >= obstacleShape.x && birdWidth <= obstacleWidth) || - (birdWidth >= obstacleShape.x && birdWidth <= obstacleWidth) || - (birdShape.x === obstacleWidth) || - (birdShape.x === obstacleShape.x) || - (birdWidth === obstacleWidth) - ) { - - if (obstacleShape.y === 0) { // check upper obstacle - - if (birdShape.y <= obstacleHeight) { - - _hitAction(); - - } - - } else { // check lower obstacle - - if (birdShape.y + birdShape.height >= obstacleShape.y) { - - _hitAction(); - - } - - } - - } - - }); - - } - /** * completely deletes canvas and all its shapes */ diff --git a/lib/collision-detection/collisionDetection.js b/lib/collision-detection/collisionDetection.js new file mode 100644 index 0000000..b224a8c --- /dev/null +++ b/lib/collision-detection/collisionDetection.js @@ -0,0 +1,87 @@ + +/* global threadify */ +class CollisionDetection { + + /** + * @param {Bird} options.bird + * @param {Array} options.obstacle + */ + static collisionDetection ({ bird, obstacles }) { + + const thread = this; + + let birdWidth = bird.x + bird.width; + + obstacles.forEach(obstacle => { + + let obstacleHeight = obstacle.y + obstacle.height; + let obstacleWidth = obstacle.x + obstacle.width; + + if ( + (bird.x >= obstacle.x && birdWidth <= obstacleWidth) || + (birdWidth >= obstacle.x && birdWidth <= obstacleWidth) || + (bird.x === obstacleWidth) || + (bird.x === obstacle.x) || + (birdWidth === obstacleWidth) + ) { + + if (obstacle.y === 0) { // check upper obstacle + + if (bird.y <= obstacleHeight) { + + thread.return(true); + + } + + } else { // check lower obstacle + + if (bird.y + bird.height >= obstacle.y) { + + thread.return(true); + + } + + } + + } + + }); + + thread.return(false); + + } + + static wrapped (canvas) { + + // cleanup objects for later use + const bird = { + x: canvas.bird.shape.x, + y: canvas.bird.shape.y, + width: canvas.bird.shape.width, + height: canvas.bird.shape.height + }; + + const obstacles = canvas.obstacles.map(o => { + + return { + x: o.shape.x, + y: o.shape.y, + width: o.shape.width, + height: o.shape.height + }; + + }); + + const wrappedFn = threadify(this.collisionDetection); + + return { + collisionDetection: wrappedFn, + collideCheckObject: { + bird, + obstacles + } + }; + + } + +} diff --git a/lib/main/main.js b/lib/main/main.js index efda47d..a2005f7 100644 --- a/lib/main/main.js +++ b/lib/main/main.js @@ -1,4 +1,4 @@ -/* global Canvas, Footer, KeyboardHandler */ +/* global Canvas, Footer, KeyboardHandler, CollisionDetection */ let mrflap, canvas, bird; function appendFooter () { @@ -93,7 +93,24 @@ function spawnObstacles () { setInterval(() => { canvas.moveObstacles(); - canvas.collisionDetection(); + + // execute collision detection inside web worker + const { + collisionDetection, + collideCheckObject + } = CollisionDetection.wrapped(canvas); + + const job = collisionDetection(collideCheckObject); + + job.done = (isCollided) => { + + if (isCollided) { + + canvas.onClear(); + + } + + }; }, 1000 / 30); diff --git a/lib/threadify/threadify.min.js b/lib/threadify/threadify.min.js new file mode 100755 index 0000000..54b1a21 --- /dev/null +++ b/lib/threadify/threadify.min.js @@ -0,0 +1 @@ +!(function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).threadify=e()}}(function(){return function i(o,s,f){function u(r,e){if(!s[r]){if(!o[r]){var t="function"==typeof require&&require;if(!e&&t)return t(r,!0);if(l)return l(r,!0);var n=new Error("Cannot find module '"+r+"'");throw n.code="MODULE_NOT_FOUND",n}var a=s[r]={exports:{}};o[r][0].call(a.exports,function(e){return u(o[r][1][e]||e)},a,a.exports,i,o,s,f)}return s[r].exports}for(var l="function"==typeof require&&require,e=0;e'); + + }; + + beforeEach(function () { + + document.body.innerHTML = __html__['test.html']; + _initPlayground(); + mrflapDiv = $('.mrflap-playground'); + + }); + describe('#collisionDetection', function () { + + let canvas, bird; + + beforeEach(function () { + + canvas = new Canvas({ + mrflapDiv: mrflapDiv + }); + + bird = canvas.drawBird(); + + }); + + it('should hit lower obstacle', function () { + + // given + canvas.drawObstacle({ + heightBottom: 50 + }); + + // when + for (let i = 0; i < 110; i++) { + + canvas.moveObstacles(); + + } + + // when + const { + collisionDetection, + collideCheckObject + } = CollisionDetection.wrapped(canvas); + + const job = collisionDetection(collideCheckObject); + + job.done = (isCollided) => { + + // then + expect(isCollided).to.be.true; + + }; + + }); + + it('should hit upper obstacle', function () { + + // given + canvas.drawObstacle({ + heightBottom: 50 + }); + + bird.moveUp({ + speed: 100 + }); + + // when + for (let i = 0; i < 110; i++) { + + canvas.moveObstacles(); + + } + + // when + const { + collisionDetection, + collideCheckObject + } = CollisionDetection.wrapped(canvas); + + const job = collisionDetection(collideCheckObject); + + job.done = (isCollided) => { + + // then + expect(isCollided).to.be.true; + + }; + + }); + + }); + +});