mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
420 lines
14 KiB
JavaScript
420 lines
14 KiB
JavaScript
//
|
|
// spaceInvadersExample.js
|
|
// examples
|
|
//
|
|
// Created by Brad Hefta-Gaub on 1/30/14.
|
|
// Copyright 2014 High Fidelity, Inc.
|
|
//
|
|
// This is an example script that demonstrates a simple space invaders style of game
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
|
|
var VIRCADIA_PUBLIC_CDN = networkingConstants.PUBLIC_BUCKET_CDN_URL;
|
|
|
|
var iteration = 0;
|
|
|
|
var gameOver = false;
|
|
|
|
// horizontal movement of invaders
|
|
var invaderStepsPerCycle = 120; // the number of update steps it takes then invaders to move one column to the right
|
|
var invaderStepOfCycle = 0; // current iteration in the cycle
|
|
var invaderMoveDirection = 1; // 1 for moving to right, -1 for moving to left
|
|
var LEFT = ",";
|
|
var RIGHT = ".";
|
|
var FIRE = "SPACE";
|
|
var QUIT = "q";
|
|
|
|
print("Use:");
|
|
print(LEFT + " to move left");
|
|
print(RIGHT + " to move right");
|
|
print(FIRE + " to fire");
|
|
print(QUIT + " to quit");
|
|
|
|
// game length...
|
|
var itemLifetimes = 60; // 1 minute
|
|
|
|
|
|
// position the game to be basically near the avatar running the game...
|
|
var gameSize = { x: 10, y: 20, z: 1 };
|
|
var positionFromAvatarZ = 10;
|
|
|
|
var avatarX = MyAvatar.position.x;
|
|
var avatarY = MyAvatar.position.y;
|
|
var avatarZ = MyAvatar.position.z;
|
|
var gameAtX = avatarX;
|
|
var gameAtY = avatarY;
|
|
var gameAtZ = avatarZ;
|
|
|
|
// move the game to be "centered" on our X
|
|
if (gameAtX > (gameSize.x/2)) {
|
|
gameAtX -= (gameSize.x/2);
|
|
}
|
|
|
|
// move the game to be "offset slightly" on our Y
|
|
if (gameAtY > (gameSize.y/4)) {
|
|
gameAtY -= (gameSize.y/4);
|
|
}
|
|
|
|
|
|
// move the game to be positioned away on our Z
|
|
if (gameAtZ > positionFromAvatarZ) {
|
|
gameAtZ -= positionFromAvatarZ;
|
|
}
|
|
|
|
var gameAt = { x: gameAtX, y: gameAtY, z: gameAtZ };
|
|
var middleX = gameAt.x + (gameSize.x/2);
|
|
var middleY = gameAt.y + (gameSize.y/2);
|
|
|
|
var invaderSize = 0.4;
|
|
var shipSize = 0.25;
|
|
var missileSize = 1.0;
|
|
var myShip;
|
|
var myShipProperties;
|
|
|
|
// create the rows of space invaders
|
|
var invaders = new Array();
|
|
var numberOfRows = 3 // FIXME 5;
|
|
var invadersPerRow = 3 // FIXME 8;
|
|
var emptyColumns = 2; // number of invader width columns not filled with invaders
|
|
var invadersBottomCorner = { x: gameAt.x, y: middleY , z: gameAt.z };
|
|
var rowHeight = ((gameAt.y + gameSize.y) - invadersBottomCorner.y) / numberOfRows;
|
|
var columnWidth = gameSize.x / (invadersPerRow + emptyColumns);
|
|
|
|
// vertical movement of invaders
|
|
var invaderRowOffset = 0;
|
|
var stepsPerRow = 20; // number of steps before invaders really move a whole row down.
|
|
var yPerStep = rowHeight/stepsPerRow;
|
|
var stepsToGround = (middleY - gameAt.y) / yPerStep;
|
|
var maxInvaderRowOffset=stepsToGround;
|
|
|
|
// missile related items
|
|
var myMissile;
|
|
|
|
// sounds
|
|
var hitSound = SoundCache.getSound(VIRCADIA_PUBLIC_CDN + "sounds/Space%20Invaders/hit.raw");
|
|
var shootSound = SoundCache.getSound(VIRCADIA_PUBLIC_CDN + "sounds/Space%20Invaders/shoot.raw");
|
|
var moveSounds = new Array();
|
|
moveSounds[0] = SoundCache.getSound(VIRCADIA_PUBLIC_CDN + "sounds/Space%20Invaders/Lo1.raw");
|
|
moveSounds[1] = SoundCache.getSound(VIRCADIA_PUBLIC_CDN + "sounds/Space%20Invaders/Lo2.raw");
|
|
moveSounds[2] = SoundCache.getSound(VIRCADIA_PUBLIC_CDN + "sounds/Space%20Invaders/Lo3.raw");
|
|
moveSounds[3] = SoundCache.getSound(VIRCADIA_PUBLIC_CDN + "sounds/Space%20Invaders/Lo4.raw");
|
|
var currentMoveSound = 0;
|
|
var numberOfSounds = 4;
|
|
var stepsPerSound = invaderStepsPerCycle / numberOfSounds;
|
|
|
|
// if you set this to false, sounds will come from the location of entities instead of the player's head
|
|
var soundInMyHead = true;
|
|
|
|
// models...
|
|
var invaderModels = new Array();
|
|
invaderModels[0] = {
|
|
modelURL: VIRCADIA_PUBLIC_CDN + "meshes/space_invader.fbx",
|
|
modelScale: 450,
|
|
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
|
|
};
|
|
invaderModels[1] = {
|
|
modelURL: VIRCADIA_PUBLIC_CDN + "meshes/space_invader.fbx",
|
|
modelScale: 450,
|
|
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
|
|
};
|
|
invaderModels[2] = {
|
|
modelURL: VIRCADIA_PUBLIC_CDN + "meshes/space_invader.fbx",
|
|
modelScale: 450,
|
|
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
|
|
};
|
|
invaderModels[3] = {
|
|
modelURL: VIRCADIA_PUBLIC_CDN + "meshes/space_invader.fbx",
|
|
modelScale: 450,
|
|
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
|
|
};
|
|
invaderModels[4] = {
|
|
modelURL: VIRCADIA_PUBLIC_CDN + "meshes/space_invader.fbx",
|
|
modelScale: 450,
|
|
modelTranslation: { x: -1.3, y: -1.3, z: -1.3 },
|
|
};
|
|
|
|
|
|
|
|
//modelURL: VIRCADIA_PUBLIC_CDN + "meshes/Feisar_Ship.FBX",
|
|
//modelURL: VIRCADIA_PUBLIC_CDN + "meshes/invader.svo",
|
|
// VIRCADIA_PUBLIC_CDN + "meshes/spaceInvader3.fbx"
|
|
|
|
function initializeMyShip() {
|
|
myShipProperties = {
|
|
type: "Model",
|
|
position: { x: middleX , y: gameAt.y, z: gameAt.z },
|
|
velocity: { x: 0, y: 0, z: 0 },
|
|
gravity: { x: 0, y: 0, z: 0 },
|
|
damping: 0,
|
|
dimensions: { x: shipSize * 2, y: shipSize * 2, z: shipSize * 2 },
|
|
color: { red: 0, green: 255, blue: 0 },
|
|
modelURL: VIRCADIA_PUBLIC_CDN + "meshes/space_invader.fbx",
|
|
lifetime: itemLifetimes
|
|
};
|
|
myShip = Entities.addEntity(myShipProperties);
|
|
}
|
|
|
|
// calculate the correct invaderPosition for an column row
|
|
function getInvaderPosition(row, column) {
|
|
var xBasePart = invadersBottomCorner.x + (column * columnWidth);
|
|
var xMovePart = 0;
|
|
if (invaderMoveDirection > 0) {
|
|
xMovePart = (invaderMoveDirection * columnWidth * (invaderStepOfCycle/invaderStepsPerCycle));
|
|
} else {
|
|
xMovePart = columnWidth + (invaderMoveDirection * columnWidth * (invaderStepOfCycle/invaderStepsPerCycle));
|
|
}
|
|
|
|
var y = invadersBottomCorner.y + (row * rowHeight) - (invaderRowOffset * rowHeight/stepsPerRow);
|
|
|
|
var invaderPosition = {
|
|
x: xBasePart + xMovePart,
|
|
y: y,
|
|
z: invadersBottomCorner.z };
|
|
|
|
return invaderPosition;
|
|
}
|
|
|
|
function initializeInvaders() {
|
|
for (var row = 0; row < numberOfRows; row++) {
|
|
invaders[row] = new Array();
|
|
for (var column = 0; column < invadersPerRow; column++) {
|
|
invaderPosition = getInvaderPosition(row, column);
|
|
invaders[row][column] = Entities.addEntity({
|
|
type: "Model",
|
|
shapeType: "box",
|
|
position: invaderPosition,
|
|
velocity: { x: 0, y: 0, z: 0 },
|
|
gravity: { x: 0, y: 0, z: 0 },
|
|
damping: 0,
|
|
dimensions: { x: invaderSize * 2, y: invaderSize * 2, z: invaderSize * 2 },
|
|
color: { red: 255, green: 0, blue: 0 },
|
|
modelURL: invaderModels[row].modelURL,
|
|
dynamic: true,
|
|
lifetime: itemLifetimes
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
function moveInvaders() {
|
|
for (var row = 0; row < numberOfRows; row++) {
|
|
for (var column = 0; column < invadersPerRow; column++) {
|
|
props = Entities.getEntityProperties(invaders[row][column]);
|
|
if (props.id) {
|
|
invaderPosition = getInvaderPosition(row, column);
|
|
Entities.editEntity(invaders[row][column],
|
|
{
|
|
position: invaderPosition,
|
|
velocity: { x: 0, y: 0, z: 0 } // always reset this, incase they got collided with
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function displayGameOver() {
|
|
gameOver = true;
|
|
print("Game over...");
|
|
}
|
|
|
|
function update(deltaTime) {
|
|
if (!gameOver) {
|
|
//print("updating space invaders... iteration="+iteration);
|
|
iteration++;
|
|
|
|
if (invaderStepOfCycle % stepsPerSound == 0) {
|
|
// play the move sound
|
|
var options = {};
|
|
|
|
if (soundInMyHead) {
|
|
options.position = { x: MyAvatar.position.x + 0.0,
|
|
y: MyAvatar.position.y + 0.1,
|
|
z: MyAvatar.position.z + 0.0 };
|
|
} else {
|
|
options.position = getInvaderPosition(invadersPerRow / 2, numberOfRows / 2);
|
|
}
|
|
|
|
Audio.playSound(moveSounds[currentMoveSound], options);
|
|
|
|
// get ready for next move sound
|
|
currentMoveSound = (currentMoveSound+1) % numberOfSounds;
|
|
}
|
|
|
|
invaderStepOfCycle++;
|
|
|
|
|
|
if (invaderStepOfCycle > invaderStepsPerCycle) {
|
|
// handle left/right movement
|
|
invaderStepOfCycle = 0;
|
|
if (invaderMoveDirection > 0) {
|
|
invaderMoveDirection = -1;
|
|
} else {
|
|
invaderMoveDirection = 1;
|
|
}
|
|
|
|
// handle downward movement
|
|
invaderRowOffset++; // move down one row
|
|
//print("invaderRowOffset="+invaderRowOffset);
|
|
|
|
// check to see if invaders have reached "ground"...
|
|
if (invaderRowOffset > maxInvaderRowOffset) {
|
|
displayGameOver();
|
|
return;
|
|
}
|
|
|
|
}
|
|
moveInvaders();
|
|
}
|
|
}
|
|
|
|
// register the call back so it fires before each data send
|
|
Script.update.connect(update);
|
|
|
|
function cleanupGame() {
|
|
print("cleaning up game...");
|
|
Entities.deleteEntity(myShip);
|
|
print("cleanupGame() ... Entities.deleteEntity(myShip)... myShip="+myShip);
|
|
for (var row = 0; row < numberOfRows; row++) {
|
|
for (var column = 0; column < invadersPerRow; column++) {
|
|
Entities.deleteEntity(invaders[row][column]);
|
|
print("cleanupGame() ... Entities.deleteEntity(invaders[row][column])... invaders[row][column]="
|
|
+invaders[row][column]);
|
|
}
|
|
}
|
|
|
|
// clean up our missile
|
|
if (myMissile) {
|
|
Entities.deleteEntity(myMissile);
|
|
}
|
|
|
|
Controller.releaseKeyEvents({text: " "});
|
|
|
|
Script.stop();
|
|
}
|
|
Script.scriptEnding.connect(cleanupGame);
|
|
|
|
function endGame() {
|
|
print("ending game...");
|
|
Script.stop();
|
|
}
|
|
|
|
function moveShipTo(position) {
|
|
Entities.editEntity(myShip, { position: position });
|
|
}
|
|
|
|
function entityCollisionWithEntity(entityA, entityB, collision) {
|
|
print("entityCollisionWithEntity() a="+entityA + " b=" + entityB);
|
|
Vec3.print('entityCollisionWithEntity() penetration=', collision.penetration);
|
|
Vec3.print('entityCollisionWithEntity() contactPoint=', collision.contactPoint);
|
|
|
|
deleteIfInvader(entityB);
|
|
}
|
|
|
|
function fireMissile() {
|
|
// we only allow one missile at a time...
|
|
var canFire = false;
|
|
|
|
// If we've fired a missile, then check to see if it's still alive
|
|
if (myMissile) {
|
|
var missileProperties = Entities.getEntityProperties(myMissile);
|
|
|
|
if (!missileProperties || (missileProperties.type === 'Unknown')) {
|
|
print("canFire = true");
|
|
canFire = true;
|
|
}
|
|
} else {
|
|
canFire = true;
|
|
}
|
|
|
|
if (canFire) {
|
|
print("firing missile");
|
|
var missilePosition = { x: myShipProperties.position.x,
|
|
y: myShipProperties.position.y + (2* shipSize),
|
|
z: myShipProperties.position.z };
|
|
|
|
myMissile = Entities.addEntity(
|
|
{
|
|
type: "Sphere",
|
|
position: missilePosition,
|
|
velocity: { x: 0, y: 5, z: 0},
|
|
gravity: { x: 0, y: 0, z: 0 },
|
|
damping: 0,
|
|
dynamic: true,
|
|
dimensions: { x: missileSize, y: missileSize, z: missileSize },
|
|
color: { red: 0, green: 0, blue: 255 },
|
|
lifetime: 5
|
|
});
|
|
Script.addEventHandler(myMissile, "collisionWithEntity", entityCollisionWithEntity);
|
|
var options = {}
|
|
if (soundInMyHead) {
|
|
options.position = { x: MyAvatar.position.x + 0.0,
|
|
y: MyAvatar.position.y + 0.1,
|
|
z: MyAvatar.position.z + 0.0 };
|
|
} else {
|
|
options.position = missilePosition;
|
|
}
|
|
|
|
Audio.playSound(shootSound, options);
|
|
|
|
}
|
|
}
|
|
|
|
function keyPressEvent(key) {
|
|
//print("keyPressEvent key.text="+key.text);
|
|
|
|
if (key.text == LEFT) {
|
|
myShipProperties.position.x -= 0.1;
|
|
if (myShipProperties.position.x < gameAt.x) {
|
|
myShipProperties.position.x = gameAt.x;
|
|
}
|
|
moveShipTo(myShipProperties.position);
|
|
} else if (key.text == RIGHT) {
|
|
myShipProperties.position.x += 0.1;
|
|
if (myShipProperties.position.x > gameAt.x + gameSize.x) {
|
|
myShipProperties.position.x = gameAt.x + gameSize.x;
|
|
}
|
|
moveShipTo(myShipProperties.position);
|
|
} else if (key.text == FIRE) {
|
|
fireMissile();
|
|
} else if (key.text == QUIT) {
|
|
endGame();
|
|
}
|
|
}
|
|
|
|
// remap the keys...
|
|
Controller.keyPressEvent.connect(keyPressEvent);
|
|
Controller.captureKeyEvents({text: " "});
|
|
|
|
function deleteIfInvader(possibleInvaderEntity) {
|
|
for (var row = 0; row < numberOfRows; row++) {
|
|
for (var column = 0; column < invadersPerRow; column++) {
|
|
if (invaders[row][column] == possibleInvaderEntity) {
|
|
Entities.deleteEntity(possibleInvaderEntity);
|
|
Entities.deleteEntity(myMissile);
|
|
|
|
// play the hit sound
|
|
var options = {};
|
|
if (soundInMyHead) {
|
|
options.position = { x: MyAvatar.position.x + 0.0,
|
|
y: MyAvatar.position.y + 0.1,
|
|
z: MyAvatar.position.z + 0.0 };
|
|
} else {
|
|
options.position = getInvaderPosition(row, column);
|
|
}
|
|
|
|
Audio.playSound(hitSound, options);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// initialize the game...
|
|
initializeMyShip();
|
|
initializeInvaders();
|
|
|
|
// shut down the game after 1 minute
|
|
var gameTimer = Script.setTimeout(endGame, itemLifetimes * 1000);
|