Editor: center/pad the level, fix some bugs with pencil drawing
This commit is contained in:
parent
349af15e05
commit
dff3081194
@ -191,7 +191,12 @@
|
|||||||
also deal with levels vs level /packs/ somehow, not sure how that'll work (including downloading them, yeargh?)
|
also deal with levels vs level /packs/ somehow, not sure how that'll work (including downloading them, yeargh?)
|
||||||
-->
|
-->
|
||||||
</header>
|
</header>
|
||||||
<div class="level"><!-- level canvas and any overlays go here --></div>
|
<div class="editor-canvas">
|
||||||
|
<div class="-container">
|
||||||
|
<!-- level canvas and any overlays go here -->
|
||||||
|
<!-- the container is to allow them to scroll as a single unit -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<nav class="controls">
|
<nav class="controls">
|
||||||
<div id="editor-toolbar">
|
<div id="editor-toolbar">
|
||||||
<!-- tools go here -->
|
<!-- tools go here -->
|
||||||
|
|||||||
@ -84,6 +84,19 @@ class MouseOperation {
|
|||||||
this.cleanup();
|
this.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*iter_touched_cells(gxf, gyf) {
|
||||||
|
for (let pt of walk_grid(
|
||||||
|
this.gx1f, this.gy1f, gxf, gyf,
|
||||||
|
// Bound the grid walk to one cell beyond the edges of the level, so that dragging the
|
||||||
|
// mouse in from outside the actual edges still works reliably
|
||||||
|
-1, -1, this.editor.stored_level.size_x, this.editor.stored_level.size_y))
|
||||||
|
{
|
||||||
|
if (this.editor.is_in_bounds(...pt)) {
|
||||||
|
yield pt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Implement these
|
// Implement these
|
||||||
start() {}
|
start() {}
|
||||||
step(x, y) {}
|
step(x, y) {}
|
||||||
@ -94,8 +107,9 @@ class MouseOperation {
|
|||||||
|
|
||||||
class PanOperation extends MouseOperation {
|
class PanOperation extends MouseOperation {
|
||||||
step(mx, my) {
|
step(mx, my) {
|
||||||
this.editor.viewport_el.scrollLeft -= mx - this.mx1;
|
let target = this.editor.viewport_el.parentNode;
|
||||||
this.editor.viewport_el.scrollTop -= my - this.my1;
|
target.scrollLeft -= mx - this.mx1;
|
||||||
|
target.scrollTop -= my - this.my1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +121,7 @@ class PencilOperation extends DrawOperation {
|
|||||||
this.editor.place_in_cell(this.gx1, this.gy1, this.editor.palette_selection);
|
this.editor.place_in_cell(this.gx1, this.gy1, this.editor.palette_selection);
|
||||||
}
|
}
|
||||||
step(mx, my, gxf, gyf) {
|
step(mx, my, gxf, gyf) {
|
||||||
for (let [x, y] of walk_grid(this.gx1f, this.gy1f, gxf, gyf)) {
|
for (let [x, y] of this.iter_touched_cells(gxf, gyf)) {
|
||||||
this.editor.place_in_cell(x, y, this.editor.palette_selection);
|
this.editor.place_in_cell(x, y, this.editor.palette_selection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,7 +139,7 @@ class ForceFloorOperation extends DrawOperation {
|
|||||||
// the same direction, but shouldn't
|
// the same direction, but shouldn't
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let prevx, prevy;
|
let prevx, prevy;
|
||||||
for (let [x, y] of walk_grid(this.gx1f, this.gy1f, gxf, gyf)) {
|
for (let [x, y] of this.iter_touched_cells(gxf, gyf)) {
|
||||||
i++;
|
i++;
|
||||||
// The very first cell is the one the mouse was already in, and we don't
|
// The very first cell is the one the mouse was already in, and we don't
|
||||||
// have a movement direction yet, so leave that alone
|
// have a movement direction yet, so leave that alone
|
||||||
@ -542,7 +556,7 @@ export class Editor extends PrimaryView {
|
|||||||
constructor(conductor) {
|
constructor(conductor) {
|
||||||
super(conductor, document.body.querySelector('main#editor'));
|
super(conductor, document.body.querySelector('main#editor'));
|
||||||
|
|
||||||
this.viewport_el = this.root.querySelector('.level');
|
this.viewport_el = this.root.querySelector('.editor-canvas .-container');
|
||||||
|
|
||||||
// FIXME don't hardcode size here, convey this to renderer some other way
|
// FIXME don't hardcode size here, convey this to renderer some other way
|
||||||
this.renderer = new CanvasRenderer(this.conductor.tileset, 32);
|
this.renderer = new CanvasRenderer(this.conductor.tileset, 32);
|
||||||
@ -575,6 +589,7 @@ export class Editor extends PrimaryView {
|
|||||||
}
|
}
|
||||||
else if (ev.button === 1) {
|
else if (ev.button === 1) {
|
||||||
// Middle button: always pan
|
// Middle button: always pan
|
||||||
|
console.log("middle button!");
|
||||||
this.mouse_op = new PanOperation(this, ev);
|
this.mouse_op = new PanOperation(this, ev);
|
||||||
|
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
@ -593,7 +608,10 @@ export class Editor extends PrimaryView {
|
|||||||
this.renderer.draw();
|
this.renderer.draw();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.viewport_el.addEventListener('mousemove', ev => {
|
// Once the mouse is down, we should accept mouse movement anywhere
|
||||||
|
window.addEventListener('mousemove', ev => {
|
||||||
|
if (! this.active)
|
||||||
|
return;
|
||||||
if (! this.mouse_op)
|
if (! this.mouse_op)
|
||||||
return;
|
return;
|
||||||
if ((ev.buttons & this.mouse_op.button_mask) === 0) {
|
if ((ev.buttons & this.mouse_op.button_mask) === 0) {
|
||||||
@ -766,7 +784,7 @@ export class Editor extends PrimaryView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is_in_level(x, y) {
|
is_in_bounds(x, y) {
|
||||||
return 0 <= x && x < this.stored_level.size_x && 0 <= y && y < this.stored_level.size_y;
|
return 0 <= x && x < this.stored_level.size_x && 0 <= y && y < this.stored_level.size_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -775,11 +793,6 @@ export class Editor extends PrimaryView {
|
|||||||
if (! name)
|
if (! name)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO seems like a big problem to silently ignore, but it can happen from mouse
|
|
||||||
// coordinates while drawing
|
|
||||||
if (! this.is_in_level(x, y))
|
|
||||||
return;
|
|
||||||
|
|
||||||
let type = TILE_TYPES[name];
|
let type = TILE_TYPES[name];
|
||||||
let direction;
|
let direction;
|
||||||
if (type.is_actor) {
|
if (type.is_actor) {
|
||||||
|
|||||||
17
js/util.js
17
js/util.js
@ -153,7 +153,7 @@ export function string_from_buffer_ascii(buf, start = 0, len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cast a line through a grid and yield every cell it touches
|
// Cast a line through a grid and yield every cell it touches
|
||||||
export function* walk_grid(x0, y0, x1, y1) {
|
export function* walk_grid(x0, y0, x1, y1, min_a, min_b, max_a, max_b) {
|
||||||
// TODO if the ray starts outside the grid (extremely unlikely), we should
|
// TODO if the ray starts outside the grid (extremely unlikely), we should
|
||||||
// find the point where it ENTERS the grid, otherwise the 'while'
|
// find the point where it ENTERS the grid, otherwise the 'while'
|
||||||
// conditions below will stop immediately
|
// conditions below will stop immediately
|
||||||
@ -193,27 +193,24 @@ export function* walk_grid(x0, y0, x1, y1) {
|
|||||||
step_a = -step_a;
|
step_a = -step_a;
|
||||||
offset_x = 1 - offset_x;
|
offset_x = 1 - offset_x;
|
||||||
}
|
}
|
||||||
// Zero offset means we're on a grid line, so we're actually a full cell
|
else if (offset_x === 0) {
|
||||||
// away from the next grid line
|
// Zero offset means we're on a grid line, so we're a full cell away from the next grid line
|
||||||
if (offset_x === 0) {
|
// (if we're moving forward; if we're moving backward, the next cell really is 0 away)
|
||||||
offset_x = 1;
|
offset_x = 1;
|
||||||
}
|
}
|
||||||
let step_b = 1;
|
let step_b = 1;
|
||||||
let offset_y = 1 - (y0 - b);
|
let offset_y = 1 - (y0 - b);
|
||||||
if (dy < 0) {
|
if (dy < 0) {
|
||||||
dy = -dy;
|
dy = -dy;
|
||||||
step_b = -step_b;
|
step_b = -step_b;
|
||||||
offset_y = 1 - offset_y;
|
offset_y = 1 - offset_y;
|
||||||
}
|
}
|
||||||
if (offset_y === 0) {
|
else if (offset_y === 0) {
|
||||||
offset_y = 1;
|
offset_y = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let err = dy * offset_x - dx * offset_y;
|
let err = dy * offset_x - dx * offset_y;
|
||||||
|
|
||||||
let min_a = 0, min_b = 0;
|
|
||||||
// TODO get these passed in fool
|
|
||||||
let max_a = 31, max_b = 31;
|
|
||||||
if (dx > dy) {
|
if (dx > dy) {
|
||||||
// Main axis is x/a
|
// Main axis is x/a
|
||||||
while (min_a <= a && a <= max_a && min_b <= b && b <= max_b) {
|
while (min_a <= a && a <= max_a && min_b <= b && b <= max_b) {
|
||||||
@ -252,6 +249,8 @@ export function* walk_grid(x0, y0, x1, y1) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
window.walk_grid = walk_grid;
|
||||||
|
// console.table(Array.from(walk_grid(13, 27.133854389190674, 12.90625, 27.227604389190674)))
|
||||||
|
|
||||||
// Root class to indirect over where we might get files from
|
// Root class to indirect over where we might get files from
|
||||||
// - a pool of uploaded in-memory files
|
// - a pool of uploaded in-memory files
|
||||||
|
|||||||
25
style.css
25
style.css
@ -883,14 +883,31 @@ main.--has-demo .demo-controls {
|
|||||||
margin: auto 1em;
|
margin: auto 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#editor .level {
|
#editor .editor-canvas {
|
||||||
grid-area: level;
|
grid-area: level;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
/* Padding and background make it easier to tell when we're at the edge of the map */
|
/* Flex layout to center the canvas and overlay together */
|
||||||
/* TODO padding should be half a cell, and svg should respect it too */
|
display: flex;
|
||||||
/* padding: 1em; */
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: safe center;
|
||||||
|
justify-content: safe center;
|
||||||
background: #202020;
|
background: #202020;
|
||||||
|
border: 0.125em solid black;
|
||||||
|
}
|
||||||
|
#editor .editor-canvas .-container {
|
||||||
|
/* Give the canvas/overlay a bit of a margin; it has to be a border because, due to some quirk
|
||||||
|
* of overflowing flexboxes I guess, padding and margins won't extend the scroll area on the
|
||||||
|
* right and bottom */
|
||||||
|
/* TODO padding should be half a cell? */
|
||||||
|
border: 1em solid transparent;
|
||||||
|
}
|
||||||
|
#editor .editor-canvas canvas {
|
||||||
|
display: block;
|
||||||
|
width: calc(var(--viewport-width) * var(--tile-width) * var(--scale));
|
||||||
|
--viewport-width: 9;
|
||||||
|
--viewport-height: 9;
|
||||||
}
|
}
|
||||||
/* SVG overlays */
|
/* SVG overlays */
|
||||||
#editor svg.level-editor-overlay {
|
#editor svg.level-editor-overlay {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user