UNPKG

fury-js

Version:

WebGL Game Engine

130 lines (109 loc) 3.67 kB
// Simple single line text mesh using Atlas // Broadly similar to tilemap, however supports varying position based on custom tile widths // Prefabs generated by Atlas do not adjust for variable width so there is unnecessary blending / overdraw const Atlas = require('./atlas'); const { vec3 } = require('./maths'); module.exports = (function(){ let exports = {}; let Alignment = exports.Alignment = { "left": 0, "center": 1, "right": 2 }; // Determines how round initial left most position when aligning // No rounding, floor to integer, or floor to the atlas.tileSize // Note: grid only works with atlases with static tile widths let AlignmentStyle = exports.AlignmentStyle = { "free": 0, "integer": 1, "grid": 2, }; // Default alignment style - Assumes UI is pixel perfect, so integer exports.alignmentStyle = AlignmentStyle.integer; let atlasWidths = {}; let generateCharWidthLookup = (atlas) => { let lookup = {}; if (hasVariableTileWidths(atlas)) { for (let i = 0, l = atlas.customTileWidths.length; i < l; i++) { let { width, tiles } = atlas.customTileWidths[i]; for (let j = 0, n = tiles.length; j < n; j++) { lookup[tiles[j]] = width; } } } atlasWidths[atlas.id] = lookup; }; let hasVariableTileWidths = exports.hasVariableTileWidths = (atlas) => { return atlas.customTileWidths && atlas.customTileWidths.length; }; let getCharWidth = exports.getCharWidth = (atlas, char) => { let tileWidth = atlas.tileWidth; let lookup = atlasWidths[atlas.id]; if (lookup && lookup[char] !== undefined) { tileWidth = lookup[char]; } return tileWidth; }; exports.create = ({ text, scene, atlas, position, alignment, color, alignmentStyle }) => { if (alignmentStyle === undefined || alignmentStyle === null) { alignmentStyle = exports.alignmentStyle; } if (!atlasWidths[atlas.id]) { generateCharWidthLookup(atlas); } let tiles = []; let textMesh = {}; textMesh.remove = () => { for (let i = 0, l = tiles.length; i < l; i++) { scene.remove(tiles[i]); } tiles.length = 0; }; let calculateWidth = textMesh.calculateWidth = (text) => { let width = 0; if (hasVariableTileWidths(atlas)) { for (let i = 0, l = text.length; i < l; i++) { width += getCharWidth(atlas, text[i]); } } else { width = text.length * atlas.tileWidth; } return width; }; let calculateAlignmentOffset = (alignment, text) => { let offset = 0; if (alignment == Alignment.center) { if (alignmentStyle == AlignmentStyle.grid && !hasVariableTileWidths(atlas)) { offset = Math.floor(text.length / 2) * atlas.tileWidth; } else { offset = calculateWidth(text) / 2; } } else if (alignment == Alignment.right) { offset = calculateWidth(text); } if (offset && alignmentStyle == AlignmentStyle.integer) { offset = Math.floor(offset); } return offset; }; textMesh.getText = () => text; textMesh.setText = (value) => { textMesh.remove(); let offset = calculateAlignmentOffset(alignment, value); let x = position[0] - offset, y = position[1], z = position[2]; for (let i = 0, l = value.length; i < l; i++) { let char = value[i]; let name = Atlas.createTilePrefab({ atlas: atlas, tile: char, color: color }); tiles.push(scene.instantiate({ name: name, position: vec3.fromValues(x, y, z) })); x += getCharWidth(atlas, char); } text = value; }; textMesh.setText(text); return textMesh; }; return exports; })();