feat: topdown

This commit is contained in:
cha0s 2019-03-25 19:03:34 -05:00
parent d5356d8186
commit ad99cd3f3f
7 changed files with 268 additions and 0 deletions

View File

@ -0,0 +1,49 @@
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
import {compose} from '@avocado/core';
import {Vector} from '@avocado/math';
import {Image} from './image';
import {Renderable} from './renderable';
const decorate = compose(
Vector.Mixin('size', 'width', 'height', {
default: [0, 0],
}),
);
export class Canvas extends decorate(Renderable) {
constructor() {
super();
this.renderTexture = PIXI.RenderTexture.create(1, 1);
}
destroy() {
this.renderTexture.destroy();
}
get internal() {
return this.renderTexture;
}
renderWith(renderable, renderer) {
renderer.render(renderable, this);
}
get size() {
return super.size;
}
set size(size) {
this.renderTexture.resize(size[0], size[1]);
super.size = size;
}
toImage() {
const image = new Image();
image.texture = this.renderTexture.clone();
return image;
}
}

View File

@ -1,6 +1,7 @@
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
export {AnimationView} from './animation-view';
export {Canvas} from './canvas';
export {Color} from './color';
export {Container} from './container';
export {hasGraphics} from './has-graphics';

View File

@ -0,0 +1,3 @@
export {TilesView} from './tiles-view';
export {Tiles} from './tiles';
export {Tileset} from './tileset';

View File

@ -0,0 +1,12 @@
{
"name": "@avocado/topdown",
"version": "1.0.0",
"main": "index.js",
"author": "cha0s",
"license": "MIT",
"dependencies": {
"@avocado/core": "1.x",
"@avocado/graphics": "1.x",
"@avocado/math": "1.x"
}
}

View File

@ -0,0 +1,72 @@
import {compose} from '@avocado/core';
import {Canvas, Container, Renderable, Sprite} from '@avocado/graphics';
import {Vector} from '@avocado/math';
export class TilesView extends Renderable {
constructor(tiles, tileset) {
super();
this.tiles = tiles;
this.tileset = tileset;
this.canvas = new Canvas();
this.sprite = undefined;
}
destroy() {
this.container.destroy();
}
indexMapFromSlice(slice) {
const indexes = new Map();
for (const i in slice) {
const tile = slice[i];
if (!indexes.get(tile)) {
indexes.set(tile, new Set());
}
indexes.get(tile).add(parseInt(i));
}
return indexes;
}
get internal() {
return this.canvas.internal;
}
renderWith(renderer) {
const size = this.tiles.size;
const tileSize = Vector.mul(this.tileset.tileSize, this.scale);
const rowWidth = size[0] * tileSize[0];
const canvasSize = Vector.mul(size, tileSize);
this.canvas.size = canvasSize;
const slice = this.tiles.slice([0, 0, size[0], size[1]]);
const indexMap = this.indexMapFromSlice(slice);
const container = new Container();
for (const [tile, indexes] of indexMap.entries()) {
let iterator = indexes.values();
let result = iterator.next();
while (!result.done) {
const position = [0, 0];
const validIndex = result.value;
for (const indexString in slice) {
const index = parseInt(indexString);
if (index === validIndex) {
const sprite = new Sprite(this.tileset.subimages[tile]);
sprite.scale = this.scale;
sprite.position = position;
container.addChild(sprite);
}
position[0] += tileSize[0];
if (rowWidth === position[0]) {
position[1] += tileSize[1];
position[0] = 0;
}
}
result = iterator.next();
}
}
this.canvas.renderWith(container, renderer);
container.destroy();
return this.canvas.toImage();
}
}

56
packages/topdown/tiles.js Normal file
View File

@ -0,0 +1,56 @@
import {compose} from '@avocado/core';
import {Rectangle, Vector} from '@avocado/math';
const decorate = compose(
Vector.Mixin('size', 'width', 'height', {
default: [0, 0],
}),
);
class TilesBase {
fromJSON(json) {
if (json.size) {
this.size = json.size;
}
if (json.data) {
this.data = json.data;
}
return this;
}
get rectangle() {
return Rectangle.compose([0, 0], this.size);
}
slice(rectangle) {
const tilesRectangle = this.rectangle;
if (!Rectangle.intersects(rectangle, tilesRectangle)) {
return [];
}
let [x, y, width, height] = Rectangle.intersection(rectangle, tilesRectangle);
const rowWidth = tilesRectangle[2];
const slice = new Array(width * height);
for (let j = 0; j < height; ++j) {
for (let i = 0; i < width; ++i) {
slice[y * width + x] = this.data[y * rowWidth + x];
x++;
}
y++;
x -= width;
}
return slice;
}
tileAt(x, y) {
const [width, height] = this.size;
return this.data[y * width + x];
}
toJSON() {
}
}
export class Tiles extends decorate(TilesBase) {}

View File

@ -0,0 +1,75 @@
import {compose} from '@avocado/core';
import {Vector} from '@avocado/math';
const decorate = compose(
Vector.Mixin('tileSize', 'tileWidth', 'tileHeight', {
default: [0, 0],
}),
);
class TilesetBase {
constructor(image) {
this.image = image;
this._rowWidth = 0;
this.subimages = [];
this._tilesCount = 0;
}
destroy() {
this.subimages.forEach((sprite) => {
sprite.destroy();
});
this.subimages = [];
}
get rowWidth() {
return this._rowWidth;
}
set tileIndex(index) {
const tileSize = this.tileSize;
const x = index % this._rowWidth;
const y = Math.floor(index / this._rowWidth)
const sourceRectangle = [
x * tileSize[0],
y * tileSize[1],
tileSize[0],
tileSize[1],
];
this.sourceRectangle = sourceRectangle;
}
get tilesCount() {
return this._tilesCount;
}
}
export class Tileset extends decorate(TilesetBase) {
get tileSize() {
return super.tileSize;
}
set tileSize(tileSize) {
const image = this.image;
const grid = Vector.div(image.size, tileSize);
this.destroy();
for (let y = 0; y < grid[1]; ++y) {
for (let x = 0; x < grid[0]; ++x) {
const subimage = image.subimage([
x * tileSize[0],
y * tileSize[1],
tileSize[0],
tileSize[1],
]);
this.subimages.push(subimage);
}
}
this._tilesCount = Vector.area(grid);
this._rowWidth = grid[0];
super.tileSize = tileSize;
}
}