Tool und Oberflächen Konsolidierung angefangen
This commit is contained in:
@@ -327,6 +327,7 @@ public class WorldScene extends BaseAppState {
|
||||
if (saveState != null) saveState.bind(mc, physicsChar::getPhysicsLocation);
|
||||
|
||||
app.getStateManager().attach(new LocationState(mc, character));
|
||||
app.getStateManager().attach(new de.blight.game.state.AreaTriggerState(mc, character));
|
||||
app.getStateManager().attach(
|
||||
new WorldItemsState(keyBindings, physicsChar, mc, playerInput));
|
||||
app.getStateManager().attach(
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package de.blight.game.state;
|
||||
|
||||
import com.jme3.app.Application;
|
||||
import com.jme3.app.state.BaseAppState;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Node;
|
||||
import de.blight.common.AreaIO;
|
||||
import de.blight.common.PlacedArea;
|
||||
import de.blight.common.model.MainCharacter;
|
||||
import de.blight.common.model.trigger.Trigger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Prüft pro Frame ob der Spieler eine PlacedArea betreten hat und feuert
|
||||
* ggf. die zugehörigen Trigger (Übergang outside → inside).
|
||||
*
|
||||
* Betretene Areas werden zusätzlich in {@code character.visitedZoneIds}
|
||||
* eingetragen, damit die {@code FirstTimeCondition} funktioniert.
|
||||
*/
|
||||
public class AreaTriggerState extends BaseAppState {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AreaTriggerState.class);
|
||||
|
||||
private final MainCharacter character;
|
||||
private final Node playerNode;
|
||||
private List<PlacedArea> areas;
|
||||
private final Set<String> active = new HashSet<>();
|
||||
|
||||
public AreaTriggerState(MainCharacter character, Node playerNode) {
|
||||
this.character = character;
|
||||
this.playerNode = playerNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(Application app) {
|
||||
try {
|
||||
areas = AreaIO.load();
|
||||
log.info("{} Area(s) für Trigger-Prüfung geladen.", areas.size());
|
||||
} catch (Exception e) {
|
||||
log.error("Areas nicht ladbar", e);
|
||||
areas = List.of();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float tpf) {
|
||||
if (areas.isEmpty() || playerNode == null) return;
|
||||
Vector3f pos = playerNode.getWorldTranslation();
|
||||
float px = pos.x, pz = pos.z;
|
||||
|
||||
for (PlacedArea area : areas) {
|
||||
boolean inside = pointInPolygon(px, pz, area.pointsX(), area.pointsZ());
|
||||
boolean wasInside = active.contains(area.areaId());
|
||||
|
||||
if (inside && !wasInside) {
|
||||
active.add(area.areaId());
|
||||
|
||||
if (area.areaId() != null && !area.areaId().isBlank()) {
|
||||
character.getVisitedZoneIds().add(area.areaId());
|
||||
}
|
||||
|
||||
List<Trigger> triggers = area.triggers();
|
||||
if (triggers != null && !triggers.isEmpty()) {
|
||||
triggers.stream()
|
||||
.filter(t -> t.isTriggarable(character))
|
||||
.forEach(t -> t.fire(character));
|
||||
log.debug("Area betreten: {} – {} Trigger geprüft.", area.areaId(), triggers.size());
|
||||
}
|
||||
} else if (!inside) {
|
||||
active.remove(area.areaId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Ray-Casting-Algorithmus für Punkt-in-Polygon-Test (XZ-Ebene). */
|
||||
private static boolean pointInPolygon(float px, float pz, float[] xs, float[] zs) {
|
||||
int n = xs.length;
|
||||
if (n < 3) return false;
|
||||
boolean inside = false;
|
||||
for (int i = 0, j = n - 1; i < n; j = i++) {
|
||||
if (((zs[i] > pz) != (zs[j] > pz)) &&
|
||||
(px < (xs[j] - xs[i]) * (pz - zs[i]) / (zs[j] - zs[i]) + xs[i])) {
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
return inside;
|
||||
}
|
||||
|
||||
@Override protected void cleanup(Application app) {}
|
||||
@Override protected void onEnable() {}
|
||||
@Override protected void onDisable() {}
|
||||
}
|
||||
@@ -222,6 +222,17 @@ public class DialogHudState extends BaseAppState {
|
||||
Monologue pending = mainCharForMonologue.pollPendingMonologue();
|
||||
if (pending != null) {
|
||||
startMonologue(pending, mainCharForMonologue);
|
||||
} else {
|
||||
String pendingNpcId = mainCharForMonologue.pollPendingDialog();
|
||||
if (pendingNpcId != null) {
|
||||
WorldNpcsState npcs = getStateManager().getState(WorldNpcsState.class);
|
||||
NPC npc = npcs != null ? npcs.findNpcById(pendingNpcId) : null;
|
||||
if (npc != null) {
|
||||
startDialog(npc, mainCharForMonologue, null, null);
|
||||
} else {
|
||||
log.warn("[DialogHud] Trigger-Dialog: NPC '{}' nicht gefunden.", pendingNpcId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -359,7 +370,14 @@ public class DialogHudState extends BaseAppState {
|
||||
playSteps(ph, speaker, steps, idx + 1, after);
|
||||
return;
|
||||
}
|
||||
String audioPath = step.getAudio() != null ? AudioResolver.get().resolve(step.getAudio()) : null;
|
||||
String audioPath;
|
||||
if (step.getAudio() != null) {
|
||||
audioPath = AudioResolver.get().resolve(step.getAudio());
|
||||
} else if (step.getText() != null && !step.getText().id().isBlank()) {
|
||||
audioPath = AudioResolver.get().resolveKey(step.getText().id());
|
||||
} else {
|
||||
audioPath = null;
|
||||
}
|
||||
showText(ph, speaker, text, audioPath, () -> playSteps(ph, speaker, steps, idx + 1, after));
|
||||
}
|
||||
|
||||
|
||||
@@ -632,6 +632,14 @@ public class WorldNpcsState extends BaseAppState {
|
||||
|
||||
// ── Accessoren ────────────────────────────────────────────────────────────
|
||||
|
||||
/** Liefert den NPC mit der gegebenen characterId, oder null wenn nicht gefunden. */
|
||||
public NPC findNpcById(String characterId) {
|
||||
if (characterId == null) return null;
|
||||
return allNpcs.stream()
|
||||
.filter(n -> characterId.equals(n.getCharacterId()))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/** Liefert das Spatial des aktuellen Dialog-NPCs, oder null wenn kein Dialog aktiv. */
|
||||
public com.jme3.scene.Spatial getDialogNpcSpatial() {
|
||||
return dialogNpc != null ? dialogNpc.visual() : null;
|
||||
|
||||
Reference in New Issue
Block a user