Last active
December 14, 2015 02:59
-
-
Save AdmiralPotato/5017984 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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=UTF-8"> | |
<title>Developer Defense</title> | |
<style> | |
.chair{ | |
position: fixed; | |
height: 32px; | |
width: 32px; | |
margin-top: -16px; | |
margin-left: -16px; | |
border-radius: 10px; | |
border: 2px solid rgba(255,255,255,0.25); | |
} | |
.chair:hover{ | |
background-color: rgba(255,255,255,0.25); | |
border-color: rgba(255,255,255,0.5); | |
} | |
</style> | |
</head> | |
<body> | |
<script type="text/javascript" src="https://raw.github.com/AdmiralPotato/npos3d/master/src/core.js"></script> | |
<script type="text/javascript" src="https://raw.github.com/AdmiralPotato/npos3d/master/src/font.js"></script> | |
<script type="text/javascript" src="https://raw.github.com/AdmiralPotato/npos3d/master/src/geom.circle.js"></script> | |
<script type="text/javascript" src="https://raw.github.com/AdmiralPotato/npos3d/master/src/utils.color.js"></script> | |
<script type="text/javascript" src="https://raw.github.com/AdmiralPotato/npos3d/master/src/fx.explosion.js"></script> | |
<script type="text/javascript" src="https://raw.github.com/AdmiralPotato/npos3d/master/src/fx.tween.js"></script> | |
<script type="text/javascript" src="https://raw.github.com/AdmiralPotato/npos3d/master/src/layout.js"></script> | |
<script> | |
var n = NPos3d; | |
var s = new n.Scene({ | |
lineWidth: 1 | |
}); | |
var shapes = {"bug":{"points":[[-0.2,0.1,0.4],[-0.2,-0.1,0.4],[0.4,0.5,0.2],[0.5,0.4,0.2],[0.7,0.6,0],[-0.4,0.1,0.3],[-0.4,0.5,0.2],[-0.5,0.4,0.2],[-0.7,0.6,0],[-0.4,-0.5,0.2],[-0.4,-0.1,0.3],[0.1,0.2,0.3],[0.7,-0.6,0],[0.5,-0.4,0.2],[-0.1,-0.2,0.3],[-0.1,0.2,0.3],[0.4,-0.5,0.2],[-0.5,-0.4,0.2],[-0.7,-0.6,0],[0.1,-0.2,0.3],[0.2,-0.1,0.4],[0.2,0.1,0.4],[0.4,-0.1,0.3],[0.4,0.1,0.3],[0.5,-0.2,0.3],[0.5,0.2,0.3],[0.7,0.1,0.3],[0.7,-0.1,0.3]],"lines":[[0,15],[0,5],[1,10],[1,14],[2,3],[2,4],[2,11],[3,4],[3,23],[5,10],[5,7],[5,15],[6,8],[6,7],[6,15],[7,8],[9,18],[9,14],[9,17],[10,17],[10,14],[11,21],[11,23],[11,15],[12,13],[12,16],[13,22],[13,16],[14,19],[16,19],[17,18],[19,22],[19,20],[20,22],[21,23],[22,27],[22,23],[22,24],[23,25],[23,26],[24,27],[25,26]],"scaleData":true,"centerData":true},"codebase":{"points":[[-0.866025,1.5,0],[0,2,0],[0.866025,1.5,0],[0.866025,0.5,0],[-0.866025,1.5,1],[0,2,1],[0.866025,1.5,1],[0.866025,0.5,1],[0.866025,-1.5,0],[0,0,0],[-0.866025,0.5,2],[1.732051,0,0],[1.732051,-1,0],[-1.732051,0,2],[0,0,1],[-1.732051,-1,2],[-0.866026,-1.5,0],[-1.732051,-1,0],[-1.732051,0,0],[-0.866025,0.5,0],[-0.866026,-1.5,2],[0,-1,0],[0,0,2],[0,-1,2],[0.866025,0.5,3],[0.866025,-1.5,3],[0,0,3],[1.732051,0,3],[1.732051,-1,3],[0,-1,3],[-0.866025,0.5,1]],"lines":[[0,1],[0,4],[0,19],[1,2],[1,5],[2,3],[2,6],[3,11],[3,24],[3,9],[4,30],[4,5],[5,6],[6,7],[7,14],[8,21],[8,25],[8,12],[9,19],[9,21],[9,26],[10,19],[10,13],[10,22],[11,27],[11,12],[12,28],[13,18],[13,15],[14,30],[15,20],[15,17],[16,20],[16,17],[16,21],[17,18],[18,19],[20,23],[21,29],[22,23],[24,26],[24,27],[25,29],[25,28],[26,29],[27,28]]},"developer":{"points":[[1.5,1.5,0],[1.5,-1.5,0],[2.5,1.5,0],[2.5,-1.5,0],[0.7,-0.7,3],[0,-1,3],[-0.7,-0.7,3],[-1,0,3],[-0.7,0.7,3],[0.7,0.7,3],[0,-0.7,3.7],[0,-0.7,2.3],[0,0.7,2.3],[0,1,3],[0,0.7,3.7],[-0.7,0,3.7],[0,0,4],[0.7,0,3.7],[1,0,3],[0.7,0,2.3],[-0.7,0,2.3],[1.5,0.5,0],[2.5,0.5,0],[1.5,0,0],[2.5,0,0],[1.5,-0.5,0],[2.5,-0.5,0],[1.5,1,0],[2.5,1,0],[1.5,-1,0],[2.5,-1,0],[2,1.5,0],[2,-1.5,0],[0,-1.4,1.2],[0,1,1.2],[0,1.4,1.2],[1.8,-1.2,0.2],[2.2,-1.2,0.2],[2.2,-0.8,0.2],[1.8,-0.8,0.2],[0.9,1.6,1.8],[0.9,1.2,1.8],[0.9,-1.2,0.5],[0.9,-1.6,0.5],[1.8,0.8,2],[2.2,0.8,2],[2.2,1.2,2],[1.8,1.2,2],[0,-1,1.2],[-0.6,0,1.2],[0,-0.7,1.7],[-0.4,0.7,0],[-0.6,0,0],[-0.4,-0.7,0],[0,0.7,1.7],[-0.5,0,1.7],[0,0,2],[0.5,0,1.7],[0.6,0,1.2],[0,-1,0],[0.4,-0.7,0],[0.4,0.7,0],[0,1,0],[0.6,0,0]],"lines":[[0,2],[0,1],[1,3],[2,3],[4,18],[4,5],[5,10],[5,6],[5,11],[6,7],[7,20],[7,15],[7,8],[8,13],[9,18],[9,13],[10,16],[11,56],[12,56],[12,13],[13,14],[14,16],[15,16],[16,17],[17,18],[18,19],[19,56],[20,56],[21,22],[23,24],[25,26],[27,28],[29,30],[31,32],[33,48],[33,43],[34,54],[34,41],[34,35],[34,62],[35,40],[36,37],[36,39],[36,43],[37,38],[38,39],[39,42],[40,47],[40,41],[41,44],[42,43],[42,48],[44,45],[44,47],[45,46],[46,47],[48,59],[48,50],[49,52],[49,55],[50,56],[51,62],[51,52],[52,53],[53,59],[54,56],[55,56],[56,57],[57,58],[58,63],[59,60],[60,63],[61,62],[61,63]]}}; | |
var commonFuncs = { | |
attack: function(target) { | |
var t = this; | |
target.health -= this.attackPower; | |
t.attackCountdown = t.attackFrequency; | |
new Lazor({ | |
a: t, | |
b: t.target | |
}); | |
//console.log(t.index, ': TARGET ATTACKED'); | |
if(target.health <= 0){ | |
gameController.playerScore += t.target.points; | |
gameController.playerMoney += t.target.cash; | |
t.target.die(); | |
t.target = false; | |
//console.log(t.index, ': TARGET DESTROYED'); | |
} | |
}, | |
getSquareDistangeToTarget: function(target) { | |
var t = this, | |
distanceSquared = n.Maths.getSquareVecLength2D(target.gPos[0] - t.gPos[0], target.gPos[1] - t.gPos[1]), | |
result = false; | |
t.target = false; | |
if(distanceSquared < t.attackRangeSquared){ | |
t.target = target; | |
result = true; | |
} | |
return result; | |
}, | |
getNewTarget: function(targetList){ | |
var t = this, | |
i, | |
len = targetList.length, | |
target; | |
for(i = 0; i < len; i += 1) { | |
target = targetList[i]; | |
t.getSquareDistangeToTarget(target); | |
if(t.target){ | |
//console.log(t.index, ': TARGET AQCUIRED'); | |
break; | |
} | |
} | |
} | |
}; | |
var bugList = []; | |
var bugSpawnPoint = new n.Ob3D({ | |
pos: [-320,0,0], | |
color: '#f00', | |
shape: new n.Geom.Circle({ | |
segments: 3, | |
radius: 20 | |
}) | |
}); | |
s.add(bugSpawnPoint); | |
var Bug = function(args) { | |
var t = this, type = 'Bug'; | |
if(t.type !== type){throw type + ' constructor requires the use of the `new` keyword.';} | |
args = args || {}; | |
n.blessWith3DBase(t,args); | |
t.pos = bugSpawnPoint.pos.slice(); | |
t.vel = [2,0,0]; | |
t.health = 10; | |
t.scaleAngle = 0; | |
t.healthLabel = new n.VText({ | |
string: t.health.toString(), | |
pos: [0,30,0], | |
fontSize: 16 | |
}); | |
t.add(t.healthLabel); | |
t.display = new n.Ob3D({ | |
shape: shapes.bug, | |
scale: [10,10,10], | |
color: 'rgba(255,0,0,0)' | |
}); | |
t.display.opacity = 0; | |
t.add(t.display); | |
new n.Fx.Tween({ //fade the enemy in from the spawn point | |
object: t.display, | |
properties: { | |
opacity: 1 | |
}, | |
onUpdate: function(tween){ | |
tween.o.color = 'rgba(255,0,0,'+(Math.round(tween.o.opacity * 100) * 0.01)+')'; | |
}, | |
frames: 10 | |
}); | |
s.add(t); | |
}; | |
Bug.prototype = { | |
type: 'Bug', | |
shape: {}, | |
points: 10, | |
cash: 5, | |
attackPower: 5, | |
update: function() { | |
var t = this, fac; | |
t.healthLabel.string = t.health.toString(); | |
t.scaleAngle += deg * 10; | |
t.display.rot[2] = cos(t.scaleAngle * 4.5) * deg * 10; | |
t.pos[0] += t.vel[0]; | |
t.pos[1] += t.vel[1]; | |
t.pos[2] += t.vel[2]; | |
fac = (Math.sin(t.scaleAngle) * 0.25) + 1; | |
t.display.scale[0] = t.display.scale[1] = t.display.scale[2] = fac * 20; | |
t.render(); | |
if(t.added !== true){ | |
//can only add bug to the list after it has been rendered for a frame | |
//so that its global position has been computed at least once! | |
bugList.push(this); | |
t.added = true; | |
} | |
}, | |
die: function() { | |
var t = this, index = bugList.indexOf(t); | |
bugList.splice(index, 1); | |
new n.Fx.Explosion({ | |
object: t.display, | |
scene: t.scene | |
}); | |
t.destroy(); | |
} | |
}; | |
var squareCentered = { | |
points: [ | |
[-1,-1,0], | |
[1,-1,0], | |
[1,1,0], | |
[-1,1,0] | |
], | |
lines: [ | |
[0,1], | |
[1,2], | |
[2,3], | |
[3,0], | |
] | |
}; | |
var squareLeft = { | |
points: [ | |
[0,-1,0], | |
[2,-1,0], | |
[2,1,0], | |
[0,1,0] | |
], | |
lines: squareCentered.lines | |
}; | |
var Lazor = function(args) { | |
var t = this, type = 'Lazor'; | |
if(t.type !== type){throw type + ' constructor requires the use of the `new` keyword.';} | |
args = args || {}; | |
n.blessWith3DBase(t,args); | |
t.life = t.maxLife; | |
t.lineWidth = 4; | |
if(!args.a || !args.b){throw type + ' requires arguments labeled both `a` and `b` to fire.';} | |
t.shape = { | |
points: [ | |
args.a.gPos.slice(), | |
args.b.gPos.slice(), | |
], | |
lines: [[0,1]] | |
}; | |
s.add(t); | |
} | |
Lazor.prototype = { | |
type: 'Lazor', | |
maxLife: 10, | |
update: function () { | |
var t = this; | |
t.color = 'rgba(0,255,255,'+(Math.round((t.life / t.maxLife) * 100) * 0.01)+')'; | |
t.render(); | |
t.life -= 1; | |
if(t.life <= 0){ | |
t.destroy(); | |
} | |
} | |
}; | |
var chairList = []; | |
var Chair = function(args) { | |
var t = this, type = 'Chair'; | |
if(t.type !== type){throw type + ' constructor requires the use of the `new` keyword.';} | |
args = args || {}; | |
n.blessWith3DBase(t, args); | |
t.element = document.createElement('a'); | |
t.element.chair = t; | |
t.element.className = 'chair'; | |
t.developer = false; | |
document.body.appendChild(t.element); | |
s.add(t); | |
}; | |
Chair.prototype = { | |
type: 'Chair', | |
shape: {}, | |
update: function(){ | |
var t = this; | |
t.render(); | |
t.element.style.left = Math.round(t.gPos[0] + s.cx).toString() + 'px'; | |
t.element.style.top = Math.round(t.gPos[1] + s.cy).toString() + 'px'; | |
}, | |
addDev: function (dev) { | |
this.developer = dev; | |
this.add(dev); | |
} | |
}; | |
var chairOffset = 64; | |
for (var i = 0; i < 9; i += 1) { | |
chairList.push(new Chair({pos: [-256 + (chairOffset * i),50,0]})); | |
chairList.push(new Chair({pos: [-256 + (chairOffset * i),-50,0]})); | |
}; | |
var chairClickHandler = function (event) { | |
var t = event.target, dev, gc = gameController; | |
if(t.className === 'chair') { | |
if(t.chair.developer){ | |
dev = t.chair.developer; | |
if(gc.playerMoney >= gc.developerUpgradePrice && dev.attackFrequency > 10){ | |
gc.playerMoney -= gc.developerUpgradePrice; | |
dev.levelUp(); | |
} | |
} else if(gc.playerMoney >= gc.developerPrice){ | |
gc.playerMoney -= gc.developerPrice; | |
t.chair.addDev(new Developer()); | |
} | |
} | |
}; | |
document.body.addEventListener('mousedown', chairClickHandler, false); | |
var developerList = []; | |
var Developer = function(args) { | |
var t = this, type = 'Developer'; | |
if(t.type !== type){throw type + ' constructor requires the use of the `new` keyword.';} | |
args = args || {}; | |
n.blessWith3DBase(t,args); | |
t.attackCountdown = 0; | |
//config for this object needs to be unique because scale and rot must be local | |
t.display = new n.Ob3D({ | |
shape: shapes.developer, | |
scale: [12,12,12], | |
rot: [0,0,pi] | |
}); | |
t.level = 1; | |
t.levelDisplay = new n.VText(t.displayLevelConfig); | |
t.radiusDisplay = new n.Ob3D(t.displayRadiusConfig); | |
t.bar = new n.Ob3D(t.displayBarConfig); | |
t.barFill = new n.Ob3D(t.displayBarFillConfig); | |
t.add(t.display); | |
t.add(t.levelDisplay); | |
t.add(t.radiusDisplay); | |
t.add(t.bar); | |
t.bar.add(t.barFill); | |
t.index = developerList.push(t); | |
t.target = false; | |
t.flip = t.flipDelay; | |
//s.add(t); | |
}; | |
Developer.prototype = { | |
type: 'Developer', | |
attackRange: 100, | |
attackRangeSquared: 10000, | |
attackPower: 5, | |
attackFrequency: 150, | |
flipDelay: 10, | |
displayLevelConfig: { | |
string: 'Lv. 01', | |
fontSize: 7, | |
pos: [0,60,0] | |
}, | |
displayRadiusConfig: { | |
shape: new n.Geom.Circle({ | |
radius: 1 | |
}), | |
color: '#ff0', | |
renderAlways: true | |
}, | |
displayBarConfig: { | |
shape: squareCentered, | |
color: '#0f0', | |
scale: [10,5,1], | |
pos: [0,40,0] | |
}, | |
displayBarFillConfig: { | |
shape: squareLeft, | |
color: '#ff0', | |
scale: [0.8,0.5,0], | |
pos: [-0.8,0,0] | |
}, | |
levelUp: function() { | |
var t = this; | |
t.level += 1; | |
t.levelDisplay.string = 'Lv. ' + (t.level < 10 ? '0' : '') + t.level; | |
t.attackRange += 10; | |
t.attackFrequency -= 10; | |
t.attackRangeSquared = n.Maths.square(t.attackRange); | |
t.attackCountdown = 0; //allows the dev to attack immedietly after upgrade | |
t.display.color = 'hsl(' + Math.round((((t.attackFrequency - 10) / 140) * -120) + 120) + ', 100%, 50%)'; | |
//console.log(dev.display.color); | |
if(t.attackFrequency === 10){ | |
t.radiusDisplay.color = '#0f0'; | |
} | |
}, | |
attack: commonFuncs.attack, | |
getSquareDistangeToTarget: commonFuncs.getSquareDistangeToTarget, | |
getNewTarget: commonFuncs.getNewTarget, | |
update: function() { | |
var t = this; | |
t.attackCountdown -= 1; | |
if(t.attackCountdown < 0){ | |
t.attackCountdown = 0; | |
} | |
t.barFill.scale[0] = (1 - (t.attackCountdown / t.attackFrequency)) * 0.8; | |
if(t.target && t.target.health <= 0){ //It's already dead, Jim! Stop targeting it! | |
t.target = false; | |
} | |
if(t.target){ | |
//is previous target still in range? | |
t.getSquareDistangeToTarget(t.target); | |
} | |
if(!t.target) { | |
//If no target is assigned... | |
t.getNewTarget(bugList); | |
} | |
if(t.target){ | |
n.Maths.pointAt(t.display, t.target.gPos); | |
} | |
t.flip -= 1; | |
if(t.flip < 1){ | |
t.display.scale[1] *= -1; | |
t.flip = t.flipDelay; | |
} | |
t.radiusDisplay.scale[0] = t.radiusDisplay.scale[1] = t.radiusDisplay.scale[2] = t.attackRange; | |
t.render(); | |
if(t.target){ | |
//don't want to spawn a lazor from the non-updated t.gpos on the frame a dev is added | |
if(t.attackCountdown < 1){ | |
t.attack(t.target); | |
t.attackCountdown = t.attackFrequency; | |
} | |
} | |
} | |
}; | |
var CodeBase = function(args) { | |
var t = this, type = 'CodeBase'; | |
if(t.type !== type){throw type + ' constructor requires the use of the `new` keyword.';} | |
args = args || {}; | |
n.blessWith3DBase(t,args); | |
t.health = args.health || 100; | |
t.maxHealth = t.health; | |
t.display = new n.Ob3D(t.displayConfig); | |
t.radiusDisplay = new n.Ob3D(t.displayRadiusConfig); | |
t.bar = new n.Ob3D(t.displayBarConfig); | |
t.barFill = new n.Ob3D(t.displayBarFillConfig); | |
t.add(t.display); | |
t.add(t.radiusDisplay); | |
t.add(t.bar); | |
t.bar.add(t.barFill); | |
s.add(t); | |
}; | |
CodeBase.prototype = { | |
type: 'CodeBase', | |
attackRange: 32, | |
attackRangeSquared: 1024, | |
shape: {}, | |
displayConfig: { | |
shape: shapes.codebase, | |
color: '#0ff', | |
scale: [12,12,12] | |
}, | |
displayRadiusConfig: { | |
shape: new n.Geom.Circle({ | |
radius: 1 | |
}), | |
color: '#ff0' | |
}, | |
displayBarConfig: { | |
shape: squareCentered, | |
color: '#0f0', | |
scale: [32,6,1], | |
pos: [0,44,0] | |
}, | |
displayBarFillConfig: { | |
shape: squareLeft, | |
color: '#f00', | |
scale: [0.9,0.5,0], | |
pos: [-0.9,0,0] | |
}, | |
getSquareDistangeToTarget: commonFuncs.getSquareDistangeToTarget, | |
getNewTarget: commonFuncs.getNewTarget, | |
update: function () { | |
var t = this; | |
t.getNewTarget(bugList); | |
if (t.target) { | |
t.health -= t.target.attackPower; | |
t.target.die(); | |
} | |
t.barFill.scale[0] = (t.health / t.maxHealth) * 0.9; | |
t.radiusDisplay.scale[0] = t.radiusDisplay.scale[1] = t.radiusDisplay.scale[2] = t.attackRange; | |
t.render(); | |
t.display.rot[2] += deg; | |
if(t.health <= 0){ | |
new n.Fx.Explosion({ | |
object: t.display, | |
scene: t.scene | |
}); | |
t.destroy(); | |
} | |
} | |
}; | |
var myCodeBase = new CodeBase({ | |
color: '#00f', | |
pos: [320,0,0], | |
health: 20 | |
}); | |
s.add(myCodeBase); | |
var playerScoreDisplay = new n.VText({ | |
textAlign: 'left', | |
pos: new n.Layout.ResponsivePoint({ | |
offset: [32, 32, 0], | |
scene: s | |
}), | |
fontSize: 16 | |
}); | |
s.add(playerScoreDisplay); | |
var gameController = { | |
enemyTimeout: 100, | |
timeUntilNextEnemy: 100, | |
playerScore: 0, | |
playerMoney: 40, | |
framesAlive: 0, | |
developerPrice: 15, | |
developerUpgradePrice: 10, | |
update: function () { | |
var t = this; | |
if(t.timeUntilNextEnemy < 1){ | |
new Bug(); | |
t.timeUntilNextEnemy = t.enemyTimeout; | |
t.enemyTimeout -= 1; | |
if(t.enemyTimeout < 5){ | |
t.enemyTimeout = 5; | |
} | |
} | |
t.timeUntilNextEnemy -= 1; | |
if(myCodeBase.health <= 0) { | |
playerScoreDisplay.string = 'GAME OVER'; | |
} else { | |
playerScoreDisplay.string = 'Developer Defence - Click the seats to hire devs!' + | |
'\nClick the seats again to upgrade the devs!' + | |
'\nDeveloperUpgradePrice: ' + t.developerUpgradePrice + | |
'\nDeveloperPrice: ' + t.developerPrice + | |
'\nCodeBaseHealth: ' + myCodeBase.health + | |
'\nMoney: ' + t.playerMoney + | |
'\nScore: ' + t.playerScore + | |
'\nEnemy In: ' + t.enemyTimeout + | |
'\nTime alive: ' + (t.framesAlive / 100); | |
t.framesAlive += 1; | |
} | |
} | |
}; | |
s.add(gameController); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment