Schleichen hinzugefügt, Bugs bei den Sounds behoben
This commit is contained in:
@@ -16,6 +16,9 @@ public enum AnimationAction {
|
||||
RUNNING_JUMP,
|
||||
ROLL,
|
||||
DUCK,
|
||||
CROUCH_IDLE,
|
||||
CROUCH_TO_STAND,
|
||||
SNEAK,
|
||||
PICK_UP,
|
||||
LIE_DOWN,
|
||||
LIE_UP,
|
||||
@@ -80,7 +83,10 @@ public enum AnimationAction {
|
||||
case JUMP -> TextRegistry.resolve(null, key, "Jump");
|
||||
case RUNNING_JUMP -> TextRegistry.resolve(null, key, "Running Jump");
|
||||
case ROLL -> TextRegistry.resolve(null, key, "Rolle");
|
||||
case DUCK -> TextRegistry.resolve(null, key, "Duck");
|
||||
case DUCK -> TextRegistry.resolve(null, key, "Hinducken");
|
||||
case CROUCH_IDLE -> TextRegistry.resolve(null, key, "Ducken (Idle)");
|
||||
case CROUCH_TO_STAND -> TextRegistry.resolve(null, key, "Aufstehen (Ducken)");
|
||||
case SNEAK -> TextRegistry.resolve(null, key, "Schleichen");
|
||||
case PICK_UP -> TextRegistry.resolve(null, key, "Pick up");
|
||||
case LIE_DOWN -> TextRegistry.resolve(null, key, "Hinlegen");
|
||||
case LIE_UP -> TextRegistry.resolve(null, key, "Aufstehen (Bett)");
|
||||
|
||||
@@ -23,6 +23,7 @@ public class KeyBindings {
|
||||
public int drawRangedWeapon = KeyInput.KEY_2;
|
||||
public int sheathWeapon = KeyInput.KEY_X;
|
||||
public int roll = KeyInput.KEY_LCONTROL;
|
||||
public int sneak = KeyInput.KEY_X;
|
||||
|
||||
/** Metadaten für die Config-UI: Feldname im Objekt + Anzeigename. */
|
||||
public static final String[][] ENTRIES = {
|
||||
@@ -44,6 +45,7 @@ public class KeyBindings {
|
||||
{"drawRangedWeapon", "Fernkampfwaffe ziehen"},
|
||||
{"sheathWeapon", "Waffe wegstecken"},
|
||||
{"roll", "Rolle"},
|
||||
{"sneak", "Schleichen"},
|
||||
};
|
||||
|
||||
public int get(String fieldName) {
|
||||
|
||||
@@ -103,11 +103,12 @@ public class PlayerInputControl {
|
||||
private static final String ACT_COMBAT_ATK = "CombatAttack";
|
||||
private static final String ACT_COMBAT_ALT = "CombatAltAction";
|
||||
private static final String ACT_ROLL = "Roll";
|
||||
private static final String ACT_SNEAK = "Sneak";
|
||||
|
||||
private static final String[] ACTION_NAMES = {
|
||||
"Forward", "Backward", "Left", "Right", "Jump", "Sprint", "Walk",
|
||||
ACT_DRAW_MELEE, ACT_DRAW_RANGED, ACT_SHEATH, ACT_COMBAT_ATK, ACT_COMBAT_ALT,
|
||||
ACT_ROLL
|
||||
ACT_ROLL, ACT_SNEAK
|
||||
};
|
||||
|
||||
private final InputManager inputManager;
|
||||
@@ -273,6 +274,12 @@ public class PlayerInputControl {
|
||||
/** Autopilot: wenn gesetzt, geht der Charakter automatisch in diese (normalisierte) Richtung. */
|
||||
private Vector3f autopilotDir = null;
|
||||
|
||||
// ── Schleichen / Ducken ───────────────────────────────────────────────────
|
||||
private enum SneakPhase { NONE, DOWN, ACTIVE, UP }
|
||||
private SneakPhase sneakPhase = SneakPhase.NONE;
|
||||
private float sneakTransitionRemaining = 0f;
|
||||
private boolean sneakKeyHeld = false;
|
||||
|
||||
// ── Dodge Roll ────────────────────────────────────────────────────────────
|
||||
private boolean rollActive = false;
|
||||
private float rollRemaining = 0f;
|
||||
@@ -333,7 +340,8 @@ public class PlayerInputControl {
|
||||
}
|
||||
}
|
||||
case ACT_COMBAT_ALT -> handleCombatAlt(isPressed);
|
||||
case ACT_ROLL -> { if (isPressed) triggerRollFromInput(); }
|
||||
case ACT_ROLL -> { if (isPressed) triggerRollFromInput(); }
|
||||
case ACT_SNEAK -> { if (!weaponDrawn) handleSneakKey(isPressed); }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -712,6 +720,7 @@ public class PlayerInputControl {
|
||||
inputManager.addMapping(ACT_COMBAT_ATK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
|
||||
inputManager.addMapping(ACT_COMBAT_ALT, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
|
||||
inputManager.addMapping(ACT_ROLL, new KeyTrigger(kb.roll));
|
||||
inputManager.addMapping(ACT_SNEAK, new KeyTrigger(kb.sneak));
|
||||
inputManager.addListener(actionListener, ACTION_NAMES);
|
||||
}
|
||||
|
||||
@@ -844,6 +853,25 @@ public class PlayerInputControl {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Sneak-Übergangs-Phasen: Timer ticken, Bewegung läuft weiter (walk speed) ──
|
||||
if (sneakPhase == SneakPhase.DOWN) {
|
||||
sneakTransitionRemaining -= tpf;
|
||||
if (sneakTransitionRemaining <= 0f) {
|
||||
if (sneakKeyHeld) {
|
||||
sneakPhase = SneakPhase.ACTIVE;
|
||||
currentAnim = null;
|
||||
} else {
|
||||
startSneakUp();
|
||||
}
|
||||
}
|
||||
} else if (sneakPhase == SneakPhase.UP) {
|
||||
sneakTransitionRemaining -= tpf;
|
||||
if (sneakTransitionRemaining <= 0f) {
|
||||
sneakPhase = SneakPhase.NONE;
|
||||
currentAnim = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Ruhezustand (liegen / sitzen) – blockiert alle Bewegungseingaben
|
||||
if (lockedInPlace) {
|
||||
physicsChar.setWalkDirection(Vector3f.ZERO);
|
||||
@@ -886,16 +914,19 @@ public class PlayerInputControl {
|
||||
// Schon ab WAITING Gehgeschwindigkeit erzwingen, damit beim Blockstart kein Sprint-Frame entsteht
|
||||
boolean inBlockStance = isBlocking() || blockPhase == BlockPhase.WAITING;
|
||||
|
||||
boolean sneaking = sneakPhase != SneakPhase.NONE;
|
||||
|
||||
// Ausdauer: Regen + Sprint-Verbrauch
|
||||
boolean isSprinting = sprint && !weaponDrawn && moving && !staminaExhausted;
|
||||
boolean isSprinting = sprint && !weaponDrawn && moving && !staminaExhausted && !sneaking;
|
||||
tickStamina(tpf, isSprinting);
|
||||
|
||||
if (moving) {
|
||||
scratchMoveDir.normalizeLocal();
|
||||
boolean canSprint = sprint && !weaponDrawn && !staminaExhausted
|
||||
boolean canSprint = !sneaking && sprint && !weaponDrawn && !staminaExhausted
|
||||
&& (mainCharacter == null || mainCharacter.getMaxStamina() <= 0
|
||||
|| mainCharacter.getCurrentStamina() > 0);
|
||||
float speed = (inDeepWater || walk || inBlockStance) ? MOVE_SPEED * WALK_MULT
|
||||
float speed = sneaking ? MOVE_SPEED * WALK_MULT
|
||||
: (inDeepWater || walk || inBlockStance) ? MOVE_SPEED * WALK_MULT
|
||||
: canSprint ? MOVE_SPEED * SPRINT_MULT
|
||||
: MOVE_SPEED;
|
||||
physicsChar.setWalkDirection(scratchWalk.set(scratchMoveDir).multLocal(speed));
|
||||
@@ -1038,10 +1069,14 @@ public class PlayerInputControl {
|
||||
if (groundGraceFrames > 0) groundGraceFrames--;
|
||||
|
||||
// Block-Phase verwaltet ihre eigenen Animationen.
|
||||
if (!combatAnimActive && !isBlocking()) {
|
||||
// Während Sneak-Übergang (DOWN/UP) läuft die Transitions-Animation durch – nicht überschreiben.
|
||||
if (!combatAnimActive && !isBlocking()
|
||||
&& sneakPhase != SneakPhase.DOWN && sneakPhase != SneakPhase.UP) {
|
||||
AnimationAction target;
|
||||
if (jumpFrames > 0 || (!physicsChar.onGround() && groundGraceFrames <= 0)) {
|
||||
target = moving ? AnimationAction.RUNNING_JUMP : AnimationAction.JUMP;
|
||||
} else if (sneaking) {
|
||||
target = moving ? AnimationAction.SNEAK : AnimationAction.CROUCH_IDLE;
|
||||
} else if (moving) {
|
||||
target = (inDeepWater || walk) ? AnimationAction.WALK
|
||||
: sprint ? AnimationAction.SPRINT
|
||||
@@ -1365,6 +1400,31 @@ public class PlayerInputControl {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handleSneakKey(boolean pressed) {
|
||||
sneakKeyHeld = pressed;
|
||||
if (pressed && sneakPhase == SneakPhase.NONE
|
||||
&& !rollActive && !pickupActive && !blockingAnimActive
|
||||
&& !turnActive && !lockedInPlace && !combatAnimActive) {
|
||||
sneakPhase = SneakPhase.DOWN;
|
||||
boolean moving = forward || backward || left || right;
|
||||
sneakTransitionRemaining = resolveClipLength(AnimationAction.DUCK, 0.5f) * (moving ? 0.5f : 1f);
|
||||
nextTransitionLength = 0.1f;
|
||||
playAction(AnimationAction.DUCK);
|
||||
currentAnim = AnimationAction.DUCK;
|
||||
} else if (!pressed && sneakPhase == SneakPhase.ACTIVE) {
|
||||
startSneakUp();
|
||||
}
|
||||
}
|
||||
|
||||
private void startSneakUp() {
|
||||
sneakPhase = SneakPhase.UP;
|
||||
boolean moving = forward || backward || left || right;
|
||||
sneakTransitionRemaining = resolveClipLength(AnimationAction.CROUCH_TO_STAND, 0.5f) * (moving ? 0.5f : 1f);
|
||||
nextTransitionLength = 0.1f;
|
||||
playAction(AnimationAction.CROUCH_TO_STAND);
|
||||
currentAnim = AnimationAction.CROUCH_TO_STAND;
|
||||
}
|
||||
|
||||
private void triggerRollFromInput() {
|
||||
if (rollActive || pickupActive || blockingAnimActive || turnActive
|
||||
|| lockedInPlace || combatAnimActive || isBlocking()) return;
|
||||
@@ -1772,22 +1832,32 @@ public class PlayerInputControl {
|
||||
}
|
||||
|
||||
private String currentAnimToGait(AnimationAction anim) {
|
||||
if (anim == AnimationAction.WALK) return "walking";
|
||||
if (anim == AnimationAction.RUN) return "running";
|
||||
if (anim == AnimationAction.SPRINT) return "sprinting";
|
||||
return null;
|
||||
if (anim == null) return null;
|
||||
return switch (anim) {
|
||||
case WALK,
|
||||
SWORD_WALK, AXE_WALK, TWO_HAND_WALK,
|
||||
BOW_WALK, CROSSBOW_WALK, CRYSTAL_WALK,
|
||||
SWORD_BLOCK_MOVE, SWORD_BLOCK_MOVE_BACKWARD,
|
||||
SWORD_BLOCK_STRAFE_LEFT, SWORD_BLOCK_STRAFE_RIGHT -> "walking";
|
||||
case RUN,
|
||||
SWORD_RUN, AXE_RUN, TWO_HAND_RUN,
|
||||
BOW_RUN, CROSSBOW_RUN, CRYSTAL_RUN -> "running";
|
||||
case SPRINT -> "sprinting";
|
||||
case SNEAK -> "walking";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private void triggerStep(String gait) {
|
||||
float vol = (sneakPhase == SneakPhase.ACTIVE) ? 0.25f : 1f;
|
||||
if (currentWaterDepth > 0f) {
|
||||
// Im Wasser: Wassergeräusche aus footsteps/water/walking bzw. /running
|
||||
float[] weights = new float[de.blight.game.audio.SurfaceType.values().length];
|
||||
weights[de.blight.game.audio.SurfaceType.WATER.ordinal()] = 1f;
|
||||
footstepSystem.play(weights, gait);
|
||||
footstepSystem.play(weights, gait, vol);
|
||||
} else {
|
||||
Vector3f pos = physicsChar.getPhysicsLocation();
|
||||
float[] weights = surfaceQuery.apply(pos.x, pos.z);
|
||||
footstepSystem.play(weights, gait);
|
||||
footstepSystem.play(weights, gait, vol);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user