Ausdauer System implementiert
This commit is contained in:
@@ -56,6 +56,14 @@ public class PlayerInputControl {
|
||||
private static final float LUNGE_FRAC_END = 0.55f;
|
||||
/** AnimComposer-Layer-Name für die prozedurale Ziehen/Wegstecken-Animation (Oberarm-Overlay). */
|
||||
private static final String DRAW_LAYER = "__draw_weapon__";
|
||||
|
||||
// ── Ausdauer ──────────────────────────────────────────────────────────────
|
||||
private static final float STAMINA_REGEN_PER_SEC = 5f;
|
||||
private static final float STAMINA_SPRINT_PER_SEC = 10f;
|
||||
private static final int STAMINA_ATTACK_COST = 10;
|
||||
private static final int STAMINA_ATTACK5_COST = 20;
|
||||
private static final int STAMINA_HEAVY_COST = 30;
|
||||
private static final int STAMINA_BLOCK_HIT_COST = 30;
|
||||
/** Dauer der Ziehen/Wegstecken-Animation in Sekunden. */
|
||||
private static final float DRAW_DURATION = 0.85f;
|
||||
// Ziel-Quaternions für die Ziehen-Animation: aus Heavy-Attack-Wind-Up bei t=0.933s gelesen
|
||||
@@ -147,6 +155,8 @@ public class PlayerInputControl {
|
||||
private static final float ATTACK5_SOUND_MIN_PROGRESS = 0.35f;
|
||||
private boolean attackSoundFired = false;
|
||||
private int currentComboStep = 0;
|
||||
private float staminaAccum = 0f; // Fließkomma-Übertrag für kontinuierliche Ausdauer-Änderungen
|
||||
private boolean staminaExhausted = false; // Sprint gesperrt bis 25% Ausdauer wiederhergestellt
|
||||
private final Vector3f lastGripPos = new Vector3f();
|
||||
private final Vector3f scratchGripVel = new Vector3f();
|
||||
// Draw/Sheath Animation System
|
||||
@@ -793,10 +803,17 @@ public class PlayerInputControl {
|
||||
// Schon ab WAITING Gehgeschwindigkeit erzwingen, damit beim Blockstart kein Sprint-Frame entsteht
|
||||
boolean inBlockStance = isBlocking() || blockPhase == BlockPhase.WAITING;
|
||||
|
||||
// Ausdauer: Regen + Sprint-Verbrauch
|
||||
boolean isSprinting = sprint && !weaponDrawn && moving && !staminaExhausted;
|
||||
tickStamina(tpf, isSprinting);
|
||||
|
||||
if (moving) {
|
||||
scratchMoveDir.normalizeLocal();
|
||||
boolean canSprint = sprint && !weaponDrawn && !staminaExhausted
|
||||
&& (mainCharacter == null || mainCharacter.getMaxStamina() <= 0
|
||||
|| mainCharacter.getCurrentStamina() > 0);
|
||||
float speed = (inDeepWater || walk || inBlockStance) ? MOVE_SPEED * WALK_MULT
|
||||
: (sprint && !weaponDrawn) ? MOVE_SPEED * SPRINT_MULT
|
||||
: canSprint ? MOVE_SPEED * SPRINT_MULT
|
||||
: MOVE_SPEED;
|
||||
physicsChar.setWalkDirection(scratchWalk.set(scratchMoveDir).multLocal(speed));
|
||||
|
||||
@@ -1041,6 +1058,8 @@ public class PlayerInputControl {
|
||||
if (isMeleeType(drawnWeaponType)) {
|
||||
int step = comboStep;
|
||||
boolean isComboFollow = comboWindowActive; // war Kombo-Fenster offen?
|
||||
int staminaCost = (step == 4) ? STAMINA_ATTACK5_COST : STAMINA_ATTACK_COST;
|
||||
if (!spendStamina(staminaCost)) return;
|
||||
AnimationAction atk = getMeleeComboAction(drawnWeaponType, step);
|
||||
lastAttackCritical = (step == 4);
|
||||
currentAttackId = ++attackIdCounter;
|
||||
@@ -1197,6 +1216,61 @@ public class PlayerInputControl {
|
||||
|| blockPhase == BlockPhase.EXITING;
|
||||
}
|
||||
|
||||
/** Wird aufgerufen wenn ein blockierter Treffer landet. Kostet 30 Ausdauer; unter 0 → Block bricht. */
|
||||
public void triggerBlockImpact() {
|
||||
if (blockPhase != BlockPhase.HOLDING || drawnWeaponType == null) return;
|
||||
if (mainCharacter != null && mainCharacter.getMaxStamina() > 0) {
|
||||
if (mainCharacter.getCurrentStamina() < STAMINA_BLOCK_HIT_COST) {
|
||||
mainCharacter.setCurrentStamina(0);
|
||||
startBlockExit();
|
||||
return;
|
||||
}
|
||||
mainCharacter.setCurrentStamina(mainCharacter.getCurrentStamina() - STAMINA_BLOCK_HIT_COST);
|
||||
}
|
||||
AnimationAction impact = getMeleeBlockImpactAction(drawnWeaponType);
|
||||
float dur = resolveClipLength(impact, 0.8f);
|
||||
hitWindowActive = false;
|
||||
attackSoundFired = true;
|
||||
combatAnimActive = true;
|
||||
combatAnimRemaining = Math.max(0.1f, dur - COMBAT_BLEND);
|
||||
combatAnimDuration = dur;
|
||||
combatAnimCallback = null;
|
||||
combatAnimSkipComboWindow = true;
|
||||
nextTransitionLength = COMBAT_BLEND;
|
||||
playAction(impact);
|
||||
currentAnim = impact;
|
||||
}
|
||||
|
||||
// ── Ausdauer-Hilfsmethoden ────────────────────────────────────────────────
|
||||
|
||||
private void tickStamina(float tpf, boolean isSprinting) {
|
||||
if (mainCharacter == null || mainCharacter.getMaxStamina() <= 0) return;
|
||||
float delta = STAMINA_REGEN_PER_SEC * tpf;
|
||||
if (isSprinting) delta -= STAMINA_SPRINT_PER_SEC * tpf;
|
||||
staminaAccum += delta;
|
||||
int intPart = (int) staminaAccum;
|
||||
if (intPart != 0) {
|
||||
staminaAccum -= intPart;
|
||||
int cur = mainCharacter.getCurrentStamina() + intPart;
|
||||
mainCharacter.setCurrentStamina(Math.max(0, Math.min(mainCharacter.getMaxStamina(), cur)));
|
||||
}
|
||||
int stamina = mainCharacter.getCurrentStamina();
|
||||
int max = mainCharacter.getMaxStamina();
|
||||
if (!staminaExhausted && stamina == 0) {
|
||||
staminaExhausted = true;
|
||||
} else if (staminaExhausted && stamina >= max / 4) {
|
||||
staminaExhausted = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Zieht {@code cost} Ausdauer ab. Gibt false zurück (Aktion verweigert) wenn nicht genug vorhanden. */
|
||||
private boolean spendStamina(int cost) {
|
||||
if (mainCharacter == null || mainCharacter.getMaxStamina() <= 0) return true;
|
||||
if (mainCharacter.getCurrentStamina() < cost) return false;
|
||||
mainCharacter.setCurrentStamina(mainCharacter.getCurrentStamina() - cost);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasShieldEquipped() {
|
||||
return mainCharacter != null && mainCharacter.getEquippedShield() != null;
|
||||
}
|
||||
@@ -1394,6 +1468,7 @@ public class PlayerInputControl {
|
||||
if (drawnWeaponType == null || !isMeleeType(drawnWeaponType)) {
|
||||
return;
|
||||
}
|
||||
if (!spendStamina(STAMINA_HEAVY_COST)) return;
|
||||
comboStep = 0;
|
||||
comboWindowActive = false;
|
||||
AnimationAction action = getMeleeHeavyAttackAction(drawnWeaponType);
|
||||
|
||||
@@ -365,6 +365,24 @@ public class WorldScene extends BaseAppState {
|
||||
|
||||
MainCharacter mc = findMainCharacter();
|
||||
if (mc != null) {
|
||||
if (mc.getMaxHp() <= 0) {
|
||||
mc.setMaxHp(100);
|
||||
mc.setCurrentHp(100);
|
||||
} else if (mc.getCurrentHp() <= 0) {
|
||||
mc.setCurrentHp(mc.getMaxHp());
|
||||
}
|
||||
if (mc.getMaxMana() <= 0) {
|
||||
mc.setMaxMana(100);
|
||||
mc.setCurrentMana(100);
|
||||
} else if (mc.getCurrentMana() <= 0) {
|
||||
mc.setCurrentMana(mc.getMaxMana());
|
||||
}
|
||||
if (mc.getMaxStamina() <= 0) {
|
||||
mc.setMaxStamina(100);
|
||||
mc.setCurrentStamina(100);
|
||||
} else if (mc.getCurrentStamina() <= 0) {
|
||||
mc.setCurrentStamina(mc.getMaxStamina());
|
||||
}
|
||||
playerInput.setMainCharacter(mc);
|
||||
var wac = new de.blight.game.control.WeaponAttachmentControl(assetManager, playerInput, mc);
|
||||
character.addControl(wac);
|
||||
|
||||
Reference in New Issue
Block a user