Add sounds and other improvements to tower defense

This commit is contained in:
Ryan Huffman 2016-12-06 09:20:26 -08:00
parent 8b9eef19c1
commit e2e0e9d96d
6 changed files with 169 additions and 45 deletions

View file

@ -18,7 +18,7 @@
y: 1, y: 1,
z: 1 z: 1
}; };
var BLOCK_LIFETIME = 10; var BLOCK_LIFETIME = 120;
var MUZZLE_SOUND_URL = Script.resolvePath("air_gun_1_converted.wav"); var MUZZLE_SOUND_URL = Script.resolvePath("air_gun_1_converted.wav");
var MUZZLE_SOUND_VOLUME = 0.5; var MUZZLE_SOUND_VOLUME = 0.5;
@ -35,6 +35,7 @@
} }
this.launchBlock = function () { this.launchBlock = function () {
print("launch.js | Launching block");
var cylinder = Entities.getEntityProperties(cylinderID, ["position", "rotation", "dimensions"]); var cylinder = Entities.getEntityProperties(cylinderID, ["position", "rotation", "dimensions"]);
var muzzlePosition = Vec3.sum(cylinder.position, var muzzlePosition = Vec3.sum(cylinder.position,
Vec3.multiplyQbyV(cylinder.rotation, { x: 0.0, y: 0.5 * (cylinder.dimensions.y + BLOCK_DIMENSIONS.y), Z: 0.0 })); Vec3.multiplyQbyV(cylinder.rotation, { x: 0.0, y: 0.5 * (cylinder.dimensions.y + BLOCK_DIMENSIONS.y), Z: 0.0 }));
@ -45,6 +46,7 @@
Entities.addEntity({ Entities.addEntity({
type: "Model", type: "Model",
name: "TD.block",
modelURL: BLOCK_MODEL_URL, modelURL: BLOCK_MODEL_URL,
shapeType: "compound", shapeType: "compound",
//compoundShapeURL: BLOCK_COMPOUND_SHAPE_URL, //compoundShapeURL: BLOCK_COMPOUND_SHAPE_URL,
@ -55,7 +57,8 @@
position: muzzlePosition, position: muzzlePosition,
rotation: Quat.multiply(cylinder.rotation, Quat.fromPitchYawRollDegrees(0.0, Math.random() * 360.0, 0.0)), rotation: Quat.multiply(cylinder.rotation, Quat.fromPitchYawRollDegrees(0.0, Math.random() * 360.0, 0.0)),
velocity: muzzleVelocity, velocity: muzzleVelocity,
lifetime: BLOCK_LIFETIME lifetime: BLOCK_LIFETIME,
script: Script.resolvePath("destructibleEntity.js")
}); });
Audio.playSound(muzzleSound, { Audio.playSound(muzzleSound, {
@ -66,14 +69,17 @@
} }
this.clickDownOnEntity = function () { this.clickDownOnEntity = function () {
print("launch.js | got click down");
this.launchBlock(); this.launchBlock();
} }
this.startNearTrigger = function () { this.startNearTrigger = function () {
print("launch.js | got start near trigger");
this.launchBlock(); this.launchBlock();
} }
this.startFarTrigger = function () { this.startFarTrigger = function () {
print("launch.js | got start far trigger");
this.launchBlock(); this.launchBlock();
} }
}) })

View file

@ -0,0 +1,9 @@
(function() {
return {
preload: function(entityID) {
Entities.editEntity(entityID, {
localRenderAlpha: 0.2
});
}
};
});

View file

