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,
z: 1
};
var BLOCK_LIFETIME = 10;
var BLOCK_LIFETIME = 120;
var MUZZLE_SOUND_URL = Script.resolvePath("air_gun_1_converted.wav");
var MUZZLE_SOUND_VOLUME = 0.5;
@ -35,6 +35,7 @@
}
this.launchBlock = function () {
print("launch.js | Launching block");
var cylinder = Entities.getEntityProperties(cylinderID, ["position", "rotation", "dimensions"]);
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 }));
@ -45,6 +46,7 @@
Entities.addEntity({
type: "Model",
name: "TD.block",
modelURL: BLOCK_MODEL_URL,
shapeType: "compound",
//compoundShapeURL: BLOCK_COMPOUND_SHAPE_URL,
@ -55,7 +57,8 @@
position: muzzlePosition,
rotation: Quat.multiply(cylinder.rotation, Quat.fromPitchYawRollDegrees(0.0, Math.random() * 360.0, 0.0)),
velocity: muzzleVelocity,
lifetime: BLOCK_LIFETIME
lifetime: BLOCK_LIFETIME,
script: Script.resolvePath("destructibleEntity.js")
});
Audio.playSound(muzzleSound, {
@ -66,14 +69,17 @@
}
this.clickDownOnEntity = function () {
print("launch.js | got click down");
this.launchBlock();
}
this.startNearTrigger = function () {
print("launch.js | got start near trigger");
this.launchBlock();
}
this.startFarTrigger = function () {
print("launch.js | got start far trigger");
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 data = parseJSON(userData);
if (data !== undefined && data.gameChannel) {
this.gameChannel = data.gameChannel
if (data !== undefined && data.gameChannel !== undefined && data.teamNumber !== undefined) {
this.gameChannel = data.gameChannel;
this.teamNumber = data.teamNumber;
} 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) {
@ -63,7 +64,8 @@ if (!Function.prototype.bind) {
this.entityIDsThatHaveCollidedWithMe.push(entityB);
Messages.sendMessage(this.gameChannel, JSON.stringify({
type: "target-hit",
entityID: this.entityID
entityID: this.entityID,
teamNumber: this.teamNumber
}));
}
}

View file

@ -7,10 +7,12 @@
function signalAC() {
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.startFarTrigger = signalAC;
this.clickDownOnEntity = signalAC;
})
})

View file

@ -29,38 +29,34 @@ var GAME_STATES = {
};
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 BASES = [
{
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 BASES_SIZE = 15;
var TARGET_SIZE = 2;
var BASES_HEIGHT = 6;
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);
@ -73,6 +69,13 @@ var bases = [];
var entityIDs = [];
var spawnerIDs = [];
var teamEntities = {
0: {},
1: {},
2: {},
3: {},
};
var currentState = GAME_STATES.IDLE;
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_FIGHTING_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/fight.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();
@ -123,7 +127,9 @@ function setup() {
})
};
// Base block
bases.push(Entities.addEntity(arenaProperties));
var arenaID = Entities.addEntity(arenaProperties)
bases.push(arenaID);
teamEntities[i].arenaID = arenaID;
const ROOF_HEIGHT = 0.2;
@ -135,16 +141,29 @@ function setup() {
registrationPoint: { x: 0.5, y: 0, z: 0.5 },
dimensions: { x: BASES_SIZE, y: ROOF_HEIGHT, z: BASES_SIZE },
color: BASES[i].color,
script: Script.resolvePath('roofEntity.js'),
userData: JSON.stringify({
gameChannel: CHANNEL_NAME,
})
}
// Player area
bases.push(Entities.addEntity(roofProperties));
var roofID = Entities.addEntity(roofProperties)
bases.push(roofID);
teamEntities[i].roofID = roofID;
}
}
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) {
Entities.deleteEntity(bases.pop());
}
@ -155,16 +174,33 @@ function cleanup() {
Entities.deleteEntity(entityIDs[i]);
}
entityIDs = [];
for (var i = 0; i < spawnerIDs.length; ++i) {
Entities.deleteEntity(spawnerIDs[i]);
}
spawnerIDs = [];
print("============= Script Stopping =============");
Script.stop();
}
Messages.messageReceived.connect(function(channel, message, senderID) {
print("Recieved: " + message + " from " + senderID);
function parseJSON(json) {
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) {
switch (message) {
case "START":
var message = parseJSON(messageJSON);
if (message === undefined) {
print("towerDefense.js | Received non-json message");
return;
}
switch (message.type) {
case 'start-game':
if (currentState != GAME_STATES.IDLE) {
print("Got start message, but not in idle state. Current state: " + currentState);
return;
@ -185,9 +221,11 @@ Messages.messageReceived.connect(function(channel, message, senderID) {
script: Script.resolvePath("targetEntity.js"),
userData: JSON.stringify({
gameChannel: CHANNEL_NAME,
teamNumber: i
}),
});
entityIDs.push(targetID);
teamEntities[i].targetID = targetID;
// Create box spawner
var spawnerID = Entities.addEntity({
@ -198,9 +236,13 @@ Messages.messageReceived.connect(function(channel, message, senderID) {
color: BASES[i].color,
script: Script.resolvePath("launch.js"),
userData: JSON.stringify({
grabbableKey: {
wantsTrigger: true
},
gameChannel: CHANNEL_NAME,
})
});
teamEntities[i].spawnerID = targetID;
spawnerIDs.push(spawnerID);
Audio.playSound(BEGIN_BUILDING_SOUND, {
volume: 1.0,
@ -210,6 +252,12 @@ Messages.messageReceived.connect(function(channel, message, senderID) {
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() {
print("============ Done building, FIGHT =============");
@ -228,17 +276,74 @@ Messages.messageReceived.connect(function(channel, message, senderID) {
}
// 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);
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, {
volume: 1.0,
position: BASE_POSITION
});
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;
}