Created
December 18, 2013 08:16
-
-
Save sufianrhazi/8018919 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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