2024-02-14 23:31:39 +01:00
|
|
|
import { Frame, defineFrame } from "./framework.js";
|
|
|
|
import tilemapRegistry from "./tilemap-registry.js";
|
|
|
|
|
|
|
|
export function canConnect(tile) {
|
|
|
|
return tile == 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function shouldConnect(a, b) {
|
|
|
|
return a == b;
|
|
|
|
}
|
|
|
|
|
|
|
|
export class TileEditor extends Frame {
|
2024-02-11 23:05:08 +01:00
|
|
|
constructor() {
|
|
|
|
super();
|
2024-02-14 23:31:39 +01:00
|
|
|
this.tileCursor = { x: 0, y: 0 };
|
|
|
|
|
|
|
|
this.colorScheme = {
|
|
|
|
background: "#F7F7F7",
|
|
|
|
grid: "#00000011",
|
|
|
|
tileCursor: "#222222",
|
|
|
|
tiles: [
|
|
|
|
"transparent",
|
|
|
|
"#eb134a",
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
|
|
|
this.tileColorPalette = [
|
|
|
|
"transparent",
|
|
|
|
"#eb134a",
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
connectedCallback() {
|
|
|
|
super.connectedCallback();
|
|
|
|
|
|
|
|
this.tileSize = parseInt(this.getAttribute("data-tile-size"));
|
|
|
|
|
|
|
|
let tilemapId = this.getAttribute("data-tilemap-id");
|
|
|
|
console.log(tilemapRegistry);
|
|
|
|
if (tilemapId != null) {
|
|
|
|
this.tilemap = tilemapRegistry[this.getAttribute("data-tilemap-id")];
|
|
|
|
} else {
|
|
|
|
throw new ReferenceError(`tilemap '${tilemapId}' does not exist`);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0st element is explicitly null because it represents the empty tile.
|
|
|
|
this.tilesets = [null];
|
|
|
|
|
|
|
|
let attachedImages = this.getElementsByTagName("img");
|
|
|
|
for (let image of attachedImages) {
|
|
|
|
if (image.hasAttribute("data-tairu-tileset")) {
|
|
|
|
let tilesetIndex = parseInt(image.getAttribute("data-tairu-tileset"));
|
|
|
|
this.tilesets[tilesetIndex] = image;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.width = this.tilemap.width * this.tileSize;
|
|
|
|
this.height = this.tilemap.height * this.tileSize;
|
|
|
|
|
|
|
|
this.hasFocus = false;
|
|
|
|
this.paintingTile = null;
|
|
|
|
|
|
|
|
this.addEventListener("mousemove", event => this.mouseMoved(event));
|
|
|
|
this.addEventListener("mousedown", event => this.mousePressed(event));
|
|
|
|
this.addEventListener("mouseup", event => this.mouseReleased(event));
|
|
|
|
|
|
|
|
this.addEventListener("mouseenter", _ => this.hasFocus = true);
|
|
|
|
this.addEventListener("mouseleave", _ => this.hasFocus = false);
|
|
|
|
|
|
|
|
this.addEventListener("contextmenu", event => event.preventDefault());
|
|
|
|
|
|
|
|
// TODO: This should also work on mobile.
|
|
|
|
}
|
|
|
|
|
|
|
|
draw() {
|
|
|
|
this.ctx.fillStyle = this.colorScheme.background;
|
|
|
|
this.ctx.fillRect(0, 0, this.width, this.height);
|
|
|
|
|
|
|
|
this.drawTiles();
|
|
|
|
this.drawGrid();
|
|
|
|
if (this.hasFocus) {
|
|
|
|
this.drawTileCursor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
drawGrid() {
|
|
|
|
this.ctx.beginPath();
|
|
|
|
for (let x = 0; x < this.tilemap.width; ++x) {
|
|
|
|
this.ctx.moveTo(x * this.tileSize, 0);
|
|
|
|
this.ctx.lineTo(x * this.tileSize, this.height);
|
|
|
|
}
|
|
|
|
for (let y = 0; y < this.tilemap.width; ++y) {
|
|
|
|
this.ctx.moveTo(0, y * this.tileSize);
|
|
|
|
this.ctx.lineTo(this.width, y * this.tileSize);
|
|
|
|
}
|
|
|
|
this.ctx.strokeStyle = this.colorScheme.grid;
|
|
|
|
this.ctx.lineWidth = 1;
|
|
|
|
this.ctx.stroke();
|
|
|
|
}
|
|
|
|
|
|
|
|
drawTileCursor() {
|
|
|
|
this.ctx.strokeStyle = this.colorScheme.tileCursor;
|
|
|
|
this.ctx.lineWidth = 5;
|
|
|
|
this.ctx.strokeRect(this.tileCursor.x * this.tileSize, this.tileCursor.y * this.tileSize, this.tileSize, this.tileSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
get hasTilesets() {
|
|
|
|
// Remember that tile 0 represents emptiness.
|
|
|
|
return this.tilesets.length > 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
drawTiles() {
|
|
|
|
if (this.hasTilesets) {
|
|
|
|
this.drawTexturedTiles();
|
|
|
|
} else {
|
|
|
|
this.drawColoredTiles();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
drawColoredTiles() {
|
|
|
|
for (let y = 0; y < this.tilemap.height; ++y) {
|
|
|
|
for (let x = 0; x < this.tilemap.width; ++x) {
|
|
|
|
let tile = this.tilemap.at(x, y);
|
|
|
|
if (tile != 0) {
|
|
|
|
this.ctx.fillStyle = this.colorScheme.tiles[tile];
|
|
|
|
this.ctx.fillRect(x * this.tileSize, y * this.tileSize, this.tileSize, this.tileSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-11 23:05:08 +01:00
|
|
|
|
2024-02-14 23:31:39 +01:00
|
|
|
drawTexturedTiles() {
|
|
|
|
this.ctx.imageSmoothingEnabled = false;
|
2024-02-11 23:05:08 +01:00
|
|
|
|
2024-02-14 23:31:39 +01:00
|
|
|
for (let y = 0; y < this.tilemap.height; ++y) {
|
|
|
|
for (let x = 0; x < this.tilemap.width; ++x) {
|
|
|
|
let tile = this.tilemap.at(x, y);
|
|
|
|
if (tile != 0) {
|
|
|
|
let tileset = this.tilesets[tile];
|
|
|
|
|
|
|
|
let connectedWithEast = shouldConnect(tile, this.tilemap.at(x + 1, y)) ? 0b0001 : 0;
|
|
|
|
let connectedWithSouth = shouldConnect(tile, this.tilemap.at(x, y + 1)) ? 0b0010 : 0;
|
|
|
|
let connectedWithWest = shouldConnect(tile, this.tilemap.at(x - 1, y)) ? 0b0100 : 0;
|
|
|
|
let connectedWithNorth = shouldConnect(tile, this.tilemap.at(x, y - 1)) ? 0b1000 : 0;
|
|
|
|
let tileIndex = connectedWithNorth
|
|
|
|
| connectedWithWest
|
|
|
|
| connectedWithSouth
|
|
|
|
| connectedWithEast;
|
|
|
|
|
|
|
|
let tilesetTileSize = tileset.height;
|
|
|
|
let tilesetX = tileIndex * tilesetTileSize;
|
|
|
|
let tilesetY = 0;
|
|
|
|
this.ctx.drawImage(
|
|
|
|
this.tilesets[tile],
|
|
|
|
tilesetX, tilesetY, tilesetTileSize, tilesetTileSize,
|
|
|
|
x * this.tileSize, y * this.tileSize, this.tileSize, this.tileSize,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mouseMoved(event) {
|
|
|
|
let mouse = this.getMousePositionFromEvent(event);
|
|
|
|
this.tileCursor.x = Math.floor(mouse.x / this.tileSize);
|
|
|
|
this.tileCursor.y = Math.floor(mouse.y / this.tileSize);
|
|
|
|
this.paintTileUnderCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
mousePressed(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
if (event.button == 0) {
|
|
|
|
this.paintingTile = 1;
|
|
|
|
} else if (event.button == 2) {
|
|
|
|
this.paintingTile = 0;
|
|
|
|
}
|
|
|
|
this.paintTileUnderCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
mouseReleased() {
|
|
|
|
this.paintingTile = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
paintTileUnderCursor() {
|
|
|
|
if (this.paintingTile != null) {
|
|
|
|
this.tilemap.setAt(this.tileCursor.x, this.tileCursor.y, this.paintingTile);
|
|
|
|
}
|
2024-02-11 23:05:08 +01:00
|
|
|
}
|
|
|
|
}
|
2024-02-14 23:31:39 +01:00
|
|
|
defineFrame("tairu-editor", TileEditor);
|
|
|
|
|
|
|
|
console.log("tairu editor loaded");
|