UNPKG

p5.raycaster

Version:

a simple p5js library for semi 3d rendering with ray casting

348 lines (315 loc) 14.1 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: World.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: World.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>import Sprite from "./Sprite"; class World { static defaultTypeTable = { MAP_FLOOR: 0, MAP_WALL: 1, MAP_WALL_SHADOW: 2, MAP_DOOR: 3, MAP_DOOR_FRAME: 4, MAP_PUSH_WALL: 5, MAP_CIRCULAR_COLUMN: 6, MAP_DIA_WALL_TR_BL: 7, MAP_DIA_WALL_TL_BR: 8, MAP_TRANSPARENT_WALL: 9, DOOR_CLOSED: 0, DOOR_OPENING: 1, DOOR_OPEN: 2, DOOR_CLOSING: 3, } static defaultSkyBox = { sky: "black", ground: "grey", front: null, middle: null, back: null, } /** * * @param {number} [width = 24] integer indicating the width of the world (number of block) * @param {number} [height = 24] integer indicating the height of the world (number of block) * @param {string} [data=null] block data for the world, e.g. "0,1,0,0,0,0,1,2,0,0,0,0...", can be an array of integer instead] * @param {Map} [textureMap=null] [[0, texture], [1, texture], ...] * @param {object} [skyBox=World.defaultSkyBox] sky box * @param {string} skyBox.sky a string notation of color or a p5.Image object * @param {string} skyBox.ground a string notation of color or a p5.Image object * @param {p5.Image} skyBox.front can be a p5.Graphics object * @param {p5.Image} skyBox.middle can be a p5.Graphics object * @param {p5.Image} skyBox.back can be a p5.Graphics object * @param {object} [typeTable = World.defaultTypeTable] block type table to interpret the data, default to the default table * @param {object} [options=null] * @param {number} options.doorSpeed how fast the door open and close, default to 0.01; * @param {boolean} options.doorAutoClose will the door close by it self, default to false; * @param {number} options.doorClosingTime if doorAutoClose is true, define how long the door will be open */ constructor(width = 24, height = 24, data = null, textureMap = null, skyBox = World.defaultSkyBox, typeTable = World.defaultTypeTable, options = null) { this.width = width; this.height = height; this.map = new Array(this.width * this.height).fill(0); this.table = typeTable; this.skyBox = skyBox; this.sprites = []; this.cameras = []; this.textureMap = textureMap; this.loadMap(data, options); } /** * * @param {string} data block data for the world separated by comma, can be an array of integer instead * @param {object} [options = null] * @param {number} options.doorSpeed how fast the door open and close, default to 0.1; * @param {boolean} options.doorAutoClose will the door close by it self, default to false; * @param {number} options.doorClosingTime if doorAutoClose is true, define how long the door will be open */ loadMap(data, options) { if (data &amp;&amp; data.length) { if (typeof data === "string") { data.split(',').forEach((b, i) => { this.map[i] = parseInt(b); if (this.map[i] % 10 === this.table.MAP_WALL_SHADOW) { console.warn(`[p5RayCaster]: MAP_WALL_SHADOW ${this.map[i]} should not be used in the map, changed to MAP_WALL ${Math.floor(this.map[i] / 10) + this.table.MAP_WALL}`); this.map[i] = Math.floor(this.map[i] / 10) + this.table.MAP_WALL; } }); } else if (typeof data[0] === "number") { data.forEach((b, i) => { this.map[i] = b; if (this.map[i] % 10 === this.table.MAP_WALL_SHADOW) { console.warn(`[p5RayCaster]: MAP_WALL_SHADOW ${this.map[i]} should not be used in the map, changed to MAP_WALL ${Math.floor(this.map[i] / 10) + this.table.MAP_WALL}`); this.map[i] = Math.floor(this.map[i] / 10) + this.table.MAP_WALL; } }); } else if (typeof data[0][0] === "number") { for (let y = 0; y &lt; data.length; y++) { for (let x = 0; x &lt; data[y].length; x++) { let idx = x + y * this.width; this.map[idx] = data[y][x]; if (this.map[idx] % 10 === this.table.MAP_WALL_SHADOW) { console.warn(`[p5RayCaster]: MAP_WALL_SHADOW ${this.map[idx]} should not be used in the map, changed to MAP_WALL ${Math.floor(this.map[idx] / 10) + this.table.MAP_WALL}`); this.map[idx] = Math.floor(this.map[idx] / 10) + this.table.MAP_WALL; } } } } } this.doorOffsets = new Array(this.width * this.height).fill(0); this.doorStates = new Array(this.width * this.height).fill(0); this.doorSpeed = options &amp;&amp; options.doorSpeed ? options.doorSpeed : 0.1; this.doorAutoClose = options &amp;&amp; options.doorAutoClose ? options.doorAutoClose : false; this.doorClosingTime = options &amp;&amp; options.doorClosingTime ? options.doorClosingTime : 0; } /** * * @param {string} floorMapData or a 1D/2D array, or a single number indicating the texture for all blocks */ loadFloor(floorMapData){ if (typeof floorMapData === "number") { this.floor = floorMapData; return; } this.floor = new Array(this.width * this.height); if(typeof floorMapData === "string") { floorMapData.split(",").forEach(data => { this.floor.push(parseInt(data)); }); return; } if(Array.isArray(floorMapData) &amp;&amp; floorMapData.length){ if (typeof floorMapData[0] === "number") { floorMapData.forEach(data => this.floor.push(data)); return; } if (typeof floorMapData[0][0] === "number") { for (let y = 0; y &lt; floorMapData.length; y++) { for (let x = 0; x &lt; floorMapData[0].length; x++) { let idx = x + y * this.width; this.floor[idx] = floorMapData[y][x]; } } } } } /** * * @param {string} ceilingMapData or a 1D/2D array, or a single number indicating the texture for all blocks */ loadCeiling(ceilingMapData){ if (typeof ceilingMapData === "number") { this.ceiling = ceilingMapData; return; } this.ceiling = new Array(this.width * this.height); if(typeof ceilingMapData === "string") { ceilingMapData.split(",").forEach(data => { this.ceiling.push(parseInt(data)); }); return; } if(Array.isArray(ceilingMapData) &amp;&amp; ceilingMapData.length){ if (typeof ceilingMapData[0] === "number") { ceilingMapData.forEach(data => this.ceiling.push(data)); return; } if (typeof ceilingMapData[0][0] === "number") { for (let y = 0; y &lt; ceilingMapData.length; y++) { for (let x = 0; x &lt; ceilingMapData[0].length; x++) { let idx = x + y * this.width; this.ceiling[idx] = ceilingMapData[y][x]; } } } } } /** * this function will not copy the Map * @param {Map} textureMap */ loadTextureMap(textureMap) { this.textureMap = textureMap; } /** * add a sprite to the world * @param {Sprite} sprite */ addSprite(sprite) { this.sprites.push(sprite); sprite.world = this; this.cameras.forEach((c) => { c.updateSpritesBuffers(); }) } /** * remove a sprite * @param {number} spriteIdx index of the sprite in the sprites array or the sprite itself */ removeSprite(spriteIdx) { if (spriteIdx instanceof Sprite) { delete spriteIdx.world let idx = this.sprites.indexOf(spriteIdx) if (idx === -1) { console.warn("invalid remove: sprite is not in the world"); return; } spriteIdx = idx; } delete this.sprites[spriteIdx].world; this.sprites.splice(spriteIdx, 1); this.cameras.forEach((c) => { c.updateSpritesBuffers(); }) } /** * update the state of the doors and push walls * @param {number} [frameRate=30] */ update(frameRate = 30) { const deltaTime = 1 / frameRate; for (let i = 0; i &lt; this.map.length; i++) { const block = this.map[i]; if (block === this.table.MAP_DOOR) { if (this.doorStates[i] === this.table.DOOR_OPENING) { this.doorOffsets[i] += deltaTime * this.doorSpeed; if (this.doorOffsets[i] > 1) { this.doorOffsets[i] = 1; this.doorStates[i] = this.table.DOOR_OPEN; if (this.doorAutoClose) { setTimeout((i) => { this.doorStates[i] = this.table.DOOR_CLOSING }, this.doorClosingTime, i); } } } else if (this.doorStates[i] === this.table.DOOR_CLOSING) { this.doorOffsets[i] -= deltaTime * this.doorSpeed; if (this.doorOffsets[i] &lt; 0) { this.doorOffsets[i] = 0; this.doorStates[i] = this.table.DOOR_CLOSED; } } } else if (block === this.table.MAP_PUSH_WALL) { if (this.doorStates[i] === this.table.DOOR_OPENING) { this.doorOffsets[i] += deltaTime * this.doorSpeed; if (this.doorOffsets[i] > 1) { this.doorOffsets[i] = 1; this.doorStates[i] = this.table.DOOR_OPEN; } } } } } /** * * @param {number} x x coordinate of the block * @param {number} y y coordinate of the block */ openDoor(x, y) { let idx = arguments.length === 1 ? x : x + y * this.width; if (this.map[idx] === this.table.MAP_DOOR || this.map[idx] === this.table.MAP_PUSH_WALL) { if (this.doorStates[idx] === this.table.DOOR_CLOSED) { this.doorStates[idx] = this.table.DOOR_OPENING; } } } /** * * @param {number} x x coordinate of the block * @param {number} y y coordinate of the block */ closeDoor(x, y) { let idx = arguments.length === 1 ? x : x + y * this.width; if (this.map[idx] === this.table.MAP_DOOR) { if (this.doorStates[idx] === this.table.DOOR_OPEN) { this.doorStates[idx] = this.table.DOOR_CLOSING; } } } /** * * @param {number} x x coordinate of the block * @param {number} y y coordinate of the block */ moveDoor(x, y) { let idx = arguments.length === 1 ? x : x + y * this.width; if (this.map[idx] === this.table.MAP_DOOR) { if (this.doorStates[idx] === this.table.DOOR_OPEN) { this.doorStates[idx] = this.table.DOOR_CLOSING; } else if (this.doorStates[idx] === this.table.DOOR_CLOSED) { this.doorStates[idx] = this.table.DOOR_OPENING; } } if (this.map[idx] === this.table.MAP_PUSH_WALL) { if (this.doorStates[idx] === this.table.DOOR_CLOSED) { this.doorStates[idx] = this.table.DOOR_OPENING; } } } } export default World</code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Camera.html">Camera</a></li><li><a href="KeyboardControl.html">KeyboardControl</a></li><li><a href="MouseControl.html">MouseControl</a></li><li><a href="PointerLockControl.html">PointerLockControl</a></li><li><a href="Sprite.html">Sprite</a></li><li><a href="TransparentWall.html">TransparentWall</a></li><li><a href="Util.html">Util</a></li><li><a href="World.html">World</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createCamera">createCamera</a></li><li><a href="global.html#createSkyBox">createSkyBox</a></li><li><a href="global.html#createSprite">createSprite</a></li><li><a href="global.html#createTextureMap">createTextureMap</a></li><li><a href="global.html#createWorld">createWorld</a></li><li><a href="global.html#initKeyboardControl">initKeyboardControl</a></li><li><a href="global.html#initMouseControl">initMouseControl</a></li><li><a href="global.html#initPointerLockControl">initPointerLockControl</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> on Thu Feb 01 2024 12:26:09 GMT+0000 (Greenwich Mean Time) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>