diff --git a/src/main/java/uno/mloluyu/desktop/character/Alice.java b/src/main/java/uno/mloluyu/characters/Alice.java similarity index 50% rename from src/main/java/uno/mloluyu/desktop/character/Alice.java rename to src/main/java/uno/mloluyu/characters/Alice.java index 05cce69..9f27ee6 100644 --- a/src/main/java/uno/mloluyu/desktop/character/Alice.java +++ b/src/main/java/uno/mloluyu/characters/Alice.java @@ -1,5 +1,5 @@ -package uno.mloluyu.desktop.character; -import uno.mloluyu.characters.Fighter; +package uno.mloluyu.characters; + import com.badlogic.gdx.graphics.g2d.TextureAtlas; /** @@ -14,44 +14,43 @@ public class Alice extends Fighter { health = maxHealth; attackPower = 12; // 攻击力中等 } - + @Override protected void loadAnimations() { - loadAnimationFromAtlas(Action.IDLE, "stand", 15, true); - loadAnimationFromAtlas(Action.WALK, "walkFront", 9, true); - loadAnimationFromAtlas(Action.JUMP, "jump", 8, false); - loadAnimationFromAtlas(Action.FALL, "hitSpin", 5, false); - loadAnimationFromAtlas(Action.ATTACK1, "attackAa", 6, false); - loadAnimationFromAtlas(Action.ATTACK2, "attackAb", 6, false); - loadAnimationFromAtlas(Action.ATTACK3, "attackAc", 6, false); - loadAnimationFromAtlas(Action.ATTACK4, "attackAd", 6, false); + loadAnimationFromAtlas(Action.IDLE, "stand/stand", 15, true); + loadAnimationFromAtlas(Action.WALK, "walkFront/walkFront", 9, true); + loadAnimationFromAtlas(Action.JUMP, "jump/jump", 8, false); + loadAnimationFromAtlas(Action.FALL, "hitSpin/hitSpin", 5, false); + loadAnimationFromAtlas(Action.ATTACK1, "attackAa/attackAa", 6, false); + loadAnimationFromAtlas(Action.ATTACK2, "attackAb/attackAb", 6, false); + loadAnimationFromAtlas(Action.ATTACK3, "attackAc/attackAc", 6, false); + loadAnimationFromAtlas(Action.ATTACK4, "attackAd/attackAd", 6, false); - loadAnimationFromAtlas(Action.HIT, "hitSpin", 5, false); - - // 为忍者特定动作设置帧间隔 + loadAnimationFromAtlas(Action.HIT, "hitSpin/hitSpin", 5, false); + + // 为特定动作设置帧间隔 setFrameDuration(Action.WALK, 0.08f); // 行走更快 setFrameDuration(Action.ATTACK1, 0.07f); // 攻击更快 setFrameDuration(Action.SPECIAL2, 0.06f); // 特殊技能2非常快 } - - // 忍者特定的移动状态处理 + + // 特定的移动状态处理 @Override protected void handleMoveState() { - // 忍者在跳跃时也能移动 + // 在跳跃时也能移动 if (currentAction != Action.ATTACK1 && currentAction != Action.ATTACK2 && - currentAction != Action.ATTACK3 && currentAction != Action.SPECIAL1 && - currentAction != Action.SPECIAL2 && currentAction != Action.DEFEND) { - + currentAction != Action.ATTACK3 && currentAction != Action.SPECIAL1 && + currentAction != Action.SPECIAL2 && currentAction != Action.DEFEND) { + if (currentAction != Action.JUMP && currentAction != Action.FALL) { changeAction(Action.WALK); } } } - - // 忍者可以在空中攻击 + + // 可以在空中攻击 @Override protected boolean canAttack() { return super.canAttack() || currentAction == Action.JUMP || currentAction == Action.FALL; } } - \ No newline at end of file diff --git a/src/main/java/uno/mloluyu/characters/Fighter.java b/src/main/java/uno/mloluyu/characters/Fighter.java index 06d9a86..aed4cdb 100644 --- a/src/main/java/uno/mloluyu/characters/Fighter.java +++ b/src/main/java/uno/mloluyu/characters/Fighter.java @@ -1,5 +1,6 @@ package uno.mloluyu.characters; +import uno.mloluyu.util.SimpleFormatter; import com.badlogic.gdx.graphics.g2d.Animation; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureAtlas; @@ -15,141 +16,145 @@ public abstract class Fighter implements Disposable { // 动作类型枚举 - 所有角色共用的基础动作 public enum Action { IDLE, WALK, JUMP, FALL, - ATTACK1, ATTACK2, ATTACK3,ATTACK4, + ATTACK1, ATTACK2, ATTACK3, ATTACK4, HIT, DEFEND, SPECIAL1, SPECIAL2, DEATH } - + // 动画帧间隔(秒) protected static final float DEFAULT_FRAME_DURATION = 0.1f; protected float[] frameDurations; - + // 当前状态 protected Action currentAction; protected float stateTime; protected boolean isFacingRight; protected boolean isAnimationFinished; - + // 动画集合 protected Animation[] animations; - + // 碰撞检测 protected Rectangle hitbox; protected Rectangle attackbox; - + // 角色属性 protected float speed; protected int health; protected int maxHealth; protected int attackPower; - + // 精灵图表 protected TextureAtlas atlas; - + @SuppressWarnings("unchecked") public Fighter(TextureAtlas atlas) { this.atlas = atlas; int actionCount = Action.values().length; - + // 初始化动画数组和帧间隔数组 animations = new Animation[actionCount]; frameDurations = new float[actionCount]; - + // 设置默认帧间隔 for (int i = 0; i < actionCount; i++) { frameDurations[i] = DEFAULT_FRAME_DURATION; } - + // 初始化碰撞框 hitbox = new Rectangle(0, 0, 64, 128); attackbox = new Rectangle(0, 0, 80, 80); - + // 初始化默认属性(子类可以重写) speed = 300f; maxHealth = 100; health = maxHealth; attackPower = 10; - + // 初始状态 isFacingRight = true; currentAction = Action.IDLE; stateTime = 0; isAnimationFinished = false; - + // 加载动画(由子类实现具体的动画帧) loadAnimations(); } - + /** * 加载角色动画,由子类实现具体的动画帧加载 */ protected abstract void loadAnimations(); - + /** * 从精灵图表加载动画 - * @param action 动作类型 + * + * @param action 动作类型 * @param regionPrefix 该动作在图表中的区域前缀 - * @param frameCount 帧数 - * @param loop 是否循环 + * @param frameCount 帧数 + * @param loop 是否循环 */ - protected void loadAnimationFromAtlas(Action action, String regionPrefix, - int frameCount, boolean loop) { + protected void loadAnimationFromAtlas(Action action, String regionPrefix, + int frameCount, boolean loop) { Array frames = new Array<>(); - + // 从精灵图表中获取所有帧 for (int i = 0; i < frameCount; i++) { - String regionName = regionPrefix + i; + // 生成带三位前导零的序号(000, 001, 002...) + String formattedIndex = SimpleFormatter.addLeadingZeros(i, 3); + // 拼接完整的区域名称(如"stand/stand" + "000" → "stand/stand000") + String regionName = regionPrefix + formattedIndex; + TextureRegion region = atlas.findRegion(regionName); - + if (region == null) { throw new IllegalArgumentException("精灵图表中未找到区域: " + regionName); } - + frames.add(region); } - + // 创建动画 Animation animation = new Animation<>( - frameDurations[action.ordinal()], - frames - ); + frameDurations[action.ordinal()], + frames); animation.setPlayMode(loop ? Animation.PlayMode.LOOP : Animation.PlayMode.NORMAL); animations[action.ordinal()] = animation; } - + /** * 为特定动作设置帧间隔 */ protected void setFrameDuration(Action action, float duration) { frameDurations[action.ordinal()] = duration; - + // 如果动画已加载,更新它 if (animations[action.ordinal()] != null) { animations[action.ordinal()].setFrameDuration(duration); } } - + /** * 更新角色状态 */ public void update(float deltaTime) { stateTime += deltaTime; isAnimationFinished = animations[currentAction.ordinal()].isAnimationFinished(stateTime); - + // 处理动画完成后的状态转换 handleAnimationTransitions(); - + // 更新碰撞框位置 updateHitboxes(); } - + /** * 处理动画完成后的状态转换,子类可以重写以实现特定逻辑 */ protected void handleAnimationTransitions() { Animation currentAnim = animations[currentAction.ordinal()]; - + // 检查非循环动画是否已完成 if (currentAnim.getPlayMode() != Animation.PlayMode.LOOP && isAnimationFinished) { switch (currentAction) { @@ -173,26 +178,26 @@ public abstract class Fighter implements Disposable { } } } - + /** * 绘制角色 */ public void render(SpriteBatch batch) { TextureRegion currentFrame = animations[currentAction.ordinal()].getKeyFrame(stateTime, true); - + // 绘制角色,考虑方向翻转 float x = hitbox.x; float y = hitbox.y; float width = hitbox.width; float height = hitbox.height; - + if (isFacingRight) { batch.draw(currentFrame, x, y, width, height); } else { batch.draw(currentFrame, x + width, y, -width, height); } } - + /** * 改变角色动作 */ @@ -201,7 +206,7 @@ public abstract class Fighter implements Disposable { if (isActionUninterruptible(currentAction)) { return false; } - + // 如果是新动作,重置状态时间 if (currentAction != newAction) { currentAction = newAction; @@ -211,14 +216,14 @@ public abstract class Fighter implements Disposable { } return false; } - + /** * 判断动作是否不可被打断 */ protected boolean isActionUninterruptible(Action action) { return action == Action.HIT || action == Action.DEATH; } - + /** * 更新碰撞框位置 */ @@ -230,7 +235,7 @@ public abstract class Fighter implements Disposable { attackbox.setPosition(hitbox.x - attackbox.width + 10, hitbox.y + 20); } } - + /** * 处理角色移动 */ @@ -238,10 +243,10 @@ public abstract class Fighter implements Disposable { if (x != 0) { // 改变朝向 isFacingRight = x > 0; - + // 移动位置 hitbox.x += x * speed * deltaTime; - + // 处理移动状态转换 handleMoveState(); } else if (currentAction == Action.WALK) { @@ -249,20 +254,20 @@ public abstract class Fighter implements Disposable { changeAction(Action.IDLE); } } - + /** * 处理移动状态转换,子类可重写 */ protected void handleMoveState() { // 如果不是攻击或特殊动作,切换到行走动画 if (currentAction != Action.ATTACK1 && currentAction != Action.ATTACK2 && - currentAction != Action.ATTACK3 && currentAction != Action.SPECIAL1 && - currentAction != Action.SPECIAL2 && currentAction != Action.JUMP && - currentAction != Action.FALL && currentAction != Action.DEFEND) { + currentAction != Action.ATTACK3 && currentAction != Action.SPECIAL1 && + currentAction != Action.SPECIAL2 && currentAction != Action.JUMP && + currentAction != Action.FALL && currentAction != Action.DEFEND) { changeAction(Action.WALK); } } - + /** * 执行攻击 */ @@ -271,7 +276,7 @@ public abstract class Fighter implements Disposable { if (!canAttack()) { return false; } - + Action attackAction; switch (attackType) { case 1: @@ -292,17 +297,17 @@ public abstract class Fighter implements Disposable { default: return false; } - + return changeAction(attackAction); } - + /** * 判断是否可以攻击,子类可重写以实现特定逻辑 */ protected boolean canAttack() { return currentAction == Action.IDLE || currentAction == Action.WALK; } - + /** * 处理受击 */ @@ -317,37 +322,36 @@ public abstract class Fighter implements Disposable { } } } - + public Rectangle getHitbox() { return hitbox; } - + public Rectangle getAttackbox() { return attackbox; } - + public boolean isFacingRight() { return isFacingRight; } - + public int getHealth() { return health; } - + public int getMaxHealth() { return maxHealth; } - + public Action getCurrentAction() { return currentAction; } - + public int getAttackPower() { return attackPower; } - + @Override public void dispose() { } } - \ No newline at end of file diff --git a/src/main/java/uno/mloluyu/desktop/GameCore.java b/src/main/java/uno/mloluyu/desktop/GameCore.java index e6c73ef..331d2d6 100644 --- a/src/main/java/uno/mloluyu/desktop/GameCore.java +++ b/src/main/java/uno/mloluyu/desktop/GameCore.java @@ -7,7 +7,7 @@ import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import uno.mloluyu.desktop.character.Alice; +import uno.mloluyu.characters.Alice; public class GameCore implements ApplicationListener { private SpriteBatch batch; @@ -17,8 +17,9 @@ public class GameCore implements ApplicationListener { @Override public void create() { - atlas = new TextureAtlas(Gdx.files.internal("characters/alice.atlas")); - alice1= new Alice(); + batch = new SpriteBatch(); + atlas = new TextureAtlas(Gdx.files.internal("src\\main\\resources\\character\\alice\\alice.atlas")); + alice1= new Alice(atlas); } @@ -31,6 +32,7 @@ public class GameCore implements ApplicationListener { alice1.update(Gdx.graphics.getDeltaTime()); batch.begin(); alice1.render(batch); + batch.end(); } @Override diff --git a/target/classes/uno/mloluyu/desktop/character/Alice.class b/target/classes/uno/mloluyu/characters/Alice.class similarity index 62% rename from target/classes/uno/mloluyu/desktop/character/Alice.class rename to target/classes/uno/mloluyu/characters/Alice.class index 5fa4ba2..91c5846 100644 Binary files a/target/classes/uno/mloluyu/desktop/character/Alice.class and b/target/classes/uno/mloluyu/characters/Alice.class differ diff --git a/target/classes/uno/mloluyu/characters/Fighter$Action.class b/target/classes/uno/mloluyu/characters/Fighter$Action.class index 7f5b853..7df1185 100644 Binary files a/target/classes/uno/mloluyu/characters/Fighter$Action.class and b/target/classes/uno/mloluyu/characters/Fighter$Action.class differ diff --git a/target/classes/uno/mloluyu/characters/Fighter.class b/target/classes/uno/mloluyu/characters/Fighter.class index 363f772..ca89213 100644 Binary files a/target/classes/uno/mloluyu/characters/Fighter.class and b/target/classes/uno/mloluyu/characters/Fighter.class differ diff --git a/target/classes/uno/mloluyu/desktop/GameCore.class b/target/classes/uno/mloluyu/desktop/GameCore.class index 2d615a1..d0a90c3 100644 Binary files a/target/classes/uno/mloluyu/desktop/GameCore.class and b/target/classes/uno/mloluyu/desktop/GameCore.class differ