diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2018-11-21 21:44:11 +0100 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2018-11-21 21:44:11 +0100 |
commit | 2c6cd362c32a2e9460e5ddebd85f050b9b5ab4e4 (patch) | |
tree | 7b02c4094968629dda47ccab5eae1c49314ffb87 | |
parent | 4443ca205812f4da4aa0ed1bf4897e731107616b (diff) | |
download | rpgedit-2c6cd362c32a2e9460e5ddebd85f050b9b5ab4e4.tar rpgedit-2c6cd362c32a2e9460e5ddebd85f050b9b5ab4e4.zip |
Allow using animated entities as map tiles
A more optimized implementation for animated tiles is planned.
-rw-r--r-- | dist/resources/entity/water.json | 12 | ||||
-rw-r--r-- | dist/resources/map/test.json | 34 | ||||
-rw-r--r-- | dist/resources/sprite/entity/water.png | bin | 0 -> 1718 bytes | |||
-rw-r--r-- | dist/resources/sprite/tile/water.png | bin | 778 -> 0 bytes | |||
-rw-r--r-- | src/view/map.ts | 127 |
5 files changed, 132 insertions, 41 deletions
diff --git a/dist/resources/entity/water.json b/dist/resources/entity/water.json new file mode 100644 index 0000000..79c7780 --- /dev/null +++ b/dist/resources/entity/water.json @@ -0,0 +1,12 @@ +{ + "sprite": "water", + "frames": 4, + "animation": { + "sequence": [ + [500, 0], + [500, 1], + [500, 2], + [500, 3] + ] + } +} diff --git a/dist/resources/map/test.json b/dist/resources/map/test.json index ec3b3fb..91efc19 100644 --- a/dist/resources/map/test.json +++ b/dist/resources/map/test.json @@ -1,22 +1,22 @@ { "tiles": [ - "stone/floor", - "stone/plate", - "stone/wall/top", - "stone/wall/right", - "stone/wall/bottom", - "stone/wall/left", - "stone/wall/top_left", - "stone/wall/top_right", - "stone/wall/bottom_right", - "stone/wall/bottom_left", - "stone/wall/top_left_inner", - "stone/wall/top_right_inner", - "stone/wall/bottom_right_inner", - "stone/wall/bottom_left_inner", - "water", - "stone/border/bottom_right", - "stone/border/bottom_left" + "-stone/floor", + "-stone/plate", + "-stone/wall/top", + "-stone/wall/right", + "-stone/wall/bottom", + "-stone/wall/left", + "-stone/wall/top_left", + "-stone/wall/top_right", + "-stone/wall/bottom_right", + "-stone/wall/bottom_left", + "-stone/wall/top_left_inner", + "-stone/wall/top_right_inner", + "-stone/wall/bottom_right_inner", + "-stone/wall/bottom_left_inner", + "@water", + "-stone/border/bottom_right", + "-stone/border/bottom_left" ], "layers": [ { diff --git a/dist/resources/sprite/entity/water.png b/dist/resources/sprite/entity/water.png Binary files differnew file mode 100644 index 0000000..61c2d4f --- /dev/null +++ b/dist/resources/sprite/entity/water.png diff --git a/dist/resources/sprite/tile/water.png b/dist/resources/sprite/tile/water.png Binary files differdeleted file mode 100644 index 4a96543..0000000 --- a/dist/resources/sprite/tile/water.png +++ /dev/null diff --git a/src/view/map.ts b/src/view/map.ts index c796c6f..5eedaca 100644 --- a/src/view/map.ts +++ b/src/view/map.ts @@ -1,3 +1,4 @@ +import { EntityView } from './entity'; import { Renderer } from './renderer/renderer'; import { SpriteCoords, SpriteView, SpriteViewBuilder } from './sprite'; import { loadImage, mkTexture } from './util/image'; @@ -6,39 +7,91 @@ import { MapData } from '../model/data/map'; import { nextPowerOf2 } from '../util'; +import { vec2 } from 'gl-matrix'; + +interface StaticMapTile { + type: 'static'; + image: HTMLImageElement; +} + +interface EntityTile { + type: 'entity'; + entity: EntityView; +} + +type MapTile = StaticMapTile | EntityTile; + +interface StaticTilesetTile { + type: 'static'; + coords: SpriteCoords; +} + +type TilesetTile = StaticTilesetTile | EntityTile; + interface Tileset { texture: WebGLTexture; - tiles: SpriteCoords[]; + tiles: TilesetTile[]; } -function loadTiles(tiles: string[]): Promise<HTMLImageElement[]> { - return Promise.all(tiles.map((t) => loadImage(`resources/sprite/tile/${t}.png`))); +async function loadTile(r: Renderer, tile: string): Promise<MapTile> { + const name = tile.substr(1); + switch (tile[0]) { + case '-': + return { + type: 'static', + image: await loadImage(`resources/sprite/tile/${name}.png`), + }; + + case '@': + return { + type: 'entity', + entity: await EntityView.load(r, name), + }; + + default: + throw new Error('invalid tile specifier'); + } +} + +function loadTiles(r: Renderer, tiles: string[]): Promise<MapTile[]> { + return Promise.all(tiles.map((tile) => loadTile(r, tile))); } function mkTileset( r: Renderer, - tiles: HTMLImageElement[], + mapTiles: MapTile[], ): Tileset { const tileSize = 32; - const canvasDim = nextPowerOf2(Math.sqrt(tiles.length)); + const canvasDim = nextPowerOf2(Math.sqrt(mapTiles.length)); const canvasSize = canvasDim * tileSize; const canvas = document.createElement('canvas'); canvas.width = canvas.height = canvasSize; let x = 0, y = 0; - const tileCoords: SpriteCoords[] = []; + const tiles: TilesetTile[] = []; const ctx = canvas.getContext('2d') as CanvasRenderingContext2D; - for (const tile of tiles) { - ctx.drawImage(tile, x * tileSize, y * tileSize); - tileCoords.push([x / canvasDim, y / canvasDim, (x + 1) / canvasDim, (y + 1) / canvasDim]); - - x++; - if (x === canvasDim) { - x = 0; - y++; + for (const tile of mapTiles) { + switch (tile.type) { + case 'static': + ctx.drawImage(tile.image, x * tileSize, y * tileSize); + tiles.push({ + type: 'static', + coords: [x / canvasDim, y / canvasDim, (x + 1) / canvasDim, (y + 1) / canvasDim], + }); + + x++; + if (x === canvasDim) { + x = 0; + y++; + } + break; + + case 'entity': + tiles.push(tile); + break; } } @@ -46,40 +99,66 @@ function mkTileset( return { texture, - tiles: tileCoords, + tiles, }; } -function addSprite(builder: SpriteViewBuilder, tileset: Tileset, x: number, y: number, tile: number) { - if (tile === 0) +function addSprite( + builder: SpriteViewBuilder, + entityTiles: Array<[[number, number], EntityView]>, + tileset: Tileset, + x: number, + y: number, + tile: number) { + if (!tile) return; - const tilePos = tileset.tiles[tile - 1]; - builder.addSprite([x, y, x + 1, y + 1], tilePos); + const tilesetTile = tileset.tiles[tile - 1]; + + switch (tilesetTile.type) { + case 'static': + builder.addSprite([x, y, x + 1, y + 1], tilesetTile.coords); + break; + + case 'entity': + entityTiles.push([[x + 0.5, y + 0.5], tilesetTile.entity]); + break; + } } function buildMapLayer(r: Renderer, tileset: Tileset, layer: number[][]): MapLayerView { const builder = new SpriteViewBuilder(r, tileset.texture); + const entityTiles: Array<[[number, number], EntityView]> = []; for (let x = 0; x < layer[0].length; x++) for (let y = 0; y < layer.length; y++) - addSprite(builder, tileset, x, y, layer[y][x]); + addSprite(builder, entityTiles, tileset, x, y, layer[y][x]); - return new MapLayerView(builder.build()); + return new MapLayerView(r, builder.build(), entityTiles); } class MapLayerView { - public constructor(private sprites: SpriteView) { + public constructor( + private r: Renderer, + private staticTiles: SpriteView, + private entityTiles: Array<[[number, number], EntityView]>, + ) { } public render(time: number): void { - this.sprites.render(); + this.r.setTranslation([0, 0]); + this.staticTiles.render(); + + for (const [coords, entity] of this.entityTiles) { + this.r.setTranslation(coords); + entity.renderByTime(time); + } } } export class MapView { public static async load(r: Renderer, map: MapData): Promise<MapView> { - const tiles = await loadTiles(map.tiles); + const tiles = await loadTiles(r, map.tiles); const tileset = mkTileset(r, tiles); const layers = map.layers.map((layer) => buildMapLayer(r, tileset, layer.tiles)); |