Skip to content

Commit

Permalink
Game is now independent of GameState
Browse files Browse the repository at this point in the history
  • Loading branch information
commana committed Jan 15, 2012
1 parent 61f4be6 commit 769eaf5
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 132 deletions.
12 changes: 2 additions & 10 deletions src/Game.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,13 @@
* limitations under the License.
*/

var Game = function(blobs, bounds, collision, state) {
var Game = function(blobs, bounds, collision) {
this.blobs = blobs;
this.bounds = bounds;
this.collision = collision;
this.state = state;
};

Game.prototype.advance = function(input, gametime) {
if (!this.state.isRunning()) {
return this;
}

var blobs = input.process(this.blobs);

var movedBlobs = [];
Expand All @@ -38,9 +33,6 @@ Game.prototype.advance = function(input, gametime) {
return b.mass() > 0;
});

return new Game(blobsAfterCollisions, this.bounds, this.collision, this.state.transition(blobsAfterCollisions));
return new Game(blobsAfterCollisions, this.bounds, this.collision);
}

Game.prototype.status = function() {
return this.state.status();
}
62 changes: 4 additions & 58 deletions src/GameState.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,65 +14,11 @@
* limitations under the License.
*/

function GameState() {};

GameState.prototype.transition = function(blobs) {
if (blobs.length === 0) {
return this.lose();
}
var playerBlobs = blobs.filter(function(b) {
return b.player > 0;
});
if (playerBlobs.length === 0) {
return this.lose();
}
// For now, we assume only one player...
var playerBlob = playerBlobs.shift();
if (!this.isWinningPossible(playerBlob, blobs)) {
return this.lose();
}

var biggestBlob = blobs.reduce(function(a, b) {
return a.mass() > b.mass() ? a : b;
});
var totalMass = blobs.mass();

if (biggestBlob.mass() > totalMass/2) {
if (biggestBlob instanceof Object(PlayerBlob)) {
return this.win();
} else {
return this.lose();
}
}

return this;
}

GameState.prototype.isWinningPossible = function(player, blobs) {
var biggerBlobs = blobs.filter(function(b) {
return b !== player && player.mass() < b.mass();
});
var smallerBlobs = blobs.filter(function(b) {
return b !== player && player.mass() >= b.mass();
});
var smallerMass = smallerBlobs.mass();
return biggerBlobs.length === 0 || biggerBlobs.some(function(b) {
return smallerMass + player.mass() > b.mass();
});
}

