///
///
///
///
'use strict';
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Vector3 = THREE.Vector3;
var Face3 = THREE.Face3;
var Material = THREE.Material;
var Geometry = THREE.Geometry;
var CanvasRenderer = THREE.CanvasRenderer;
var WebGLRenderer = THREE.WebGLRenderer;
//wtf fix..
Physijs.scripts.worker = "physi_js/physijs_worker.js";
Physijs.scripts.ammo = "ammo.js";
var PointerLock = (function () {
function PointerLock(game, blocker, instructions, overlay) {
var _this = this;
this.game = game;
this.blocker = blocker;
this.instructions = instructions;
this.overlay = overlay;
this.hasLock = false;
this.onChange = function (event) {
var element = document.body;
var doc = document;
if (doc.pointerLockElement === element || doc.mozPointerLockElement === element || doc.webkitPointerLockElement === element) {
//gained
_this.hasLock = true;
_this.blocker.style.display = "none";
if (_this.game.state == GameState.INITIALIZED || _this.game.state == GameState.PAUSED) {
_this.game.start();
}
}
else {
//lost
_this.hasLock = false;
_this.blocker.style.display = '-webkit-box';
_this.blocker.style.display = '-moz-box';
_this.blocker.style.display = 'box';
_this.instructions.style.display = "";
if (_this.game.state == GameState.STARTED) {
_this.game.pause();
}
}
};
this.onError = function (event) {
_this.instructions.style.display = "";
};
this.onClick = function (event) {
var element = document.body;
element.requestPointerLock = element.requestPointerLock || element.mozRequestPointerLock || element.webkitRequestPointerLock;
_this.instructions.style.display = "none";
element.requestPointerLock();
};
}
PointerLock.prototype.gain = function () {
var havePointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document;
if (!havePointerLock) {
return;
}
document.addEventListener('pointerlockchange', this.onChange, false);
document.addEventListener('mozpointerlockchange', this.onChange, false);
document.addEventListener('webkitpointerlockchange', this.onChange, false);
document.addEventListener('pointerlockerror', this.onError, false);
document.addEventListener('mozpointerlockerror', this.onError, false);
document.addEventListener('webkitpointerlockerror', this.onError, false);
this.blocker.addEventListener("click", this.onClick, false);
};
return PointerLock;
}());
var Keyboard = (function () {
function Keyboard() {
var _this = this;
this.status = {};
this.onKeyDown = function (event) {
var key = Keyboard.keyName(event.keyCode);
if (!_this.status[key])
_this.status[key] = { down: false, pressed: false, up: false, updatedPreviously: false };
};
this.onKeyUp = function (event) {
var key = Keyboard.keyName(event.keyCode);
if (_this.status[key])
_this.status[key].pressed = false;
};
}
Keyboard.prototype.update = function () {
for (var key in this.status) {
// insure that every keypress has "down" status exactly once
if (!this.status[key].updatedPreviously) {
this.status[key].down = true;
this.status[key].pressed = true;
this.status[key].updatedPreviously = true;
}
else {
this.status[key].down = false;
}
// key has been flagged as "up" since last update
if (this.status[key].up) {
delete this.status[key];
continue; // move on to next key
}
if (!this.status[key].pressed)
this.status[key].up = true;
}
};
Keyboard.prototype.down = function (key) {
return (this.status[key] && this.status[key].down);
};
Keyboard.prototype.pressed = function (key) {
return (this.status[key] && this.status[key].pressed);
};
Keyboard.prototype.up = function (key) {
return (this.status[key] && this.status[key].up);
};
Keyboard.prototype.register = function () {
document.addEventListener("keydown", this.onKeyDown, false);
document.addEventListener("keyup", this.onKeyUp, false);
};
Keyboard.prototype.unregister = function () {
document.removeEventListener("keydown", this.onKeyDown, false);
document.removeEventListener("keyup", this.onKeyUp, false);
};
Keyboard.keyName = function (keyCode) {
return (Keyboard.k[keyCode] != null) ?
Keyboard.k[keyCode] :
String.fromCharCode(keyCode);
};
/*
Credit to: https://github.com/stemkoski
*/
Keyboard.k = {
8: "backspace", 9: "tab", 13: "enter", 16: "shift",
17: "ctrl", 18: "alt", 27: "esc", 32: "space",
33: "pageup", 34: "pagedown", 35: "end", 36: "home",
37: "left", 38: "up", 39: "right", 40: "down",
45: "insert", 46: "delete", 186: ";", 187: "=",
188: ",", 189: "-", 190: ".", 191: "/",
219: "[", 220: "\\", 221: "]", 222: "'"
};
return Keyboard;
}());
/**
*
*/
var Mouse = (function () {
function Mouse(player) {
var _this = this;
this.player = player;
this.xMovement = 0;
this.yMovement = 0;
this.buttons = {};
this.onMouseMove = function (event) {
_this.x = event.screenX;
_this.xMovement = event.movementX;
_this.y = event.screenY;
_this.yMovement = event.movementY;
_this.player.rotate(event.movementX);
_this.player.look(event.movementY);
};
this.onMouseDown = function (event) {
_this.buttons[event.button] = true;
_this.player.click(event.button);
};
this.onMouseUp = function (event) {
_this.buttons[event.button] = false;
};
}
Mouse.prototype.pressed = function (button) {
return this.buttons[button];
};
Mouse.prototype.register = function () {
document.addEventListener("mousemove", this.onMouseMove, false);
document.addEventListener("mousedown", this.onMouseDown, false);
document.addEventListener("mouseup", this.onMouseUp, false);
};
Mouse.prototype.unregister = function () {
document.removeEventListener("mousemove", this.onMouseMove, false);
document.removeEventListener("mousedown", this.onMouseDown, false);
document.removeEventListener("mouseup", this.onMouseUp, false);
};
return Mouse;
}());
var Poly = (function (_super) {
__extends(Poly, _super);
function Poly(pos, polarity) {
var _this = this;
_super.call(this, Poly.generateGeometry(), polarity > 0 ? Poly.blue : Poly.red, 0.3);
this.polarity = polarity;
this.addEventListener("ready", function () { return _this.init(); });
this.position.copy(pos);
}
Poly.prototype.init = function () {
//launch the poly into space
this.setLinearVelocity(Poly.generateDirection().normalize());
};
Poly.generateDirection = function () {
var verts = [];
for (var i = 0; i < 3; i++) {
verts.push(Math.random() * (Math.random() > 0.5 ? 1 : -1));
}
verts[1] = Math.abs(verts[1]);
return new Vector3().fromArray(verts);
};
Poly.generateGeometry = function () {
//generate two random verts, construct a triangle
var geom = new THREE.Geometry();
geom.vertices.push(new Vector3());
geom.vertices.push(Poly.generateDirection());
geom.vertices.push(Poly.generateDirection());
geom.faces.push(new THREE.Face3(0, 1, 2));
return geom;
};
Poly.prototype.collides = function (other) {
return this.position.clone().sub(other.position).lengthSq() <= ((other.radius) ^ 2);
};
Poly.prototype.dispose = function () {
this.geometry.dispose();
};
Poly.red = Physijs.createMaterial(new THREE.MeshBasicMaterial({
color: 0xa01000
}), 1, 1);
Poly.blue = Physijs.createMaterial(new THREE.MeshBasicMaterial({
color: 0x00a0b0
}), 1, 1);
return Poly;
}(Physijs.PlaneMesh));
var Morph = (function (_super) {
__extends(Morph, _super);
function Morph(pos, level, material, mass) {
var _this = this;
_super.call(this, Morph.generateGeometry(level), material, mass);
this.level = level;
this.radius = this.geometry.boundingSphere.radius;
this.position.copy(pos);
this.addEventListener("ready", function () { return _this.init(); });
}
Morph.prototype.init = function () {
this.castShadow = true;
};
Morph.generateGeometry = function (level) {
var numFaces = Morph.levels[level];
switch (numFaces) {
case 4:
return new THREE.TetrahedronGeometry();
case 6:
return new THREE.BoxGeometry(1, 1, 1, 1, 1, 1);
case 12:
return new THREE.IcosahedronGeometry(1, 0);
case 20:
return new THREE.DodecahedronGeometry(1, 0);
default:
return new THREE.TetrahedronGeometry();
}
};
Morph.prototype.updateGeometry = function () {
this.geometry.dispose();
this.geometry = Morph.generateGeometry(this.level);
this.geometry.computeBoundingSphere();
this.radius = this.geometry.boundingSphere.radius;
};
Morph.prototype.shrink = function () {
if (this.level > 0) {
this.level--;
this.updateGeometry();
}
};
Morph.prototype.grow = function () {
if (this.level < 3) {
this.level++;
this.updateGeometry();
}
};
Morph.prototype.collides = function (other) {
return this.position.clone().sub(other.position).length() <= (this.radius + other.radius);
};
Morph.prototype.dispose = function () {
this.geometry.dispose();
};
Morph.levels = [4, 6, 12, 20];
return Morph;
}(Physijs.SphereMesh));
var Projectile = (function (_super) {
__extends(Projectile, _super);
function Projectile(pos, dir, level) {
_super.call(this, pos.clone().add(dir.clone().setLength(2)), level, Projectile.mat, 0.05);
this.pos = pos;
this.dir = dir;
this.time = 0;
}
Projectile.prototype.init = function () {
this.launch();
};
;
Projectile.prototype.launch = function () {
this.setLinearVelocity(this.dir);
};
Projectile.prototype.tick = function (delta) {
this.time += delta;
};
Projectile.mat = Physijs.createMaterial(new THREE.MeshBasicMaterial({
color: 0x303030
}), 0.5, 0.3);
return Projectile;
}(Morph));
var LiveMorph = (function (_super) {
__extends(LiveMorph, _super);
function LiveMorph() {
_super.apply(this, arguments);
this.life = 100;
}
LiveMorph.prototype.damage = function (by) {
if (this.isAlive())
this.life -= by;
};
LiveMorph.prototype.isAlive = function () {
return this.life > 0;
};
LiveMorph.prototype.getSpeed = function () {
return this.speeds[this.level];
};
return LiveMorph;
}(Morph));
var Mob = (function (_super) {
__extends(Mob, _super);
function Mob(pos, level) {
_super.call(this, pos, level, Mob.mat, 2);
this.speeds = [25.1, 23, 21, 19];
}
Mob.prototype.approach = function (player) {
var toPlayer = player.position.clone().sub(this.position).normalize();
this.setLinearVelocity(toPlayer.setLength(this.getSpeed()));
};
Mob.prototype.die = function () {
var polys = [];
var amount = Math.floor(Math.random() * 10) + 3;
for (var i = 0; i < amount; i++) {
var poly = new Poly(this.position, Math.random() > 0.5 ? 1 : -1);
polys.push(poly);
}
return polys;
};
Mob.mat = Physijs.createMaterial(new THREE.MeshBasicMaterial({
color: 0xa01000
}), .8, .6);
return Mob;
}(LiveMorph));
var Player = (function (_super) {
__extends(Player, _super);
function Player(pos) {
_super.call(this, pos, 0, Physijs.createMaterial(new THREE.MeshBasicMaterial({
color: 0x00a0b0
}), 1, 0.1), 0.5);
this.minus = 5;
this.plus = 5;
this.forward = new Vector3(0, 0, -1);
this.upward = new Vector3(0, 1, 0);
this.camera = new Vector3(0, 6, 10);
this.heading = 0;
this.pitch = 0;
this.score = 0;
this.projectiles = [];
this.speeds = [25, 24, 22, 20];
this.listener = new THREE.AudioListener();
this.add(this.listener);
}
Player.prototype.init = function () {
this.castShadow = true;
this.setDamping(0.05, 0.05);
};
Player.prototype.jump = function () {
this.applyCentralImpulse(new Vector3(0, 8, 0));
};
Player.prototype.rotate = function (xMovement) {
this.heading -= xMovement * 0.002;
};
Player.prototype.look = function (yMovement) {
this.pitch -= yMovement * 0.002;
};
Player.prototype.click = function (button) {
if (button == THREE.MOUSE.LEFT) {
this.projectiles.push(new Projectile(this.position, this.getDirection().multiplyScalar(35), this.level));
}
};
Player.prototype.getRight = function () {
return this.getForward().cross(this.upward).normalize();
};
Player.prototype.getDirection = function () {
return this.getForward().applyAxisAngle(this.getRight(), this.pitch);
};
Player.prototype.getForward = function () {
return this.forward.clone().applyAxisAngle(this.upward, this.heading);
};
Player.prototype.getCamera = function () {
return this.camera.clone().applyAxisAngle(this.upward, this.heading).applyAxisAngle(this.getRight(), this.pitch);
};
return Player;
}(LiveMorph));
var Level = (function (_super) {
__extends(Level, _super);
function Level(player, level) {
_super.call(this);
this.player = player;
this.level = level;
this.mobs = [];
this.projectiles = [];
this.polygons = [];
this.time = 0;
this.setGravity(new THREE.Vector3(0, -40, 0));
this.add(player);
for (var i = 0; i < 3; i++) {
this.spawn(20, 20);
}
var groundGeometry = new THREE.BoxGeometry(1200, 1, 1200);
this.ground = new Physijs.BoxMesh(groundGeometry, Level.mat, 0);
this.add(this.ground);
}
Level.prototype.random = function (start, range) {
var a = Math.random() > 0.5 ? -1 : 1;
var b = Math.random() > 0.5 ? -1 : 1;
var x = Math.floor(Math.random() * range + start);
var z = Math.floor(Math.random() * range + start);
return new Vector3(a * x, 2, b * z);
};
Level.prototype.spawnMob = function (where, size) {
var mob = new Mob(where, size);
this.add(mob);
this.mobs.push(mob);
};
Level.prototype.spawnGroup = function (where, amount, size) {
for (var i = 0; i < amount; i++) {
this.spawnMob(where, size);
}
};
Level.prototype.spawn = function (start, range, size) {
if (!size) {
size = Math.floor(Math.random() * 4);
}
this.spawnMob(this.player.position.clone().add(this.random(start, range)), size);
};
Level.prototype.tick = function (delta) {
var _this = this;
this.time += delta;
//push projectiles queued from player into the world.
while (this.player.projectiles.length > 0) {
var projectile = this.player.projectiles.pop();
this.projectiles.push(projectile);
this.add(projectile);
}
//enemy movement
this.mobs.forEach(function (mob) {
mob.approach(_this.player);
if (mob.collides(_this.player)) {
//collide?
_this.player.damage((mob.level + 1));
}
});
//tick projectiles and remove them if time out/on hit
this.projectiles = this.projectiles.filter(function (projectile) {
projectile.tick(delta);
var keep = projectile.time < 10 * 1000;
var collided = false;
if (!keep) {
_this.remove(projectile);
}
else {
for (var _i = 0, _a = _this.mobs; _i < _a.length; _i++) {
var mob = _a[_i];
if (mob.collides(projectile)) {
if (mob.level == projectile.level) {
collided = true;
mob.damage(34);
break;
}
}
}
}
if (collided) {
_this.remove(projectile);
}
return keep && !collided;
});
this.mobs = this.mobs.filter(function (mob) {
var alive = mob.isAlive();
if (!alive) {
_this.player.score += mob.level + 1;
var polys = mob.die();
polys.forEach(function (poly) {
_this.add(poly);
poly.init();
_this.polygons.push(poly);
});
_this.remove(mob);
}
return alive;
});
this.polygons = this.polygons.filter(function (poly) {
if (poly.collides(_this.player)) {
if (poly.polarity > 0) {
_this.player.plus += 1;
}
else {
_this.player.minus += 1;
}
_this.remove(poly);
return false;
}
return true;
});
//spawn new mob?
var amount = 0.004 * ((this.level + 1) / 2 + 0.8);
if (this.level == Level.numLevels - 1) {
amount += (this.time / 1000) / 2000;
}
if (Math.random() < amount) {
var size = Math.floor(Math.random() * 4);
var pos = this.random(20, 10);
this.spawnGroup(pos, 3, size);
}
//physijs
this.simulate(delta, 1);
};
Level.prototype.timeLeft = function () {
return Level.durations[this.level] - (this.time / 1000);
};
Level.prototype.dispose = function () {
var _this = this;
this.remove(this.ground);
this.ground.geometry.dispose();
this.mobs.forEach(function (obj) {
_this.remove(obj);
obj.dispose();
});
this.projectiles.forEach(function (obj) {
_this.remove(obj);
obj.dispose();
});
this.polygons.forEach(function (obj) {
_this.remove(obj);
obj.dispose();
});
};
//unused
Level.generateGeometry = function (level) {
switch (level) {
default:
case 0:
var vertices = [
1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1
];
var verts = [];
for (var i = 0; i < 4; i++) {
verts.push(new Vector3().fromArray(vertices, i * 3));
}
var indices = [
0, 1, 2, 2, 3, 0, 0, 3, 1, 1, 3, 2
];
var faces = [];
for (var i = 0; i < 4; i++) {
faces.push(new Face3(indices[i * 3], indices[i * 3 + 1], indices[i * 3 + 2]));
}
return [new THREE.PolyhedronGeometry(verts, faces, 200)];
}
};
Level.durations = [25, 30, 45, Infinity];
Level.numLevels = Level.durations.length;
Level.mat = Physijs.createMaterial(new THREE.MeshBasicMaterial({ color: 0xcacaca }), 1, 1);
return Level;
}(Physijs.Scene));
var GameState;
(function (GameState) {
GameState[GameState["INITIALIZED"] = 0] = "INITIALIZED";
GameState[GameState["STARTED"] = 1] = "STARTED";
GameState[GameState["PAUSED"] = 2] = "PAUSED";
GameState[GameState["STOPPED"] = 3] = "STOPPED";
})(GameState || (GameState = {}));
var Game = (function () {
function Game() {
var _this = this;
this.ticks = 0;
this.delta = 0;
this.lastFrame = 0;
this.timestep = 1000 / 60;
this.maxFPS = 60;
this.onWindowResize = function () {
_this.camera.aspect = window.innerWidth / window.innerHeight;
_this.camera.updateProjectionMatrix();
_this.renderer.setSize(window.innerWidth, window.innerHeight);
};
if (Detector.webgl) {
this.renderer = new THREE.WebGLRenderer({ antialias: true });
var rendr = this.renderer;
rendr.setClearColor(0xcacaca);
rendr.setPixelRatio(window.devicePixelRatio);
rendr.setSize(window.innerWidth, window.innerHeight);
}
else {
this.renderer = new THREE.CanvasRenderer();
var rendr = this.renderer;
rendr.setClearColor(0xcacaca);
rendr.setPixelRatio(window.devicePixelRatio);
rendr.setSize(window.innerWidth, window.innerHeight);
}
document.body.appendChild(this.renderer.domElement);
window.addEventListener("resize", this.onWindowResize, false);
this.overlay = document.getElementById("overlay");
this.camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 1, 1000);
}
Game.prototype.init = function () {
//init player
this.player = new Player(new Vector3(0, 2, 0));
//init audio
this.audio = new THREE.Audio(this.player.listener);
this.audio.load("background.ogg");
this.audio.autoplay = true;
this.audio.setLoop(true);
this.audio.setVolume(0.5);
//init keyboard and mouse
this.keyboard = new Keyboard();
this.mouse = new Mouse(this.player);
this.state = GameState.INITIALIZED;
this.newLevel(0);
};
Game.prototype.newLevel = function (num) {
//init level
this.level = new Level(this.player, num);
//init camera
this.camera.position.addVectors(this.player.position, this.player.camera);
this.camera.lookAt(this.player.position);
this.updateOverlay();
};
Game.prototype.updateOverlay = function () {
this.overlay.querySelector("#score").innerHTML = "Score: " + this.player.score;
this.overlay.querySelector("#time").innerHTML = "Time left: " + this.level.timeLeft().toFixed(0) + "s";
this.overlay.querySelector("#level").innerHTML = "Level: " + (this.level.level + 1) + "/" + Level.numLevels;
this.overlay.querySelector("#life").innerHTML = "Life: " + this.player.life + "%";
this.overlay.querySelector("#positive").innerHTML = "Pos polygons(E): " + this.player.plus;
this.overlay.querySelector("#negative").innerHTML = "Neg polygons(Q): " + this.player.minus;
};
/**
* Just render the scene.
*/
Game.prototype.render = function () {
this.renderer.render(this.level, this.camera);
};
/**
* Update logic based on @param delta.
* @param delta
*/
Game.prototype.tick = function (delta) {
this.ticks++;
if (this.ticks % 60 == 0) {
this.updateOverlay();
}
this.keyboard.update();
//camera
this.camera.position.addVectors(this.player.position, this.player.getCamera());
this.camera.lookAt(this.player.position);
//player movement
var playerSpeed = this.player.getSpeed();
var forward = this.player.getForward();
forward.setLength(playerSpeed);
var right = forward.clone().cross(this.player.upward);
right.setLength(playerSpeed);
if (this.keyboard.pressed("W")) {
this.player.applyCentralForce(forward);
}
if (this.keyboard.pressed("S")) {
this.player.applyCentralForce(forward.negate());
}
if (this.keyboard.pressed("D")) {
this.player.applyCentralForce(right);
}
if (this.keyboard.pressed("A")) {
this.player.applyCentralForce(right.negate());
}
//clamp speed, TODO into a method
var velocity = this.player.getLinearVelocity().clampLength(-playerSpeed, playerSpeed);
this.player.setLinearVelocity(velocity);
//morph!
if (this.keyboard.down("Q")) {
if (this.player.minus > 0 && this.player.level > 0) {
this.player.shrink();
this.player.minus--;
}
}
else if (this.keyboard.down("E")) {
if (this.player.plus > 0 && this.player.level < 3) {
this.player.grow();
this.player.plus--;
}
}
//jump!
if (this.keyboard.down("space")) {
this.player.jump();
}
//debug shoot
if (this.keyboard.down("C")) {
this.player.click(THREE.MOUSE.LEFT);
}
this.level.tick(delta);
//die!
if (!this.player.isAlive()) {
this.stop(false);
}
//next level
if (this.level.timeLeft() < 0) {
this.stop(true);
}
};
Game.prototype.run = function (timestamp) {
var _this = this;
if (!timestamp) {
timestamp = performance.now();
}
if (timestamp < this.lastFrame + (1000 / this.maxFPS)) {
if (this.keepRunning) {
requestAnimationFrame(function () { return _this.run(); });
}
return;
}
this.delta += timestamp - this.lastFrame;
this.lastFrame = timestamp;
var numUpdateSteps = 0;
while (this.delta >= this.timestep) {
this.tick(this.timestep);
this.delta -= this.timestep;
if (++numUpdateSteps >= 240) {
// panic here, reset delta
this.delta = 0;
break;
}
}
this.render();
if (this.keepRunning) {
requestAnimationFrame(function (time) { return _this.run(time); });
}
};
Game.prototype.start = function () {
this.state = GameState.STARTED;
this.keepRunning = true;
this.lastFrame = performance.now();
this.keyboard.register();
this.mouse.register();
this.run();
};
Game.prototype.pause = function () {
this.updateOverlay();
this.state = GameState.PAUSED;
this.keyboard.unregister();
this.mouse.unregister();
this.keepRunning = false;
};
Game.prototype.stop = function (result) {
if (result === void 0) { result = false; }
this.pause();
this.state = GameState.STOPPED;
if (this.level.level != Level.numLevels - 1) {
if (result) {
//next level, shit!
this.level.dispose();
this.newLevel(this.level.level + 1);
this.start();
return;
}
}
else {
result = true; //fix last level not winning
}
this.level.dispose();
window.removeEventListener("resize", this.onWindowResize, false);
var blocker = document.getElementById("block");
blocker.style.display = '-webkit-box';
blocker.style.display = '-moz-box';
blocker.style.display = 'box';
var instructions = document.getElementById("instructions");
instructions.style.fontSize = "40px";
instructions.innerHTML = result ? "You won!" : "You lost!";
instructions.style.display = "";
if (Detector.webgl) {
this.renderer.dispose();
}
};
return Game;
}());
window.onload = function () {
var game = new Game();
game.init();
//make sure we have pointerlock here
//from three.js example(PointerLock), thanks
var block = document.getElementById("block");
var instructions = document.getElementById("instructions");
var overlay = document.getElementById("overlay");
var plock = new PointerLock(game, block, instructions, overlay);
plock.gain();
};
//# sourceMappingURL=game.js.map