From 87cfe5aed6e5c866ebc127fe54788ec6ff669c6f Mon Sep 17 00:00:00 2001 From: wangsj <3305688534@qq.com> Date: Sun, 21 Sep 2025 22:20:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=A7=92=E8=89=B2=E7=B1=BBAl?= =?UTF-8?q?ice=EF=BC=8C=E7=BB=A7=E6=89=BF=E8=87=AAFighter=EF=BC=8C?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E5=B1=9E=E6=80=A7=E5=92=8C=E5=8A=A8=E7=94=BB?= =?UTF-8?q?=EF=BC=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../character => characters}/Alice.java | 45 +++--- .../java/uno/mloluyu/characters/Fighter.java | 132 +++++++++--------- .../java/uno/mloluyu/desktop/GameCore.java | 8 +- .../character => characters}/Alice.class | Bin 1902 -> 1953 bytes .../mloluyu/characters/Fighter$Action.class | Bin 1724 -> 1724 bytes .../uno/mloluyu/characters/Fighter.class | Bin 8581 -> 8731 bytes .../uno/mloluyu/desktop/GameCore.class | Bin 1704 -> 2013 bytes 7 files changed, 95 insertions(+), 90 deletions(-) rename src/main/java/uno/mloluyu/{desktop/character => characters}/Alice.java (50%) rename target/classes/uno/mloluyu/{desktop/character => characters}/Alice.class (62%) 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 5fa4ba2acfbde028439807467fe4e4e4ded07af3..91c5846a92f8156cf4b7ff8fb6687992ebbdded4 100644 GIT binary patch delta 200 zcmaFIw~$}p)W2Q(7#J9A8A{k0m>3ykCOa^RZ`5ODWR#n1&m=K9m~lTlcX3H#UW)!? zVW#?E;qt_sY`3EPyb^sli<3c#!I+1^gh7pwfyFD-H-Lk|jFEvet2DPjA4GuUEqE9# z!SZg7K0X`_){G4N8JQ))1(|vJlg}|Ja0w=slq4o+J0|K+e$S)`=O*b-7Gy?nll3PX OBXLvoH-|DyvH$>;O*Fg! delta 167 zcmZ3;|Bg@h)W2Q(7#J9A8A{k0m>3z9OY`#eb93@@N-InCQ&NkwOY#f!lQR;F5|c|( zi#DpUG0Lm@;8io(h4BC*>tt@GdPdI4Q<>x$Stjpdl44|^e3waqkz+DDv!XIbVo6D2 ta<*d=+?1``HhhAajVhBgLKhD8iw3>z2(C!c3EVHBLq!nOkdx=#rN delta 39 vcmdnPyN7qfE>=-N1``G$hAakQhBgKfhD8jb3>z2(CZA_DVHB9m!nOkdxy%Ut diff --git a/target/classes/uno/mloluyu/characters/Fighter.class b/target/classes/uno/mloluyu/characters/Fighter.class index 363f772d204039063e58ea54f0334555e1a000a6..ca89213c9a87d1ffaff087bb7e6ff2b40d2dff80 100644 GIT binary patch delta 3735 zcmZu!3tZLJ9si#D`2X*{{DBL|+M-1kW^4t=k<36)&+{Y0^KW%8~b{>IV+xG zdJL?_RRYPY0#~+G_jF$o=xgfeYbUm*FVNk$#wsvV-mWFcPIr_{*PL>Xmf#3rje$O_ z-Kl+Bte49*ueMRKxms@53LWckt$|!zC!f~RwV;6;@E!S%mXp89z>U}}p!f7rwLq7E zwZL2FLMgVW^EV6R6x7J`oEb5*yx(+UD{j%TO`v3FREgcdt=KNN>J@2QvBSXa*e;-5 zyl`=Sm0vNC2JXO}@*RCBHfF_$H(KkuTiZ4a-Qk!kk_QCb|7*RDAIsCuHQG-MJdB^p zc2`#7pn-S{3D^p1yqCBj@VJ3td9N$icF@2R@|Y`Ed(yzqa73PR)g>P_FcD9y)80#I zhQKic&*C}hkE*ntFz|D^BWkJkYXdLfMfqV=VeM}W{1y%YvB8NMc-g@3%+*GHUUj{zLzvbHKy5MI9{)+-8 zPJ5ucwX3bZXI)!kU!bo|vG~Hkmx_h0smi}V5zZPorwDr0k|kBu3ra~7!Vs2mv@%7r z8Nxn}HdWDdLpT)8(YR<{bzPO;yzKHCB5FLI_za^-_C76$9)S?}A=!PF_P>-u|F@jjg5?G9z(I}TETpm11jxN^Vro(7k zb^t5O?bhkq04fqS?I7CA^&*dchzwBf@a>1!;}}M7xzpo3f%wB%x6I=>gbly}T=SI2 z?r{#|`WrQosAb%L?wP|VUB)Zt7Y?Jp#A82zo60qhmT21r=ODg20BsPr4I{XdXQrw% z9<6a7^{`QM&<;1ht+aF{V%dC>aV4F+ilOgesjWsO?U~QLMOaU3H{fz?#B$=Tv~fMI zK|ij=rR1<0QT%SgWjvvNHsO2poG`Jwa5pSL6WxV$SWWEvh@%QlvbhKM!VUv-$v7Pv zRVcv^ctxioldzkZgX*N=hq#aDTaktP@c_>~NIprhjPUpod4%^u+-v4u1MFuItD{Yv zMTs879$o!^=rcIak*}^p=qMsh5Vq;Gmaz038UCLw3%7K3DI43zBQz_Y{MXYGWlP?u z^Ya=;U0ik??g*YYjJ^BlKps{ek0%q*Z!T=6`ZuX&XnHU^%q-%;yod+$@F-niF^#f9 z;^JW_ zG>YhPg^p#{BnAfzZ#09K$?!E}fOYZ^bLIE8{E3PqzAzhIb!8D@hp zObHQdCeJ9?V!uQ)!{Tx=l6W4!ls(C*!LUPY!}!%vJXB9@EB51LO&Gp3(-uZvnQ0Fr zug%nm_;(?`uqZ#-mTXVfhVjP%B&emmMN!t7BxO=Kd_J>?4D8S2J!$H9yl(7gn zBpAS1n2guu@{}a+8_Zq{f51u=YWnc260x5=R4@yCG=|antK6MZ-1-82^di0X5)$z; zQpq<9uOJVvGWlN{=kbDwW(9c9tl4JrvcVFa!Y_x-h?IpRQsN5-@qP#f!6{klN%Fll zj#+$!S^P-)DrQVtH+elFukz%!oE(WkOZ@2-Vf3Z=f3ytapG=|2Bvgfo>R8o&ys{$x zbj#O|jm09I-|x}E@1qbO;5-h*#rQ~m>dCTxf=^{iYEkfHE^p86%G{~16c zDGh`8e2VRjhPLYNxHoFRC_m=Qvj ziQ#x?#1Ii1G7b5BwD!V@no1K?OPe6#9Gv$~Tqs;v#Nqob5iL8@vXkRQLRc#?fm*3f z*5n%&6XgAAzTlbq0ZgP;1gV3AOZgM2hSTYS!BO|*z<^4;{z)KqF0E}rew zUlq@^uvbsXtc>)IQ)3G-6s+B&v zDp0G@lb}=k-O;0av1;WSS*f|vudW3ZPtfQ6Zs+J83$))hdd=V>B8|#+q}3AgbNkh=))=70(j?%_NhBHYiJaFj4y5oWMh6{=&X3~T1^BBa&o zV#+zN^a$0b5dN`Ga12%0g2>Xu#+K$4a|xR`PYDpkqJ)q&BBnF9W|-d#n5p2a)yAhw hskpGx!;B3uTb-g(%weXoOnG)5=`}oO10VK9UjgvY|1kgn delta 3583 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 delta 811 zcmYjNOHUI~7(KTSrX4P?N<%0J0|?Aew7f(GRFIcweIQVEIkeX@W|(Pirz~7ZO#B06 z_O6XPiNRE(hK&nt>>W{ylz5=+8CkN`!&|vnU zwLPBSF{PRJggp53dcWnlxo2i<(tzcXvycZF-jLXeH@x z+hTV{Q{$UEf?7`5la;*ZN^QZm@tE^R=f_P>*qM)kiKsQGd&NC$S?5Wg-CoQKq zYvkG(8l<2B8Ha{`1%3W+*4a3K3k;#6&7k?mkuLvTn8$}4qz~ zrr@f-9_bmF!E8V+yd`0K=BBkP7{a=-qEeVQ72IGLpfIOT!pzhX;F!k(?NlihOphia zIynjC7C98eR4ijv!HWNqjdpO{Ml(ZnTNEuPpuNMT4O4MHKpoBkW6pJn`GCCRpGcrw6BjwVBR{10@Gl%oIu