New chunk-based rendering method, reorganized file structure

This commit is contained in:
Nicole Collings 2020-04-20 14:20:15 -07:00
parent f989793a55
commit 74fd7c491f
44 changed files with 1603 additions and 1721 deletions

View File

@ -105,7 +105,7 @@ class LoadScene extends Phaser.Scene {
this.patching = this.add.sprite(this.cameras.main.width / 2, this.cameras.main.height / 2 - 100, "loader_patching");
this.patching.setScale(6);
this.text.setText(" Patching Tiles...");
this.text.setText(" Loading Map...");
setTimeout(() => {
this.game.scene.start('MapScene');

79
src/MapScene/FogOfWar.ts Normal file
View File

@ -0,0 +1,79 @@
// class FogOfWar {
// scene: MapScene;
// tex: Phaser.GameObjects.RenderTexture;
// map: Phaser.Tilemaps.Tilemap;
// historyLayer: Phaser.Tilemaps.DynamicTilemapLayer;
// dims: Vec2;
// constructor(scene: MapScene, dims: Vec2) {
// this.scene = scene;
// this.dims = dims;
// this.tex = new Phaser.GameObjects.RenderTexture(this.scene, 0, 0, this.dims.x*16, this.dims.y*16);
// this.tex.setScale(4, 4);
// this.tex.setAlpha(0.7);
// this.scene.add.existing(this.tex);
// // this.map = this.scene.add.tilemap(null, 16, 16, 0, 0);
// // this.map.addTilesetImage("history", "wall_shadow", 16, 16, 0, 0);
// // this.map.setLayer("history");
// // this.historyLayer = this.map.createBlankDynamicLayer("history", "wall_shadow", 0, 0, this.dims.x, this.dims.y, 16, 16);
// // this.historyLayer.setScale(4, 4);
// // for (let i = 0; i < this.dims.x; i++) {
// // for (let j = 0; j < this.dims.y; j++) {
// // if ((j % 2 == 0 && i % 2 == 0) || (j % 2 != 0 && i % 2 != 0)) this.historyLayer.putTileAt(0, i, j);
// // }
// // }
// }
// update() {
// let resetSquare = new Phaser.GameObjects.Rectangle(this.scene, 0, 0, this.dims.x*16, this.dims.y*16, 0x000000);
// this.tex.draw(resetSquare);
// for (let token of this.scene.tokens) {
// let startTile = new Vec2(Math.floor(token.x / 64), Math.floor(token.y / 64))
// let points: Vec2[] = [];
// for (let i = 0; i < 288; i++) {
// let ray = new Vec2(0.5, 0.5);
// let dir = new Vec2(Math.cos(i * 1.25 * (Math.PI / 180)) / 32, Math.sin(i * 1.25 * (Math.PI / 180)) / 32);
// let dist = 0;
// let maxDist = 12;
// while (this.scene.map.getWall(Math.floor(startTile.x + ray.x), Math.floor(startTile.y + ray.y)) == -1 &&
// (dist = Math.sqrt(Math.pow(ray.x, 2) + Math.pow(ray.y, 2))) < maxDist) {
// ray.x += dir.x;
// ray.y += dir.y;
// }
// ray.x -= dir.x * maxDist * 2.4;
// ray.y -= dir.y * maxDist * 2.4;
// ray.x += dir.x * ((maxDist - dist) * 2.8);
// ray.y += dir.y * ((maxDist - dist) * 2.8);
// points.push(new Vec2(ray.x * 4, ray.y * 4));
// }
// let poly = new Phaser.GameObjects.Polygon(this.scene, token.x / 4, token.y / 4, points, 0xffffff, 0.4);
// poly.setScale(4, 4);
// poly.setBlendMode('ERASE');
// poly.setDisplayOrigin(0, 0);
// poly.setOrigin(0, 0);
// for (let i = 0; i < 10; i++) {
// poly.scaleX += 0.04;
// poly.scaleY += 0.04;
// // poly.x = token.x / 4 + 50 * poly.scaleX;
// // poly.y = token.y / 4 + 50 * poly.scaleY;
// this.tex.draw(poly);
// }
// }
// }
// }

View File

@ -13,7 +13,7 @@ class HistoryElement {
console.log("Undo", this.type);
if (this.type == "tile") {
for (let tile of this.data as {pos: Vec2, layer: Layer, lastTile: number, tile: number}[])
this.scene.map.setTile(tile.pos.x, tile.pos.y, tile.lastTile, tile.layer);
this.scene.map.setTile(tile.layer, tile.lastTile, tile.pos.x, tile.pos.y);
}
else if (this.type == "token_modify") {
let data = this.data as { old: string[], new: string[] };
@ -61,7 +61,7 @@ class HistoryElement {
console.log("Redo", this.type);
if (this.type == "tile") {
for (let tile of this.data as {pos: Vec2, layer: Layer, lastTile: number, tile: number}[])
this.scene.map.setTile(tile.pos.x, tile.pos.y, tile.tile, tile.layer);
this.scene.map.setTile(tile.layer, tile.tile, tile.pos.x, tile.pos.y);
}
else if (this.type == "token_modify") {
let data = this.data as { old: string[], new: string[] };

View File

@ -49,15 +49,15 @@ class UITileSidebar extends UISidebar {
elemClick(x: number, y: number): void {
if (y < 4) {
this.scene.architect.activeTileset = this.scene.map.manager.indexes[this.walls[x + y * 3]];
this.scene.architect.activeLayer = Layer.WALL;
this.scene.architect.activeLayer = Layer.wall;
}
else if (y < 8) {
this.scene.architect.activeTileset = this.scene.map.manager.indexes[this.grounds[x + (y - 4) * 3]];
this.scene.architect.activeLayer = Layer.GROUND;
this.scene.architect.activeLayer = Layer.floor;
}
else {
this.scene.architect.activeTileset = this.scene.map.manager.indexes[this.overlays[x + (y - 8) * 3]];
this.scene.architect.activeLayer = Layer.OVERLAY;
this.scene.architect.activeLayer = Layer.overlay;
}
}

View File

@ -11,7 +11,7 @@ class ArchitectMode {
pointerPrimaryDown: boolean = false;
activeTileset: number = 0;
activeLayer: Layer = Layer.WALL;
activeLayer: Layer = Layer.wall;
manipulated: {pos: Vec2, layer: Layer, lastTile: number, tile: number}[] = [];
@ -33,7 +33,7 @@ class ArchitectMode {
this.cursor.setPosition(selectedTilePos.x * 64, selectedTilePos.y * 64);
this.cursor.setVisible((selectedTilePos.x >= 0 && selectedTilePos.y >= 0 &&
selectedTilePos.x < this.scene.map.dimensions.x && selectedTilePos.y < this.scene.map.dimensions.y));
selectedTilePos.x < this.scene.map.size.x && selectedTilePos.y < this.scene.map.size.y));
// Place Tiles
switch(this.placeMode) {
@ -188,12 +188,12 @@ class ArchitectMode {
placeTileAndPushManip(manipPos: Vec2, solid: boolean) {
let tile = solid ? this.activeTileset : -1;
let layer = (tile == -1 && this.activeLayer == Layer.GROUND) ? Layer.WALL : this.activeLayer;
let layer = (tile == -1 && this.activeLayer == Layer.floor) ? Layer.wall : this.activeLayer;
let lastTile = this.scene.map.getTile(manipPos.x, manipPos.y, layer);
let lastTile = this.scene.map.getTileset(layer, manipPos.x, manipPos.y);
if (tile == lastTile) return;
this.scene.map.setTile(manipPos.x, manipPos.y, tile, layer);
this.scene.map.setTile(layer, tile, manipPos.x, manipPos.y);
this.manipulated.push({
pos: manipPos,

View File

@ -19,6 +19,8 @@ class UIView {
this.camera.scrollX = -10000;
this.o = this.scene.add.container(-10000, 0);
this.createElements();
}
createElements() {
@ -81,6 +83,23 @@ class UIView {
this.displayToken();
}
}
if (this.scene.i.keyPressed('TAB')) this.scene.mode = (this.scene.mode == 0 ? 1 : 0);
if (this.scene.mode == 0) {
if (this.uiActive) this.scene.architect.cleanup();
else {
this.scene.architect.update();
this.scene.token.cleanup();
}
}
else {
if (this.uiActive) this.scene.token.cleanup();
else {
this.scene.token.update();
this.scene.architect.cleanup();
}
}
}
displayArchitect() {

View File

@ -0,0 +1,9 @@
class Lighting {
constructor(...any) {
}
update() {
}
}

View File

@ -0,0 +1,90 @@
class MapChunk {
static CHUNK_SIZE = 16;
static TILE_SIZE = 16;
static DIRTY_LIMIT = 32;
private pos: Vec2;
private map: MapData;
private canvas: Phaser.GameObjects.RenderTexture;
private dirtyList: Vec2[] = [];
private fullyDirty: boolean = false;
constructor(map: MapData, x: number, y: number) {
this.pos = new Vec2(x, y);
this.canvas = map.scene.add.renderTexture(
x * MapChunk.CHUNK_SIZE * MapChunk.TILE_SIZE * 4, y * MapChunk.CHUNK_SIZE * MapChunk.TILE_SIZE * 4,
MapChunk.CHUNK_SIZE * MapChunk.TILE_SIZE, MapChunk.CHUNK_SIZE * MapChunk.TILE_SIZE);
this.map = map;
this.canvas.setScale(4);
this.canvas.setOrigin(0, 0);
for (let i = 0; i < MapChunk.CHUNK_SIZE * MapChunk.CHUNK_SIZE; i++) {
let x = i % MapChunk.CHUNK_SIZE;
let y = Math.floor(i / MapChunk.CHUNK_SIZE);
let mX = x + this.pos.x * MapChunk.CHUNK_SIZE;
let mY = y + this.pos.y * MapChunk.CHUNK_SIZE;
if (mX >= this.map.size.x || mY >= this.map.size.y) continue;
this.drawTile(x, y);
}
}
dirty(pos: Vec2): void {
if (!this.fullyDirty) {
for (let v of this.dirtyList) if (v.equals(pos)) return;
this.dirtyList.push(pos);
if (this.dirtyList.length > MapChunk.DIRTY_LIMIT) {
this.fullyDirty = true;
this.dirtyList = [];
}
}
}
rebuild(): boolean {
if (this.fullyDirty) {
for (let i = 0; i < MapChunk.CHUNK_SIZE * MapChunk.CHUNK_SIZE; i++) {
let x = i % MapChunk.CHUNK_SIZE;
let y = Math.floor(i / MapChunk.CHUNK_SIZE);
let mX = x + this.pos.x * MapChunk.CHUNK_SIZE;
let mY = y + this.pos.y * MapChunk.CHUNK_SIZE;
if (mX >= this.map.size.x || mY >= this.map.size.y) continue;
this.drawTile(x, y);
}
this.fullyDirty = false;
return true;
}
if (this.dirtyList.length == 0) return false;
for (let elem of this.dirtyList) this.drawTile(elem.x, elem.y);
this.dirtyList = [];
return true;
}
private drawTile(x: number, y: number): void {
let mX = x + this.pos.x * MapChunk.CHUNK_SIZE;
let mY = y + this.pos.y * MapChunk.CHUNK_SIZE;
let wallTile = this.map.getTile(Layer.wall, mX, mY);
if (this.map.getTileset(Layer.wall, mX, mY) == -1 || (wallTile < 54 || wallTile > 60)) {
this.canvas.drawFrame(this.map.manager.groundLocations[this.map.getTileset(Layer.floor, mX, mY)].key,
this.map.getTile(Layer.floor, mX, mY), x * MapChunk.TILE_SIZE, y * MapChunk.TILE_SIZE);
if (this.map.getTileset(Layer.overlay, mX, mY) != -1)
this.canvas.drawFrame(this.map.manager.overlayLocations[this.map.getTileset(Layer.overlay, mX, mY)].key,
this.map.getTile(Layer.overlay, mX, mY), x * MapChunk.TILE_SIZE, y * MapChunk.TILE_SIZE);
}
if (this.map.getTileset(Layer.wall, mX, mY) != -1)
this.canvas.drawFrame(this.map.manager.wallLocations[this.map.getTileset(Layer.wall, mX, mY)].key,
this.map.getTile(Layer.wall, mX, mY), x * MapChunk.TILE_SIZE, y * MapChunk.TILE_SIZE);
if ((x % 2 == 0 && y % 2 == 0) || (x % 2 != 0 && y % 2 != 0)) this.canvas.drawFrame('grid_tile', 0, x * MapChunk.TILE_SIZE, y * MapChunk.TILE_SIZE);
}
}

138
src/MapScene/Map/MapData.ts Normal file
View File

@ -0,0 +1,138 @@
const enum Layer {
floor = 0,
wall = 1,
overlay = 2
}
class MapData {
scene: MapScene;
size: Vec2;
manager: TilesetManager;
private layers: {[key: number]: { tiles: number[][], tilesets: number[][] }} = {};
private chunks: MapChunk[][] = [];
constructor(scene: MapScene, size: Vec2) {
this.scene = scene;
this.size = size;
this.manager = new TilesetManager(scene);
this.registerLayer(Layer.floor, () => Math.floor(Math.random() * 6) + 54, 0);
this.registerLayer(Layer.wall, 0, -1);
this.registerLayer(Layer.overlay, 0, -1);
for (let i = 0; i < Math.ceil(size.y / MapChunk.CHUNK_SIZE); i++) {
this.chunks[i] = [];
for (let j = 0; j < Math.ceil(size.x / MapChunk.CHUNK_SIZE); j++) {
this.chunks[i][j] = new MapChunk(this, j, i);
}
}
}
update(): void {
let start = Date.now();
for (let arr of this.chunks) for (let chunk of arr) {
chunk.rebuild();
if (Date.now() - start > 10) break;
}
}
setTile(layer: Layer, tileset: number, xx: number | Vec2, yy?: number): boolean {
let x: number, y: number;
if (xx instanceof Vec2) { x = xx.x; y = xx.y; }
else { x = xx; y = yy; }
if (x < 0 || y < 0 || x >= this.size.x || y >= this.size.y) return false;
let oldTileset = this.getTileset(layer, x, y);
if (oldTileset == tileset) return false;
this.setTileset(layer, x, y, tileset);
this.smartTile(x, y);
return true;
}
setTileset(key: number, x: number | Vec2, a?: number, b?: number): void {
if (x instanceof Vec2) this.layers[key].tilesets[x.y][x.x] = a;
else this.layers[key].tilesets[a][x] = b;
}
getTile(key: number, xx: number | Vec2, yy?: number): number {
let x: number, y: number;
if (xx instanceof Vec2) { x = xx.x; y = xx.y; }
else { x = xx; y = yy; }
return this.layers[key].tiles[clamp(y, 0, this.size.y - 1)][clamp(x, 0, this.size.x - 1)];
}
getTileset(key: number, xx: number | Vec2, yy?: number): number {
let x: number, y: number;
if (xx instanceof Vec2) { x = xx.x; y = xx.y; }
else { x = xx; y = yy; }
return this.layers[key].tilesets[clamp(y, 0, this.size.y - 1)][clamp(x, 0, this.size.x - 1)];
}
private smartTile(x: number, y: number): void {
for (let i = clamp(x - 1, this.size.x - 1, 0); i <= clamp(x + 1, this.size.x - 1, 0); i++) {
for (let j = clamp(y - 1, this.size.y - 1, 0); j <= clamp(y + 1, this.size.y - 1, 0); j++) {
const solids = this.getTilesetsAt(Layer.wall, i, j).map(i => i != -1);
const wall = SmartTiler.wall(solids, this.getTile(Layer.wall, i, j));
if (wall != -1) this.setTileRaw(Layer.wall, i, j, wall);
const floor = SmartTiler.floor(solids, this.getTile(Layer.floor, i, j));
if (floor != -1) this.setTileRaw(Layer.floor, i, j, floor);
const overlay = SmartTiler.overlay(this.getTilesetsAt(Layer.overlay, i, j)
.map(t => t == this.getTileset(Layer.overlay, i, j)), this.getTileset(Layer.overlay, i, j));
if (overlay != -1) this.setTileRaw(Layer.overlay, i, j, overlay);
}
}
}
private setTileRaw(key: number, x: number | Vec2, a?: number, b?: number, c?: number): void {
if (x instanceof Vec2) {
this.layers[key].tiles[x.y][x.x] = a;
if (b !== undefined) this.setTileset(key, x, b);
this.chunks[Math.floor(x.y / MapChunk.CHUNK_SIZE)][Math.floor(x.x / MapChunk.CHUNK_SIZE)]
.dirty(new Vec2(x.x % MapChunk.CHUNK_SIZE, x.y % MapChunk.CHUNK_SIZE));
}
else {
this.layers[key].tiles[a][x] = b;
if (c !== undefined) this.setTileset(key, x, a, c);
this.chunks[Math.floor(a / MapChunk.CHUNK_SIZE)][Math.floor(x / MapChunk.CHUNK_SIZE)]
.dirty(new Vec2(x % MapChunk.CHUNK_SIZE, a % MapChunk.CHUNK_SIZE));
}
}
private getTilesetsAt(layer: Layer, x: number, y: number): number[] {
let tilesets: number[] = [];
for (let i = -1; i <= 1; i++)
for (let j = -1; j <= 1; j++)
tilesets.push(this.getTileset(layer, clamp(x + j, 0, this.size.x - 1), clamp(y + i, 0, this.size.y - 1)));
return tilesets;
}
private registerLayer(key: number, startTile: any = 0, startTileset: number = -1): void {
let layer = {
tiles: [],
tilesets: []
}
for (let i = 0; i < this.size.y; i++) {
layer.tiles[i] = [];
layer.tilesets[i] = [];
for (let j = 0; j < this.size.x; j++) {
let tile = typeof(startTile) == "number" ? startTile : startTile();
layer.tiles[i][j] = tile;
layer.tilesets[i][j] = startTileset;
}
}
this.layers[key] = layer;
}
}

View File

@ -219,7 +219,7 @@ namespace SmartTiler {
return tile;
}
export function ground(walls: boolean[], current: number): number {
export function floor(walls: boolean[], current: number): number {
const TL = 0, T = 1, TR = 2, L = 3, C = 4, R = 5, BL = 6, B = 7, BR = 8;
if (current == -1) return -1;

View File

@ -0,0 +1,31 @@
class TilesetManager {
scene: MapScene;
private currentWallInd: number = 0;
private currentGroundInd: number = 0;
private currentOverlayInd: number = 0;
wallLocations: {[key: number /*Index*/]: { res: number, ind: number, key: string }} = {};
groundLocations: {[key: number /*Index*/]: { res: number, ind: number, key: string }} = {};
overlayLocations: {[key: number /*Index*/]: { res: number, ind: number, key: string }} = {};
indexes: {[key: string /*Tileset Key*/]: number} = {};
constructor(scene: MapScene) {
this.scene = scene;
for (let tileset of WALLS ) this.addTileset(tileset.key, Layer.wall);
for (let tileset of GROUNDS ) this.addTileset(tileset.key, Layer.floor);
for (let tileset of OVERLAYS) this.addTileset(tileset.key, Layer.overlay);
}
private addTileset(key: string, layer: Layer): void {
let res = this.scene.textures.get(key).getSourceImage(0).width / 9;
let ind = (layer == Layer.wall ? this.currentWallInd : layer == Layer.floor ? this.currentGroundInd : this.currentOverlayInd);
this[layer == Layer.wall ? "wallLocations" : layer == Layer.floor ? "groundLocations" : "overlayLocations"][ind] = { res: res, ind: ind, key: key };
this.indexes[key] = ind;
layer == Layer.wall ? this.currentWallInd++ :
layer == Layer.floor ? this.currentGroundInd++ :
this.currentOverlayInd++;
}
}

58
src/MapScene/MapScene.ts Normal file
View File

@ -0,0 +1,58 @@
class MapScene extends Phaser.Scene {
i: InputManager;
history: HistoryManager;
architect: ArchitectMode;
token: TokenMode;
world: WorldView;
map: MapData;
lighting: Lighting;
ui: UIView;
mode: number = 0;
tokens: Token[] = [];
constructor() { super({key: "MapScene"}); }
preload(): void {
window.addEventListener('resize', () => {
let frame = document.getElementById("game");
this.game.scale.resize(frame.offsetWidth, frame.offsetHeight);
});
}
create(): void {
this.i = new InputManager(this);
(this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).addPipeline('outline', new OutlinePipeline(this.game));
(this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).addPipeline('brighten', new BrightenPipeline(this.game));
this.history = new HistoryManager(this);
this.world = new WorldView(this);
this.ui = new UIView(this);
const size = new Vec2(300, 300);
this.map = new MapData(this, size);
this.lighting = new Lighting(this, size);
this.architect = new ArchitectMode(this);
this.token = new TokenMode(this);
}
update(time: number, delta: number): void {
this.i.update();
this.history.update();
this.world.update();
this.ui.update();
this.map.update();
this.lighting.update();
}
}

View File

@ -15,6 +15,10 @@ class Vec2 {
this.y = (x as any as {x: number, y:number}).y;
}
}
equals(o: Vec2) {
return this.x == o.x && this.y == o.y;
}
}
class Vec3 {
@ -42,6 +46,10 @@ class Vec3 {
this.z = (x as any as {x: number, y:number, z:number}).z;
}
}
equals(o: Vec3) {
return this.x == o.x && this.y == o.y && this.z == o.z;
}
}
class Vec4 {
@ -73,4 +81,8 @@ class Vec4 {
this.w = (x as any).w;
}
}
equals(o: Vec4) {
return this.x == o.x && this.y == o.y && this.z == o.z && this.w == o.w;
}
}

View File

@ -1,79 +0,0 @@
class FogOfWar {
scene: MapScene;
tex: Phaser.GameObjects.RenderTexture;
map: Phaser.Tilemaps.Tilemap;
historyLayer: Phaser.Tilemaps.DynamicTilemapLayer;
dims: Vec2;
constructor(scene: MapScene, dims: Vec2) {
this.scene = scene;
this.dims = dims;
this.tex = new Phaser.GameObjects.RenderTexture(this.scene, 0, 0, this.dims.x*16, this.dims.y*16);
this.tex.setScale(4, 4);
this.tex.setAlpha(0.7);
this.scene.add.existing(this.tex);
// this.map = this.scene.add.tilemap(null, 16, 16, 0, 0);
// this.map.addTilesetImage("history", "wall_shadow", 16, 16, 0, 0);
// this.map.setLayer("history");
// this.historyLayer = this.map.createBlankDynamicLayer("history", "wall_shadow", 0, 0, this.dims.x, this.dims.y, 16, 16);
// this.historyLayer.setScale(4, 4);
// for (let i = 0; i < this.dims.x; i++) {
// for (let j = 0; j < this.dims.y; j++) {
// if ((j % 2 == 0 && i % 2 == 0) || (j % 2 != 0 && i % 2 != 0)) this.historyLayer.putTileAt(0, i, j);
// }
// }
}
update() {
let resetSquare = new Phaser.GameObjects.Rectangle(this.scene, 0, 0, this.dims.x*16, this.dims.y*16, 0x000000);
this.tex.draw(resetSquare);
for (let token of this.scene.tokens) {
let startTile = new Vec2(Math.floor(token.x / 64), Math.floor(token.y / 64))
let points: Vec2[] = [];
for (let i = 0; i < 288; i++) {
let ray = new Vec2(0.5, 0.5);
let dir = new Vec2(Math.cos(i * 1.25 * (Math.PI / 180)) / 32, Math.sin(i * 1.25 * (Math.PI / 180)) / 32);
let dist = 0;
let maxDist = 12;
while (this.scene.map.getWall(Math.floor(startTile.x + ray.x), Math.floor(startTile.y + ray.y)) == -1 &&
(dist = Math.sqrt(Math.pow(ray.x, 2) + Math.pow(ray.y, 2))) < maxDist) {
ray.x += dir.x;
ray.y += dir.y;
}
ray.x -= dir.x * maxDist * 2.4;
ray.y -= dir.y * maxDist * 2.4;
ray.x += dir.x * ((maxDist - dist) * 2.8);
ray.y += dir.y * ((maxDist - dist) * 2.8);
points.push(new Vec2(ray.x * 4, ray.y * 4));
}
let poly = new Phaser.GameObjects.Polygon(this.scene, token.x / 4, token.y / 4, points, 0xffffff, 0.4);
poly.setScale(4, 4);
poly.setBlendMode('ERASE');
poly.setDisplayOrigin(0, 0);
poly.setOrigin(0, 0);
for (let i = 0; i < 10; i++) {
poly.scaleX += 0.04;
poly.scaleY += 0.04;
// poly.x = token.x / 4 + 50 * poly.scaleX;
// poly.y = token.y / 4 + 50 * poly.scaleY;
this.tex.draw(poly);
}
}
}
}

View File

@ -1,76 +0,0 @@
class MapScene extends Phaser.Scene {
i: InputManager;
history: HistoryManager;
architect: ArchitectMode;
token: TokenMode;
world: WorldView;
map: Tilemap;
ui: UIView;
fog: FogOfWar;
mode: number = 0;
tokens: Token[] = [];
constructor() { super({key: "MapScene"}); }
preload(): void {
window.addEventListener('resize', () => {
let frame = document.getElementById("game");
this.game.scale.resize(frame.offsetWidth, frame.offsetHeight);
// this.chat.x = -10000 + this.cameras.main.width - 309;
});
}
create(): void {
this.i = new InputManager(this);
(<Phaser.Renderer.WebGL.WebGLRenderer>this.game.renderer).addPipeline('outline', new OutlinePipeline(this.game));
(<Phaser.Renderer.WebGL.WebGLRenderer>this.game.renderer).addPipeline('brighten', new BrightenPipeline(this.game));
this.history = new HistoryManager(this);
this.world = new WorldView(this);
this.ui = new UIView(this);
this.ui.createElements();
this.map = new Tilemap("gameMap", this, 300, 300);
this.architect = new ArchitectMode(this);
this.token = new TokenMode(this);
this.fog = new FogOfWar(this, new Vec2(300, 300));
}
update(time: number, delta: number): void {
this.i.update();
this.world.update();
this.ui.update();
// this.chat.update();
this.history.update();
this.fog.update();
if (this.i.keyPressed('TAB')) this.mode = (this.mode == 0 ? 1 : 0);
if (this.mode == 0) {
if (this.ui.uiActive) this.architect.cleanup();
else {
this.architect.update();
this.token.cleanup();
}
}
else {
if (this.ui.uiActive) this.token.cleanup();
else {
this.token.update();
this.architect.cleanup();
}
}
}
}

View File

@ -1,183 +0,0 @@
class Tilemap {
scene: MapScene;
map: Phaser.Tilemaps.Tilemap;
dimensions: Vec2 = new Vec2();
manager: TilesetManager;
layers: {[key: number]: Phaser.Tilemaps.DynamicTilemapLayer[]} = {};
groundAt: number[][];
wallAt: number[][];
overlayAt: number[][];
constructor(key: string, scene: MapScene, xwid: number, ywid: number) {
this.scene = scene;
this.dimensions = new Vec2(xwid, ywid);
this.groundAt = [];
this.wallAt = [];
this.overlayAt = [];
for (let i = 0; i < xwid; i++) {
this.groundAt[i] = [];
this.wallAt[i] = [];
this.overlayAt[i] = [];
for (let j = 0; j < ywid; j++) {
this.groundAt[i][j] = -1;
this.wallAt[i][j] = -1;
this.overlayAt[i][j] = -1;
}
}
this.manager = new TilesetManager(scene);
this.map = this.scene.add.tilemap(null, 16, 16, 0, 0);
for (let res of this.manager.resolutions()) this.createLayers(parseInt(res));
for (let x = 0; x < this.dimensions.x; x ++) {
for (let y = 0; y < this.dimensions.y; y ++) {
this.setTileRaw(x, y, 1, 54 + Math.floor(Math.random() * 6), Layer.GROUND);
}
}
this.map.addTilesetImage("grid_tile", "grid_tile", 16, 16, 0, 0);
this.map.setLayer("grid");
let gridlayer = this.map.createBlankDynamicLayer("grid", "grid_tile", 0, 0, this.dimensions.x, this.dimensions.y, 16, 16);
gridlayer.setScale(4, 4);
gridlayer.setDepth(500);
for (let i = 0; i < xwid; i++) {
for (let j = 0; j < ywid; j++) {
if ((j % 2 == 0 && i % 2 == 0) || (j % 2 != 0 && i % 2 != 0)) gridlayer.putTileAt(0, i, j);
}
}
}
private createLayers(res: number) {
this.map.addTilesetImage("tileset_" + res + "_ground", "tileset_" + res + "_ground", res, res, 2, 4);
this.map.addTilesetImage("tileset_" + res + "_wall", "tileset_" + res + "_wall", res, res, 2, 4);
this.map.addTilesetImage("tileset_" + res + "_overlay", "tileset_" + res + "_overlay", res, res, 2, 4);
this.map.setLayer("layer_" + res + "_ground");
let ground = this.map.createBlankDynamicLayer("layer_" + res + "_ground",
"tileset_" + res + "_ground", 0, 0, this.dimensions.x, this.dimensions.y, res, res);
ground.setScale(4 / (res / 16), 4 / (res / 16));
ground.setDepth(-1500 + res);
this.map.setLayer("layer_" + res + "_overlay");
let overlay = this.map.createBlankDynamicLayer("layer_" + res + "_overlay",
"tileset_" + res + "_overlay", 0, 0, this.dimensions.x, this.dimensions.y, res, res);
overlay.setScale(4 / (res / 16), 4 / (res / 16));
overlay.setDepth(-1000 + res);
this.map.setLayer("layer_" + res + "_wall");
let wall = this.map.createBlankDynamicLayer("layer_" + res + "_wall",
"tileset_" + res + "_wall", 0, 0, this.dimensions.x, this.dimensions.y, res, res);
wall.setScale(4 / (res / 16), 4 / (res / 16));
wall.setDepth(-500 + res);
this.layers[res] = [ground, wall, overlay];
}
getWall(x: number, y: number): number {
return this.wallAt[clamp(x, 0, this.dimensions.x - 1)][clamp(y, 0, this.dimensions.y - 1)];
}
setWall(x: number, y: number, tileset: number): boolean {
return this.setTile(x, y, tileset, Layer.WALL);
}
getGround(x: number, y: number): number {
return this.groundAt[clamp(x, 0, this.dimensions.x - 1)][clamp(y, 0, this.dimensions.y - 1)];
}
setGround(x: number, y: number, tileset: number): boolean {
return this.setTile(x, y, tileset, Layer.GROUND);
}
getOverlay(x: number, y: number): number {
return this.overlayAt[clamp(x, 0, this.dimensions.x - 1)][clamp(y, 0, this.dimensions.y - 1)];
}
setOverlay(x: number, y: number, tileset: number): boolean {
return this.setTile(x, y, tileset, Layer.OVERLAY);
}
getTile(x: number, y: number, layer: Layer) {
return (layer == Layer.WALL ? this.getWall(x, y) : layer == Layer.GROUND ? this.getGround(x, y) : this.getOverlay(x, y));
}
setTile(x: number, y: number, tileset: number, layer: Layer): boolean {
if (x < 0 || y < 0 || x > this.dimensions.x - 1 || y > this.dimensions.y - 1) return false;
let arr = (layer == Layer.GROUND ? this.groundAt : layer == Layer.WALL ? this.wallAt : this.overlayAt);
if (arr[x][y] == tileset) return false;
if (arr[x][y] != -1) {
this.layers[this.manager.getTilesetRes(arr[x][y], layer)][layer].removeTileAt(x, y, true);
arr[x][y] = -1;
}
if (tileset != -1) this.layers[this.manager.getTilesetRes(tileset, layer)][layer].putTileAt(
this.manager.getGlobalTileIndex(tileset, 0, layer), x, y);
arr[x][y] = tileset;
this.calculateSmartTilesAround(x, y);
return true;
}
private setTileRaw(x: number, y: number, tileset: number, tile: number, layer: Layer): void {
let arr = (layer == Layer.GROUND ? this.groundAt : layer == Layer.WALL ? this.wallAt : this.overlayAt);
if (arr[x][y] != -1) {
this.layers[this.manager.getTilesetRes(arr[x][y], layer)][layer].removeTileAt(x, y, true);
arr[x][y] = -1;
}
let loc = this.manager.getTilesetRes(tileset, layer);
this.layers[loc][layer].putTileAt(this.manager.getGlobalTileIndex(tileset, tile, layer), x, y);
arr[x][y] = tileset;
}
private getTileAt(x: number, y: number, layer: number): number {
let arr = (layer == Layer.GROUND ? this.groundAt : layer == Layer.WALL ? this.wallAt : this.overlayAt);
if (arr[x][y] == -1) return -1;
return this.manager.getLocalTileIndex(arr[x][y], this.layers[this.manager.getTilesetRes(arr[x][y], layer)][layer].getTileAt(x, y, true).index, layer);
}
private calculateSmartTilesAround(x: number, y: number): void {
for (let i = clamp(x - 1, this.dimensions.x - 1, 0); i <= clamp(x + 1, this.dimensions.x - 1, 0); i++) {
for (let j = clamp(y - 1, this.dimensions.y - 1, 0); j <= clamp(y + 1, this.dimensions.y - 1, 0); j++) {
let wall = SmartTiler.wall(this.getWallsAround(i, j), this.getTileAt(i, j, Layer.WALL));
if (wall != -1) this.setTileRaw(i, j, this.wallAt[i][j], wall, Layer.WALL);
let ground = SmartTiler.ground(this.getWallsAround(i, j), this.getTileAt(i, j, Layer.GROUND));
if (ground != -1) this.setTileRaw(i, j, this.groundAt[i][j], ground, Layer.GROUND);
let overlay = SmartTiler.overlay(this.getOverlaysAround(i, j, this.overlayAt[i][j]), this.getTileAt(i, j, Layer.OVERLAY));
if (overlay != -1) this.setTileRaw(i, j, this.overlayAt[i][j], overlay, Layer.OVERLAY);
}
}
}
private getWallsAround(x: number, y: number): boolean[] {
let solid: boolean[] = [];
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
solid.push(this.getWall(x + j, y + i) != -1);
}
}
return solid;
}
private getOverlaysAround(x: number, y: number, targetTileset: number): boolean[] {
let solid: boolean[] = [];
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
solid.push(this.getOverlay(x + j, y + i) == targetTileset);
}
}
return solid;
}
}

View File

@ -1,108 +0,0 @@
class TilesetCanvas {
manager: TilesetManager;
res: number;
width: number;
height: number;
canvas: Phaser.Textures.CanvasTexture;
indexes: number[] = [];
indMap: number[] = [];
pad: number = 2;
constructor(manager: TilesetManager, res: number, layer: Layer) {
this.manager = manager;
this.res = res;
this.width = Math.floor(1024 / ((this.res + this.pad * 2) * 9));
this.height = Math.floor(1024 / ((this.res + this.pad * 2) * 7));
this.canvas = manager.scene.textures.createCanvas("tileset_" + res +
(layer == Layer.WALL ? "_wall" : layer == Layer.GROUND ? "_ground" : "_overlay"),
this.width * 9 * (this.res + this.pad * 2), this.height * 7 * (this.res + this.pad * 2));
}
addTileset(key: string, ind: number) {
const x = this.indexes.length % this.width;
const y = Math.floor(this.indexes.length / this.width);
this.drawTileset(key, x, y);
this.indMap[ind] = this.indexes.length;
this.indexes.push(ind);
}
getGlobalIndex(tileset: number, tile: number) {
const lX = tile % 9;
const lY = Math.floor(tile / 9);
const gX = tileset % this.width;
const gY = Math.floor(tileset / this.width);
const xx = lX + gX * 9;
const yy = lY + gY * 9;
return yy * this.width * 9 + xx;
}
getLocalIndex(tile: number): number {
const gX = tile % (this.width * 9);
const gY = Math.floor(tile / (this.width * 9));
const lX = gX % 9;
const lY = gY % 7;
return lX + lY * 9;
}
private drawTileset(key: string, x: number, y: number) {
let img: HTMLImageElement = this.manager.scene.textures.get(key).getSourceImage() as HTMLImageElement;
let refCanvas = document.createElement('canvas');
refCanvas.width = img.width;
refCanvas.height = img.height;
refCanvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
let imageOffX = 9 * (this.res + this.pad * 2) * x;
let imageOffY = 7 * (this.res + this.pad * 2) * y;
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 7; j++) {
let frame = i + j * 9;
let tileOffX = imageOffX + i * (this.res + this.pad * 2);
let tileOffY = imageOffY + j * (this.res + this.pad * 2);
for (let k = 0; k < this.res + this.pad * 2; k++) {
for (let l = 0; l < this.pad * 2; l++) {
let sX = clamp(k - this.pad, 0, this.res - 1);
let sY = l < this.pad ? 0 : this.res - 1;
let oY = l < this.pad ? l : l + this.res;
let pixel = refCanvas.getContext('2d').getImageData(this.res * i + sX, this.res * j + sY, 1, 1).data;
this.canvas.setPixel(tileOffX + k, tileOffY + oY, pixel[0], pixel[1], pixel[2], pixel[3]);
}
}
for (let k = 0; k < this.pad * 2; k++) {
for (let l = 0; l < this.res; l++) {
let sX = k < this.pad ? 0 : this.res - 1;
let sY = clamp(l, 0, this.res - 1);
let oX = k < this.pad ? k : k + this.res;
let pixel = refCanvas.getContext('2d').getImageData(this.res * i + sX, this.res * j + sY, 1, 1).data;
this.canvas.setPixel(tileOffX + oX, tileOffY + l + this.pad, pixel[0], pixel[1], pixel[2], pixel[3]);
}
}
this.canvas.drawFrame(key, frame,
9 * (this.res + this.pad * 2) * x + i * (this.res + this.pad * 2) + this.pad,
7 * (this.res + this.pad * 2) * y + j * (this.res + this.pad * 2) + this.pad)
}
}
refCanvas.remove();
}
}

View File

@ -1,65 +0,0 @@
const enum Layer {
GROUND = 0,
WALL = 1,
OVERLAY = 2
}
class TilesetManager {
scene: MapScene;
private currentWallInd: number = 0;
private currentGroundInd: number = 0;
private currentOverlayInd: number = 0;
private wallLocations: {[key: number /*Index*/]: { res: number, ind: number, key: string }} = {};
private groundLocations: {[key: number /*Index*/]: { res: number, ind: number, key: string }} = {};
private overlayLocations: {[key: number /*Index*/]: { res: number, ind: number, key: string }} = {};
private canvases: {[key: number /*Resolution*/]: TilesetCanvas[] } = {};
indexes: {[key: string /*Tileset Key*/]: number} = {};
constructor(scene: MapScene) {
this.scene = scene;
for (let tileset of WALLS ) this.addTileset(tileset.key, Layer.WALL);
for (let tileset of GROUNDS) this.addTileset(tileset.key, Layer.GROUND);
for (let tileset of OVERLAYS) this.addTileset(tileset.key, Layer.OVERLAY);
}
private addTileset(key: string, layer: Layer): void {
let res = this.scene.textures.get(key).getSourceImage(0).width / 9;
if (this.canvases[res] == undefined)
this.canvases[res] = [ new TilesetCanvas(this, res, Layer.GROUND), new TilesetCanvas(this, res, Layer.WALL), new TilesetCanvas(this, res, Layer.OVERLAY) ];
let ind = (layer == Layer.WALL ? this.currentWallInd : layer == Layer.GROUND ? this.currentGroundInd : this.currentOverlayInd);
let canvas = this.canvases[res];
this[layer == Layer.WALL ? "wallLocations" : layer == Layer.GROUND ? "groundLocations" : "overlayLocations"][ind] = { res: res, ind: ind, key: key };
this.indexes[key] = ind;
canvas[layer].addTileset(key, ind);
layer == Layer.WALL ? this.currentWallInd++ :
layer == Layer.GROUND ? this.currentGroundInd++ :
this.currentOverlayInd++;
}
resolutions(): string[] {
let resList: string[] = [];
for (let res of Object.keys(this.canvases)) resList.push(res);
return resList;
}
getTilesetRes(tileset: number, layer: Layer): number {
return layer == Layer.WALL ? this.wallLocations[tileset].res
: layer == Layer.GROUND ? this.groundLocations[tileset].res
: this.overlayLocations[tileset].res;
}
getGlobalTileIndex(tileset: number, tile: number, layer: Layer): number {
return this.canvases[this.getTilesetRes(tileset, layer)][layer].getGlobalIndex(tileset, tile);
}
getLocalTileIndex(tileset: number, tile: number, layer: Layer): number {
return this.canvases[this.getTilesetRes(tileset, layer)][layer].getLocalIndex(tile);
}
}

2350
tool.js

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
{
"lib": "es6",
"compilerOptions": {
"target": "es5",
"target": "es6",
"rootDirs": [
"src/",
"src/*"