mirror of
https://github.com/markmanx/isoflow.git
synced 2025-02-08 12:27:53 +00:00
feat: implements node drag and drop
This commit is contained in:
parent
3848a648f0
commit
b350320387
7 changed files with 107 additions and 18 deletions
|
@ -5,7 +5,11 @@ import { Mouse } from "./types";
|
|||
|
||||
export class ModeManager {
|
||||
renderer?: Renderer = undefined;
|
||||
currentMode?: ModeBase = undefined;
|
||||
currentMode?: {
|
||||
instance: ModeBase;
|
||||
class: typeof ModeBase;
|
||||
};
|
||||
lastMode?: typeof ModeBase;
|
||||
mouse: Mouse = {
|
||||
position: { x: 0, y: 0 },
|
||||
delta: null,
|
||||
|
@ -19,19 +23,34 @@ export class ModeManager {
|
|||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
activateMode(Mode: typeof ModeBase) {
|
||||
activateMode<T extends typeof ModeBase>(
|
||||
Mode: T,
|
||||
init?: (instance: InstanceType<T>) => void
|
||||
) {
|
||||
if (!this.renderer) return;
|
||||
|
||||
const lastMode = this.currentMode;
|
||||
this.currentMode?.exit();
|
||||
if (this.currentMode) {
|
||||
this.currentMode.instance.exit();
|
||||
this.lastMode = this.currentMode.class;
|
||||
}
|
||||
|
||||
this.currentMode = new Mode({
|
||||
renderer: this.renderer,
|
||||
activateMode: this.activateMode.bind(this),
|
||||
deactivate: lastMode?.exit ?? (() => {}),
|
||||
});
|
||||
this.currentMode = {
|
||||
instance: new Mode({
|
||||
renderer: this.renderer,
|
||||
activateMode: this.activateMode.bind(this),
|
||||
deactivate: this.deactivate.bind(this),
|
||||
}),
|
||||
class: Mode,
|
||||
};
|
||||
|
||||
this.currentMode.entry(this.mouse);
|
||||
init?.(this.currentMode.instance as InstanceType<T>);
|
||||
this.currentMode.instance.entry(this.mouse);
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
if (!this.lastMode) return;
|
||||
|
||||
this.activateMode(this.lastMode);
|
||||
}
|
||||
|
||||
onMouseEvent(eventName: string, mouse: Mouse) {
|
||||
|
@ -43,6 +62,6 @@ export class ModeManager {
|
|||
send(eventName: string, params?: any) {
|
||||
// TODO: Improve typings below
|
||||
// @ts-ignore
|
||||
this.currentMode?.[eventName]?.(params);
|
||||
this.currentMode.instance?.[eventName]?.(params);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import { ModeBase } from "./ModeBase";
|
||||
import { Mouse } from "./types";
|
||||
import { getTargetFromSelection } from "./utils";
|
||||
import { SelectNode } from "./SelectNode";
|
||||
import { Node } from "../renderer/elements/Node";
|
||||
|
||||
export class Select extends ModeBase {
|
||||
entry(mouse: Mouse) {
|
||||
|
@ -24,6 +27,20 @@ export class Select extends ModeBase {
|
|||
this.ctx.renderer.sceneElements.cursor.disable();
|
||||
}
|
||||
|
||||
MOUSE_DOWN(mouse: Mouse) {
|
||||
const { renderer } = this.ctx;
|
||||
const { x, y } = renderer.getTileFromMouse(
|
||||
mouse.position.x,
|
||||
mouse.position.y
|
||||
);
|
||||
const items = renderer.getItemsByTile(x, y);
|
||||
const target = getTargetFromSelection(items);
|
||||
|
||||
if (target instanceof Node) {
|
||||
this.ctx.activateMode(SelectNode, (instance) => (instance.node = target));
|
||||
}
|
||||
}
|
||||
|
||||
MOUSE_MOVE(mouse: Mouse) {
|
||||
const tile = this.ctx.renderer.getTileFromMouse(
|
||||
mouse.position.x,
|
||||
|
|
26
src/modes/SelectNode.ts
Normal file
26
src/modes/SelectNode.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { ModeBase } from "./ModeBase";
|
||||
import { Mouse, ModeContext } from "./types";
|
||||
import { Node } from "../renderer/elements/Node";
|
||||
|
||||
export class SelectNode extends ModeBase {
|
||||
node?: Node;
|
||||
|
||||
constructor(ctx: ModeContext) {
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
MOUSE_MOVE(mouse: Mouse) {
|
||||
if (!this.node) return;
|
||||
|
||||
const tile = this.ctx.renderer.getTileFromMouse(
|
||||
mouse.position.x,
|
||||
mouse.position.y
|
||||
);
|
||||
|
||||
this.node.moveTo(tile.x, tile.y);
|
||||
}
|
||||
|
||||
MOUSE_UP() {
|
||||
this.ctx.deactivate();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { Renderer } from "../renderer/Renderer";
|
||||
import type { ModeBase } from "./ModeBase";
|
||||
import type { ModeManager } from "./ModeManager";
|
||||
|
||||
export interface Mode {
|
||||
initial: string;
|
||||
|
@ -19,6 +19,6 @@ export interface Mouse {
|
|||
|
||||
export interface ModeContext {
|
||||
renderer: Renderer;
|
||||
activateMode: (mode: typeof ModeBase) => void;
|
||||
deactivate: () => void;
|
||||
activateMode: ModeManager["activateMode"];
|
||||
deactivate: ModeManager["deactivate"];
|
||||
}
|
||||
|
|
11
src/modes/utils.ts
Normal file
11
src/modes/utils.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { Node } from "../renderer/elements/Node";
|
||||
|
||||
export const getTargetFromSelection = (items: (Node | undefined)[]) => {
|
||||
const node = items.find((item) => item instanceof Node);
|
||||
|
||||
if (node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
|
@ -258,6 +258,12 @@ export class Renderer {
|
|||
this.callbacks.onSceneChange(sceneEvent.event, this.exportScene());
|
||||
}
|
||||
|
||||
getItemsByTile(x: number, y: number) {
|
||||
const node = this.nodes.getNodeByTile(x, y);
|
||||
|
||||
return [node].filter((i) => Boolean(i));
|
||||
}
|
||||
|
||||
get nodes() {
|
||||
return this.sceneElements.nodes;
|
||||
}
|
||||
|
|
|
@ -19,10 +19,6 @@ export class Nodes {
|
|||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
getNodeById(id: string) {
|
||||
return this.nodes.find((node) => node.id === id);
|
||||
}
|
||||
|
||||
addNode(options: NodeOptions, sceneEvent?: SceneEvent) {
|
||||
const node = new Node(
|
||||
this.ctx,
|
||||
|
@ -51,9 +47,23 @@ export class Nodes {
|
|||
|
||||
onMove(x: number, y: number, node: Node) {
|
||||
const tile = this.ctx.getTileBounds(x, y);
|
||||
node.position = {
|
||||
x,
|
||||
y,
|
||||
};
|
||||
node.container.position.set(tile.bottom);
|
||||
}
|
||||
|
||||
getNodeById(id: string) {
|
||||
return this.nodes.find((node) => node.id === id);
|
||||
}
|
||||
|
||||
getNodeByTile(x: number, y: number) {
|
||||
return this.nodes.find(
|
||||
(node) => node.position.x === x && node.position.y === y
|
||||
);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.nodes.forEach((node) => node.destroy());
|
||||
this.nodes = [];
|
||||
|
|
Loading…
Reference in a new issue