Editor: center/pad the level, fix some bugs with pencil drawing

This commit is contained in:
Eevee (Evelyn Woods) 2020-11-28 11:07:02 -07:00
parent 349af15e05
commit dff3081194
4 changed files with 60 additions and 26 deletions

View File

@ -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 -->

View File

@ -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) {

View File

@ -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

View File

@ -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 {