Files
2020-05-17 15:24:44 -05:00

167 lines
6.4 KiB
JavaScript

/*!
* Howler.js 3D Sound Demo
* howlerjs.com
*
* (c) 2013-2020, James Simpson of GoldFire Studios
* goldfirestudios.com
*
* MIT License
*/
'use strict';
/**
* Generates the map and calculates the casting of arrays for the camera to display on screen.
* @param {Number} size Grid size of the map to use.
*/
var Map = function(size) {
this.size = size;
this.grid = new Array(size * size);
this.skybox = new Texture('./assets/skybox.jpg', 4096, 1024);
this.wall = new Texture('./assets/wall.jpg', 1024, 1024);
this.speaker = new Texture('./assets/speaker.jpg', 1024, 1024);
this.light = 0;
// Define the pre-defined map template on a 25x25 grid.
this.grid = [1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1];
};
Map.prototype = {
/**
* Sets up the map including the speaker audio points.
*/
setup: function() {
// Loop through the tiles and setup the audio listeners.
for (var i=0; i<this.grid.length; i++) {
if (this.grid[i] === 2) {
var y = Math.floor(i / this.size);
var x = i % this.size;
game.audio.speaker(x, y);
}
}
},
/**
* Check if a gird location is out of bounds, a wall or empty.
* @param {Number} x x-coordinate
* @param {Number} y y-coordinate
* @return {Number} -1, 0, 1
*/
check: function(x, y) {
x = Math.floor(x);
y = Math.floor(y);
if (x < 0 || x > this.size - 1 || y < 0 || y > this.size - 1) {
return -1;
}
return this.grid[y * this.size + x];
},
/**
* Emit a ray to beginb uilding the scene.
* @param {Number} sin Sine of the cast angle.
* @param {Number} cos Cosine of the cast angle.
* @param {Number} range Max length of the ray.
* @param {Object} origin x, y, height and sitance
*/
ray: function(sin, cos, range, origin) {
var stepX = this.step(sin, cos, origin.x, origin.y, false);
var stepY = this.step(cos, sin, origin.y, origin.x, true);
var inspectX = [sin, cos, stepX, 1, 0, origin.dist, stepX.y];
var inspectY = [sin, cos, stepY, 0, 1, origin.dist, stepY.x];
var next = this.inspect.apply(this, (stepX.len2 < stepY.len2) ? inspectX : inspectY);
if (next.dist > range) {
return [origin];
}
return [origin].concat(this.ray(sin, cos, range, next));
},
/**
* Processes each step along the ray.
* @param {Number} rise Slope of line: sine of the cast angle.
* @param {Number} run Slope of line: cosine of the cast angle.
* @param {Number} x Origin x-position.
* @param {Number} y Origin y-position.
* @param {Boolean} inverted
*/
step: function(rise, run, x, y, inverted) {
if (run === 0) {
return {len2: Infinity};
}
var dx = run > 0 ? Math.floor(x + 1) - x : Math.ceil(x - 1) - x;
var dy = dx * (rise / run);
return {
x: inverted ? y + dy : x + dx,
y: inverted ? x + dx : y + dy,
len2: dx * dx + dy * dy
};
},
/**
* Inspect the next position to determine distance, height, shading, etc.
* @param {Number} sin Sine of the cast angle.
* @param {Number} cos Cosine of the cast angle.
* @param {Object} step x, y and length of the step.
* @param {Number} shiftX X shifted by 1 or 0.
* @param {Number} shiftY Y shifted by 1 or 0.
* @param {Number} dist Distnace from origin.
* @param {Number} offset Step offset.
*/
inspect: function(sin, cos, step, shiftX, shiftY, dist, offset) {
var dx = (cos < 0) ? shiftX : 0;
var dy = (sin < 0) ? shiftY : 0;
step.type = this.check(step.x - dx, step.y - dy);
step.height = (step.type) > 0 ? 1 : 0;
step.dist = dist + Math.sqrt(step.len2);
if (shiftX) {
step.shading = (cos < 0) ? 2 : 0;
} else {
step.shading = (sin < 0) ? 2 : 1;
}
step.offset = offset - Math.floor(offset);
return step;
},
/**
* Casts a ray from the camera and returns the results.
* @param {Object} point Player/camera's x/y position.
* @param {Number} angle Angle (in radians) of camera.
* @param {Number} range Max length of the ray.
*/
cast: function(point, angle, range) {
var sin = Math.sin(angle);
var cos = Math.cos(angle);
return this.ray(sin, cos, range, {
x: point.x,
y: point.y,
height: 0,
dist: 0
});
},
/**
* Update loop on the map, in this case used to add in lightning by adjusting global lighting.
* @param {Number} secs Seconds since last tick.
*/
update: function(secs) {
if (this.light > 0) {
this.light = Math.max(this.light - 10 * secs, 0);
} else if (Math.random() * 6 < secs) {
this.light = 2;
// Play the lightning sound.
game.audio.lightning();
}
}
};