@ -46,10 +46,11 @@ if (!Function.prototype.bind) {
var userData = Entities.getEntityProperties(this.entityID, 'userData').userData; var userData = Entities.getEntityProperties(this.entityID, 'userData').userData;
var data = parseJSON(userData); var data = parseJSON(userData);
if (data !== undefined && data.gameChannel) { if (data !== undefined && data.gameChannel !== undefined && data.teamNumber !== undefined) {
this.gameChannel = data.gameChannel this.gameChannel = data.gameChannel;
this.teamNumber = data.teamNumber;
} else { } else {
print("targetEntity.js | ERROR: userData does not contain a game channel"); print("targetEntity.js | ERROR: userData does not contain a game channel and/or team number");
} }
}, },
onCollide: function(entityA, entityB, collision) { onCollide: function(entityA, entityB, collision) {
@ -63,7 +64,8 @@ if (!Function.prototype.bind) {
this.entityIDsThatHaveCollidedWithMe.push(entityB); this.entityIDsThatHaveCollidedWithMe.push(entityB);
Messages.sendMessage(this.gameChannel, JSON.stringify({ Messages.sendMessage(this.gameChannel, JSON.stringify({
type: "target-hit", type: "target-hit",
entityID: this.entityID entityID: this.entityID,
teamNumber: this.teamNumber
})); }));
} }
} }

View file

@ -7,10 +7,12 @@
function signalAC() { function signalAC() {
var userData = Entities.getEntityProperties(itemID, ["userData"]).userData; var userData = Entities.getEntityProperties(itemID, ["userData"]).userData;
Messages.sendMessage(JSON.parse(userData).gameChannel, "START"); Messages.sendMessage(JSON.parse(userData).gameChannel, JSON.stringify({
type: 'start-game'
}));
} }
this.startNearTrigger = signalAC; this.startNearTrigger = signalAC;
this.startFarTrigger = signalAC; this.startFarTrigger = signalAC;
this.clickDownOnEntity = signalAC; this.clickDownOnEntity = signalAC;
}) })

View file

