135 lines
3.9 KiB
JavaScript
135 lines
3.9 KiB
JavaScript
import { Sketch } from "treehouse/sandbox.js";
|
|
|
|
export class TileEditor extends Sketch {
|
|
constructor({ tilemap, tileSize }) {
|
|
super(tilemap.width * tileSize, tilemap.height * tileSize);
|
|
|
|
this.colorScheme = {
|
|
background: "#F7F7F7",
|
|
grid: "#00000011",
|
|
tileCursor: "#222222",
|
|
tiles: [
|
|
"transparent", // never actually drawn to the screen with the default renderer!
|
|
"#eb134a",
|
|
],
|
|
};
|
|
|
|
this.tilemap = tilemap;
|
|
this.tileSize = tileSize;
|
|
|
|
this.hasFocus = false;
|
|
this.paintingTile = null;
|
|
this.tileCursor = { x: 0, y: 0 };
|
|
|
|
this.canvas.addEventListener("mousemove", event => this.mouseMoved(event));
|
|
this.canvas.addEventListener("mousedown", event => this.mousePressed(event));
|
|
this.canvas.addEventListener("mouseup", event => this.mouseReleased(event));
|
|
|
|
this.canvas.addEventListener("mouseenter", _ => this.mouseEnter());
|
|
this.canvas.addEventListener("mouseleave", _ => this.mouseLeave());
|
|
|
|
this.canvas.addEventListener("contextmenu", event => event.preventDefault());
|
|
|
|
// Only draw first frame after the constructor already runs.
|
|
// That way we can modify the color scheme however much we want without causing additional
|
|
// redraws.
|
|
requestAnimationFrame(() => this.draw());
|
|
}
|
|
|
|
draw() {
|
|
this.drawBackground();
|
|
this.drawTilemap();
|
|
this.drawGrid();
|
|
if (this.hasFocus) {
|
|
this.drawTileCursor();
|
|
}
|
|
}
|
|
|
|
drawBackground() {
|
|
this.ctx.fillStyle = this.colorScheme.background;
|
|
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
}
|
|
|
|
drawTilemap() {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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.canvas.height);
|
|
}
|
|
for (let y = 0; y < this.tilemap.width; ++y) {
|
|
this.ctx.moveTo(0, y * this.tileSize);
|
|
this.ctx.lineTo(this.canvas.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);
|
|
}
|
|
|
|
|
|
mouseMoved(event) {
|
|
this.tileCursor.x = Math.floor(event.offsetX / this.tileSize);
|
|
this.tileCursor.y = Math.floor(event.offsetY / this.tileSize);
|
|
this.paintTileUnderCursor();
|
|
|
|
this.draw();
|
|
}
|
|
|
|
mousePressed(event) {
|
|
event.preventDefault();
|
|
|
|
if (event.button == 0) {
|
|
this.paintingTile = 1;
|
|
} else if (event.button == 2) {
|
|
this.paintingTile = 0;
|
|
}
|
|
|
|
this.paintTileUnderCursor();
|
|
|
|
this.draw();
|
|
}
|
|
|
|
mouseReleased(_event) {
|
|
this.stopPainting();
|
|
this.draw();
|
|
}
|
|
|
|
mouseEnter() {
|
|
this.hasFocus = true;
|
|
this.draw();
|
|
}
|
|
|
|
mouseLeave() {
|
|
this.hasFocus = false;
|
|
this.stopPainting();
|
|
this.draw();
|
|
}
|
|
|
|
paintTileUnderCursor() {
|
|
if (this.paintingTile != null) {
|
|
this.tilemap.setAt(this.tileCursor.x, this.tileCursor.y, this.paintingTile);
|
|
}
|
|
}
|
|
|
|
stopPainting() {
|
|
this.paintingTile = null;
|
|
}
|
|
}
|