Skip to content

Commit

Permalink
split into two files
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel-Hug committed Apr 13, 2017
1 parent ad9c744 commit df60e58
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 164 deletions.
1 change: 1 addition & 0 deletions index.html
Expand Up @@ -35,6 +35,7 @@

<!-- JS -->
<script src="js/helpers.js"></script>
<script src="js/maze-engine.js"></script>
<script src="js/app.js"></script>

</body>
Expand Down
187 changes: 23 additions & 164 deletions js/app.js
@@ -1,193 +1,52 @@
// Get element position:
function getOffset(el) {
return {
top: el.offsetTop,
left: el.offsetLeft,
bottom: el.offsetTop + el.offsetHeight,
right: el.offsetLeft + el.offsetWidth
};
}


// Game constructor:
var Game = function(options) {
// options will override the following defaults if set
var offset = extend(options, extend({
// Initial game state defaults
score: 0,
finished: false,
player: {},
step: 2
}, this));

// Setup interval. Delay controlls tickrate:
this.frameRefresher = createInterval(function() {
this.movTick();
}, 10, this);

this.frameRefresher.start();
};


// Checks if an element is inside its viewport:
Game.prototype.insideGameArea = function(offset) {
return !(
offset.left < 0 ||
offset.top < 0 ||
offset.right > this.viewport.width ||
offset.bottom > this.viewport.height
);
};

// Checks if rectangle a overlaps rectangle b
Game.prototype.overlaps = function(a, b) {
// no horizontal overlap
if (a.left >= b.right || b.left >= a.right) return false;

// no vertical overlap
if (a.top >= b.bottom || b.top >= a.bottom) return false;

return true;
};

// Checks if rectangle a touches rectangle b
Game.prototype.touches = function(a, b) {
// has horizontal gap
if (a.left > b.right || b.left > a.right) return false;

// has vertical gap
if (a.top > b.bottom || b.top > a.bottom) return false;

return true;
};

Game.prototype.getNewPlayerPosition = (function() {
// Which keys are pressed:
var keys = {
left: false,
right: false,
up: false,
down: false
};

var keyCodeMap = {
37: 'left',
38: 'up',
39: 'right',
40: 'down'
};

// Keydown listener
document.body.addEventListener('keydown', function(event) {
Object.keys(keyCodeMap).forEach(function(keyCode) {
if (event.keyCode === +keyCode) keys[keyCodeMap[keyCode]] = true;
});
});

// Keyup listener
document.body.addEventListener('keyup', function(e) {
Object.keys(keyCodeMap).forEach(function(keyCode) {
if (event.keyCode === +keyCode) keys[keyCodeMap[keyCode]] = false;
});
});

return function() {
var moved = false;
var offset = extend(this.player.pos, {});

if (!(keys.up && keys.down)) {
if (keys.up) { offset.top -= this.step; offset.bottom -= this.step; moved = true; }
else if (keys.down) { offset.top += this.step; offset.bottom += this.step; moved = true; }
}
if (!(keys.left && keys.right)) {
if (keys.left) { offset.left -= this.step; offset.right -= this.step; moved = true; }
else if (keys.right) { offset.left += this.step; offset.right += this.step; moved = true; }
}
return moved ? offset : null;
};
})();

Game.prototype.isValidPlayerPosition = function(sidePositions) {
// Ensure move is inside the game area:
if (!this.insideGameArea(sidePositions)) return false;

// Ensure we're not entering a solid:
if ([].some.call(this.solids, function(solidPos, i) {
return this.overlaps(sidePositions, solidPos);
}, this)) return false;

return true;
};

Game.prototype.movePlayer = function(sidePositions) {
var ps = this.player.el.style;
ps.left = sidePositions.left + 'px';
ps.top = sidePositions.top + 'px';
this.player.pos = sidePositions;
};

// Move one pixel for each direction and check if move is valid.
Game.prototype.movTick = function() {
var t = this;

// ensure player position changed
var newPos = this.getNewPlayerPosition();
if (!newPos) return;

// ensure valid player position
if (!this.isValidPlayerPosition(newPos)) return;

// Touchable collisions:
Object.keys(this.touchables).forEach(function(name) {
var touchable = this.touchables[name];
var positions = touchable.positions;
for (var i = 0; i < positions.length; i++) {
if (this.touches(newPos, positions[i])) {
touchable.onTouch.call(this, positions[i], i);
}
}
}, t);

this.movePlayer(newPos);
};


