mirror of
https://github.com/lubosz/overte.git
synced 2025-08-08 03:48:38 +02:00
Add wave game sounds, fix wave 10 bug, update the way waves spawn
This commit is contained in:
parent
871c5ad38b
commit
9f5435133a
10 changed files with 431 additions and 215 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,3 +1,30 @@
|
||||||
|
var leftHandPosition = {
|
||||||
|
"x": 0,//-0.0881,
|
||||||
|
"y": 0.0559,
|
||||||
|
"z": 0.0159
|
||||||
|
};
|
||||||
|
var leftHandRotation = Quat.fromPitchYawRollDegrees(90, -90, 0);
|
||||||
|
var rightHandPosition = Vec3.multiplyVbyV(leftHandPosition, { x: -1, y: 0, z: 0 });
|
||||||
|
var rightHandRotation = Quat.fromPitchYawRollDegrees(90, 90, 0);
|
||||||
|
|
||||||
|
var userData = {
|
||||||
|
"grabbableKey": {
|
||||||
|
"grabbable": true
|
||||||
|
},
|
||||||
|
"wearable": {
|
||||||
|
"joints": {
|
||||||
|
"LeftHand": [
|
||||||
|
leftHandPosition,
|
||||||
|
leftHandRotation
|
||||||
|
],
|
||||||
|
"RightHand": [
|
||||||
|
rightHandPosition,
|
||||||
|
rightHandRotation
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Entities.addEntity({
|
Entities.addEntity({
|
||||||
position: MyAvatar.position,
|
position: MyAvatar.position,
|
||||||
"collisionsWillMove": 1,
|
"collisionsWillMove": 1,
|
||||||
|
@ -22,8 +49,9 @@ Entities.addEntity({
|
||||||
"y": -0.10469216108322144,
|
"y": -0.10469216108322144,
|
||||||
"z": -0.14418250322341919
|
"z": -0.14418250322341919
|
||||||
},
|
},
|
||||||
"script": Script.resolvePath("bow.js"),
|
"script": Script.resolvePath("bow.js") + "?" + Date.now(),
|
||||||
"shapeType": "compound",
|
"shapeType": "compound",
|
||||||
"type": "Model",
|
"type": "Model",
|
||||||
"userData": "{\"grabbableKey\":{\"grabbable\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.0813,\"y\":0.0452,\"z\":0.0095},{\"x\":-0.3946,\"y\":-0.6604,\"z\":0.4748,\"w\":-0.4275}],\"LeftHand\":[{\"x\":-0.0881,\"y\":0.0259,\"z\":0.0159},{\"x\":0.4427,\"y\":-0.6519,\"z\":0.4592,\"w\":0.4099}]}}}"
|
"userData": JSON.stringify(userData),
|
||||||
|
lifetime: 40
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,39 +1,5 @@
|
||||||
if (!Function.prototype.bind) {
|
|
||||||
Function.prototype.bind = function(oThis) {
|
|
||||||
if (typeof this !== 'function') {
|
|
||||||
// closest thing possible to the ECMAScript 5
|
|
||||||
// internal IsCallable function
|
|
||||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
|
||||||
}
|
|
||||||
|
|
||||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
|
||||||
fToBind = this,
|
|
||||||
fNOP = function() {},
|
|
||||||
fBound = function() {
|
|
||||||
return fToBind.apply(this instanceof fNOP
|
|
||||||
? this
|
|
||||||
: oThis,
|
|
||||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.prototype) {
|
|
||||||
// Function.prototype doesn't have a prototype property
|
|
||||||
fNOP.prototype = this.prototype;
|
|
||||||
}
|
|
||||||
fBound.prototype = new fNOP();
|
|
||||||
|
|
||||||
return fBound;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
function parseJSON(json) {
|
Script.include('utils.js');
|
||||||
try {
|
|
||||||
return JSON.parse(json);
|
|
||||||
} catch(e) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Enemy = function() {
|
Enemy = function() {
|
||||||
};
|
};
|
||||||
|
@ -46,7 +12,7 @@ if (!Function.prototype.bind) {
|
||||||
this.entityIDsThatHaveCollidedWithMe = [];
|
this.entityIDsThatHaveCollidedWithMe = [];
|
||||||
|
|
||||||
var userData = Entities.getEntityProperties(this.entityID, 'userData').userData;
|
var userData = Entities.getEntityProperties(this.entityID, 'userData').userData;
|
||||||
var data = parseJSON(userData);
|
var data = utils.parseJSON(userData);
|
||||||
if (data !== undefined && data.gameChannel !== undefined) {
|
if (data !== undefined && data.gameChannel !== undefined) {
|
||||||
this.gameChannel = data.gameChannel;
|
this.gameChannel = data.gameChannel;
|
||||||
} else {
|
} else {
|
||||||
|
@ -54,7 +20,6 @@ if (!Function.prototype.bind) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onCollide: function(entityA, entityB, collision) {
|
onCollide: function(entityA, entityB, collision) {
|
||||||
print("Collided with: ", entityB);
|
|
||||||
if (this.entityIDsThatHaveCollidedWithMe.indexOf(entityB) > -1) {
|
if (this.entityIDsThatHaveCollidedWithMe.indexOf(entityB) > -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -65,6 +30,7 @@ if (!Function.prototype.bind) {
|
||||||
// If the other entity's name includes 'projectile' and we haven't hit it before,
|
// If the other entity's name includes 'projectile' and we haven't hit it before,
|
||||||
// continue on.
|
// continue on.
|
||||||
if (colliderName.indexOf("projectile") > -1) {
|
if (colliderName.indexOf("projectile") > -1) {
|
||||||
|
print("Collided with: ", entityB);
|
||||||
Messages.sendMessage(this.gameChannel, JSON.stringify({
|
Messages.sendMessage(this.gameChannel, JSON.stringify({
|
||||||
type: "enemy-killed",
|
type: "enemy-killed",
|
||||||
entityID: this.entityID,
|
entityID: this.entityID,
|
||||||
|
@ -74,6 +40,7 @@ if (!Function.prototype.bind) {
|
||||||
Messages.sendMessage(this.gameChannel, JSON.stringify({
|
Messages.sendMessage(this.gameChannel, JSON.stringify({
|
||||||
type: "enemy-escaped",
|
type: "enemy-escaped",
|
||||||
entityID: this.entityID,
|
entityID: this.entityID,
|
||||||
|
position: Entities.getEntityProperties(this.entityID, 'position').position
|
||||||
}));
|
}));
|
||||||
Entities.deleteEntity(this.entityID);
|
Entities.deleteEntity(this.entityID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,72 +1,72 @@
|
||||||
print("============= Script Starting =============");
|
print("============= Script Starting =============");
|
||||||
|
|
||||||
if (!Function.prototype.bind) {
|
var BEGIN_BUILDING_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/letTheGamesBegin.wav"));
|
||||||
Function.prototype.bind = function(oThis) {
|
var GAME_OVER_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/gameOver.wav"));
|
||||||
if (typeof this !== 'function') {
|
var WAVE_COMPLETE_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/waveComplete.wav"));
|
||||||
// closest thing possible to the ECMAScript 5
|
var EXPLOSION_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/explosion.wav"));
|
||||||
// internal IsCallable function
|
|
||||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
|
||||||
}
|
|
||||||
|
|
||||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
Script.include('utils.js');
|
||||||
fToBind = this,
|
print(utils.parseJSON);
|
||||||
fNOP = function() {},
|
print(utils.findSurfaceBelowPosition);
|
||||||
fBound = function() {
|
|
||||||
return fToBind.apply(this instanceof fNOP
|
|
||||||
? this
|
|
||||||
: oThis,
|
|
||||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.prototype) {
|
var randomNums = [0.550327773205936,0.9845642729196697,0.0923804109916091,0.02317189099267125,0.3967760754749179,0.31739208032377064,0.12527672364376485,0.7785351350903511,0.5003328016027808,0.7325339165981859,0.9973437152802944,0.5696579017676413,0.3218349125236273,0.31624294770881534,0.1574797066859901,0.607193318894133,0.6456831728573889,0.762436268851161,0.055773367173969746,0.2516116350889206,0.9599523325450718,0.7358639598824084,0.6161336801014841,0.5886498105246574,0.994422614807263,0.7153528861235827,0.31696250033564866,0.7215959236491472,0.4992282949388027,0.913538035703823,0.03025316959246993,0.10350738768465817,0.995452782837674,0.5243359236046672,0.9341779642272741,0.27633642544969916,0.24957748572342098,0.8252806619275361,0.9339258212130517,0.03701223572716117,0.9452723823487759,0.6275276178494096,0.5341641567647457,0.4005412443075329,0.6898896538186818,0.11714944546110928,0.131995229749009,0.1973097778391093,0.8488441850058734,0.6566063927020878,0.8172534313052893,0.7988312132656574,0.27918070019222796,0.7423286908306181,0.3513789263088256,0.418984186835587,0.4163232871796936,0.44792668521404266,0.056147431721910834,0.4671320249326527,0.2205709801055491,0.816504409071058,0.726218594936654,0.48132069990970194,0.33418917655944824,0.2568618259392679,0.7884722277522087,0.19624578021466732,0.24001670349389315,0.05126210208982229,0.8809637068770826,0.08631141181103885,0.83980125002563,0.38965122890658677,0.7475115314591676,0.22781660920009017,0.7292001177556813,0.12802458507940173,0.6163305244408548,0.8507104918826371,0.026970824925228953,0.45111535978503525,0.6384737638290972,0.9973178182262927,0.19859008654020727,0.9765442060306668,0.9542752094566822,0.4875906065572053,0.333038471871987,0.937375855166465,0.7295125185046345,0.9273903956636786,0.9793413057923317,0.613529595779255,0.3908261926844716,0.6914237674791366,0.34551386488601565,0.13964610872790217,0.5300214979797602,0.7015589624643326];
|
||||||
// Function.prototype doesn't have a prototype property
|
var currentRandomIdx = 0;
|
||||||
fNOP.prototype = this.prototype;
|
function getRandom() {
|
||||||
}
|
return Math.random();
|
||||||
fBound.prototype = new fNOP();
|
//currentRandomIdx = randomNums
|
||||||
|
//return randomNums[];
|
||||||
return fBound;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Utility functions
|
|
||||||
function parseJSON(json) {
|
|
||||||
try {
|
|
||||||
return JSON.parse(json);
|
|
||||||
} catch (e) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findSurfaceBelowPosition(pos) {
|
|
||||||
var result = Entities.findRayIntersection({
|
|
||||||
origin: pos,
|
|
||||||
direction: { x: 0, y: -1, z: 0 }
|
|
||||||
});
|
|
||||||
if (result.intersects) {
|
|
||||||
return result.intersection;
|
|
||||||
}
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
// End of utility function
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var GAME_STATES = {
|
var GAME_STATES = {
|
||||||
IDLE: 0,
|
IDLE: 0,
|
||||||
PLAYING: 1,
|
PLAYING: 1,
|
||||||
GAME_OVER: 2,
|
BETWEEN_WAVES: 2,
|
||||||
|
GAME_OVER: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
var COMM_CHANNEL_NAME = 'wavegame';
|
var COMM_CHANNEL_NAME = 'wavegame';
|
||||||
var entityIDs = [];
|
var entityIDs = [];
|
||||||
|
|
||||||
function GameManager(gatePosition, roofPosition, spawnPositions, startButtonID) {
|
var baseEnemyProperties = {
|
||||||
|
name: "WG.Enemy",
|
||||||
|
type: "Box",
|
||||||
|
registrationPoint: { x: 0.5, y: 0, z: 0.5 },
|
||||||
|
dimensions: { x: 0.7, y: 0.7, z: 0.7 },
|
||||||
|
velocity: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: -3
|
||||||
|
},
|
||||||
|
dynamic: true,
|
||||||
|
gravity: {
|
||||||
|
x: 0,
|
||||||
|
y: -10,
|
||||||
|
z: 0,
|
||||||
|
},
|
||||||
|
restitution: 0,
|
||||||
|
friction: 0,
|
||||||
|
damping: 0,
|
||||||
|
linearDamping: 0,
|
||||||
|
lifetime: 100,
|
||||||
|
script: Script.resolvePath('enemyEntity.js'),
|
||||||
|
userData: JSON.stringify({
|
||||||
|
gameChannel: COMM_CHANNEL_NAME,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function GameManager(rootPosition, gatePosition, roofPosition, spawnPositions, startButtonID, waveDisplayID, scoreDisplayID, livesDisplayID) {
|
||||||
this.gameState = GAME_STATES.IDLE;
|
this.gameState = GAME_STATES.IDLE;
|
||||||
|
|
||||||
|
this.rootPosition = rootPosition;
|
||||||
this.spawnPositions = spawnPositions;
|
this.spawnPositions = spawnPositions;
|
||||||
this.gatePosition = gatePosition;
|
this.gatePosition = gatePosition;
|
||||||
this.roofPosition = roofPosition;
|
this.roofPosition = roofPosition;
|
||||||
this.startButtonID = startButtonID;
|
this.startButtonID = startButtonID;
|
||||||
|
this.waveDisplayID = waveDisplayID;
|
||||||
|
this.scoreDisplayID = scoreDisplayID;
|
||||||
|
this.livesDisplayID = livesDisplayID;
|
||||||
|
|
||||||
// Gameplay state
|
// Gameplay state
|
||||||
this.waveNumber = 0;
|
this.waveNumber = 0;
|
||||||
|
@ -76,6 +76,44 @@ function GameManager(gatePosition, roofPosition, spawnPositions, startButtonID)
|
||||||
this.spawnEnemyTimers = [];
|
this.spawnEnemyTimers = [];
|
||||||
this.enemyIDs = [];
|
this.enemyIDs = [];
|
||||||
this.entityIDs = [];
|
this.entityIDs = [];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Spawn bows
|
||||||
|
const bowPosition = Vec3.sum(this.roofPosition, { x: 0, y: 1, z: 0 });
|
||||||
|
for (var j = 0; j < 20; ++j) {
|
||||||
|
this.entityIDs.push(Entities.addEntity({
|
||||||
|
position: bowPosition,
|
||||||
|
"collisionsWillMove": 1,
|
||||||
|
"compoundShapeURL": Script.resolvePath("bow/bow_collision_hull.obj"),
|
||||||
|
"created": "2016-09-01T23:57:55Z",
|
||||||
|
"dimensions": {
|
||||||
|
"x": 0.039999999105930328,
|
||||||
|
"y": 1.2999999523162842,
|
||||||
|
"z": 0.20000000298023224
|
||||||
|
},
|
||||||
|
"dynamic": 1,
|
||||||
|
"gravity": {
|
||||||
|
"x": 0,
|
||||||
|
"y": -1,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"modelURL": Script.resolvePath("bow/bow-deadly.fbx"),
|
||||||
|
"name": "WG.Hifi-Bow",
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.9718012809753418,
|
||||||
|
"x": 0.15440607070922852,
|
||||||
|
"y": -0.10469216108322144,
|
||||||
|
"z": -0.14418250322341919
|
||||||
|
},
|
||||||
|
"script": Script.resolvePath("bow/bow.js"),
|
||||||
|
"shapeType": "compound",
|
||||||
|
"type": "Model",
|
||||||
|
"userData": "{\"grabbableKey\":{\"grabbable\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.0813,\"y\":0.0452,\"z\":0.0095},{\"x\":-0.3946,\"y\":-0.6604,\"z\":0.4748,\"w\":-0.4275}],\"LeftHand\":[{\"x\":-0.0881,\"y\":0.0259,\"z\":0.0159},{\"x\":0.4427,\"y\":-0.6519,\"z\":0.4592,\"w\":0.4099}]}}}"
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GameManager.prototype = {
|
GameManager.prototype = {
|
||||||
cleanup: function() {
|
cleanup: function() {
|
||||||
|
@ -83,6 +121,10 @@ GameManager.prototype = {
|
||||||
Entities.deleteEntity(this.entityIDs[i]);
|
Entities.deleteEntity(this.entityIDs[i]);
|
||||||
}
|
}
|
||||||
this.entityIDs = [];
|
this.entityIDs = [];
|
||||||
|
for (var i = 0; i < this.enemyIDs.length; i++) {
|
||||||
|
Entities.deleteEntity(this.enemyIDs[i]);
|
||||||
|
}
|
||||||
|
this.enemyIDs = [];
|
||||||
},
|
},
|
||||||
startGame: function() {
|
startGame: function() {
|
||||||
if (this.gameState !== GAME_STATES.IDLE) {
|
if (this.gameState !== GAME_STATES.IDLE) {
|
||||||
|
@ -96,111 +138,110 @@ GameManager.prototype = {
|
||||||
|
|
||||||
// Initialize game state
|
// Initialize game state
|
||||||
this.waveNumber = 0;
|
this.waveNumber = 0;
|
||||||
this.score = 0;
|
this.setScore(0);
|
||||||
this.livesLeft = 5;
|
this.setLivesLeft(10);
|
||||||
|
|
||||||
this.nextWaveTimer = Script.setTimeout(this.startNextWave.bind(this), 100);
|
this.nextWaveTimer = Script.setTimeout(this.startNextWave.bind(this), 100);
|
||||||
this.spawnEnemyTimers = [];
|
this.spawnEnemyTimers = [];
|
||||||
this.checkEnemyPositionsTimer = null;
|
this.checkEnemyPositionsTimer = null;
|
||||||
this.enemyIDs = [];
|
this.enemyIDs = [];
|
||||||
|
|
||||||
this.gameState = GAME_STATES.PLAYING;
|
this.spawnQueue = [];
|
||||||
this.checkEnemyPositionsTimer = Script.setInterval(this.checkForEscapedEnemies.bind(this), 100);
|
|
||||||
|
this.gameState = GAME_STATES.PLAYING;
|
||||||
|
|
||||||
|
Audio.playSound(BEGIN_BUILDING_SOUND, {
|
||||||
|
volume: 1.0,
|
||||||
|
position: this.rootPosition
|
||||||
|
});
|
||||||
|
|
||||||
// Spawn bows
|
|
||||||
const bowPosition = Vec3.sum(this.roofPosition, { x: 0, y: 1, z: 0 });
|
|
||||||
for (var j = 0; j < 4; ++j) {
|
|
||||||
this.entityIDs.push(Entities.addEntity({
|
|
||||||
position: bowPosition,
|
|
||||||
"collisionsWillMove": 1,
|
|
||||||
"compoundShapeURL": Script.resolvePath("bow/bow_collision_hull.obj"),
|
|
||||||
"created": "2016-09-01T23:57:55Z",
|
|
||||||
"dimensions": {
|
|
||||||
"x": 0.039999999105930328,
|
|
||||||
"y": 1.2999999523162842,
|
|
||||||
"z": 0.20000000298023224
|
|
||||||
},
|
|
||||||
"dynamic": 1,
|
|
||||||
"gravity": {
|
|
||||||
"x": 0,
|
|
||||||
"y": -1,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"modelURL": Script.resolvePath("bow/bow-deadly.fbx"),
|
|
||||||
"name": "WG.Hifi-Bow",
|
|
||||||
"rotation": {
|
|
||||||
"w": 0.9718012809753418,
|
|
||||||
"x": 0.15440607070922852,
|
|
||||||
"y": -0.10469216108322144,
|
|
||||||
"z": -0.14418250322341919
|
|
||||||
},
|
|
||||||
"script": Script.resolvePath("bow/bow.js"),
|
|
||||||
"shapeType": "compound",
|
|
||||||
"type": "Model",
|
|
||||||
"userData": "{\"grabbableKey\":{\"grabbable\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.0813,\"y\":0.0452,\"z\":0.0095},{\"x\":-0.3946,\"y\":-0.6604,\"z\":0.4748,\"w\":-0.4275}],\"LeftHand\":[{\"x\":-0.0881,\"y\":0.0259,\"z\":0.0159},{\"x\":0.4427,\"y\":-0.6519,\"z\":0.4592,\"w\":0.4099}]}}}"
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
startNextWave: function() {
|
startNextWave: function() {
|
||||||
print("Starting next wave");
|
print("Starting next wave");
|
||||||
|
this.gameState = GAME_STATES.PLAYING;
|
||||||
this.waveNumber++;
|
this.waveNumber++;
|
||||||
this.enemyIDs = [];
|
this.enemyIDs = [];
|
||||||
const numberOfEnemiesToSpawn = this.waveNumber * 2;
|
this.spawnQueue = [];
|
||||||
print("Number to spawn:", numberOfEnemiesToSpawn, this.waveNumber);
|
this.spawnStartTime = Date.now();
|
||||||
for (var i = 0; i < numberOfEnemiesToSpawn; ++i) {
|
|
||||||
Vec3.print(i, this.spawnPositions[i % this.spawnPositions.length]);
|
Entities.editEntity(this.waveDisplayID, {
|
||||||
// Spawn enemy
|
text: "Wave: " + this.waveNumber
|
||||||
var enemyID = Entities.addEntity({
|
});
|
||||||
name: "WG.Enemy",
|
|
||||||
type: "Box",
|
var numberOfEnemiesLeftToSpawn = this.waveNumber * 2;
|
||||||
position: this.spawnPositions[i % this.spawnPositions.length],
|
var delayBetweenSpawns = 2000 / Math.max(1, Math.log(this.waveNumber));
|
||||||
registrationPoint: { x: 0.5, y: 0, z: 0.5 },
|
var currentDelay = 2000;
|
||||||
dimensions: { x: 0.7, y: 0.7, z: 0.7 },
|
|
||||||
velocity: {
|
print("Number of enemies:", numberOfEnemiesLeftToSpawn);
|
||||||
x: 0,
|
this.checkEnemyPositionsTimer = Script.setInterval(this.checkForEscapedEnemies.bind(this), 100);
|
||||||
y: 0,
|
|
||||||
z: -3
|
for (var i = 0; i < numberOfEnemiesLeftToSpawn; ++i) {
|
||||||
},
|
print("Adding enemy");
|
||||||
dynamic: true,
|
var idx = Math.floor(getRandom() * this.spawnPositions.length);
|
||||||
gravity: {
|
this.spawnQueue.push({ spawnAt: currentDelay, position: this.spawnPositions[idx] });
|
||||||
x: 0,
|
currentDelay += delayBetweenSpawns;
|
||||||
y: -10,
|
|
||||||
z: 0,
|
|
||||||
},
|
|
||||||
restitution: 0,
|
|
||||||
friction: 0,
|
|
||||||
damping: 0,
|
|
||||||
linearDamping: 0,
|
|
||||||
lifetime: 100,
|
|
||||||
script: Script.resolvePath('enemyEntity.js'),
|
|
||||||
userData: JSON.stringify({
|
|
||||||
gameChannel: COMM_CHANNEL_NAME,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
this.enemyIDs.push(enemyID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("Starting wave", this.waveNumber);
|
||||||
|
|
||||||
},
|
},
|
||||||
checkWaveComplete: function() {
|
checkWaveComplete: function() {
|
||||||
if (this.gameState !== GAME_STATES.PLAYING) {
|
if (this.gameState !== GAME_STATES.PLAYING) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.enemyIDs.length == 0) {
|
if (this.spawnQueue.length <= 0 && this.enemyIDs.length === 0) {
|
||||||
Script.setTimeout(this.startNextWave.bind(this), 1000);
|
this.gameState = GAME_STATES.BETWEEN_WAVES;
|
||||||
|
Script.setTimeout(this.startNextWave.bind(this), 5000);
|
||||||
|
|
||||||
|
Script.clearInterval(this.checkEnemyPositionsTimer);
|
||||||
|
this.checkEnemyPositionsTimer = null;
|
||||||
|
|
||||||
|
Audio.playSound(WAVE_COMPLETE_SOUND, {
|
||||||
|
volume: 1.0,
|
||||||
|
position: this.rootPosition
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setLivesLeft: function(lives) {
|
||||||
|
lives = Math.max(0, lives);
|
||||||
|
this.livesLeft = lives;
|
||||||
|
Entities.editEntity(this.livesDisplayID, {
|
||||||
|
text: "Lives: " + this.livesLeft
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setScore: function(score) {
|
||||||
|
this.score = score;
|
||||||
|
Entities.editEntity(this.scoreDisplayID, {
|
||||||
|
text: "Score: " + utils.formatNumberWithCommas(this.score)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
checkSpawnQueue: function() {
|
||||||
|
var waveElapsedTime = Date.now() - this.spawnStartTime;
|
||||||
|
while (this.spawnQueue.length > 0 && waveElapsedTime > this.spawnQueue[0].spawnAt) {
|
||||||
|
baseEnemyProperties.position = this.spawnQueue[0].position;
|
||||||
|
var entityID = Entities.addEntity(baseEnemyProperties);
|
||||||
|
this.enemyIDs.push(entityID);
|
||||||
|
this.spawnQueue.splice(0, 1);
|
||||||
|
}
|
||||||
|
print("Spawn queue size: ", this.spawnQueue.length, "Elapsed time: ", waveElapsedTime, "Number of enemies:", this.enemyIDs.length);
|
||||||
|
},
|
||||||
checkForEscapedEnemies: function() {
|
checkForEscapedEnemies: function() {
|
||||||
|
// Move this somewhere else?
|
||||||
|
this.checkSpawnQueue();
|
||||||
|
|
||||||
var enemiesEscaped = false;
|
var enemiesEscaped = false;
|
||||||
for (var i = this.enemyIDs.length - 1; i >= 0; --i) {
|
for (var i = this.enemyIDs.length - 1; i >= 0; --i) {
|
||||||
var position = Entities.getEntityProperties(this.enemyIDs[i], 'position').position;
|
var position = Entities.getEntityProperties(this.enemyIDs[i], 'position').position;
|
||||||
if (position && position.z < this.gatePosition.z) {
|
if (position && position.z < this.gatePosition.z) {
|
||||||
Entities.deleteEntity(this.enemyIDs[i]);
|
Entities.deleteEntity(this.enemyIDs[i]);
|
||||||
this.enemyIDs.splice(i, 1);
|
this.enemyIDs.splice(i, 1);
|
||||||
this.livesLeft--;
|
this.setLivesLeft(this.livesLeft - 1);
|
||||||
|
this.numberOfEntitiesLeftForWave--;
|
||||||
enemiesEscaped = true;
|
enemiesEscaped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print("LIVES LEFT: ", this.livesLeft);
|
print("LIVES LEFT: ", this.livesLeft, this.numberOfEntitiesLeftForWave);
|
||||||
if (this.livesLeft <= 0) {
|
if (this.livesLeft <= 0) {
|
||||||
this.endGame();
|
this.endGame();
|
||||||
} else if (enemiesEscaped) {
|
} else if (enemiesEscaped) {
|
||||||
|
@ -212,7 +253,12 @@ GameManager.prototype = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entities.editEntity(this.startButtonID, { visible: true });
|
Audio.playSound(GAME_OVER_SOUND, {
|
||||||
|
volume: 1.0,
|
||||||
|
position: this.rootPosition
|
||||||
|
});
|
||||||
|
|
||||||
|
Entities.editEntity(this.livesDisplayID, { text: "GAME OVER" });
|
||||||
|
|
||||||
this.gameState = GAME_STATES.GAME_OVER;
|
this.gameState = GAME_STATES.GAME_OVER;
|
||||||
print("GAME OVER");
|
print("GAME OVER");
|
||||||
|
@ -222,16 +268,23 @@ GameManager.prototype = {
|
||||||
this.nextWaveTimer = null;
|
this.nextWaveTimer = null;
|
||||||
for (var i = 0; i < this.spawnEnemyTimers.length; ++i) {
|
for (var i = 0; i < this.spawnEnemyTimers.length; ++i) {
|
||||||
Script.clearTimeout(this.spawnEnemyTimers[i]);
|
Script.clearTimeout(this.spawnEnemyTimers[i]);
|
||||||
this.spawnEnemyTimers = [];
|
|
||||||
}
|
}
|
||||||
|
this.spawnEnemyTimers = [];
|
||||||
|
|
||||||
Script.clearInterval(this.checkEnemyPositionsTimer);
|
Script.clearInterval(this.checkEnemyPositionsTimer);
|
||||||
this.checkEnemyPositionsTimer = null;
|
this.checkEnemyPositionsTimer = null;
|
||||||
|
|
||||||
Script.setTimeout(function() {
|
Script.setTimeout(function() {
|
||||||
|
Entities.editEntity(this.startButtonID, { visible: true });
|
||||||
this.gameState = GAME_STATES.IDLE;
|
this.gameState = GAME_STATES.IDLE;
|
||||||
}.bind(this), 3000);
|
}.bind(this), 3000);
|
||||||
|
|
||||||
|
for (var i = 0; i < this.enemyIDs.length; i++) {
|
||||||
|
Entities.deleteEntity(this.enemyIDs[i]);
|
||||||
|
}
|
||||||
|
this.enemyIDs = [];
|
||||||
},
|
},
|
||||||
onEnemyKilled: function(entityID) {
|
onEnemyKilled: function(entityID, position) {
|
||||||
if (this.gameState !== GAME_STATES.PLAYING) {
|
if (this.gameState !== GAME_STATES.PLAYING) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -239,9 +292,14 @@ GameManager.prototype = {
|
||||||
var idx = this.enemyIDs.indexOf(entityID);
|
var idx = this.enemyIDs.indexOf(entityID);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
this.enemyIDs.splice(idx, 1);
|
this.enemyIDs.splice(idx, 1);
|
||||||
|
Audio.playSound(EXPLOSION_SOUND, {
|
||||||
|
volume: 1.0,
|
||||||
|
position: position
|
||||||
|
});
|
||||||
|
|
||||||
|
this.numberOfEntitiesLeftForWave--;
|
||||||
// Update score
|
// Update score
|
||||||
this.score += 100;
|
this.setScore(this.score + 100);
|
||||||
print("SCORE: ", this.score);
|
print("SCORE: ", this.score);
|
||||||
|
|
||||||
this.checkWaveComplete();
|
this.checkWaveComplete();
|
||||||
|
@ -263,7 +321,7 @@ GameManager.prototype = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function createLocalGame() {
|
function createLocalGame() {
|
||||||
const rootPosition = findSurfaceBelowPosition(MyAvatar.position);
|
const rootPosition = utils.findSurfaceBelowPosition(MyAvatar.position);
|
||||||
|
|
||||||
// Create start button
|
// Create start button
|
||||||
var buttonProperties = {
|
var buttonProperties = {
|
||||||
|
@ -350,8 +408,111 @@ function createLocalGame() {
|
||||||
spawnPositions.push(spawnPosition);
|
spawnPositions.push(spawnPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const waveDisplayID = Entities.addEntity({
|
||||||
|
type: "Text",
|
||||||
|
name: "WG.Wave",
|
||||||
|
position: Vec3.sum(rootPosition, {
|
||||||
|
x: 0,
|
||||||
|
y: 9,
|
||||||
|
z: 10
|
||||||
|
}),
|
||||||
|
"backgroundColor": {
|
||||||
|
"blue": 255,
|
||||||
|
"green": 255,
|
||||||
|
"red": 255
|
||||||
|
},
|
||||||
|
"lineHeight": 1,
|
||||||
|
"rotation": {
|
||||||
|
"w": -4.3711388286737929e-08,
|
||||||
|
"x": 0,
|
||||||
|
"y": -1,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"dimensions": {
|
||||||
|
"x": 10,
|
||||||
|
"y": 1.7218999862670898,
|
||||||
|
"z": 0.0099999997764825821
|
||||||
|
},
|
||||||
|
"text": "Game Over",
|
||||||
|
"textColor": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0
|
||||||
|
},
|
||||||
|
});
|
||||||
|
entityIDs.push(waveDisplayID);
|
||||||
|
|
||||||
|
const scoreDisplayID = Entities.addEntity({
|
||||||
|
type: "Text",
|
||||||
|
name: "WG.Score",
|
||||||
|
position: Vec3.sum(rootPosition, {
|
||||||
|
x: 0,
|
||||||
|
y: 7,
|
||||||
|
z: 10
|
||||||
|
}),
|
||||||
|
"backgroundColor": {
|
||||||
|
"blue": 255,
|
||||||
|
"green": 255,
|
||||||
|
"red": 255
|
||||||
|
},
|
||||||
|
"lineHeight": 1,
|
||||||
|
"rotation": {
|
||||||
|
"w": -4.3711388286737929e-08,
|
||||||
|
"x": 0,
|
||||||
|
"y": -1,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"dimensions": {
|
||||||
|
"x": 10,
|
||||||
|
"y": 1.7218999862670898,
|
||||||
|
"z": 0.0099999997764825821
|
||||||
|
},
|
||||||
|
"text": "Game Over",
|
||||||
|
"textColor": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0
|
||||||
|
},
|
||||||
|
});
|
||||||
|
entityIDs.push(scoreDisplayID);
|
||||||
|
|
||||||
|
const livesDisplayID = Entities.addEntity({
|
||||||
|
type: "Text",
|
||||||
|
name: "WG.Lives",
|
||||||
|
position: Vec3.sum(rootPosition, {
|
||||||
|
x: 0,
|
||||||
|
y: 5,
|
||||||
|
z: 10
|
||||||
|
}),
|
||||||
|
"backgroundColor": {
|
||||||
|
"blue": 255,
|
||||||
|
"green": 255,
|
||||||
|
"red": 255
|
||||||
|
},
|
||||||
|
"lineHeight": 1,
|
||||||
|
"rotation": {
|
||||||
|
"w": -4.3711388286737929e-08,
|
||||||
|
"x": 0,
|
||||||
|
"y": -1,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"dimensions": {
|
||||||
|
"x": 10,
|
||||||
|
"y": 1.7218999862670898,
|
||||||
|
"z": 0.0099999997764825821
|
||||||
|
},
|
||||||
|
"text": "Game Over",
|
||||||
|
"textColor": {
|
||||||
|
"blue": 0,
|
||||||
|
"green": 0,
|
||||||
|
"red": 0
|
||||||
|
},
|
||||||
|
});
|
||||||
|
entityIDs.push(livesDisplayID);
|
||||||
|
|
||||||
|
|
||||||
var goalPositionFront = Vec3.sum(goalPosition, { x: 0, y: 0, z: BASES_SIZE / 2 });
|
var goalPositionFront = Vec3.sum(goalPosition, { x: 0, y: 0, z: BASES_SIZE / 2 });
|
||||||
return new GameManager(goalPositionFront, roofPosition, spawnPositions, buttonID);
|
return new GameManager(rootPosition, goalPositionFront, roofPosition, spawnPositions, buttonID, waveDisplayID, scoreDisplayID, livesDisplayID);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createACGame() {
|
function createACGame() {
|
||||||
|
@ -372,7 +533,7 @@ Messages.subscribe(COMM_CHANNEL_NAME);
|
||||||
Messages.messageReceived.connect(function(channel, messageJSON, senderID) {
|
Messages.messageReceived.connect(function(channel, messageJSON, senderID) {
|
||||||
print("playWaveGame.js | Recieved: " + messageJSON + " from " + senderID);
|
print("playWaveGame.js | Recieved: " + messageJSON + " from " + senderID);
|
||||||
if (channel === COMM_CHANNEL_NAME) {
|
if (channel === COMM_CHANNEL_NAME) {
|
||||||
var message = parseJSON(messageJSON);
|
var message = utils.parseJSON(messageJSON);
|
||||||
if (message === undefined) {
|
if (message === undefined) {
|
||||||
print("playWaveGame.js | Received non-json message");
|
print("playWaveGame.js | Received non-json message");
|
||||||
return;
|
return;
|
||||||
|
@ -382,7 +543,7 @@ Messages.messageReceived.connect(function(channel, messageJSON, senderID) {
|
||||||
gameManager.startGame();
|
gameManager.startGame();
|
||||||
break;
|
break;
|
||||||
case 'enemy-killed':
|
case 'enemy-killed':
|
||||||
gameManager.onEnemyKilled(message.entityID);
|
gameManager.onEnemyKilled(message.entityID, message.position);
|
||||||
break;
|
break;
|
||||||
case 'enemy-escaped':
|
case 'enemy-escaped':
|
||||||
gameManager.onEnemyEscaped(message.entityID);
|
gameManager.onEnemyEscaped(message.entityID);
|
||||||
|
|
|
@ -1,20 +1,35 @@
|
||||||
(function() {
|
(function() {
|
||||||
var itemID;
|
Script.include('utils.js');
|
||||||
|
|
||||||
this.preload = function(entityID) {
|
StartButton = function() {
|
||||||
itemID = entityID;
|
};
|
||||||
}
|
StartButton.prototype = {
|
||||||
|
preload: function(entityID) {
|
||||||
|
this.entityID = entityID;
|
||||||
|
Script.addEventHandler(entityID, "collisionWithEntity", this.onCollide.bind(this));
|
||||||
|
},
|
||||||
|
signalAC: function() {
|
||||||
|
print("Button pressed");
|
||||||
|
var userData = Entities.getEntityProperties(this.entityID, ["userData"]).userData;
|
||||||
|
print("Sending message to: ", JSON.parse(userData).gameChannel);
|
||||||
|
Messages.sendMessage(JSON.parse(userData).gameChannel, JSON.stringify({
|
||||||
|
type: 'start-game'
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
onCollide: function(entityA, entityB, collision) {
|
||||||
|
print("Collided with: ", entityB);
|
||||||
|
|
||||||
function signalAC() {
|
var colliderName = Entities.getEntityProperties(entityB, 'name').name;
|
||||||
print("Button pressed");
|
|
||||||
var userData = Entities.getEntityProperties(itemID, ["userData"]).userData;
|
|
||||||
print("Sending message to: ", JSON.parse(userData).gameChannel);
|
|
||||||
Messages.sendMessage(JSON.parse(userData).gameChannel, JSON.stringify({
|
|
||||||
type: 'start-game'
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.startNearTrigger = signalAC;
|
if (colliderName.indexOf("projectile") > -1) {
|
||||||
this.startFarTrigger = signalAC;
|
this.signalAC();
|
||||||
this.clickDownOnEntity = signalAC;
|
}
|
||||||
})
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
StartButton.prototype.startNearTrigger = StartButton.prototype.signalAC;
|
||||||
|
StartButton.prototype.startFarTrigger = StartButton.prototype.signalAC;
|
||||||
|
StartButton.prototype.clickDownOnEntity = StartButton.prototype.signalAC;
|
||||||
|
|
||||||
|
return new StartButton();
|
||||||
|
});
|
||||||
|
|
|
@ -1,32 +1,6 @@
|
||||||
if (!Function.prototype.bind) {
|
|
||||||
Function.prototype.bind = function(oThis) {
|
|
||||||
if (typeof this !== 'function') {
|
|
||||||
// closest thing possible to the ECMAScript 5
|
|
||||||
// internal IsCallable function
|
|
||||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
|
||||||
}
|
|
||||||
|
|
||||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
|
||||||
fToBind = this,
|
|
||||||
fNOP = function() {},
|
|
||||||
fBound = function() {
|
|
||||||
return fToBind.apply(this instanceof fNOP
|
|
||||||
? this
|
|
||||||
: oThis,
|
|
||||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.prototype) {
|
|
||||||
// Function.prototype doesn't have a prototype property
|
|
||||||
fNOP.prototype = this.prototype;
|
|
||||||
}
|
|
||||||
fBound.prototype = new fNOP();
|
|
||||||
|
|
||||||
return fBound;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
Script.include('utils.js');
|
||||||
|
|
||||||
function parseJSON(json) {
|
function parseJSON(json) {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(json);
|
return JSON.parse(json);
|
||||||
|
@ -45,7 +19,7 @@ if (!Function.prototype.bind) {
|
||||||
this.entityIDsThatHaveCollidedWithMe = [];
|
this.entityIDsThatHaveCollidedWithMe = [];
|
||||||
|
|
||||||
var userData = Entities.getEntityProperties(this.entityID, 'userData').userData;
|
var userData = Entities.getEntityProperties(this.entityID, 'userData').userData;
|
||||||
var data = parseJSON(userData);
|
var data = utils.parseJSON(userData);
|
||||||
if (data !== undefined && data.gameChannel !== undefined && data.teamNumber !== undefined) {
|
if (data !== undefined && data.gameChannel !== undefined && data.teamNumber !== undefined) {
|
||||||
this.gameChannel = data.gameChannel;
|
this.gameChannel = data.gameChannel;
|
||||||
this.teamNumber = data.teamNumber;
|
this.teamNumber = data.teamNumber;
|
||||||
|
|
|
@ -38,6 +38,10 @@
|
||||||
enterEntity: function() {
|
enterEntity: function() {
|
||||||
print("teamAreaEntity.js | Entered");
|
print("teamAreaEntity.js | Entered");
|
||||||
this.inEntity = true;
|
this.inEntity = true;
|
||||||
|
var props = Entities.getEntityProperties(this.entityID, ['position', 'dimensions', 'registrationPoint']);
|
||||||
|
var teleportPoint = MyAvatar.position;
|
||||||
|
teleportPoint.y = props.position.y + (props.dimensions.y * (1 - props.registrationPoint.y)) + 0.5;
|
||||||
|
MyAvatar.position = teleportPoint;
|
||||||
},
|
},
|
||||||
leaveEntity: function() {
|
leaveEntity: function() {
|
||||||
print("teamAreaEntity.js | Exited");
|
print("teamAreaEntity.js | Exited");
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
if (!Function.prototype.bind) {
|
||||||
|
Function.prototype.bind = function(oThis) {
|
||||||
|
if (typeof this !== 'function') {
|
||||||
|
// closest thing possible to the ECMAScript 5
|
||||||
|
// internal IsCallable function
|
||||||
|
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
||||||
|
}
|
||||||
|
|
||||||
|
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||||
|
fToBind = this,
|
||||||
|
fNOP = function() {},
|
||||||
|
fBound = function() {
|
||||||
|
return fToBind.apply(this instanceof fNOP
|
||||||
|
? this
|
||||||
|
: oThis,
|
||||||
|
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.prototype) {
|
||||||
|
// Function.prototype doesn't have a prototype property
|
||||||
|
fNOP.prototype = this.prototype;
|
||||||
|
}
|
||||||
|
fBound.prototype = new fNOP();
|
||||||
|
|
||||||
|
return fBound;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
utils = {
|
||||||
|
parseJSON: function(json) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(json);
|
||||||
|
} catch(e) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
findSurfaceBelowPosition: function(pos) {
|
||||||
|
var result = Entities.findRayIntersection({
|
||||||
|
origin: pos,
|
||||||
|
direction: { x: 0, y: -1, z: 0 }
|
||||||
|
});
|
||||||
|
if (result.intersects) {
|
||||||
|
return result.intersection;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
},
|
||||||
|
formatNumberWithCommas: function(number) {
|
||||||
|
return number + "";
|
||||||
|
if (number === 0) {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
var str = "";
|
||||||
|
|
||||||
|
while (number > 0) {
|
||||||
|
// Grab the digits in the
|
||||||
|
var belowThousand = number % 1000;
|
||||||
|
if (str !== "") {
|
||||||
|
str = "," + str;
|
||||||
|
}
|
||||||
|
str = belowThousand + str;
|
||||||
|
number = Math.floor(number / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in a new issue