overte/examples/flappyBird.js
2016-03-02 15:53:13 -08:00

316 lines
No EOL
7.1 KiB
JavaScript

//
// flappyBird.js
//
// Created by Clement 3/2/16
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// Constants
var OBJECTS_LIFETIME = 1;
var G = 4.0;
Number.prototype.clamp = function(min, max) {
return Math.min(Math.max(this, min), max);
};
// Class definitions
function Game() {
// public methods
this.start = function() {
if (!isRunning) {
isRunning = true;
setup();
Script.update.connect(idle);
}
}
this.stop = function() {
if (isRunning) {
Script.update.disconnect(idle);
cleanup();
isRunning = false;
}
}
this.keyPressed = function(event) {
if (event.text === "SPACE" && (gameTime - lastLost) > coolDown) {
isJumping = true;
startedPlaying = true;
}
}
// Constants
var spaceDimensions = { x: 1.5, y: 0.8, z: 0.01 };
var spaceDistance = 1.5;
var spaceYOffset = 0.6;
var jumpVelocity = 1.0;
// Private game state
var that = this;
var entityManager = new EntityManager();
var isRunning = false;
var startedPlaying = false;
var coolDown = 1;
var lastLost = -coolDown;
var gameTime = 0;
var isJumping = false;
var space = null
var board = null;
var bird = null;
var birdXPos = spaceDimensions.x / 2.0;
var birdDimensions = 0.05;
// ALong Y axis
var birdPos = spaceDimensions.y / 2.0;
var birdVel = 0.0;
var birdAcc = -G;
var pipes = new Array();
var lastPipe = 0;
var pipesInterval = 0.5;
var pipesVelocity = 1.0;
var pipeWidth = 0.05;
var pipeLength = 0.4;
// Game loop setup
function idle(deltaTime) {
inputs();
update(deltaTime);
draw();
}
function setup() {
print("setup");
space = {
position: getSpacePosition(),
orientation: getSpaceOrientation(),
dimensions: getSpaceDimensions()
}
board = entityManager.add({
type: "Box",
position: space.position,
rotation: space.orientation,
dimensions: space.dimensions,
color: { red: 100, green: 200, blue: 200 }
});
bird = entityManager.add({
type: "Sphere",
position: to3DPosition({ x: birdXPos, y: birdPos }),
dimensions: { x: birdDimensions, y: birdDimensions, z: birdDimensions },
color: { red: 0, green: 0, blue: 255 }
});
}
function inputs() {
//print("inputs");
}
function update(deltaTime) {
//print("update: " + deltaTime);
// Keep entities alive
gameTime += deltaTime;
entityManager.update(deltaTime);
if (!startedPlaying && (gameTime - lastLost) < coolDown) {
return;
}
// Update Bird
if (!startedPlaying && birdPos < spaceDimensions.y / 2.0) {
isJumping = true;
}
// Apply jumps
if (isJumping) {
birdVel = jumpVelocity;
isJumping = false;
}
// Apply gravity
birdPos += deltaTime * (birdVel + deltaTime * birdAcc / 2.0);
birdVel += deltaTime * birdAcc;
// Move pipes forward
pipes.forEach(function(element) {
element.position -= deltaTime * pipesVelocity;
});
// Delete pipes over the end
var count = 0;
while(count < pipes.length && pipes[count].position <= 0.0) {
entityManager.remove(pipes[count].id);
count++;
}
if (count > 0) {
pipes = pipes.splice(count);
}
// Move pipes forward
if (startedPlaying && gameTime - lastPipe > pipesInterval) {
print("New pipe");
var newPipe = entityManager.add({
type: "Box",
position: to3DPosition({ x: space.dimensions.x, y: 0.2 }),
dimensions: { x: pipeWidth, y: pipeLength, z: pipeWidth },
color: { red: 0, green: 255, blue: 0 }
});
pipes.push({ id: newPipe, position: space.dimensions.x });
lastPipe = gameTime;
}
// Check lost
var hasLost = birdPos < 0.0 || birdPos > space.dimensions.y;
if (!hasLost) {
pipes.forEach(function(element) {
var deltaX = Math.abs(element.position - birdXPos);
if (deltaX < (birdDimensions + pipeWidth) / 2.0) {
var deltaY = birdPos - pipeLength;
if (deltaY < 0 || deltaY < birdDimensions / 2.0) {
hasLost = true;
}
}
});
}
// Cleanup
if (hasLost) {
birdPos = spaceDimensions.y / 2.0;
birdVel = 0.0;
startedPlaying = false;
lastLost = gameTime;
// Clearing pipes
print("Clearing pipes: " + pipes.length);
pipes.forEach(function(element) {
entityManager.remove(element.id);
});
pipes = new Array();
}
}
function draw() {
//print("draw");
Entities.editEntity(bird, { position: to3DPosition({ x: birdXPos, y: birdPos }) });
pipes.forEach(function(element) {
Entities.editEntity(element.id, { position: to3DPosition({ x: element.position, y: 0.2 }) });
});
}
function cleanup() {
print("cleanup");
entityManager.removeAll();
}
// Private methods
function getSpacePosition() {
var forward = Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.FRONT);
var spacePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(spaceDistance, forward));
return Vec3.sum(spacePosition, Vec3.multiply(spaceYOffset, Vec3.UP));
}
function getSpaceOrientation() {
return MyAvatar.orientation;
}
function getSpaceDimensions() {
return spaceDimensions;
}
function project(point, plane) {
var v = Vec3.subtract(point, plane.origin);
var dist = Vec3.dot(v, plane.normal);
return Vec3.subtract(point, Vec3.multiply(dist, v));
}
function to3DPosition(position) {
var position2D = {
x: position.x - space.dimensions.x / 2.0,
y: position.y - space.dimensions.y / 2.0,
z: 0.0
}
return Vec3.sum(space.position, Vec3.multiplyQbyV(space.orientation, position2D));
}
function to2DPosition(position) {
var position3D = project(position, {
origin: Vec3.subtract(space.position, {
x: space.dimensions.x / 2.0,
y: space.dimensions.y / 2.0,
z: 0.0
}),
normal: Vec3.multiplyQbyV(space.orientation, Vec3.FRONT)
});
var position2D = {
x: position3D.x.clamp(0.0, space.dimensions.x),
y: position3D.y.clamp(0.0, space.dimensions.y)
}
return position2D;
}
}
function EntityManager() {
var entities = new Array();
var lifetime = OBJECTS_LIFETIME;
this.setLifetime = function(newLifetime) {
lifetime = newLifetime;
this.update();
}
this.add = function(properties) {
// Add to scene
properties.lifetime = lifetime;
var entityID = Entities.addEntity(properties);
// Add to array
entities.push({ id: entityID, properties: properties });
return entityID;
}
this.update = function(deltaTime) {
entities.forEach(function(element) {
// Get entity's age
var properties = Entities.getEntityProperties(element.id, ["age"]);
// Update entity's lifetime
Entities.editEntity(element.id, { lifetime: properties.age + lifetime });
});
}
this.remove = function(entityID) {
// Remove from scene
Entities.deleteEntity(entityID);
// Remove from array
entities = entities.filter(function(element) {
return element.id !== entityID;
});
}
this.removeAll = function() {
// Remove all from scene
entities.forEach(function(element) {
Entities.deleteEntity(element.id);
});
// Remove all from array
entities = new Array();
}
}
// Script logic
function scriptStarting() {
var game = new Game();
Controller.keyPressEvent.connect(function(event) {
game.keyPressed(event);
});
Script.scriptEnding.connect(function() {
game.stop();
});
game.start();
}
scriptStarting();