@ -29,38 +29,34 @@ var GAME_STATES = {
}; };
var BASE_POSITION = findSurfaceBelowPosition(MyAvatar.position); var BASE_POSITION = findSurfaceBelowPosition(MyAvatar.position);
var BUILD_TIME_SECONDS = 5; var BUILD_TIME_SECONDS = 60;
var BUTTON_POSITION = { x: 0, y: 0, z: 0 }; var BUTTON_POSITION = { x: 0, y: 0, z: 0 };
var BASES = [ var BASES_SIZE = 15;
{
position: { x: -20, y: 0, z: 0 },
color: { red: 255, green: 0, blue: 0 },
spawnerPosition: { x: -20, y: 0, z: -1 },
buttonPosition: { x: -20, y: 0, z: -1 },
},
{
position: { x: 20, y: 0, z: 0 },
color: { red: 0, green: 255, blue: 0 },
spawnerPosition: { x: 20, y: 0, z: 1 },
buttonPosition: { x: 20, y: 0, z: 1 },
},
{
position: { x: 0, y: 0, z: -20 },
color: { red: 0, green: 0, blue: 255 },
spawnerPosition: { x: 1, y: 0, z: -20 },
buttonPosition: { x: 1, y: 0, z: -20 },
},
{
position: { x: 0, y: 0, z: 20 },
color: { red: 255, green: 0, blue: 255 },
spawnerPosition: { x: -1, y: 0, z: 20 },
buttonPosition: { x: -1, y: 0, z: 20 },
},
];
var BASES_SIZE = 20;
var TARGET_SIZE = 2; var TARGET_SIZE = 2;
var BASES_HEIGHT = 6; var BASES_HEIGHT = 6;
var BASES_TRANSPARENCY = 0.2; var BASES_TRANSPARENCY = 0.2;
var BASES = [
{
position: { x: -15, y: 0, z: 0 },
color: { red: 255, green: 0, blue: 0 },
spawnerPosition: { x: -15 + BASES_SIZE/2, y: 0, z: -BASES_SIZE/2 },
},
{
position: { x: 15, y: 0, z: 0 },
color: { red: 0, green: 255, blue: 0 },
spawnerPosition: { x: 15 - BASES_SIZE/2, y: 0, z: BASES_SIZE/2 },
},
{
position: { x: 0, y: 0, z: -15 },
color: { red: 0, green: 0, blue: 255 },
spawnerPosition: { x: BASES_SIZE/2, y: 0, z: -15 + BASES_SIZE/2 },
},
{
position: { x: 0, y: 0, z: 15 },
color: { red: 255, green: 0, blue: 255 },
spawnerPosition: { x: -BASES_SIZE/2, y: 0, z: 15 - BASES_SIZE/2 },
},
];
var CHANNEL_NAME = "tower-defense-" //+ Math.floor(Math.random() * 9999); var CHANNEL_NAME = "tower-defense-" //+ Math.floor(Math.random() * 9999);
@ -73,6 +69,13 @@ var bases = [];
var entityIDs = []; var entityIDs = [];
var spawnerIDs = []; var spawnerIDs = [];
var teamEntities = {
0: {},
1: {},
2: {},
3: {},
};
var currentState = GAME_STATES.IDLE; var currentState = GAME_STATES.IDLE;
Messages.subscribe(CHANNEL_NAME); Messages.subscribe(CHANNEL_NAME);
@ -85,6 +88,7 @@ if (this.EntityViewer) {
var BEGIN_BUILDING_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/letTheGamesBegin.wav")); var BEGIN_BUILDING_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/letTheGamesBegin.wav"));
var BEGIN_FIGHTING_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/fight.wav")); var BEGIN_FIGHTING_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/fight.wav"));
var GAME_OVER_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/gameOver.wav")); var GAME_OVER_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/gameOver.wav"));
var TEN_SECONDS_REMAINING_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/tenSecondsRemaining.wav"));
setup(); setup();
@ -123,7 +127,9 @@ function setup() {
}) })
}; };
// Base block // Base block
bases.push(Entities.addEntity(arenaProperties)); var arenaID = Entities.addEntity(arenaProperties)
bases.push(arenaID);
teamEntities[i].arenaID = arenaID;
const ROOF_HEIGHT = 0.2; const ROOF_HEIGHT = 0.2;
@ -135,16 +141,29 @@ function setup() {
registrationPoint: { x: 0.5, y: 0, z: 0.5 }, registrationPoint: { x: 0.5, y: 0, z: 0.5 },
dimensions: { x: BASES_SIZE, y: ROOF_HEIGHT, z: BASES_SIZE }, dimensions: { x: BASES_SIZE, y: ROOF_HEIGHT, z: BASES_SIZE },
color: BASES[i].color, color: BASES[i].color,
script: Script.resolvePath('roofEntity.js'),
userData: JSON.stringify({ userData: JSON.stringify({
gameChannel: CHANNEL_NAME, gameChannel: CHANNEL_NAME,
}) })
} }
// Player area // Player area
bases.push(Entities.addEntity(roofProperties)); var roofID = Entities.addEntity(roofProperties)
bases.push(roofID);
teamEntities[i].roofID = roofID;
} }
} }
function cleanup() { function cleanup() {
for (var i = 0; i < 4; ++i) {
var t = teamEntities[i];
Entities.deleteEntity(t.targetID);
Entities.deleteEntity(t.spawnerID);
for (var j = 0; j < t.bowIDs.length; ++j) {
Entities.deleteEntity(t.bowIDs[j]);
}
Entities.deleteEntity(t.roofID);
Entities.deleteEntity(t.arenaID);
}
while (bases.length > 0) { while (bases.length > 0) {
Entities.deleteEntity(bases.pop()); Entities.deleteEntity(bases.pop());
} }
@ -155,16 +174,33 @@ function cleanup() {
Entities.deleteEntity(entityIDs[i]); Entities.deleteEntity(entityIDs[i]);
} }
entityIDs = []; entityIDs = [];
for (var i = 0; i < spawnerIDs.length; ++i) {
Entities.deleteEntity(spawnerIDs[i]);
}
spawnerIDs = [];
print("============= Script Stopping ============="); print("============= Script Stopping =============");
Script.stop(); Script.stop();
} }
Messages.messageReceived.connect(function(channel, message, senderID) { function parseJSON(json) {
print("Recieved: " + message + " from " + senderID); try {
return JSON.parse(json);
} catch (e) {
return undefined;
}
}
Messages.messageReceived.connect(function(channel, messageJSON, senderID) {
print("Recieved: " + messageJSON + " from " + senderID);
if (channel === CHANNEL_NAME) { if (channel === CHANNEL_NAME) {
switch (message) { var message = parseJSON(messageJSON);
case "START": if (message === undefined) {
print("towerDefense.js | Received non-json message");
return;
}
switch (message.type) {
case 'start-game':
if (currentState != GAME_STATES.IDLE) { if (currentState != GAME_STATES.IDLE) {
print("Got start message, but not in idle state. Current state: " + currentState); print("Got start message, but not in idle state. Current state: " + currentState);
return; return;
@ -185,9 +221,11 @@ Messages.messageReceived.connect(function(channel, message, senderID) {
script: Script.resolvePath("targetEntity.js"), script: Script.resolvePath("targetEntity.js"),
userData: JSON.stringify({ userData: JSON.stringify({
gameChannel: CHANNEL_NAME, gameChannel: CHANNEL_NAME,
teamNumber: i
}), }),
}); });
entityIDs.push(targetID); entityIDs.push(targetID);
teamEntities[i].targetID = targetID;
// Create box spawner // Create box spawner
var spawnerID = Entities.addEntity({ var spawnerID = Entities.addEntity({
@ -198,9 +236,13 @@ Messages.messageReceived.connect(function(channel, message, senderID) {
color: BASES[i].color, color: BASES[i].color,
script: Script.resolvePath("launch.js"), script: Script.resolvePath("launch.js"),
userData: JSON.stringify({ userData: JSON.stringify({
grabbableKey: {
wantsTrigger: true
},
gameChannel: CHANNEL_NAME, gameChannel: CHANNEL_NAME,
}) })
}); });
teamEntities[i].spawnerID = targetID;
spawnerIDs.push(spawnerID); spawnerIDs.push(spawnerID);
Audio.playSound(BEGIN_BUILDING_SOUND, { Audio.playSound(BEGIN_BUILDING_SOUND, {
volume: 1.0, volume: 1.0,
@ -210,6 +252,12 @@ Messages.messageReceived.connect(function(channel, message, senderID) {
currentState = GAME_STATES.BUILD; currentState = GAME_STATES.BUILD;
Script.setTimeout(function() {
Audio.playSound(TEN_SECONDS_REMAINING_SOUND, {
volume: 1.0,
position: BASE_POSITION
});
}, (BUILD_TIME_SECONDS - 10) * 1000);
Script.setTimeout(function() { Script.setTimeout(function() {
print("============ Done building, FIGHT ============="); print("============ Done building, FIGHT =============");
@ -228,17 +276,74 @@ Messages.messageReceived.connect(function(channel, message, senderID) {
} }
// Spawn bows // Spawn bows
for (var i = 0; i < BASES.length; ++i) {
var position = Vec3.sum(BASE_POSITION, BASES[i].position);
position.y += BASES_HEIGHT + 1;
teamEntities[i].bowIDs = [];
for (var j = 0; j < 4; ++j) {
teamEntities[i].bowIDs.push(Entities.addEntity({
position: position,
"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": "TD.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}]}}}"
}));
}
}
}, BUILD_TIME_SECONDS * 1000); }, BUILD_TIME_SECONDS * 1000);
break; break;
case "STOP": case 'target-hit':
print("Got target-hit for: ", message.teamNumber);
if (currentState !== GAME_STATES.FIGHT) {
return;
}
print("game is over");
Audio.playSound(GAME_OVER_SOUND, { Audio.playSound(GAME_OVER_SOUND, {
volume: 1.0, volume: 1.0,
position: BASE_POSITION position: BASE_POSITION
}); });
currentState = GAME_STATES.GAME_OVER; currentState = GAME_STATES.GAME_OVER;
cleanup();
currentState = GAME_STATES.IDLE; // Delete the entities for the team that lost
var t = teamEntities[message.teamNumber];
Entities.deleteEntity(t.targetID);
Entities.deleteEntity(t.spawnerID);
Entities.deleteEntity(t.roofID);
Entities.deleteEntity(t.arenaID);
// TODO If more than 1 team is still alive, don't cleanup
// Do a full cleanup after 10 seconds
Script.setTimeout(function() {
cleanup();
currentState = GAME_STATES.IDLE;
}, 10 * 1000);
break;
default:
print("towerDefense.js | Ignoring unknown message type: ", message.type);
break; break;
} }