Wege System erweitert
This commit is contained in:
@@ -1048,6 +1048,16 @@ public class SharedInput {
|
|||||||
public final ConcurrentLinkedQueue<PathNetworkClick> pathNetworkClickQueue =
|
public final ConcurrentLinkedQueue<PathNetworkClick> pathNetworkClickQueue =
|
||||||
new ConcurrentLinkedQueue<>();
|
new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JFX → JME: Drag-Ereignis im Wegnetz-Modus (Knoten verschieben).
|
||||||
|
* phase: START=0, MOVE=1, END=2.
|
||||||
|
*/
|
||||||
|
public record PathNetworkDrag(float screenX, float screenY, int phase) {
|
||||||
|
public static final int START = 0, MOVE = 1, END = 2;
|
||||||
|
}
|
||||||
|
public final ConcurrentLinkedQueue<PathNetworkDrag> pathNetworkDragQueue =
|
||||||
|
new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
/** JME → JFX: Wegnetz wurde verändert, UI-Refresh nötig. */
|
/** JME → JFX: Wegnetz wurde verändert, UI-Refresh nötig. */
|
||||||
public volatile boolean pathNetworkChanged = false;
|
public volatile boolean pathNetworkChanged = false;
|
||||||
|
|
||||||
|
|||||||
@@ -34,25 +34,22 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* <p>Interaktionsmodell:
|
* <p>Interaktionsmodell:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Linksklick auf leeres Terrain → neuen Knoten platzieren</li>
|
* <li>LMK auf leeres Terrain → neuen Knoten platzieren</li>
|
||||||
* <li>Linksklick auf Knoten → Knoten auswählen; ist bereits einer gewählt,
|
* <li>LMK auf Kante → Kante splitten, neuen Knoten einfügen</li>
|
||||||
* wird eine Kante zwischen beiden erzeugt</li>
|
* <li>LMK auf Knoten → auswählen; ist bereits einer gewählt, Kante erzeugen</li>
|
||||||
* <li>Linksklick auf Terrain mit gewähltem Knoten → neuen Knoten platzieren
|
* <li>LMK Drag auf Knoten → Knoten auf neuer Terrain-Position ablegen</li>
|
||||||
* UND mit dem gewählten Knoten verbinden</li>
|
* <li>RMK auf Knoten → Knoten und seine Kanten löschen</li>
|
||||||
* <li>Rechtsklick auf Knoten → Knoten und alle seine Kanten löschen</li>
|
* <li>RMK auf Terrain → Auswahl aufheben</li>
|
||||||
* <li>Rechtsklick auf Terrain → Auswahl aufheben</li>
|
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
|
||||||
* Änderungen werden sofort in die Datei geschrieben.
|
|
||||||
*/
|
*/
|
||||||
public class PathNetworkEditorState extends BaseAppState {
|
public class PathNetworkEditorState extends BaseAppState {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(PathNetworkEditorState.class);
|
private static final Logger log = LoggerFactory.getLogger(PathNetworkEditorState.class);
|
||||||
|
|
||||||
/** Radius in Welt-Einheiten, innerhalb dessen ein Klick einen Knoten trifft. */
|
private static final float NODE_HIT_RADIUS = 3f;
|
||||||
private static final float NODE_HIT_RADIUS = 3f;
|
|
||||||
private static final float NODE_SPHERE_RADIUS = 0.6f;
|
private static final float NODE_SPHERE_RADIUS = 0.6f;
|
||||||
private static final float EDGE_RADIUS = 0.15f;
|
private static final float EDGE_RADIUS = 0.15f;
|
||||||
|
private static final float EDGE_HIT_THRESHOLD = 3f;
|
||||||
|
|
||||||
private final SharedInput input;
|
private final SharedInput input;
|
||||||
private Camera cam;
|
private Camera cam;
|
||||||
@@ -60,13 +57,13 @@ public class PathNetworkEditorState extends BaseAppState {
|
|||||||
private Node rootNode;
|
private Node rootNode;
|
||||||
private TerrainQuad terrain;
|
private TerrainQuad terrain;
|
||||||
|
|
||||||
private final PathNetwork network = new PathNetwork();
|
private final PathNetwork network = new PathNetwork();
|
||||||
private PathNode selectedNode = null;
|
private PathNode selectedNode = null;
|
||||||
|
private PathNode draggedNode = null;
|
||||||
|
|
||||||
// Szene-Graph-Knoten für Visualisierung
|
private final Node netRoot = new Node("pathnet_root");
|
||||||
private final Node netRoot = new Node("pathnet_root");
|
private final Node nodeRoot = new Node("pathnet_nodes");
|
||||||
private final Node nodeRoot = new Node("pathnet_nodes");
|
private final Node edgeRoot = new Node("pathnet_edges");
|
||||||
private final Node edgeRoot = new Node("pathnet_edges");
|
|
||||||
|
|
||||||
private Material matDefault;
|
private Material matDefault;
|
||||||
private Material matSelected;
|
private Material matSelected;
|
||||||
@@ -83,9 +80,9 @@ public class PathNetworkEditorState extends BaseAppState {
|
|||||||
assets = app.getAssetManager();
|
assets = app.getAssetManager();
|
||||||
rootNode = app.getRootNode();
|
rootNode = app.getRootNode();
|
||||||
|
|
||||||
matDefault = mat(new ColorRGBA(1f, 0.85f, 0f, 1f)); // gelb
|
matDefault = mat(new ColorRGBA(1f, 0.85f, 0f, 1f));
|
||||||
matSelected = mat(new ColorRGBA(1f, 0.4f, 0f, 1f)); // orange
|
matSelected = mat(new ColorRGBA(1f, 0.4f, 0f, 1f));
|
||||||
matEdge = mat(new ColorRGBA(0.3f, 0.9f, 0.3f, 1f)); // grün
|
matEdge = mat(new ColorRGBA(0.3f, 0.9f, 0.3f, 1f));
|
||||||
|
|
||||||
netRoot.attachChild(nodeRoot);
|
netRoot.attachChild(nodeRoot);
|
||||||
netRoot.attachChild(edgeRoot);
|
netRoot.attachChild(edgeRoot);
|
||||||
@@ -111,6 +108,7 @@ public class PathNetworkEditorState extends BaseAppState {
|
|||||||
protected void onDisable() {
|
protected void onDisable() {
|
||||||
netRoot.removeFromParent();
|
netRoot.removeFromParent();
|
||||||
selectedNode = null;
|
selectedNode = null;
|
||||||
|
draggedNode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTerrain(TerrainQuad t) { this.terrain = t; }
|
public void setTerrain(TerrainQuad t) { this.terrain = t; }
|
||||||
@@ -123,21 +121,31 @@ public class PathNetworkEditorState extends BaseAppState {
|
|||||||
while ((click = input.pathNetworkClickQueue.poll()) != null) {
|
while ((click = input.pathNetworkClickQueue.poll()) != null) {
|
||||||
handleClick(click);
|
handleClick(click);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MOVE-Events kollabieren: nur den aktuellsten pro Frame verarbeiten,
|
||||||
|
// START/END sofort durchlassen.
|
||||||
|
SharedInput.PathNetworkDrag pendingMove = null;
|
||||||
|
SharedInput.PathNetworkDrag drag;
|
||||||
|
while ((drag = input.pathNetworkDragQueue.poll()) != null) {
|
||||||
|
if (drag.phase() == SharedInput.PathNetworkDrag.MOVE) {
|
||||||
|
pendingMove = drag;
|
||||||
|
} else {
|
||||||
|
if (pendingMove != null) { handleDrag(pendingMove); pendingMove = null; }
|
||||||
|
handleDrag(drag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pendingMove != null) { handleDrag(pendingMove); }
|
||||||
|
|
||||||
if (input.deletePathNodeRequested) {
|
if (input.deletePathNodeRequested) {
|
||||||
input.deletePathNodeRequested = false;
|
input.deletePathNodeRequested = false;
|
||||||
deleteSelected();
|
deleteSelected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Klick ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private void handleClick(SharedInput.PathNetworkClick click) {
|
private void handleClick(SharedInput.PathNetworkClick click) {
|
||||||
float jmeX = click.screenX() * (float) input.viewportScaleX;
|
Ray ray = screenToRay(click.screenX(), click.screenY());
|
||||||
float jmeY = cam.getHeight() - click.screenY() * (float) input.viewportScaleY;
|
|
||||||
|
|
||||||
Vector3f near = cam.getWorldCoordinates(new Vector2f(jmeX, jmeY), 0f);
|
|
||||||
Vector3f far = cam.getWorldCoordinates(new Vector2f(jmeX, jmeY), 1f);
|
|
||||||
Ray ray = new Ray(near, far.subtract(near).normalizeLocal());
|
|
||||||
|
|
||||||
// Knoten in der Nähe des Strahls suchen
|
|
||||||
PathNode hitNode = findNodeNearRay(ray);
|
PathNode hitNode = findNodeNearRay(ray);
|
||||||
|
|
||||||
if (click.rightClick()) {
|
if (click.rightClick()) {
|
||||||
@@ -149,35 +157,37 @@ public class PathNetworkEditorState extends BaseAppState {
|
|||||||
|
|
||||||
private void handleLeftClick(Ray ray, PathNode hitNode) {
|
private void handleLeftClick(Ray ray, PathNode hitNode) {
|
||||||
if (hitNode != null) {
|
if (hitNode != null) {
|
||||||
// Klick auf Knoten
|
|
||||||
if (selectedNode == null) {
|
if (selectedNode == null) {
|
||||||
select(hitNode);
|
select(hitNode);
|
||||||
} else if (selectedNode == hitNode) {
|
} else if (selectedNode == hitNode) {
|
||||||
select(null); // Abwählen
|
select(null);
|
||||||
} else {
|
} else {
|
||||||
network.addEdge(selectedNode.getUuid(), hitNode.getUuid());
|
network.addEdge(selectedNode.getUuid(), hitNode.getUuid());
|
||||||
select(hitNode);
|
select(hitNode);
|
||||||
saveAndNotify();
|
saveAndNotify();
|
||||||
rebuildVisuals();
|
rebuildVisuals();
|
||||||
}
|
}
|
||||||
} else {
|
return;
|
||||||
// Klick auf Terrain → neuer Knoten
|
|
||||||
WorldPoint pt = terrainHit(ray);
|
|
||||||
if (pt == null) return;
|
|
||||||
PathNode newNode = new PathNode(pt);
|
|
||||||
network.addNode(newNode);
|
|
||||||
if (selectedNode != null) {
|
|
||||||
network.addEdge(selectedNode.getUuid(), newNode.getUuid());
|
|
||||||
}
|
|
||||||
select(newNode);
|
|
||||||
saveAndNotify();
|
|
||||||
rebuildVisuals();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WorldPoint pt = terrainHit(ray);
|
||||||
|
if (pt == null) return;
|
||||||
|
|
||||||
|
// Kante in der Nähe? → splitten und neuen Knoten einfügen
|
||||||
|
PathEdge edgeHit = findEdgeNearPoint(pt);
|
||||||
|
PathNode newNode = (edgeHit != null) ? insertNodeOnEdge(edgeHit, pt) : newNodeAt(pt);
|
||||||
|
|
||||||
|
if (selectedNode != null) {
|
||||||
|
network.addEdge(selectedNode.getUuid(), newNode.getUuid());
|
||||||
|
}
|
||||||
|
select(newNode);
|
||||||
|
saveAndNotify();
|
||||||
|
rebuildVisuals();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleRightClick(PathNode hitNode) {
|
private void handleRightClick(PathNode hitNode) {
|
||||||
if (hitNode != null) {
|
if (hitNode != null) {
|
||||||
if (selectedNode == hitNode) selectedNode = null;
|
if (selectedNode == hitNode) { selectedNode = null; }
|
||||||
network.removeNode(hitNode.getUuid());
|
network.removeNode(hitNode.getUuid());
|
||||||
saveAndNotify();
|
saveAndNotify();
|
||||||
rebuildVisuals();
|
rebuildVisuals();
|
||||||
@@ -186,6 +196,83 @@ public class PathNetworkEditorState extends BaseAppState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Drag (Knoten verschieben) ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
private void handleDrag(SharedInput.PathNetworkDrag drag) {
|
||||||
|
Ray ray = screenToRay(drag.screenX(), drag.screenY());
|
||||||
|
|
||||||
|
switch (drag.phase()) {
|
||||||
|
case SharedInput.PathNetworkDrag.START -> {
|
||||||
|
PathNode node = findNodeNearRay(ray);
|
||||||
|
if (node != null) {
|
||||||
|
draggedNode = node;
|
||||||
|
select(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case SharedInput.PathNetworkDrag.MOVE -> {
|
||||||
|
if (draggedNode != null) {
|
||||||
|
WorldPoint pt = terrainHit(ray);
|
||||||
|
if (pt != null) {
|
||||||
|
draggedNode.setPosition(pt);
|
||||||
|
moveNodeVisual(draggedNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case SharedInput.PathNetworkDrag.END -> {
|
||||||
|
if (draggedNode != null) {
|
||||||
|
WorldPoint pt = terrainHit(ray);
|
||||||
|
if (pt != null) { draggedNode.setPosition(pt); }
|
||||||
|
saveAndNotify();
|
||||||
|
rebuildVisuals();
|
||||||
|
draggedNode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Kanten-Insertion ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private PathEdge findEdgeNearPoint(WorldPoint pt) {
|
||||||
|
PathEdge best = null;
|
||||||
|
float bestDist = EDGE_HIT_THRESHOLD;
|
||||||
|
for (PathEdge e : network.getEdges()) {
|
||||||
|
PathNode a = network.nodeById(e.getNodeUuidA());
|
||||||
|
PathNode b = network.nodeById(e.getNodeUuidB());
|
||||||
|
if (a == null || b == null) continue;
|
||||||
|
float d = distPointToSegmentXZ(pt, a.getPosition(), b.getPosition());
|
||||||
|
if (d < bestDist) { bestDist = d; best = e; }
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float distPointToSegmentXZ(WorldPoint p, WorldPoint a, WorldPoint b) {
|
||||||
|
float dx = b.x - a.x, dz = b.z - a.z;
|
||||||
|
float len2 = dx * dx + dz * dz;
|
||||||
|
if (len2 < 0.001f) {
|
||||||
|
float ex = p.x - a.x, ez = p.z - a.z;
|
||||||
|
return (float) Math.sqrt(ex * ex + ez * ez);
|
||||||
|
}
|
||||||
|
float t = Math.max(0f, Math.min(1f, ((p.x - a.x) * dx + (p.z - a.z) * dz) / len2));
|
||||||
|
float cx = a.x + t * dx, cz = a.z + t * dz;
|
||||||
|
float ex = p.x - cx, ez = p.z - cz;
|
||||||
|
return (float) Math.sqrt(ex * ex + ez * ez);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PathNode insertNodeOnEdge(PathEdge edge, WorldPoint pos) {
|
||||||
|
PathNode newNode = new PathNode(pos);
|
||||||
|
network.addNode(newNode);
|
||||||
|
network.removeEdge(edge.getNodeUuidA(), edge.getNodeUuidB());
|
||||||
|
network.addEdge(edge.getNodeUuidA(), newNode.getUuid());
|
||||||
|
network.addEdge(newNode.getUuid(), edge.getNodeUuidB());
|
||||||
|
return newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PathNode newNodeAt(WorldPoint pos) {
|
||||||
|
PathNode n = new PathNode(pos);
|
||||||
|
network.addNode(n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
// ── Visualisierung ─────────────────────────────────────────────────────────
|
// ── Visualisierung ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private void rebuildVisuals() {
|
private void rebuildVisuals() {
|
||||||
@@ -193,8 +280,7 @@ public class PathNetworkEditorState extends BaseAppState {
|
|||||||
edgeRoot.detachAllChildren();
|
edgeRoot.detachAllChildren();
|
||||||
|
|
||||||
for (PathNode n : network.getNodes()) {
|
for (PathNode n : network.getNodes()) {
|
||||||
Geometry g = new Geometry("node_" + n.getUuid(),
|
Geometry g = new Geometry("node_" + n.getUuid(), new Sphere(8, 8, NODE_SPHERE_RADIUS));
|
||||||
new Sphere(8, 8, NODE_SPHERE_RADIUS));
|
|
||||||
g.setMaterial(n == selectedNode ? matSelected : matDefault);
|
g.setMaterial(n == selectedNode ? matSelected : matDefault);
|
||||||
g.setLocalTranslation(n.getPosition().x, n.getPosition().y + NODE_SPHERE_RADIUS, n.getPosition().z);
|
g.setLocalTranslation(n.getPosition().x, n.getPosition().y + NODE_SPHERE_RADIUS, n.getPosition().z);
|
||||||
g.setUserData("nodeUuid", n.getUuid());
|
g.setUserData("nodeUuid", n.getUuid());
|
||||||
@@ -210,6 +296,27 @@ public class PathNetworkEditorState extends BaseAppState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Effizienter Update: nur Sphere-Position + betroffene Kanten neu bauen. */
|
||||||
|
private void moveNodeVisual(PathNode node) {
|
||||||
|
Geometry sphere = (Geometry) nodeRoot.getChild("node_" + node.getUuid());
|
||||||
|
if (sphere != null) {
|
||||||
|
sphere.setLocalTranslation(
|
||||||
|
node.getPosition().x, node.getPosition().y + NODE_SPHERE_RADIUS, node.getPosition().z);
|
||||||
|
}
|
||||||
|
String uuid = node.getUuid();
|
||||||
|
for (PathEdge e : network.getEdges()) {
|
||||||
|
if (!e.involves(uuid)) continue;
|
||||||
|
PathNode a = network.nodeById(e.getNodeUuidA());
|
||||||
|
PathNode b = network.nodeById(e.getNodeUuidB());
|
||||||
|
if (a == null || b == null) continue;
|
||||||
|
String edgeName = "edge_" + a.getUuid() + "_" + b.getUuid();
|
||||||
|
Spatial old = edgeRoot.getChild(edgeName);
|
||||||
|
if (old != null) { old.removeFromParent(); }
|
||||||
|
Geometry g = buildEdgeGeometry(a, b);
|
||||||
|
if (g != null) { edgeRoot.attachChild(g); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Geometry buildEdgeGeometry(PathNode a, PathNode b) {
|
private Geometry buildEdgeGeometry(PathNode a, PathNode b) {
|
||||||
float ax = a.getPosition().x, ay = a.getPosition().y, az = a.getPosition().z;
|
float ax = a.getPosition().x, ay = a.getPosition().y, az = a.getPosition().z;
|
||||||
float bx = b.getPosition().x, by = b.getPosition().y, bz = b.getPosition().z;
|
float bx = b.getPosition().x, by = b.getPosition().y, bz = b.getPosition().z;
|
||||||
@@ -225,26 +332,30 @@ public class PathNetworkEditorState extends BaseAppState {
|
|||||||
g.setMaterial(matEdge);
|
g.setMaterial(matEdge);
|
||||||
g.setLocalTranslation(mid);
|
g.setLocalTranslation(mid);
|
||||||
|
|
||||||
// Zylinder liegt entlang lokaler Y-Achse.
|
|
||||||
// Rotationsmatrix: Spalten = wohin lokale Achsen X, Y, Z in Weltkoordinaten zeigen.
|
|
||||||
// Lokale Y → Richtung des Weges (nx, 0, nz) im XZ-Boden.
|
|
||||||
// Lokale Z → Welt-Y (oben), damit Zylinder nicht rollt.
|
|
||||||
// Lokale X = lokale Y × lokale Z = (nz, 0, -nx).
|
|
||||||
Matrix3f rot = new Matrix3f();
|
Matrix3f rot = new Matrix3f();
|
||||||
rot.setColumn(0, new Vector3f( nz, 0f, -nx)); // lokales X
|
rot.setColumn(0, new Vector3f( nz, 0f, -nx));
|
||||||
rot.setColumn(1, new Vector3f( nx, 0f, nz)); // lokales Y → dir
|
rot.setColumn(1, new Vector3f( nx, 0f, nz));
|
||||||
rot.setColumn(2, new Vector3f( 0f, 1f, 0f)); // lokales Z → Welt-oben
|
rot.setColumn(2, new Vector3f( 0f, 1f, 0f));
|
||||||
g.setLocalRotation(new Quaternion().fromRotationMatrix(rot));
|
g.setLocalRotation(new Quaternion().fromRotationMatrix(rot));
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateNodeMaterial(PathNode node) {
|
private void updateNodeMaterial(PathNode node) {
|
||||||
Geometry g = (Geometry) nodeRoot.getChild("node_" + node.getUuid());
|
Geometry g = (Geometry) nodeRoot.getChild("node_" + node.getUuid());
|
||||||
if (g != null) g.setMaterial(node == selectedNode ? matSelected : matDefault);
|
if (g != null) { g.setMaterial(node == selectedNode ? matSelected : matDefault); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Hilfsmethoden ──────────────────────────────────────────────────────────
|
// ── Hilfsmethoden ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private Ray screenToRay(float screenX, float screenY) {
|
||||||
|
float jmeX = screenX * (float) input.viewportScaleX;
|
||||||
|
float jmeY = cam.getHeight() - screenY * (float) input.viewportScaleY;
|
||||||
|
Vector2f sc = new Vector2f(jmeX, jmeY);
|
||||||
|
Vector3f near = cam.getWorldCoordinates(sc, 0f);
|
||||||
|
Vector3f far = cam.getWorldCoordinates(sc, 1f);
|
||||||
|
return new Ray(near, far.subtract(near).normalizeLocal());
|
||||||
|
}
|
||||||
|
|
||||||
private PathNode findNodeNearRay(Ray ray) {
|
private PathNode findNodeNearRay(Ray ray) {
|
||||||
PathNode best = null;
|
PathNode best = null;
|
||||||
float bestDist = NODE_HIT_RADIUS;
|
float bestDist = NODE_HIT_RADIUS;
|
||||||
@@ -273,8 +384,8 @@ public class PathNetworkEditorState extends BaseAppState {
|
|||||||
private void select(PathNode node) {
|
private void select(PathNode node) {
|
||||||
PathNode prev = selectedNode;
|
PathNode prev = selectedNode;
|
||||||
selectedNode = node;
|
selectedNode = node;
|
||||||
if (prev != null) updateNodeMaterial(prev);
|
if (prev != null) { updateNodeMaterial(prev); }
|
||||||
if (node != null) updateNodeMaterial(node);
|
if (node != null) { updateNodeMaterial(node); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveAndNotify() {
|
private void saveAndNotify() {
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ public class ViewportController {
|
|||||||
private int editPressAction;
|
private int editPressAction;
|
||||||
private javafx.animation.Timeline editTimer;
|
private javafx.animation.Timeline editTimer;
|
||||||
|
|
||||||
|
// Wegnetz-Drag-Tracking
|
||||||
|
private float pathNetPressX, pathNetPressY;
|
||||||
|
private boolean pathNetPressPending;
|
||||||
|
private boolean pathNetDragging;
|
||||||
|
private boolean pathNetRightPress;
|
||||||
|
|
||||||
public ViewportController(SharedInput input, WritableImage jfxImage, Runnable scheduleAutoSave) {
|
public ViewportController(SharedInput input, WritableImage jfxImage, Runnable scheduleAutoSave) {
|
||||||
this.input = input;
|
this.input = input;
|
||||||
this.initialImage = jfxImage;
|
this.initialImage = jfxImage;
|
||||||
@@ -140,12 +146,12 @@ public class ViewportController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (input.activeLayer == SharedInput.LAYER_PATH_NETWORK) {
|
if (input.activeLayer == SharedInput.LAYER_PATH_NETWORK) {
|
||||||
if (e.getButton() == MouseButton.PRIMARY && !bothDown) {
|
if (!bothDown && (e.getButton() == MouseButton.PRIMARY || e.getButton() == MouseButton.SECONDARY)) {
|
||||||
input.pathNetworkClickQueue.offer(
|
pathNetPressX = (float) e.getX();
|
||||||
new SharedInput.PathNetworkClick((float)e.getX(), (float)e.getY(), false));
|
pathNetPressY = (float) e.getY();
|
||||||
} else if (e.getButton() == MouseButton.SECONDARY && !bothDown) {
|
pathNetPressPending = true;
|
||||||
input.pathNetworkClickQueue.offer(
|
pathNetDragging = false;
|
||||||
new SharedInput.PathNetworkClick((float)e.getX(), (float)e.getY(), true));
|
pathNetRightPress = e.getButton() == MouseButton.SECONDARY;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -225,6 +231,25 @@ public class ViewportController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input.activeLayer == SharedInput.LAYER_PATH_NETWORK
|
||||||
|
&& e.isPrimaryButtonDown() && !pathNetRightPress) {
|
||||||
|
if (pathNetPressPending) {
|
||||||
|
float ddx = (float)(e.getX() - pathNetPressX);
|
||||||
|
float ddy = (float)(e.getY() - pathNetPressY);
|
||||||
|
if (ddx * ddx + ddy * ddy > 16f) {
|
||||||
|
input.pathNetworkDragQueue.offer(new SharedInput.PathNetworkDrag(
|
||||||
|
pathNetPressX, pathNetPressY, SharedInput.PathNetworkDrag.START));
|
||||||
|
pathNetDragging = true;
|
||||||
|
pathNetPressPending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pathNetDragging) {
|
||||||
|
input.pathNetworkDragQueue.offer(new SharedInput.PathNetworkDrag(
|
||||||
|
(float) e.getX(), (float) e.getY(), SharedInput.PathNetworkDrag.MOVE));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Play-Tool EDIT: Drag-Events an JME3 weiterleiten
|
// Play-Tool EDIT: Drag-Events an JME3 weiterleiten
|
||||||
if (input.activeLayer == SharedInput.LAYER_PLAY_TOOL
|
if (input.activeLayer == SharedInput.LAYER_PLAY_TOOL
|
||||||
&& input.playToolMode == SharedInput.PlayToolMode.EDIT
|
&& input.playToolMode == SharedInput.PlayToolMode.EDIT
|
||||||
@@ -245,6 +270,17 @@ public class ViewportController {
|
|||||||
viewport.setOnMouseReleased(e -> {
|
viewport.setOnMouseReleased(e -> {
|
||||||
objDragging = false;
|
objDragging = false;
|
||||||
if (!isObjectMode()) { stopEditTimer(); }
|
if (!isObjectMode()) { stopEditTimer(); }
|
||||||
|
if (input.activeLayer == SharedInput.LAYER_PATH_NETWORK) {
|
||||||
|
if (pathNetDragging) {
|
||||||
|
input.pathNetworkDragQueue.offer(new SharedInput.PathNetworkDrag(
|
||||||
|
(float) e.getX(), (float) e.getY(), SharedInput.PathNetworkDrag.END));
|
||||||
|
pathNetDragging = false;
|
||||||
|
} else if (pathNetPressPending) {
|
||||||
|
input.pathNetworkClickQueue.offer(new SharedInput.PathNetworkClick(
|
||||||
|
pathNetPressX, pathNetPressY, pathNetRightPress));
|
||||||
|
pathNetPressPending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (input.activeLayer == SharedInput.LAYER_WATER) {
|
if (input.activeLayer == SharedInput.LAYER_WATER) {
|
||||||
input.waterDragEnd = true;
|
input.waterDragEnd = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ public enum AnimationAction {
|
|||||||
TALK2,
|
TALK2,
|
||||||
DISAPPOINT,
|
DISAPPOINT,
|
||||||
SECRET,
|
SECRET,
|
||||||
TALK_SITTING;
|
TALK_SITTING,
|
||||||
|
SWORD_ATTACK_1;
|
||||||
|
|
||||||
/** Lesbare Bezeichnung für UI-Anzeige, via TextRegistry aufgelöst. */
|
/** Lesbare Bezeichnung für UI-Anzeige, via TextRegistry aufgelöst. */
|
||||||
public String displayName() {
|
public String displayName() {
|
||||||
@@ -60,6 +61,7 @@ public enum AnimationAction {
|
|||||||
case DISAPPOINT -> TextRegistry.resolve(null, key, "Enttäuscht");
|
case DISAPPOINT -> TextRegistry.resolve(null, key, "Enttäuscht");
|
||||||
case SECRET -> TextRegistry.resolve(null, key, "Geheimnis");
|
case SECRET -> TextRegistry.resolve(null, key, "Geheimnis");
|
||||||
case TALK_SITTING -> TextRegistry.resolve(null, key, "Reden (Sitzend)");
|
case TALK_SITTING -> TextRegistry.resolve(null, key, "Reden (Sitzend)");
|
||||||
|
case SWORD_ATTACK_1 -> TextRegistry.resolve(null, key, "Angriff 1(Schwert)");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,17 +9,27 @@ NODE d886a17b-4ad0-4437-9dbf-6c0df951742f - 252.24966 6.40171 -892.78693
|
|||||||
NODE caa8813b-d828-4db8-ae77-9cf369309618 - 254.10876 2.00000 -852.84991
|
NODE caa8813b-d828-4db8-ae77-9cf369309618 - 254.10876 2.00000 -852.84991
|
||||||
NODE ff5bb246-2c95-4e76-b592-5881c51dab51 - 254.28955 2.00035 -826.95752
|
NODE ff5bb246-2c95-4e76-b592-5881c51dab51 - 254.28955 2.00035 -826.95752
|
||||||
NODE 28a87ffd-a39b-4347-a79f-fe5ead071b59 - 291.11404 2.00004 -817.18658
|
NODE 28a87ffd-a39b-4347-a79f-fe5ead071b59 - 291.11404 2.00004 -817.18658
|
||||||
NODE 7e3c1080-d37e-4fc9-b489-c0784f34fac1 - 306.78833 2.00000 -777.88641
|
NODE 7e3c1080-d37e-4fc9-b489-c0784f34fac1 - 306.97855 2.00000 -784.28113
|
||||||
NODE c29223fa-67a0-4df0-8055-91381ec8c83f - 317.70370 2.00000 -782.45502
|
NODE c29223fa-67a0-4df0-8055-91381ec8c83f - 317.70370 2.00000 -782.45502
|
||||||
NODE 43677d9c-a19b-45f2-8eb3-d3368251d0b9 - 349.32700 2.00000 -774.56525
|
NODE 43677d9c-a19b-45f2-8eb3-d3368251d0b9 - 349.32700 2.00000 -774.56525
|
||||||
|
NODE aeb4a96f-b1d7-404a-a654-e98f74e5c856 - 299.91858 2.00001 -803.26099
|
||||||
|
NODE 64a2b232-6180-4f6d-9984-82820ac79053 - 298.20966 2.00000 -787.21967
|
||||||
|
NODE 0bcd1776-f65a-4d2f-9f2f-b7cff6db8dc6 - 288.40808 2.00000 -778.93536
|
||||||
|
NODE 2b4e0e77-30a4-4314-87ad-0d3582feffd0 - 280.04413 2.00000 -766.30432
|
||||||
|
NODE 4f3a890b-a973-41fc-9798-d897209b12d0 - 295.18164 2.00000 -735.89783
|
||||||
EDGE c7fe03f3-736b-4d81-accb-27dd6649e000 fa3be430-7714-49ed-9a81-4e4fb45ba564
|
EDGE c7fe03f3-736b-4d81-accb-27dd6649e000 fa3be430-7714-49ed-9a81-4e4fb45ba564
|
||||||
EDGE fa3be430-7714-49ed-9a81-4e4fb45ba564 5618a5ba-d0a5-4897-ab4d-a4a2932edb18
|
EDGE fa3be430-7714-49ed-9a81-4e4fb45ba564 5618a5ba-d0a5-4897-ab4d-a4a2932edb18
|
||||||
EDGE f8f01e21-3963-4530-a5d6-bfdd0cb77233 d886a17b-4ad0-4437-9dbf-6c0df951742f
|
EDGE f8f01e21-3963-4530-a5d6-bfdd0cb77233 d886a17b-4ad0-4437-9dbf-6c0df951742f
|
||||||
EDGE caa8813b-d828-4db8-ae77-9cf369309618 ff5bb246-2c95-4e76-b592-5881c51dab51
|
EDGE caa8813b-d828-4db8-ae77-9cf369309618 ff5bb246-2c95-4e76-b592-5881c51dab51
|
||||||
EDGE ff5bb246-2c95-4e76-b592-5881c51dab51 28a87ffd-a39b-4347-a79f-fe5ead071b59
|
EDGE ff5bb246-2c95-4e76-b592-5881c51dab51 28a87ffd-a39b-4347-a79f-fe5ead071b59
|
||||||
EDGE 28a87ffd-a39b-4347-a79f-fe5ead071b59 7e3c1080-d37e-4fc9-b489-c0784f34fac1
|
|
||||||
EDGE 7e3c1080-d37e-4fc9-b489-c0784f34fac1 c29223fa-67a0-4df0-8055-91381ec8c83f
|
EDGE 7e3c1080-d37e-4fc9-b489-c0784f34fac1 c29223fa-67a0-4df0-8055-91381ec8c83f
|
||||||
EDGE c29223fa-67a0-4df0-8055-91381ec8c83f 43677d9c-a19b-45f2-8eb3-d3368251d0b9
|
EDGE c29223fa-67a0-4df0-8055-91381ec8c83f 43677d9c-a19b-45f2-8eb3-d3368251d0b9
|
||||||
EDGE 5618a5ba-d0a5-4897-ab4d-a4a2932edb18 f8f01e21-3963-4530-a5d6-bfdd0cb77233
|
EDGE 5618a5ba-d0a5-4897-ab4d-a4a2932edb18 f8f01e21-3963-4530-a5d6-bfdd0cb77233
|
||||||
EDGE 5618a5ba-d0a5-4897-ab4d-a4a2932edb18 caa8813b-d828-4db8-ae77-9cf369309618
|
EDGE 5618a5ba-d0a5-4897-ab4d-a4a2932edb18 caa8813b-d828-4db8-ae77-9cf369309618
|
||||||
EDGE f8f01e21-3963-4530-a5d6-bfdd0cb77233 caa8813b-d828-4db8-ae77-9cf369309618
|
EDGE f8f01e21-3963-4530-a5d6-bfdd0cb77233 caa8813b-d828-4db8-ae77-9cf369309618
|
||||||
|
EDGE 28a87ffd-a39b-4347-a79f-fe5ead071b59 aeb4a96f-b1d7-404a-a654-e98f74e5c856
|
||||||
|
EDGE aeb4a96f-b1d7-404a-a654-e98f74e5c856 64a2b232-6180-4f6d-9984-82820ac79053
|
||||||
|
EDGE 64a2b232-6180-4f6d-9984-82820ac79053 7e3c1080-d37e-4fc9-b489-c0784f34fac1
|
||||||
|
EDGE 64a2b232-6180-4f6d-9984-82820ac79053 0bcd1776-f65a-4d2f-9f2f-b7cff6db8dc6
|
||||||
|
EDGE 0bcd1776-f65a-4d2f-9f2f-b7cff6db8dc6 2b4e0e77-30a4-4314-87ad-0d3582feffd0
|
||||||
|
EDGE 2b4e0e77-30a4-4314-87ad-0d3582feffd0 4f3a890b-a973-41fc-9798-d897209b12d0
|
||||||
|
|||||||
Reference in New Issue
Block a user