Zwischenstand

This commit is contained in:
2026-10-16 13:52:21 +02:00
parent d19538bb63
commit 93a3c266e1
18 changed files with 577 additions and 70 deletions

View File

@@ -12,6 +12,8 @@ import com.jme3.scene.control.AbstractControl;
import de.blight.common.model.Item;
import de.blight.common.model.ItemGrip;
import de.blight.common.model.ItemSubCategory;
import de.blight.common.model.ShieldAttachmentIO;
import de.blight.common.model.ShieldCategoryAttachment;
import de.blight.common.model.WeaponAttachmentIO;
import de.blight.common.model.WeaponCategoryAttachment;
import de.blight.game.animation.RetargetingSystem;
@@ -35,7 +37,8 @@ public class NpcWeaponAttachmentControl extends AbstractControl {
private static final float DEG_TO_RAD = (float) Math.PI / 180f;
private static final float HALF_PI = (float) Math.PI * 0.5f;
private static final Vector3f BACK_GRIP_OFFSET = new Vector3f(0.0f, 0.40f, -0.13f);
private static final Vector3f BACK_GRIP_OFFSET = new Vector3f(0.0f, 0.40f, -0.13f);
private static final Vector3f TWO_HAND_BACK_GRIP_OFFSET = new Vector3f(0.0f, 0.40f, -0.03f);
private static final Vector3f HAND_GRIP_OFFSET = new Vector3f(
ItemGrip.HAND_GRIP_OFFSET_X, ItemGrip.HAND_GRIP_OFFSET_Y, ItemGrip.HAND_GRIP_OFFSET_Z);
private static final Vector3f SHIELD_BACK_OFFSET = new Vector3f(0.12f, -0.10f, -0.10f);
@@ -157,8 +160,10 @@ public class NpcWeaponAttachmentControl extends AbstractControl {
applyHandTransform(weaponSpatial, attachInChar, boneRotInChar, wGrip, cfg);
}
} else {
boolean twoHanded = weaponItem != null
&& weaponItem.getSubCategory() == ItemSubCategory.TWO_HANDED_SWORD;
applyBackTransform(weaponSpatial, boneInChar, boneRotInChar,
weaponItem != null ? weaponItem.getGrip() : null);
weaponItem != null ? weaponItem.getGrip() : null, twoHanded);
}
}
}
@@ -169,7 +174,9 @@ public class NpcWeaponAttachmentControl extends AbstractControl {
if (drawn && leftForeArmNode != null) {
Vector3f boneInChar = charWorldRotInv.mult(leftForeArmNode.getWorldTranslation().subtract(charWorldPos));
Quaternion boneRotInChar = charWorldRotInv.mult(leftForeArmNode.getWorldRotation());
applyShieldArmTransform(shieldSpatial, boneInChar, boneRotInChar, grip);
ShieldCategoryAttachment shieldCfg = ShieldAttachmentIO.get(
shieldItem != null ? shieldItem.getSubCategory() : null);
applyShieldArmTransform(shieldSpatial, boneInChar, boneRotInChar, grip, shieldCfg);
shieldSpatial.setCullHint(Spatial.CullHint.Inherit);
} else if (!drawn && backNode != null) {
Vector3f boneInChar = charWorldRotInv.mult(backNode.getWorldTranslation().subtract(charWorldPos));
@@ -275,7 +282,7 @@ public class NpcWeaponAttachmentControl extends AbstractControl {
private static final Quaternion BACK_ROT_NORM = new Quaternion(0f, -(float) Math.sqrt(0.5), (float) Math.sqrt(0.5), 0f);
private void applyBackTransform(Spatial s, Vector3f boneInChar,
Quaternion boneRotInChar, ItemGrip grip) {
Quaternion boneRotInChar, ItemGrip grip, boolean twoHanded) {
Quaternion gripRot = (grip != null)
? new Quaternion().fromAngles(DEG_TO_RAD * grip.getRotX(),
DEG_TO_RAD * grip.getRotY(),
@@ -286,7 +293,8 @@ public class NpcWeaponAttachmentControl extends AbstractControl {
? new Quaternion().fromAngles(com.jme3.math.FastMath.PI, 0f, 0f)
: new Quaternion();
Quaternion weaponRot = boneRotInChar.mult(BACK_ROT_NORM).mult(bladeFlip2).mult(gripRot.inverse());
Vector3f target = boneInChar.add(boneRotInChar.mult(BACK_GRIP_OFFSET));
Vector3f target = boneInChar.add(boneRotInChar.mult(
twoHanded ? TWO_HAND_BACK_GRIP_OFFSET : BACK_GRIP_OFFSET));
Vector3f gripPos = grip != null
? new Vector3f(grip.getPosX(), grip.getPosY(), grip.getPosZ()) : Vector3f.ZERO;
Vector3f backPos = target.subtract(weaponRot.mult(gripPos));
@@ -298,15 +306,17 @@ public class NpcWeaponAttachmentControl extends AbstractControl {
// ── Schild-Transforms (1:1 von WeaponAttachmentControl) ──────────────────────
private void applyShieldArmTransform(Spatial s, Vector3f bonePosInChar,
Quaternion boneRotInChar, ItemGrip grip) {
Quaternion boneRotInChar, ItemGrip grip,
ShieldCategoryAttachment cfg) {
Quaternion animDelta = (leftForeArmBindRotInChar != null)
? boneRotInChar.mult(leftForeArmBindRotInChar.inverse())
: boneRotInChar;
Quaternion armRot = new Quaternion().fromAngles(SHIELD_ARM_ROT_X, SHIELD_ARM_ROT_Y, SHIELD_ARM_ROT_Z);
Quaternion armRot = new Quaternion().fromAngles(
DEG_TO_RAD * cfg.getRotX(), DEG_TO_RAD * cfg.getRotY(), DEG_TO_RAD * cfg.getRotZ());
Quaternion shieldRot = animDelta.mult(armRot);
Vector3f gripPos = (grip != null)
? new Vector3f(grip.getPosX(), grip.getPosY(), grip.getPosZ()) : Vector3f.ZERO;
Vector3f anchor = bonePosInChar.add(boneRotInChar.mult(new Vector3f(0f, -SHIELD_ARM_ELBOW_OFFSET, 0f)));
Vector3f anchor = bonePosInChar.add(boneRotInChar.mult(new Vector3f(0f, -cfg.getElbowOffset(), 0f)));
s.setLocalRotation(shieldRot);
s.setLocalTranslation(anchor.subtract(shieldRot.mult(gripPos)));
}

View File

@@ -6,6 +6,7 @@ import com.jme3.anim.tween.Tween;
import com.jme3.anim.tween.action.BaseAction;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.RawInputListener;
import com.jme3.input.controls.ActionListener;
@@ -110,11 +111,14 @@ public class PlayerInputControl implements CombatStyleBase.AnimReceiver {
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 ACT_BORED_1 = "BoredAnim1";
private static final String ACT_BORED_2 = "BoredAnim2";
private static final String ACT_BORED_3 = "BoredAnim3";
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_SNEAK
ACT_ROLL, ACT_SNEAK, ACT_BORED_1, ACT_BORED_2, ACT_BORED_3
};
private final InputManager inputManager;
@@ -381,8 +385,11 @@ public class PlayerInputControl implements CombatStyleBase.AnimReceiver {
}
}
case ACT_COMBAT_ALT -> handleCombatAlt(isPressed);
case ACT_ROLL -> { if (isPressed) triggerRollFromInput(); }
case ACT_SNEAK -> { if (!weaponDrawn) handleSneakKey(isPressed); }
case ACT_ROLL -> { if (isPressed) triggerRollFromInput(); }
case ACT_SNEAK -> { if (!weaponDrawn) handleSneakKey(isPressed); }
case ACT_BORED_1 -> { if (isPressed) triggerBoredAnim(0); }
case ACT_BORED_2 -> { if (isPressed) triggerBoredAnim(1); }
case ACT_BORED_3 -> { if (isPressed) triggerBoredAnim(2); }
}
};
@@ -468,6 +475,7 @@ public class PlayerInputControl implements CombatStyleBase.AnimReceiver {
public void setMainCharacter(MainCharacter mc) { this.mainCharacter = mc; }
public boolean isWeaponDrawn() { return weaponDrawn; }
public boolean isDrawAnimActive() { return drawAnimActive; }
public ItemSubCategory getDrawnWeaponType() { return drawnWeaponType; }
public boolean isLastAttackCritical() { return lastAttackCritical; }
public com.jme3.anim.SkinningControl getSkinningControl() { return skinningControl; }
@@ -832,6 +840,9 @@ public class PlayerInputControl implements CombatStyleBase.AnimReceiver {
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.addMapping(ACT_BORED_1, new KeyTrigger(KeyInput.KEY_F1));
inputManager.addMapping(ACT_BORED_2, new KeyTrigger(KeyInput.KEY_F2));
inputManager.addMapping(ACT_BORED_3, new KeyTrigger(KeyInput.KEY_F3));
inputManager.addListener(actionListener, ACTION_NAMES);
}
@@ -1222,7 +1233,8 @@ public class PlayerInputControl implements CombatStyleBase.AnimReceiver {
} else {
boolean swordShield = drawnWeaponType == de.blight.common.model.ItemSubCategory.SWORD
&& hasShieldEquipped();
if (swordShield) {
boolean twoHand = drawnWeaponType == ItemSubCategory.TWO_HANDED_SWORD;
if (swordShield || twoHand) {
if (boredAnimRemaining > 0f) {
boredAnimRemaining -= tpf;
target = boredVariant;
@@ -1231,9 +1243,15 @@ public class PlayerInputControl implements CombatStyleBase.AnimReceiver {
if (boredIdleTimer >= BORED_IDLE_DELAY) {
boredIdleTimer = 0f;
int pick = playerRng.nextInt(3);
boredVariant = pick == 0 ? AnimationAction.SWORD_IDLE_BORED
: pick == 1 ? AnimationAction.SWORD_IDLE_BORED_2
: AnimationAction.SWORD_IDLE_BORED_3;
if (swordShield) {
boredVariant = pick == 0 ? AnimationAction.SWORD_IDLE_BORED
: pick == 1 ? AnimationAction.SWORD_IDLE_BORED_2
: AnimationAction.SWORD_IDLE_BORED_3;
} else {
boredVariant = pick == 0 ? AnimationAction.TWO_HAND_IDLE_BORED
: pick == 1 ? AnimationAction.TWO_HAND_IDLE_BORED_2
: AnimationAction.TWO_HAND_IDLE_BORED_3;
}
boredAnimRemaining = resolveClipLength(boredVariant, 3.0f);
target = boredVariant;
} else {
@@ -1676,6 +1694,25 @@ public class PlayerInputControl implements CombatStyleBase.AnimReceiver {
currentAnim = AnimationAction.CROUCH_TO_STAND;
}
private void triggerBoredAnim(int variant) {
if (!weaponDrawn || forward || backward || left || right || combatAnimActive || drawAnimActive) return;
if (physicsChar != null && !physicsChar.onGround()) return;
boolean swordShield = drawnWeaponType == de.blight.common.model.ItemSubCategory.SWORD && hasShieldEquipped();
boolean twoHand = drawnWeaponType == ItemSubCategory.TWO_HANDED_SWORD;
if (!swordShield && !twoHand) return;
if (swordShield) {
boredVariant = variant == 0 ? AnimationAction.SWORD_IDLE_BORED
: variant == 1 ? AnimationAction.SWORD_IDLE_BORED_2
: AnimationAction.SWORD_IDLE_BORED_3;
} else {
boredVariant = variant == 0 ? AnimationAction.TWO_HAND_IDLE_BORED
: variant == 1 ? AnimationAction.TWO_HAND_IDLE_BORED_2
: AnimationAction.TWO_HAND_IDLE_BORED_3;
}
boredAnimRemaining = resolveClipLength(boredVariant, 3.0f);
boredIdleTimer = 0f;
}
private void triggerRollFromInput() {
if (!weaponDrawn) return;
if (rollActive || pickupActive || blockingAnimActive || turnActive

View File

@@ -13,6 +13,8 @@ import de.blight.common.model.Item;
import de.blight.common.model.ItemGrip;
import de.blight.common.model.ItemSubCategory;
import de.blight.common.model.MainCharacter;
import de.blight.common.model.ShieldAttachmentIO;
import de.blight.common.model.ShieldCategoryAttachment;
import de.blight.common.model.WeaponAttachmentIO;
import de.blight.common.model.WeaponCategoryAttachment;
import org.slf4j.Logger;
@@ -38,7 +40,8 @@ public class WeaponAttachmentControl extends AbstractControl {
private static final float DEG_TO_RAD = (float) Math.PI / 180f;
private static final float HALF_PI = (float) Math.PI * 0.5f;
private static final Vector3f BACK_GRIP_OFFSET = new Vector3f(0.0f, 0.40f, -0.13f);
private static final Vector3f BACK_GRIP_OFFSET = new Vector3f(0.0f, 0.40f, -0.13f);
private static final Vector3f TWO_HAND_BACK_GRIP_OFFSET = new Vector3f(0.0f, 0.40f, -0.03f);
private static final Vector3f HAND_GRIP_OFFSET = new Vector3f(
ItemGrip.HAND_GRIP_OFFSET_X, ItemGrip.HAND_GRIP_OFFSET_Y, ItemGrip.HAND_GRIP_OFFSET_Z);
@@ -196,14 +199,16 @@ public class WeaponAttachmentControl extends AbstractControl {
: boneInChar;
boolean usesTwoHand = isTwoHand && leftForeArmNode != null
&& grip != null
&& (grip.getGrip2PosX() != 0f || grip.getGrip2PosY() != 0f || grip.getGrip2PosZ() != 0f);
&& (grip.getGrip2PosX() != 0f || grip.getGrip2PosY() != 0f || grip.getGrip2PosZ() != 0f)
&& !playerInput.isDrawAnimActive();
if (usesTwoHand) {
applyTwoHandTransform(attachInChar, boneRotInChar, grip, charWorldRotInv, charWorldPos, cfg);
} else {
applyHandTransform(attachInChar, boneRotInChar, grip, cfg);
}
} else {
applyBackTransform(boneInChar, boneRotInChar, grip);
boolean twoHanded = item != null && item.getSubCategory() == ItemSubCategory.TWO_HANDED_SWORD;
applyBackTransform(boneInChar, boneRotInChar, grip, twoHanded);
}
}
@@ -356,7 +361,8 @@ public class WeaponAttachmentControl extends AbstractControl {
// Ergebnis für Kurzschwert (gripRot=fromAngles(0,-90°,90°)) identisch zur alten Formel.
private static final Quaternion BACK_ROT_NORM = new Quaternion(0f, -(float) Math.sqrt(0.5), (float) Math.sqrt(0.5), 0f);
private void applyBackTransform(Vector3f bonePosInChar, Quaternion boneRotInChar, ItemGrip grip) {
private void applyBackTransform(Vector3f bonePosInChar, Quaternion boneRotInChar, ItemGrip grip,
boolean twoHanded) {
Quaternion gripRot = (grip != null)
? new Quaternion().fromAngles(DEG_TO_RAD * grip.getRotX(),
DEG_TO_RAD * grip.getRotY(),
@@ -369,7 +375,8 @@ public class WeaponAttachmentControl extends AbstractControl {
? new Quaternion().fromAngles(com.jme3.math.FastMath.PI, 0f, 0f)
: new Quaternion();
Quaternion weaponRot = boneRotInChar.mult(BACK_ROT_NORM).mult(bladeFlip).mult(gripRot.inverse());
Vector3f gripTarget = bonePosInChar.add(boneRotInChar.mult(BACK_GRIP_OFFSET));
Vector3f gripTarget = bonePosInChar.add(boneRotInChar.mult(
twoHanded ? TWO_HAND_BACK_GRIP_OFFSET : BACK_GRIP_OFFSET));
Vector3f gripPos = (grip != null)
? new Vector3f(grip.getPosX(), grip.getPosY(), grip.getPosZ())
: Vector3f.ZERO;
@@ -406,7 +413,9 @@ public class WeaponAttachmentControl extends AbstractControl {
Vector3f boneInChar = charWorldRotInv.mult(
leftForeArmNode.getWorldTranslation().subtract(charWorldPos));
Quaternion boneRotInChar = charWorldRotInv.mult(leftForeArmNode.getWorldRotation());
applyShieldArmTransform(boneInChar, boneRotInChar, grip);
ShieldCategoryAttachment shieldCfg = ShieldAttachmentIO.get(
shield != null ? shield.getSubCategory() : null);
applyShieldArmTransform(boneInChar, boneRotInChar, grip, shieldCfg);
shieldSpatial.setCullHint(Spatial.CullHint.Inherit);
} else if (!drawn && backNode != null) {
Vector3f boneInChar = charWorldRotInv.mult(
@@ -419,17 +428,18 @@ public class WeaponAttachmentControl extends AbstractControl {
}
}
private void applyShieldArmTransform(Vector3f bonePosInChar, Quaternion boneRotInChar, ItemGrip grip) {
private void applyShieldArmTransform(Vector3f bonePosInChar, Quaternion boneRotInChar,
ItemGrip grip, ShieldCategoryAttachment cfg) {
Quaternion animDelta = (leftForeArmBindRotInChar != null)
? boneRotInChar.mult(leftForeArmBindRotInChar.inverse())
: boneRotInChar;
Quaternion armRot = new Quaternion().fromAngles(SHIELD_ARM_ROT_X, SHIELD_ARM_ROT_Y, SHIELD_ARM_ROT_Z);
Quaternion armRot = new Quaternion().fromAngles(
DEG_TO_RAD * cfg.getRotX(), DEG_TO_RAD * cfg.getRotY(), DEG_TO_RAD * cfg.getRotZ());
Quaternion shieldRot = animDelta.mult(armRot);
Vector3f gripPos = (grip != null)
? new Vector3f(grip.getPosX(), grip.getPosY(), grip.getPosZ())
: Vector3f.ZERO;
// Ankerpunkt Richtung Ellbogen verschieben (lokale −Y des LeftHand-Bones)
Vector3f anchor = bonePosInChar.add(boneRotInChar.mult(new Vector3f(0f, -SHIELD_ARM_ELBOW_OFFSET, 0f)));
Vector3f anchor = bonePosInChar.add(boneRotInChar.mult(new Vector3f(0f, -cfg.getElbowOffset(), 0f)));
shieldSpatial.setLocalRotation(shieldRot);
shieldSpatial.setLocalTranslation(anchor.subtract(shieldRot.mult(gripPos)));
}