// Create a game:
var game = (function() {
// Viewport element & style:
var viewportEl = qs(".game");
var cs = getComputedStyle(viewportEl);

// Grab necessary game elements:
var solidEls = qsa('.solid', viewportEl);
var scoreEls = qsa('.score', viewportEl);
var playerEl = qs(".player", viewportEl);

// Use array to enable easy removal with splice
var solidEls = [].slice.call(qsa('.solid', viewportEl));
var scoreEls = [].slice.call(qsa('.score', viewportEl));
var coinEls = [].slice.call(qsa('.coin', viewportEl));

var solids = [].map.call(solidEls, getOffset);

var finishI = [].indexOf.call(solidEls, qs(".finish", viewportEl));

// Get element position:
function getOffset(el) {
return {
top: el.offsetTop,
left: el.offsetLeft,
bottom: el.offsetTop + el.offsetHeight,
right: el.offsetLeft + el.offsetWidth
};
}

// Create game passing initial state
return new Game({
viewport: {
width: parseInt(cs.width, 10),
height: parseInt(cs.height, 10)
},

// Player and their position:
// Player position and move function:
player: {
el: playerEl,
pos: getOffset(playerEl)
pos: getOffset(playerEl),
move: function(sidePositions) {
var ps = playerEl.style;
ps.left = sidePositions.left + 'px';
ps.top = sidePositions.top + 'px';
this.player.pos = sidePositions;
}
},

// Positions of solids:
solids: solids,

touchables: {
coin: {
positions: [].map.call(coinEls, getOffset),
positions: coinEls.map(getOffset),
onTouch: function(pos, i) {
this.setScore('add', 50);
this.touchables.coin.positions.splice(i, 1);
Expand All @@ -209,7 +68,7 @@ var game = (function() {
if (method === 'add') this.score += amount;
else this.score -= amount;

[].forEach.call(scoreEls, function(scoreEl) {
scoreEls.forEach(function(scoreEl) {
scoreEl.textContent = this.score;
}, this);
}
Expand Down
134 changes: 134 additions & 0 deletions js/maze-engine.js
@@ -0,0 +1,134 @@
// Game constructor:
var Game = function(options) {
// options will override the following defaults if set
var offset = extend(options, extend({
// Initial game state defaults
score: 0,
finished: false,
player: {},
step: 2
}, this));

// Setup interval. Delay controlls tickrate:
this.frameRefresher = createInterval(function() {
this.movTick();
}, 10, this);

this.frameRefresher.start();
};


// Checks if an element is inside its viewport:
Game.prototype.insideGameArea = function(offset) {
return !(
offset.left < 0 ||
offset.top < 0 ||
offset.right > this.viewport.width ||
offset.bottom > this.viewport.height
);
};

// Checks if rectangle a overlaps rectangle b
Game.prototype.overlaps = function(a, b) {
// no horizontal overlap
if (a.left >= b.right || b.left >= a.right) return false;

// no vertical overlap
if (a.top >= b.bottom || b.top >= a.bottom) return false;

return true;
};

// Checks if rectangle a touches rectangle b
Game.prototype.touches = function(a, b) {
// has horizontal gap
if (a.left > b.right || b.left > a.right) return false;

// has vertical gap
if (a.top > b.bottom || b.top > a.bottom) return false;

return true;
};

Game.prototype.getNewPlayerPosition = (function() {
// Which keys are pressed:
var keys = {
left: false,
right: false,
up: false,
down: false
};

var keyCodeMap = {
37: 'left',
38: 'up',
39: 'right',
40: 'down'
};

// Keydown listener
document.body.addEventListener('keydown', function(event) {
Object.keys(keyCodeMap).forEach(function(keyCode) {
if (event.keyCode === +keyCode) keys[keyCodeMap[keyCode]] = true;
});
});

// Keyup listener
document.body.addEventListener('keyup', function(e) {
Object.keys(keyCodeMap).forEach(function(keyCode) {
if (event.keyCode === +keyCode) keys[keyCodeMap[keyCode]] = false;
});
});

return function() {
var moved = false;
var offset = extend(this.player.pos, {});

if (!(keys.up && keys.down)) {
if (keys.up) { offset.top -= this.step; offset.bottom -= this.step; moved = true; }
else if (keys.down) { offset.top += this.step; offset.bottom += this.step; moved = true; }
}
if (!(keys.left && keys.right)) {
if (keys.left) { offset.left -= this.step; offset.right -= this.step; moved = true; }
else if (keys.right) { offset.left += this.step; offset.right += this.step; moved = true; }
}
return moved ? offset : null;
};
})();

Game.prototype.isValidPlayerPosition = function(sidePositions) {
// Ensure move is inside the game area:
if (!this.insideGameArea(sidePositions)) return false;

// Ensure we're not entering a solid:
if ([].some.call(this.solids, function(solidPos, i) {
return this.overlaps(sidePositions, solidPos);
}, this)) return false;

return true;
};

// Move one pixel for each direction and check if move is valid.
Game.prototype.movTick = function() {
var t = this;

// ensure player position changed
var newPos = this.getNewPlayerPosition();
if (!newPos) return;

// ensure valid player position
if (!this.isValidPlayerPosition(newPos)) return;

// Touchable collisions:
Object.keys(this.touchables).forEach(function(name) {
var touchable = this.touchables[name];
var positions = touchable.positions;
for (var i = 0; i < positions.length; i++) {
if (this.touches(newPos, positions[i])) {
touchable.onTouch.call(this, positions[i], i);
}
}
}, t);

this.player.move.call(this, newPos);
};

0 comments on commit df60e58

Please sign in to comment.