Skip to content

Instantly share code, notes, and snippets.

@AdmiralPotato
Last active December 14, 2015 02:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AdmiralPotato/5017984 to your computer and use it in GitHub Desktop.
Save AdmiralPotato/5017984 to your computer and use it in GitHub Desktop.
<!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