feat: topdown
This commit is contained in:
parent
d5356d8186
commit
ad99cd3f3f
49
packages/graphics/canvas.js
Normal file
49
packages/graphics/canvas.js
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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';
|
||||
|
|
3
packages/topdown/index.js
Normal file
3
packages/topdown/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
export {TilesView} from './tiles-view';
|
||||
export {Tiles} from './tiles';
|
||||
export {Tileset} from './tileset';
|
12
packages/topdown/package.json
Normal file
12
packages/topdown/package.json
Normal 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"
|
||||
}
|
||||
}
|
72
packages/topdown/tiles-view.js
Normal file
72
packages/topdown/tiles-view.js
Normal 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
56
packages/topdown/tiles.js
Normal 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) {}
|
75
packages/topdown/tileset.js
Normal file
75
packages/topdown/tileset.js
Normal 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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user