Schleichen hinzugefügt, Bugs bei den Sounds behoben
This commit is contained in:
BIN
assets/imported/animations/Crouched To Standing.fbx
Normal file
BIN
assets/imported/animations/Crouched To Standing.fbx
Normal file
Binary file not shown.
BIN
assets/imported/animations/Crouching Idle.fbx
Normal file
BIN
assets/imported/animations/Crouching Idle.fbx
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/imported/animations/Standing To Crouched.fbx
Normal file
BIN
assets/imported/animations/Standing To Crouched.fbx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -26,7 +26,11 @@
|
|||||||
"Sword And Shield Strafe Right",
|
"Sword And Shield Strafe Right",
|
||||||
"Sword And Shield Heavy Attack",
|
"Sword And Shield Heavy Attack",
|
||||||
"Picking Up",
|
"Picking Up",
|
||||||
"Roll"
|
"Roll",
|
||||||
|
"Crouched To Standing",
|
||||||
|
"Crouching Idle",
|
||||||
|
"Sneaking Forward",
|
||||||
|
"Standing To Crouched"
|
||||||
],
|
],
|
||||||
"actionMap": {
|
"actionMap": {
|
||||||
"DEFAULT": "Idle",
|
"DEFAULT": "Idle",
|
||||||
@@ -55,7 +59,11 @@
|
|||||||
"SWORD_BLOCK_STRAFE_RIGHT": "Sword And Shield Strafe Right",
|
"SWORD_BLOCK_STRAFE_RIGHT": "Sword And Shield Strafe Right",
|
||||||
"SWORD_HEAVY_ATTACK": "Sword And Shield Heavy Attack",
|
"SWORD_HEAVY_ATTACK": "Sword And Shield Heavy Attack",
|
||||||
"PICK_UP": "Picking Up",
|
"PICK_UP": "Picking Up",
|
||||||
"ROLL": "Roll"
|
"ROLL": "Roll",
|
||||||
|
"DUCK": "Standing To Crouched",
|
||||||
|
"CROUCH_IDLE": "Crouching Idle",
|
||||||
|
"SNEAK": "Sneaking Forward",
|
||||||
|
"CROUCH_TO_STAND": "Crouched To Standing"
|
||||||
},
|
},
|
||||||
"previewModelPath": "Characters/Models/hero.j3o",
|
"previewModelPath": "Characters/Models/hero.j3o",
|
||||||
"animOffsets": {
|
"animOffsets": {
|
||||||
@@ -116,6 +124,7 @@
|
|||||||
"Sword And Shield Strafe Left",
|
"Sword And Shield Strafe Left",
|
||||||
"Sword And Shield Strafe Right",
|
"Sword And Shield Strafe Right",
|
||||||
"Sword And Shield Heavy Attack",
|
"Sword And Shield Heavy Attack",
|
||||||
"Roll"
|
"Roll",
|
||||||
|
"Sneaking Forward"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,9 @@ public enum AnimationAction {
|
|||||||
RUNNING_JUMP,
|
RUNNING_JUMP,
|
||||||
ROLL,
|
ROLL,
|
||||||
DUCK,
|
DUCK,
|
||||||
|
CROUCH_IDLE,
|
||||||
|
CROUCH_TO_STAND,
|
||||||
|
SNEAK,
|
||||||
PICK_UP,
|
PICK_UP,
|
||||||
LIE_DOWN,
|
LIE_DOWN,
|
||||||
LIE_UP,
|
LIE_UP,
|
||||||
@@ -80,7 +83,10 @@ public enum AnimationAction {
|
|||||||
case JUMP -> TextRegistry.resolve(null, key, "Jump");
|
case JUMP -> TextRegistry.resolve(null, key, "Jump");
|
||||||
case RUNNING_JUMP -> TextRegistry.resolve(null, key, "Running Jump");
|
case RUNNING_JUMP -> TextRegistry.resolve(null, key, "Running Jump");
|
||||||
case ROLL -> TextRegistry.resolve(null, key, "Rolle");
|
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 PICK_UP -> TextRegistry.resolve(null, key, "Pick up");
|
||||||
case LIE_DOWN -> TextRegistry.resolve(null, key, "Hinlegen");
|
case LIE_DOWN -> TextRegistry.resolve(null, key, "Hinlegen");
|
||||||
case LIE_UP -> TextRegistry.resolve(null, key, "Aufstehen (Bett)");
|
case LIE_UP -> TextRegistry.resolve(null, key, "Aufstehen (Bett)");
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public class KeyBindings {
|
|||||||
public int drawRangedWeapon = KeyInput.KEY_2;
|
public int drawRangedWeapon = KeyInput.KEY_2;
|
||||||
public int sheathWeapon = KeyInput.KEY_X;
|
public int sheathWeapon = KeyInput.KEY_X;
|
||||||
public int roll = KeyInput.KEY_LCONTROL;
|
public int roll = KeyInput.KEY_LCONTROL;
|
||||||
|
public int sneak = KeyInput.KEY_X;
|
||||||
|
|
||||||
/** Metadaten für die Config-UI: Feldname im Objekt + Anzeigename. */
|
/** Metadaten für die Config-UI: Feldname im Objekt + Anzeigename. */
|
||||||
public static final String[][] ENTRIES = {
|
public static final String[][] ENTRIES = {
|
||||||
@@ -44,6 +45,7 @@ public class KeyBindings {
|
|||||||
{"drawRangedWeapon", "Fernkampfwaffe ziehen"},
|
{"drawRangedWeapon", "Fernkampfwaffe ziehen"},
|
||||||
{"sheathWeapon", "Waffe wegstecken"},
|
{"sheathWeapon", "Waffe wegstecken"},
|
||||||
{"roll", "Rolle"},
|
{"roll", "Rolle"},
|
||||||
|
{"sneak", "Schleichen"},
|
||||||
};
|
};
|
||||||
|
|
||||||
public int get(String fieldName) {
|
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_ATK = "CombatAttack";
|
||||||
private static final String ACT_COMBAT_ALT = "CombatAltAction";
|
private static final String ACT_COMBAT_ALT = "CombatAltAction";
|
||||||
private static final String ACT_ROLL = "Roll";
|
private static final String ACT_ROLL = "Roll";
|
||||||
|
private static final String ACT_SNEAK = "Sneak";
|
||||||
|
|
||||||
private static final String[] ACTION_NAMES = {
|
private static final String[] ACTION_NAMES = {
|
||||||
"Forward", "Backward", "Left", "Right", "Jump", "Sprint", "Walk",
|
"Forward", "Backward", "Left", "Right", "Jump", "Sprint", "Walk",
|
||||||
ACT_DRAW_MELEE, ACT_DRAW_RANGED, ACT_SHEATH, ACT_COMBAT_ATK, ACT_COMBAT_ALT,
|
ACT_DRAW_MELEE, ACT_DRAW_RANGED, ACT_SHEATH, ACT_COMBAT_ATK, ACT_COMBAT_ALT,
|
||||||
ACT_ROLL
|
ACT_ROLL, ACT_SNEAK
|
||||||
};
|
};
|
||||||
|
|
||||||
private final InputManager inputManager;
|
private final InputManager inputManager;
|
||||||
@@ -273,6 +274,12 @@ public class PlayerInputControl {
|
|||||||
/** Autopilot: wenn gesetzt, geht der Charakter automatisch in diese (normalisierte) Richtung. */
|
/** Autopilot: wenn gesetzt, geht der Charakter automatisch in diese (normalisierte) Richtung. */
|
||||||
private Vector3f autopilotDir = null;
|
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 ────────────────────────────────────────────────────────────
|
// ── Dodge Roll ────────────────────────────────────────────────────────────
|
||||||
private boolean rollActive = false;
|
private boolean rollActive = false;
|
||||||
private float rollRemaining = 0f;
|
private float rollRemaining = 0f;
|
||||||
@@ -334,6 +341,7 @@ public class PlayerInputControl {
|
|||||||
}
|
}
|
||||||
case ACT_COMBAT_ALT -> handleCombatAlt(isPressed);
|
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_ATK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
|
||||||
inputManager.addMapping(ACT_COMBAT_ALT, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
|
inputManager.addMapping(ACT_COMBAT_ALT, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
|
||||||
inputManager.addMapping(ACT_ROLL, new KeyTrigger(kb.roll));
|
inputManager.addMapping(ACT_ROLL, new KeyTrigger(kb.roll));
|
||||||
|
inputManager.addMapping(ACT_SNEAK, new KeyTrigger(kb.sneak));
|
||||||
inputManager.addListener(actionListener, ACTION_NAMES);
|
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
|
// Ruhezustand (liegen / sitzen) – blockiert alle Bewegungseingaben
|
||||||
if (lockedInPlace) {
|
if (lockedInPlace) {
|
||||||
physicsChar.setWalkDirection(Vector3f.ZERO);
|
physicsChar.setWalkDirection(Vector3f.ZERO);
|
||||||
@@ -886,16 +914,19 @@ public class PlayerInputControl {
|
|||||||
// Schon ab WAITING Gehgeschwindigkeit erzwingen, damit beim Blockstart kein Sprint-Frame entsteht
|
// Schon ab WAITING Gehgeschwindigkeit erzwingen, damit beim Blockstart kein Sprint-Frame entsteht
|
||||||
boolean inBlockStance = isBlocking() || blockPhase == BlockPhase.WAITING;
|
boolean inBlockStance = isBlocking() || blockPhase == BlockPhase.WAITING;
|
||||||
|
|
||||||
|
boolean sneaking = sneakPhase != SneakPhase.NONE;
|
||||||
|
|
||||||
// Ausdauer: Regen + Sprint-Verbrauch
|
// Ausdauer: Regen + Sprint-Verbrauch
|
||||||
boolean isSprinting = sprint && !weaponDrawn && moving && !staminaExhausted;
|
boolean isSprinting = sprint && !weaponDrawn && moving && !staminaExhausted && !sneaking;
|
||||||
tickStamina(tpf, isSprinting);
|
tickStamina(tpf, isSprinting);
|
||||||
|
|
||||||
if (moving) {
|
if (moving) {
|
||||||
scratchMoveDir.normalizeLocal();
|
scratchMoveDir.normalizeLocal();
|
||||||
boolean canSprint = sprint && !weaponDrawn && !staminaExhausted
|
boolean canSprint = !sneaking && sprint && !weaponDrawn && !staminaExhausted
|
||||||
&& (mainCharacter == null || mainCharacter.getMaxStamina() <= 0
|
&& (mainCharacter == null || mainCharacter.getMaxStamina() <= 0
|
||||||
|| mainCharacter.getCurrentStamina() > 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
|
: canSprint ? MOVE_SPEED * SPRINT_MULT
|
||||||
: MOVE_SPEED;
|
: MOVE_SPEED;
|
||||||
physicsChar.setWalkDirection(scratchWalk.set(scratchMoveDir).multLocal(speed));
|
physicsChar.setWalkDirection(scratchWalk.set(scratchMoveDir).multLocal(speed));
|
||||||
@@ -1038,10 +1069,14 @@ public class PlayerInputControl {
|
|||||||
if (groundGraceFrames > 0) groundGraceFrames--;
|
if (groundGraceFrames > 0) groundGraceFrames--;
|
||||||
|
|
||||||
// Block-Phase verwaltet ihre eigenen Animationen.
|
// 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;
|
AnimationAction target;
|
||||||
if (jumpFrames > 0 || (!physicsChar.onGround() && groundGraceFrames <= 0)) {
|
if (jumpFrames > 0 || (!physicsChar.onGround() && groundGraceFrames <= 0)) {
|
||||||
target = moving ? AnimationAction.RUNNING_JUMP : AnimationAction.JUMP;
|
target = moving ? AnimationAction.RUNNING_JUMP : AnimationAction.JUMP;
|
||||||
|
} else if (sneaking) {
|
||||||
|
target = moving ? AnimationAction.SNEAK : AnimationAction.CROUCH_IDLE;
|
||||||
} else if (moving) {
|
} else if (moving) {
|
||||||
target = (inDeepWater || walk) ? AnimationAction.WALK
|
target = (inDeepWater || walk) ? AnimationAction.WALK
|
||||||
: sprint ? AnimationAction.SPRINT
|
: sprint ? AnimationAction.SPRINT
|
||||||
@@ -1365,6 +1400,31 @@ public class PlayerInputControl {
|
|||||||
return true;
|
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() {
|
private void triggerRollFromInput() {
|
||||||
if (rollActive || pickupActive || blockingAnimActive || turnActive
|
if (rollActive || pickupActive || blockingAnimActive || turnActive
|
||||||
|| lockedInPlace || combatAnimActive || isBlocking()) return;
|
|| lockedInPlace || combatAnimActive || isBlocking()) return;
|
||||||
@@ -1772,22 +1832,32 @@ public class PlayerInputControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String currentAnimToGait(AnimationAction anim) {
|
private String currentAnimToGait(AnimationAction anim) {
|
||||||
if (anim == AnimationAction.WALK) return "walking";
|
if (anim == null) return null;
|
||||||
if (anim == AnimationAction.RUN) return "running";
|
return switch (anim) {
|
||||||
if (anim == AnimationAction.SPRINT) return "sprinting";
|
case WALK,
|
||||||
return null;
|
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) {
|
private void triggerStep(String gait) {
|
||||||
|
float vol = (sneakPhase == SneakPhase.ACTIVE) ? 0.25f : 1f;
|
||||||
if (currentWaterDepth > 0f) {
|
if (currentWaterDepth > 0f) {
|
||||||
// Im Wasser: Wassergeräusche aus footsteps/water/walking bzw. /running
|
|
||||||
float[] weights = new float[de.blight.game.audio.SurfaceType.values().length];
|
float[] weights = new float[de.blight.game.audio.SurfaceType.values().length];
|
||||||
weights[de.blight.game.audio.SurfaceType.WATER.ordinal()] = 1f;
|
weights[de.blight.game.audio.SurfaceType.WATER.ordinal()] = 1f;
|
||||||
footstepSystem.play(weights, gait);
|
footstepSystem.play(weights, gait, vol);
|
||||||
} else {
|
} else {
|
||||||
Vector3f pos = physicsChar.getPhysicsLocation();
|
Vector3f pos = physicsChar.getPhysicsLocation();
|
||||||
float[] weights = surfaceQuery.apply(pos.x, pos.z);
|
float[] weights = surfaceQuery.apply(pos.x, pos.z);
|
||||||
footstepSystem.play(weights, gait);
|
footstepSystem.play(weights, gait, vol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user