GameState.prototype.lose = function() {
return new LosingGameState();
function GameState(game) {
this.game = game;
}

GameState.prototype.win = function() {
return new WinningGameState();
}
GameState.prototype.handle = function(input, gametime) {}

GameState.prototype.status = function() {
return "Running...";
}
GameState.prototype.status = function() {}

GameState.prototype.isRunning = function() {
return true;
}
9 changes: 3 additions & 6 deletions src/LosingGameState.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,17 @@
* limitations under the License.
*/

var LosingGameState = function() {
GameState.call(this);
var LosingGameState = function(game) {
GameState.call(this, game);
}

LosingGameState.prototype = new GameState();

LosingGameState.prototype.transition = function(blobs) {
LosingGameState.prototype.handle = function(input, gametime) {
return this;
}

LosingGameState.prototype.status = function() {
return "Lost!";
}

LosingGameState.prototype.isRunning = function() {
return false;
}
73 changes: 73 additions & 0 deletions src/RunningGameState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2011, 2012 Christoph Thelen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* 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.
*/

var RunningGameState = function(game) {
GameState.call(this, game);
}

RunningGameState.prototype = new GameState();

RunningGameState.prototype.handle = function(input, gametime) {
var blobs = this.game.blobs;

if (blobs.length === 0) {
return new LosingGameState();
}
var playerBlobs = blobs.filter(function(b) {
return b.player > 0;
});
if (playerBlobs.length === 0) {
return new LosingGameState(this.game);
}
// For now, we assume only one player...
var playerBlob = playerBlobs.shift();
if (!this.isWinningPossible(playerBlob, blobs)) {
return new LosingGameState(this.game);
}

var biggestBlob = blobs.reduce(function(a, b) {
return a.mass() > b.mass() ? a : b;
});
var totalMass = blobs.mass();

if (biggestBlob.mass() > totalMass/2) {
if (biggestBlob instanceof Object(PlayerBlob)) {
return new WinningGameState(this.game);
} else {
return new LosingGameState(this.game);
}
}

return new RunningGameState(this.game.advance(input, gametime));
}

RunningGameState.prototype.isWinningPossible = function(player, blobs) {
var biggerBlobs = blobs.filter(function(b) {
return b !== player && player.mass() < b.mass();
});
var smallerBlobs = blobs.filter(function(b) {
return b !== player && player.mass() >= b.mass();
});
var smallerMass = smallerBlobs.mass();
return biggerBlobs.length === 0 || biggerBlobs.some(function(b) {
return smallerMass + player.mass() > b.mass();
});
}

RunningGameState.prototype.status = function() {
return "Running...";
}

9 changes: 3 additions & 6 deletions src/WinningGameState.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,17 @@
* limitations under the License.
*/

var WinningGameState = function() {
GameState.call(this);
var WinningGameState = function(game) {
GameState.call(this, game);
}

WinningGameState.prototype = new GameState();

WinningGameState.prototype.transition = function(blobs) {
WinningGameState.prototype.handle = function(input, gametime) {
return this;
}

WinningGameState.prototype.status = function() {
return "Won!";
}

WinningGameState.prototype.isRunning = function() {
return false;
}
8 changes: 4 additions & 4 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ exports.gameLoop = function(canvas) {
new Blob(new Position(540, 200), new Velocity(5, 0), 40)
];
var bounds = new BouncyBounds(0, 0, 640, 480);
var world = new Game(blobs, bounds, new MassTransformationCollision(), new GameState());
var world = new RunningGameState(new Game(blobs, bounds, new MassTransformationCollision()));

return setInterval(function() {
var input = new InputHandler(InputQueue.slice());
InputQueue = [];
world = world.advance(input, gametime);
world = world.handle(input, gametime);
draw(world, canvas);
}, 1000/fps);
}
Expand All @@ -56,8 +56,8 @@ function draw(world, canvas) {
ctx.textBaseline = "top";
ctx.fillText(world.status(), 0, 0);

for (var i = 0; i < world.blobs.length; i++) {
var blob = world.blobs[i];
for (var i = 0; i < world.game.blobs.length; i++) {
var blob = world.game.blobs[i];

ctx.beginPath();
ctx.arc(blob.position.x, blob.position.y, blob.radius, 0, Math.PI*2, false);
Expand Down
33 changes: 3 additions & 30 deletions test/GameTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ GameTest.prototype.testShouldReturnNewBlobs = function() {
var blob2 = new SpyBlob();

var spyCollision = new SpyCollision();
var oldWorld = new Game([blob1, blob2], null, spyCollision, new StubGameState);
var oldWorld = new Game([blob1, blob2], null, spyCollision);
var newWorld = oldWorld.advance(this.inputHandler);

assertEquals([blob1.state, blob2.state], newWorld.blobs);
Expand All @@ -37,7 +37,7 @@ GameTest.prototype.testShouldInitiateCollisionCheck = function() {
var blob2 = new Blob(P(), V(), 0);

var spyCollision = new SpyCollision();
var oldWorld = new Game([blob1, blob2], this.bounds, spyCollision, new StubGameState);
var oldWorld = new Game([blob1, blob2], this.bounds, spyCollision);
oldWorld.advance(this.inputHandler, new GameTime(1, 1));

assertTrue(spyCollision.called);
Expand All @@ -47,29 +47,12 @@ GameTest.prototype.testShouldRemoveMasslessBlobs = function() {
var blob1 = new Blob(P(), V(), 0);
var blob2 = new Blob(P(), V(), 0);

var oldWorld = new Game([blob1, blob2], this.bounds, new SpyCollision(), new StubGameState);
var oldWorld = new Game([blob1, blob2], this.bounds, new SpyCollision());
var newWorld = oldWorld.advance(this.inputHandler, new GameTime(1, 1));

assertEquals([], newWorld.blobs);
}

GameTest.prototype.testShouldTransitionState = function() {
var spyGameState = new SpyGameState();
var world = new Game([], this.bounds, new SpyCollision(), spyGameState);
world.advance(this.inputHandler, new GameTime(1, 1));

assertTrue(spyGameState.called);
}

GameTest.prototype.testShouldStopPlayingIfGameIsNotInRunningState = function() {
var spyCollision = new SpyCollision();
var stubGameState = new StubGameState(false);
var world = new Game([], this.bounds, spyCollision, stubGameState);
world.advance(this.inputHandler, new GameTime(1, 1));

assertFalse(spyCollision.called);
}

var SpyBlob = function() {
this.state = {};
}
Expand All @@ -88,13 +71,3 @@ SpyCollision.prototype.perform = function(blobs) {
return blobs;
}

var SpyGameState = function() {
this.called = false;
this.isRunning = function () { return true; }
this.transition = function (blobs) { this.called = true; return this; };
}

var StubGameState = function(running) {
this.isRunning = function () { return typeof running === "undefined" ? true : false; }
this.transition = function (blobs) { return this; }
}
Loading

0 comments on commit 769eaf5

Please sign in to comment.