Skip to content

Instantly share code, notes, and snippets.

@sufianrhazi
Created December 18, 2013 08:16
Show Gist options
  • Save sufianrhazi/8018919 to your computer and use it in GitHub Desktop.
Save sufianrhazi/8018919 to your computer and use it in GitHub Desktop.
//
// BEGIN your existing code, annotated
//
// You have a common data structure representing *all* power ups
function PowerUp(type, colour, x, y){
this.type = type;
this.x = x;
this.y = y;
// ...
}
// You really only have four types of powerups
function createLevel() {
// ...
if (substring[col] =='H'){
p = new PowerUp("health","GREEN", x, y);
powerups.push(p);
}
if (substring[col] =='A'){
p = new PowerUp("armour","BLUE", x, y);
powerups.push(p);
}
if (substring[col] =='N'){
p = new PowerUp("energy","PURPLE", x, y);
powerups.push(p);
}
if (substring[col] =='B'){
p = new PowerUp("buff","ORANGE", x, y);
powerups.push(p);
}
// ...
}
// Each of these four types of powerups has custom handling when the action happens
function checkCollision() {
// ...
if (checkCollideWithPlayer(powerup) /* && ... */) {
// ...
switch(powerup.type){
case "health":
player.life += 20;
// ...
break;
case "armour":
player.armour += 20;
// ...
break;
case "energy":
player.energy += 20;
// ...
break;
case "buff":
player.buffed = true;
// ...
debuffRE = setInterval(function(){player.buffed = false;
clearInterval(debuffRe)}, 15000);
break;
}
powerups[p] = powerup;
}
// ...
}
//
// END your existing code, annotated
//
// All of this stuff is coupled together, mostly because each of the things
// that define what a power up is and how it works are spread out across
// different parts of your code.
//
// Instead, let's define the _interface_ of a powerup to have an "effect" on a "target"
// Given a powerup "p" and a target "t":
// - p.applyTo(t) will apply the effect of the powerup to the target
//
// This interface satisfies a sort of "contract" (or guarantee) that any power
// up has: it affects other things. So code that deals with powerups can just
// assume that it has the capacity to affect things.
//
// Now we can create different classes (object factories, data structures,
// whatever you want to call them...) that all satisfy the same powerup
// interface:
function Health(x, y) {
this.colour = 'GREEN';
this.x = x;
this.y = y;
}
Health.prototype = {
applyTo: function (target) {
target.addLife(20);
}
};
function Armour(x, y) {
this.colour = 'BLUE';
this.x = x;
this.y = y;
}
Armour.prototype = {
applyTo: function (target) {
target.addArmour(20);
}
};
function Energy(x, y) {
this.colour = 'PURPLE';
this.x = x;
this.y = y;
}
Energy.prototype = {
applyTo: function (target) {
target.addEnergy(20);
}
};
function Buff(x, y) {
this.colour = 'ORANGE';
this.x = x;
this.y = y;
}
Buff.prototype = {
applyTo: function (target) {
target.setBuffed(true);
setTimeout(function(){
target.setBuffed(false);
}, 15000);
}
};
// Now, instead of calling to create a powerup with a specific type,
// p = new PowerUp('health', 'BLUE', x, y);
// we can simply create a new object of the specific type.
// p = new Health(x, y);
//
// This doesn't seem like that much of a difference, but the real effect is now
// when you have a collision of a powerup with a player, you can simply have
// the powerup apply to the player:
//
// if (checkCollideWithPlayer(powerup)) {
// powerup.applyTo(player);
// }
//
// This opens up all sorts of other convenient things: what if we wanted to
// allow enemies to use powerups? We could simply write:
//
// $.each(enemies, function (_, enemy) {
// if (checkCollideWith(powerup, enemy)) {
// powerup.applyTo(enemy);
// }
// });
//
//
// Taking this to the extreme, you can extract other "interfaces" and
// "contracts" from your existing behavior, and have objects talk to other
// objects that satisfy the same interfaces, rather than having logic that
// checks for all specific cases when they are needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment