diff --git a/docs/perf_hotspots.md b/docs/perf_hotspots.md
new file mode 100644
index 0000000..984dffb
--- /dev/null
+++ b/docs/perf_hotspots.md
@@ -0,0 +1,12 @@
+# 性能热点初稿
+
+首轮标记:
+
+| 区域 | 说明 | 优先级 | 说明 |
+|------|------|--------|------|
+GameScreen.render | 多次集合遍历 + 远程玩家循环内更新 | 高 | 后续拆分逻辑/渲染阶段 |
+SimpleFighter.update | 物理与攻击状态混杂 | 中 | 拆分到组件式(动作/物理) |
+网络同步(待补) | sendPosition 每帧发送 | 中 | 引入位置压缩/频率限制 |
+清屏/批处理 | 现已静态化 | 已改善 | 继续合并渲染批次 |
+
+后续收集: 帧时间分布 / GC 次数。
diff --git a/pom.xml b/pom.xml
index aab8140..4036ec1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,71 +14,87 @@
21
21
+ 21
UTF-8
1.12.1
-
- com.badlogicgames.gdx
- gdx
- 1.12.1
+
+
+ com.badlogicgames.gdx
+ gdx
+ ${gdx.version}
+
+
+
+
+ com.badlogicgames.gdx
+ gdx-backend-lwjgl
+ ${gdx.version}
+
+
+
+
+ com.badlogicgames.gdx
+ gdx-platform
+ ${gdx.version}
+ natives-desktop
-
- com.badlogicgames.gdx
- gdx-freetype
- 1.12.1
-
-
-
-
- com.badlogicgames.gdx
- gdx-freetype-platform
- 1.12.1
- natives-desktop
-
-
- com.badlogicgames.gdx
- gdx-backend-lwjgl
- 1.12.1
-
-
- com.badlogicgames.gdx
- gdx-platform
- 1.12.1
- natives-desktop
-
com.badlogicgames.gdx
- gdx
- 1.12.1
+ gdx-freetype
+ ${gdx.version}
com.badlogicgames.gdx
- gdx-backend-lwjgl3
- 1.12.1
-
-
- com.badlogicgames.gdx
- gdx-platform
- 1.12.1
+ gdx-freetype-platform
+ ${gdx.version}
natives-desktop
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.10.2
+ test
+
+
+
+ org.apache.maven.plugins
+ maven-enforcer-plugin
+ 3.4.1
+
+
+ enforce
+ enforce
+
+
+
+ [21,)
+
+
+
+ false
+
+
+
+
org.apache.maven.plugins
maven-compiler-plugin
3.13.0
-
- 17
- 17
-
+
+ ${maven.compiler.source}
+ ${maven.compiler.target}
+ ${maven.compiler.release}
@@ -87,8 +103,6 @@
exec-maven-plugin
3.1.0
-
-
uno.mloluyu.desktop.DesktopLauncher
@@ -107,6 +121,31 @@
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.2.5
+
+ false
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.11
+
+
+ prepare-agent
+
+
+ report
+ test
+ report
+
+
+
diff --git a/src/main/java/uno/mloluyu/characters/ActionStateGuard.java b/src/main/java/uno/mloluyu/characters/ActionStateGuard.java
new file mode 100644
index 0000000..13737c0
--- /dev/null
+++ b/src/main/java/uno/mloluyu/characters/ActionStateGuard.java
@@ -0,0 +1,20 @@
+package uno.mloluyu.characters;
+
+/** 提供状态切换验证。 */
+public final class ActionStateGuard {
+ private ActionStateGuard() {
+ }
+
+ public static Action transition(FighterBase fighter, Action next) {
+ Action current = fighter.getCurrentAction();
+ if (current == next)
+ return current;
+ if (!ActionTransitionMap.can(current, next)) {
+ return current;
+ }
+ if (fighter instanceof uno.mloluyu.characters.SimpleFighter sf) {
+ sf.directSetAction(next);
+ }
+ return next;
+ }
+}
diff --git a/src/main/java/uno/mloluyu/characters/ActionTransitionMap.java b/src/main/java/uno/mloluyu/characters/ActionTransitionMap.java
new file mode 100644
index 0000000..45dc5d5
--- /dev/null
+++ b/src/main/java/uno/mloluyu/characters/ActionTransitionMap.java
@@ -0,0 +1,25 @@
+package uno.mloluyu.characters;
+
+import java.util.*;
+
+/** 定义合法动作迁移,供校验/日志使用。 */
+public final class ActionTransitionMap {
+ private static final Map> ALLOWED = new EnumMap<>(Action.class);
+ static {
+ allow(Action.IDLE, Action.MOVE, Action.JUMP, Action.ATTACK, Action.DEFEND, Action.HIT, Action.DEAD);
+ allow(Action.MOVE, Action.IDLE, Action.JUMP, Action.ATTACK, Action.HIT, Action.DEAD);
+ allow(Action.JUMP, Action.HIT, Action.ATTACK, Action.DEAD, Action.IDLE, Action.MOVE);
+ allow(Action.ATTACK, Action.HIT, Action.DEAD, Action.IDLE, Action.MOVE);
+ allow(Action.DEFEND, Action.HIT, Action.IDLE, Action.MOVE, Action.DEAD);
+ allow(Action.HIT, Action.IDLE, Action.MOVE, Action.DEAD);
+ allow(Action.DEAD); // 终止状态
+ }
+
+ private static void allow(Action from, Action... tos) {
+ ALLOWED.put(from, new HashSet<>(Arrays.asList(tos)));
+ }
+
+ public static boolean can(Action from, Action to) {
+ return ALLOWED.getOrDefault(from, Collections.emptySet()).contains(to);
+ }
+}
diff --git a/src/main/java/uno/mloluyu/characters/AdvancedFighter.java b/src/main/java/uno/mloluyu/characters/AdvancedFighter.java
index 3382dca..da5a912 100644
--- a/src/main/java/uno/mloluyu/characters/AdvancedFighter.java
+++ b/src/main/java/uno/mloluyu/characters/AdvancedFighter.java
@@ -3,14 +3,12 @@ package uno.mloluyu.characters;
public class AdvancedFighter extends SimpleFighter {
public AdvancedFighter(String name) {
- super(name); // 调用父类构造函数
+ super(name);
}
@Override
public void attack(String attackType) {
- // 先使用父类的攻击逻辑来保证 isAttacking/attackTimer/attackbox 等状态被正确设置
super.attack(attackType);
- // 在这里可以添加 AdvancedFighter 特有的扩展行为(攻击力、特效等)
- // 例如:根据 attackType 调整伤害或触发粒子/声音,但不要忘记保留父类的状态设置
+
}
}
diff --git a/src/main/java/uno/mloluyu/characters/FighterBase.java b/src/main/java/uno/mloluyu/characters/FighterBase.java
new file mode 100644
index 0000000..831673a
--- /dev/null
+++ b/src/main/java/uno/mloluyu/characters/FighterBase.java
@@ -0,0 +1,47 @@
+package uno.mloluyu.characters;
+
+import com.badlogic.gdx.math.Rectangle;
+import com.badlogic.gdx.graphics.Color;
+import java.util.concurrent.ThreadLocalRandom;
+
+/** 公共角色基类:后续 Simple/Advanced 统一继承。 */
+public abstract class FighterBase {
+ protected String name;
+ protected Action currentAction = Action.IDLE;
+ protected Rectangle hitbox = new Rectangle(0, 0, 64, 128);
+ protected Rectangle attackbox = new Rectangle(0, 0, 80, 80);
+ protected final Color debugColor;
+
+ public FighterBase(String name) {
+ this.name = name;
+ ThreadLocalRandom r = ThreadLocalRandom.current();
+ float rr = 0.35f + r.nextFloat() * 0.65f;
+ float gg = 0.35f + r.nextFloat() * 0.65f;
+ float bb = 0.35f + r.nextFloat() * 0.65f;
+ this.debugColor = new Color(rr, gg, bb, 1f);
+ }
+
+ public Action getCurrentAction() {
+ return currentAction;
+ }
+
+ public Rectangle getHitbox() {
+ return hitbox;
+ }
+
+ public Rectangle getAttackbox() {
+ return attackbox;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Color getDebugColor() {
+ return debugColor;
+ }
+
+ protected void setAction(Action next) {
+ this.currentAction = next;
+ }
+}
diff --git a/src/main/java/uno/mloluyu/characters/SimpleFighter.java b/src/main/java/uno/mloluyu/characters/SimpleFighter.java
index afb72ef..d010d6a 100644
--- a/src/main/java/uno/mloluyu/characters/SimpleFighter.java
+++ b/src/main/java/uno/mloluyu/characters/SimpleFighter.java
@@ -10,21 +10,21 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Rectangle;
import uno.mloluyu.network.NetworkManager;
+import uno.mloluyu.util.GameConstants;
/**
* 简化版角色类,仅包含移动、攻击、受击等基础功能。
*/
-public class SimpleFighter {
+public class SimpleFighter extends FighterBase {
- private String name; // 角色名称
- private Action currentAction = Action.IDLE; // 当前动作状态
+ // 继承: name, currentAction, hitbox, attackbox
private float verticalSpeed = 0f; // 垂直速度(跳跃/下落)
private boolean isGrounded = true; // 是否着地
private Rectangle hitbox = new Rectangle(0, 0, 64, 128); // 碰撞盒
private Rectangle attackbox = new Rectangle(0, 0, 80, 80); // 攻击判定盒
private boolean isFacingRight = true; // 朝向(右/左)
- private float speed = 300f; // 水平移动速度
- private int health = 100; // 生命值
+ private float speed = GameConstants.MOVE_SPEED; // 水平移动速度
+ private int health = 200; // 生命值
private boolean isAttacking = false; // 是否正在攻击
private boolean attackJustStarted = false; // 攻击是否刚开始
private float attackTimer = 0f; // 攻击计时器
@@ -41,7 +41,7 @@ public class SimpleFighter {
private static final float KNOCKBACK_DURATION = 0.12f;
public SimpleFighter(String name) {
- this.name = name;
+ super(name);
}
public void update(float deltaTime) {
@@ -76,10 +76,10 @@ public class SimpleFighter {
}
if (!isGrounded) {
- verticalSpeed -= 2500 * deltaTime;
+ verticalSpeed -= GameConstants.GRAVITY * deltaTime;
hitbox.y += verticalSpeed * deltaTime;
- if (hitbox.y <= 0) {
- hitbox.y = 0;
+ if (hitbox.y <= GameConstants.GROUND_Y) {
+ hitbox.y = GameConstants.GROUND_Y;
verticalSpeed = 0;
isGrounded = true;
changeAction(Action.IDLE);
@@ -103,7 +103,7 @@ public class SimpleFighter {
hitbox.y + hitbox.height * 0.7f);
}
- public void handleInput(int keycode, boolean isPressed) {
+ public void handleInput(int keycode, boolean isPressed, float duration) {
if (isPressed) {
if (keycode == Input.Keys.LEFT || keycode == Input.Keys.A) {
move(-1, Gdx.graphics.getDeltaTime());
@@ -138,12 +138,16 @@ public class SimpleFighter {
}
public void changeAction(Action newAction) {
- this.currentAction = newAction;
+ this.currentAction = ActionStateGuard.transition(this, newAction);
+ }
+
+ void directSetAction(Action a) {
+ this.currentAction = a;
}
public void jump() {
if (isGrounded) {
- verticalSpeed = 1000f;
+ verticalSpeed = GameConstants.JUMP_SPEED;
isGrounded = false;
changeAction(Action.JUMP);
}
@@ -181,28 +185,32 @@ public class SimpleFighter {
}
private void updateAttackbox(String attackType) {
- float offsetX, offsetY = 20, width = 80, height = 80;
+ float baseOffsetY = 20f;
+ float width = 80f, height = 80f;
+ float offsetX;
+ float offsetY = baseOffsetY;
+ // 先决定尺寸,再根据朝向计算 offset(不再用旧 attackbox.width 避免漂移)
switch (attackType) {
case "heavy":
- offsetX = isFacingRight ? hitbox.width : -100;
- offsetY = 40;
- width = 100;
- height = 100;
- break;
- case "light":
- offsetX = isFacingRight ? hitbox.width - 10 : -attackbox.width + 10;
+ width = 100f;
+ height = 100f;
+ offsetY = 40f;
+ offsetX = isFacingRight ? hitbox.width : -width; // 重击靠近身体或覆盖前方
break;
case "special":
- offsetX = isFacingRight ? hitbox.width + 20 : -attackbox.width - 20;
- offsetY = 50;
- width = 120;
- height = 60;
+ width = 120f;
+ height = 60f;
+ offsetY = 50f;
+ offsetX = isFacingRight ? hitbox.width + 20f : -width - 20f;
break;
+ case "light":
default:
- offsetX = isFacingRight ? hitbox.width - 10 : -attackbox.width + 10;
+ // 轻击稍微往前,不再参考旧 attackbox.width
+ offsetX = isFacingRight ? hitbox.width - 10f : -80f + 10f;
+ break;
}
- attackbox.setPosition(hitbox.x + offsetX, hitbox.y + offsetY);
attackbox.setSize(width, height);
+ attackbox.setPosition(hitbox.x + offsetX, hitbox.y + offsetY);
}
public void attack(String attackType) {
@@ -304,6 +312,13 @@ public class SimpleFighter {
hitbox.setPosition(x, y);
}
+ /** 若当前 Y 低于地面则贴到地面。 */
+ public void alignToGround() {
+ if (hitbox.y < GameConstants.GROUND_Y) {
+ hitbox.y = GameConstants.GROUND_Y;
+ }
+ }
+
public float getAttackTimer() {
return attackTimer;
}
diff --git a/src/main/java/uno/mloluyu/desktop/BaseScreen.java b/src/main/java/uno/mloluyu/desktop/BaseScreen.java
new file mode 100644
index 0000000..18f709c
--- /dev/null
+++ b/src/main/java/uno/mloluyu/desktop/BaseScreen.java
@@ -0,0 +1,16 @@
+package uno.mloluyu.desktop;
+
+import com.badlogic.gdx.ScreenAdapter;
+
+/** 所有 Screen 的基础类,集中生命周期钩子扩展。 */
+public abstract class BaseScreen extends ScreenAdapter {
+ protected final MainGame game;
+
+ protected BaseScreen(MainGame game) {
+ this.game = game;
+ }
+
+ /** 提供可选的资源预加载完成回调 */
+ public void onAssetsReady() {
+ }
+}
diff --git a/src/main/java/uno/mloluyu/desktop/CharacterSelectScreen.java b/src/main/java/uno/mloluyu/desktop/CharacterSelectScreen.java
index 274a7d6..9ca4967 100644
--- a/src/main/java/uno/mloluyu/desktop/CharacterSelectScreen.java
+++ b/src/main/java/uno/mloluyu/desktop/CharacterSelectScreen.java
@@ -33,14 +33,12 @@ public class CharacterSelectScreen extends ScreenAdapter implements InputProcess
private SimpleFighter selectedFighter2;
private final List bgs = Arrays.asList(
- new Texture(Gdx.files.internal("src/main/resources/selectpage/10b_back_blue2p.png")),
- //new Texture(Gdx.files.internal("src/main/resources/selectpage/back_door.png")),
- new Texture(Gdx.files.internal("src/main/resources/selectpage/11b_back_red1p.png"))
- );
+ new Texture(Gdx.files.internal("selectpage/10b_back_blue2p.png")),
+ // new Texture(Gdx.files.internal("selectpage/back_door.png")),
+ new Texture(Gdx.files.internal("selectpage/11b_back_red1p.png")));
private final List charsTexts = Arrays.asList(
- new Texture(Gdx.files.internal("src/main/resources/selectpage/character_03.png")),
- new Texture(Gdx.files.internal("src/main/resources/selectpage/character_00.png"))
- );
+ new Texture(Gdx.files.internal("selectpage/character_03.png")),
+ new Texture(Gdx.files.internal("selectpage/character_00.png")));
private final List characters = Arrays.asList("Alice", "Reimu", "暂定");
private Texture profile1p = charsTexts.get(0);
private Texture profile2p = charsTexts.get(1);
@@ -49,11 +47,13 @@ public class CharacterSelectScreen extends ScreenAdapter implements InputProcess
private static int selectedIndex = 0;
private static boolean is1P = true;
- private static final int BUTTON_WIDTH = 300;
- private static final int BUTTON_HEIGHT = 80;
- private static final int BUTTON_X = 800;
- private static final int CONFIRM_Y = 200;
- private static final int BACK_Y = 100;
+ // 下面这些按钮常量原本用于文本/按钮绘制,当前 UI 逻辑已注释。
+ // 如果后续恢复 renderTexts() 可重新启用;为减少无用警告暂时注释。
+ // private static final int BUTTON_WIDTH = 300;
+ // private static final int BUTTON_HEIGHT = 80;
+ // private static final int BUTTON_X = 800;
+ // private static final int CONFIRM_Y = 200;
+ // private static final int BACK_Y = 100;
public CharacterSelectScreen(MainGame game) {
this.game = game;
@@ -75,13 +75,14 @@ public class CharacterSelectScreen extends ScreenAdapter implements InputProcess
@Override
public void render(float delta) {
- new ClearScreen();
+ // 清屏:使用工具静态方法,避免误用私有构造器
+ ClearScreen.clear();
int mouseX = Gdx.input.getX();
int mouseY = Gdx.graphics.getHeight() - Gdx.input.getY();
renderBackground();
renderCharacters(multiplayerMode);
-// renderTexts();
+ // renderTexts();
handleInput(mouseX, mouseY);
if (multiplayerMode) {
@@ -99,7 +100,7 @@ public class CharacterSelectScreen extends ScreenAdapter implements InputProcess
private void renderBackground() {
batch.begin();
- for (int i = 0; i < bgs.size(); i ++) {
+ for (int i = 0; i < bgs.size(); i++) {
batch.draw(bgs.get(i), 0, 528 * i, 1920, 528);
}
batch.end();
@@ -107,45 +108,47 @@ public class CharacterSelectScreen extends ScreenAdapter implements InputProcess
private void renderCharacters(boolean multiplayerMode) {
batch.begin();
- batch.draw(profile1p, 0, 0, profile1p.getWidth()*3, profile1p.getHeight()*3);
- batch.draw(profile2p, 0, 528, profile2p.getWidth()*3, profile2p.getHeight()*3);
+ batch.draw(profile1p, 0, 0, profile1p.getWidth() * 3, profile1p.getHeight() * 3);
+ batch.draw(profile2p, 0, 528, profile2p.getWidth() * 3, profile2p.getHeight() * 3);
batch.end();
}
-//
-// private void renderTexts() {
-// batch.begin();
-// font.draw(batch, "选择你的角色", 200, 650);
-// for (int i = 0; i < characters.size(); i++) {
-// int x = 200 + 30;
-// int y = 500 - i * 120 + 50;
-// font.draw(batch, characters.get(i), x, y);
-//
-// }
-// if (selectedIndex != -1) {
-// font.draw(batch, "已选择: " + characters.get(selectedIndex), 200, 100);
-// }
-// drawButtonText(CONFIRM_Y, "确认");
-// drawButtonText(BACK_Y, "返回");
-// batch.end();
-// }
-//
+ //
+ // private void renderTexts() {
+ // batch.begin();
+ // font.draw(batch, "选择你的角色", 200, 650);
+ // for (int i = 0; i < characters.size(); i++) {
+ // int x = 200 + 30;
+ // int y = 500 - i * 120 + 50;
+ // font.draw(batch, characters.get(i), x, y);
+ //
+ // }
+ // if (selectedIndex != -1) {
+ // font.draw(batch, "已选择: " + characters.get(selectedIndex), 200, 100);
+ // }
+ // drawButtonText(CONFIRM_Y, "确认");
+ // drawButtonText(BACK_Y, "返回");
+ // batch.end();
+ // }
+ //
private void handleInput(int mouseX, int mouseY) {
- if (selectedFighter1 != null && selectedFighter2 != null) {
- if (multiplayerMode) {
- // 设置唯一玩家 ID 并发送角色选择
- if (NetworkManager.getInstance().getLocalPlayerId() == null) {
- String playerId = UUID.randomUUID().toString();
- NetworkManager.getInstance().setLocalPlayerId(playerId);
- Gdx.app.log("Network", "设置玩家ID: " + playerId);
- }
- NetworkManager.getInstance().sendCharacterSelection(selectedFighter1.getName());
+ // 单人模式:只要1P选择了角色就进入游戏
+ if (!multiplayerMode && selectedFighter1 != null) {
+ game.setScreen(new GameScreen(game, selectedFighter1));
+ return;
+ }
+ // 联机模式:等待双方选择(当前逻辑仍采用2人都选才进入)
+ if (multiplayerMode && selectedFighter1 != null && selectedFighter2 != null) {
+ if (NetworkManager.getInstance().getLocalPlayerId() == null) {
+ String playerId = UUID.randomUUID().toString();
+ NetworkManager.getInstance().setLocalPlayerId(playerId);
+ Gdx.app.log("Network", "设置玩家ID: " + playerId);
}
+ NetworkManager.getInstance().sendCharacterSelection(selectedFighter1.getName());
game.setScreen(new GameScreen(game, selectedFighter1));
}
}
-
@Override
public void dispose() {
batch.dispose();
@@ -168,7 +171,7 @@ public class CharacterSelectScreen extends ScreenAdapter implements InputProcess
}
value = true;
} else {
- //占坑说是
+ // 占坑说是
}
if (i == Input.Keys.Z) {
if (is1P) {
diff --git a/src/main/java/uno/mloluyu/desktop/DesktopLauncher.java b/src/main/java/uno/mloluyu/desktop/DesktopLauncher.java
index 64b8942..65f45f9 100644
--- a/src/main/java/uno/mloluyu/desktop/DesktopLauncher.java
+++ b/src/main/java/uno/mloluyu/desktop/DesktopLauncher.java
@@ -3,6 +3,8 @@ package uno.mloluyu.desktop;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
+// 日志功能已移除
+
/**
* Desktop 平台启动器
*/
@@ -10,6 +12,8 @@ public class DesktopLauncher {
public static void main(String[] args) {
+ // 若需要异常抓取,可在此处添加简单的 Thread.setDefaultUncaughtExceptionHandler
+
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
float scale = 1.0F;
diff --git a/src/main/java/uno/mloluyu/desktop/GameScreen.java b/src/main/java/uno/mloluyu/desktop/GameScreen.java
index 6672e50..417a340 100644
--- a/src/main/java/uno/mloluyu/desktop/GameScreen.java
+++ b/src/main/java/uno/mloluyu/desktop/GameScreen.java
@@ -5,6 +5,7 @@ import com.badlogic.gdx.ScreenAdapter;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.GL20;
import uno.mloluyu.characters.Action;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
@@ -18,6 +19,9 @@ import uno.mloluyu.characters.SimpleFighter;
import uno.mloluyu.characters.AdvancedFighter;
import uno.mloluyu.network.NetworkManager;
import uno.mloluyu.util.ClearScreen;
+import uno.mloluyu.perf.PerfMetrics;
+import uno.mloluyu.util.TimeStepLimiter;
+import uno.mloluyu.util.GameConstants;
import uno.mloluyu.versatile.FighterController;
public class GameScreen extends ScreenAdapter {
@@ -30,6 +34,37 @@ public class GameScreen extends ScreenAdapter {
private SpriteBatch batch;
private ShapeRenderer shapeRenderer;
private OrthographicCamera camera;
+ private Texture background;
+ // 世界尺寸(基于背景原始尺寸 * 缩放)。如果需要可读取 Texture 宽高后动态设。
+ private float worldWidth;
+ private float worldHeight;
+ // 背景整体缩放倍数:>1 表示背景比屏幕大,可只显示局部
+ private static final float BACKGROUND_SCALE = 1.5f;
+ // 摄像机竖直偏移(正值=镜头上移,让玩家更靠下;这里改为较小的正值防止看不到下方)
+ private static final float CAMERA_Y_OFFSET = 60f;
+ // 允许相机向下多看到的底部扩展(不被 clamp 过早挡住),解决放大 hitbox 下半部分出框
+ private static final float CAMERA_BOTTOM_MARGIN = -30f;
+ // 平滑跟随的垂直插值系数(独立控制 y,防止瞬间跳)
+ private static final float CAMERA_LERP_ALPHA = 0.12f;
+ // ========== 摄像机缩放配置 ==========
+ // 是否使用动态缩放(多人时根据距离自动拉远 / 靠近)
+ private static final boolean CAMERA_DYNAMIC_ZOOM = true;
+ // (保留)固定缩放模式开关 & 数值;若需要强制固定视角可把 CAMERA_DYNAMIC_ZOOM 设 false
+ private static final boolean CAMERA_USE_FIXED_ZOOM = false;
+ private static final float CAMERA_FIXED_ZOOM = 0.80f;
+ // 动态缩放参数:最小与最大(OrthographicCamera: <1 视角更近,>1 更远)
+ private static final float CAMERA_MIN_ZOOM = 0.55f; // 角色很近时
+ private static final float CAMERA_MAX_ZOOM = 1.25f; // 距离很远时
+ // 达到最大缩放所对应的“玩家距离”基准(屏幕世界单位,按你的角色移动范围调)
+ private static final float CAMERA_MAX_DISTANCE = 1800f;
+ // 缩放插值速度(越大越快贴近目标)
+ private static final float CAMERA_ZOOM_LERP = 0.10f;
+ // 显示地面参考线
+ private static final boolean SHOW_GROUND_LINE = true;
+ // 半透明地面条带显示
+ private static final boolean SHOW_GROUND_STRIP = true;
+ private static final float GROUND_STRIP_HEIGHT = 14f; // 条带厚度
+ private static final float GROUND_STRIP_ALPHA = 0.20f; // 透明度 (0~1)
public GameScreen(MainGame game, SimpleFighter player) {
this.player = player;
@@ -38,18 +73,33 @@ public class GameScreen extends ScreenAdapter {
@Override
public void show() {
+ // 确保角色初始贴地(地面抬高后老存档/默认 0 需要调整)
+ player.alignToGround();
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(player.getHitbox().x, player.getHitbox().y, 0); // 初始化摄像机位置
+ // 初始化缩放:动态优先,否则固定
+ if (CAMERA_DYNAMIC_ZOOM) {
+ camera.zoom = CAMERA_MIN_ZOOM;
+ } else if (CAMERA_USE_FIXED_ZOOM) {
+ camera.zoom = CAMERA_FIXED_ZOOM;
+ }
camera.update();
batch = new SpriteBatch();
shapeRenderer = new ShapeRenderer();
Gdx.input.setInputProcessor(controller);
+ // 背景图(与主菜单共用 bg.png),可后续扩展成多关卡背景
+ background = new Texture(Gdx.files.internal("innerbg.png"));
+ worldWidth = background.getWidth() * BACKGROUND_SCALE;
+ worldHeight = background.getHeight() * BACKGROUND_SCALE;
}
@Override
public void render(float delta) {
- new ClearScreen();
+ delta = TimeStepLimiter.clamp(delta);
+ ClearScreen.clear();
+ PerfMetrics.frame(delta);
+ // (原先背景在摄像机更新前绘制,会出现一帧“滞后”错位;已移到摄像机更新后)
// 输入 / 逻辑
player.update(delta);
@@ -150,7 +200,7 @@ public class GameScreen extends ScreenAdapter {
String pid = dt.getKey();
// 重生位置简单放原点附近随机
float rx = (float) (Math.random() * 200 - 100);
- float ry = 0;
+ float ry = GameConstants.GROUND_Y;
NetworkManager.getInstance().sendRespawn(pid, rx, ry);
deathTimers.remove(pid);
}
@@ -197,6 +247,9 @@ public class GameScreen extends ScreenAdapter {
}
}
+ // 本地与远程玩家之间简单碰撞(防穿人)——放在摄像机更新前
+ resolvePlayerCollisions();
+
// 摄像机跟随
// 摄像头跟随:若有一个远程玩家,则居中于本地和远程玩家中点
Vector3 targetPos;
@@ -204,32 +257,87 @@ public class GameScreen extends ScreenAdapter {
SimpleFighter remote = otherPlayers.values().iterator().next();
float midX = (player.getHitbox().x + remote.getHitbox().x) * 0.5f;
float midY = (player.getHitbox().y + remote.getHitbox().y) * 0.5f;
- targetPos = new Vector3(midX, midY, 0);
+ targetPos = new Vector3(midX, midY + CAMERA_Y_OFFSET, 0);
} else {
// 默认为跟随本地玩家
- targetPos = new Vector3(player.getHitbox().x, player.getHitbox().y, 0);
+ targetPos = new Vector3(player.getHitbox().x, player.getHitbox().y + CAMERA_Y_OFFSET, 0);
}
- camera.position.lerp(targetPos, 0.1f);
+ // 仅对 x,y 做分量插值,可单独调节速度
+ camera.position.x += (targetPos.x - camera.position.x) * CAMERA_LERP_ALPHA;
+ camera.position.y += (targetPos.y - camera.position.y) * (CAMERA_LERP_ALPHA * 1.1f);
+ // 计算动态缩放目标
+ if (CAMERA_DYNAMIC_ZOOM && otherPlayers.size() >= 1) {
+ // 取所有玩家(本地 + 远程)x 坐标的最大跨度作为距离依据,可扩展为对角线距离
+ float minX = player.getHitbox().x;
+ float maxX = player.getHitbox().x;
+ float minY = player.getHitbox().y;
+ float maxY = player.getHitbox().y;
+ for (SimpleFighter r : otherPlayers.values()) {
+ Rectangle hb = r.getHitbox();
+ if (hb.x < minX)
+ minX = hb.x;
+ if (hb.x > maxX)
+ maxX = hb.x;
+ if (hb.y < minY)
+ minY = hb.y;
+ if (hb.y > maxY)
+ maxY = hb.y;
+ }
+ float dx = maxX - minX;
+ float dy = maxY - minY;
+ // 这里主要横向对战,优先 dx;若想考虑纵向可用距离 = max(dx, dy*系数)
+ float dist = Math.max(dx, dy * 0.6f);
+ float t = Math.min(1f, dist / CAMERA_MAX_DISTANCE); // 0~1
+ float targetZoom = CAMERA_MIN_ZOOM + (CAMERA_MAX_ZOOM - CAMERA_MIN_ZOOM) * t;
+ camera.zoom += (targetZoom - camera.zoom) * CAMERA_ZOOM_LERP;
+ } else if (CAMERA_USE_FIXED_ZOOM) {
+ // 固定缩放平滑
+ if (Math.abs(camera.zoom - CAMERA_FIXED_ZOOM) > 0.0001f) {
+ camera.zoom += (CAMERA_FIXED_ZOOM - camera.zoom) * 0.25f;
+ }
+ }
+ // 约束摄像机在世界边界内(视口以中心为基准)
+ float halfW = (camera.viewportWidth * camera.zoom) / 2f;
+ float halfH = (camera.viewportHeight * camera.zoom) / 2f;
+ camera.position.x = Math.max(halfW, Math.min(worldWidth - halfW, camera.position.x));
+ float minY = halfH - CAMERA_BOTTOM_MARGIN; // 允许比世界底部再低一些显示底部区域
+ camera.position.y = Math.max(minY, Math.min(worldHeight - halfH, camera.position.y));
camera.update();
batch.setProjectionMatrix(camera.combined);
shapeRenderer.setProjectionMatrix(camera.combined);
+ // -------- Background pass --------
+ batch.begin();
+ // 仅绘制背景的局部:通过在更大的缩放空间中直接拉伸整张图并限制摄像机
+ // 若想真正裁剪一部分,可改用纹理区域;此处使用整图放大后让摄像机在其内游走
+ batch.draw(background,
+ 0, 0,
+ worldWidth, worldHeight);
+ batch.end();
+
// 混合
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
// -------- Filled pass --------
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
- drawHitbox(player, Color.BLUE);
+ // 半透明地面条带(先于 hitbox 绘制,这样人物在其上方)
+ if (SHOW_GROUND_STRIP) {
+ float y = GameConstants.GROUND_Y - GROUND_STRIP_HEIGHT * 0.5f; // 居中穿过地面线
+ shapeRenderer.setColor(0.9f, 0.9f, 0.9f, GROUND_STRIP_ALPHA); // 近白轻薄层
+ shapeRenderer.rect(0f, y, worldWidth, GROUND_STRIP_HEIGHT);
+ }
+ drawHitbox(player, player.getDebugColor());
boolean showPlayerAttack = player.isAttacking()
|| (player.getCurrentAction() == Action.ATTACK && player.getAttackTimer() > 0);
if (showPlayerAttack)
- drawAttackBox(player, 1f, 0f, 0f, 0.35f);
+ // 攻击框颜色改为蓝色(原红色)
+ drawAttackBox(player, 0.0f, 0.45f, 1f, 0.35f);
for (SimpleFighter remote : otherPlayers.values()) {
- drawHitbox(remote, Color.GREEN);
+ drawHitbox(remote, remote.getDebugColor());
if (remote.isAttacking())
- drawAttackBox(remote, 1f, 0f, 0f, 0.25f);
+ drawAttackBox(remote, 0.0f, 0.45f, 1f, 0.25f);
}
shapeRenderer.end();
@@ -240,11 +348,13 @@ public class GameScreen extends ScreenAdapter {
// -------- Debug line pass --------
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
+ if (SHOW_GROUND_LINE) {
+ shapeRenderer.setColor(0.65f, 0.65f, 0.65f, 1f); // 浅灰色参考线
+ shapeRenderer.line(0f, GameConstants.GROUND_Y, worldWidth, GameConstants.GROUND_Y);
+ }
player.renderDebug(shapeRenderer);
for (SimpleFighter remote : otherPlayers.values())
remote.renderDebug(shapeRenderer);
- shapeRenderer.setColor(Color.WHITE);
- shapeRenderer.rect(0, 0, 1000, 1000);
shapeRenderer.end();
// -------- UI health bar pass --------
// 使用屏幕坐标绘制血条
@@ -274,18 +384,45 @@ public class GameScreen extends ScreenAdapter {
idx++;
}
shapeRenderer.end();
+ // 原定期性能日志已移除(日志系统删除)
}
private void drawHitbox(SimpleFighter fighter, Color color) {
shapeRenderer.setColor(color);
Rectangle r = fighter.getHitbox();
- shapeRenderer.rect(r.x, r.y, r.width, r.height);
+ float scale = GameConstants.DEBUG_BOX_SCALE;
+ if (scale <= 1.0001f && scale >= 0.9999f) { // 视为 1
+ shapeRenderer.rect(r.x, r.y, r.width, r.height);
+ return;
+ }
+ float cx = r.x + r.width / 2f;
+ float cy = r.y + r.height / 2f;
+ float w = r.width * scale;
+ float h = r.height * scale;
+ if (GameConstants.DEBUG_SCALE_FROM_CENTER) {
+ shapeRenderer.rect(cx - w / 2f, cy - h / 2f, w, h);
+ } else {
+ shapeRenderer.rect(r.x, r.y, w, h);
+ }
}
private void drawAttackBox(SimpleFighter fighter, float r, float g, float b, float a) {
shapeRenderer.setColor(r, g, b, a);
Rectangle box = fighter.getAttackbox();
- shapeRenderer.rect(box.x, box.y, box.width, box.height);
+ float scale = GameConstants.DEBUG_BOX_SCALE;
+ if (scale <= 1.0001f && scale >= 0.9999f) {
+ shapeRenderer.rect(box.x, box.y, box.width, box.height);
+ return;
+ }
+ float cx = box.x + box.width / 2f;
+ float cy = box.y + box.height / 2f;
+ float w = box.width * scale;
+ float h = box.height * scale;
+ if (GameConstants.DEBUG_SCALE_FROM_CENTER) {
+ shapeRenderer.rect(cx - w / 2f, cy - h / 2f, w, h);
+ } else {
+ shapeRenderer.rect(box.x, box.y, w, h);
+ }
}
// private void checkPlayerAttacks() {
@@ -303,6 +440,41 @@ public class GameScreen extends ScreenAdapter {
public void dispose() {
batch.dispose();
shapeRenderer.dispose();
+ if (background != null)
+ background.dispose();
NetworkManager.getInstance().disconnect();
}
+
+ /**
+ * 解决本地玩家与每个远程玩家的水平重叠,避免“穿人”视觉效果。
+ * 当前策略:仅移动本地玩家(不修改远程玩家坐标,避免产生需要网络回传的状态)。
+ * 若需要更严格的对等碰撞,可在主机端双向分离并广播,但此处先满足基本需求。
+ */
+ private void resolvePlayerCollisions() {
+ if (otherPlayers.isEmpty())
+ return;
+ Rectangle a = player.getHitbox();
+ for (SimpleFighter remote : otherPlayers.values()) {
+ Rectangle b = remote.getHitbox();
+ if (!a.overlaps(b))
+ continue;
+ // 仅考虑水平最小位移分离(2D 侧向格斗常见做法)
+ float axCenter = a.x + a.width / 2f;
+ float bxCenter = b.x + b.width / 2f;
+ float dx = axCenter - bxCenter; // 正值:本地在右侧
+ float overlapX = (a.width + b.width) / 2f - Math.abs(dx);
+ if (overlapX > 0) {
+ if (dx >= 0) {
+ a.x += overlapX; // 本地向右推
+ } else {
+ a.x -= overlapX; // 本地向左推
+ }
+ // 世界边界限制(假设世界从 0 开始到 worldWidth)
+ if (a.x < 0)
+ a.x = 0;
+ if (a.x + a.width > worldWidth)
+ a.x = worldWidth - a.width;
+ }
+ }
+ }
}
diff --git a/src/main/java/uno/mloluyu/desktop/MainGame.java b/src/main/java/uno/mloluyu/desktop/MainGame.java
index 699842e..1cdc690 100644
--- a/src/main/java/uno/mloluyu/desktop/MainGame.java
+++ b/src/main/java/uno/mloluyu/desktop/MainGame.java
@@ -1,8 +1,6 @@
package uno.mloluyu.desktop;
import com.badlogic.gdx.Game;
-import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.graphics.Texture;
public class MainGame extends Game {
public static final float WORLD_WIDTH = 1920;
diff --git a/src/main/java/uno/mloluyu/desktop/MainMenuScreen.java b/src/main/java/uno/mloluyu/desktop/MainMenuScreen.java
index 8206052..e19c657 100644
--- a/src/main/java/uno/mloluyu/desktop/MainMenuScreen.java
+++ b/src/main/java/uno/mloluyu/desktop/MainMenuScreen.java
@@ -9,8 +9,6 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
-import uno.mloluyu.versatile.FighterController;
-
import static uno.mloluyu.util.Font.loadChineseFont;
public class MainMenuScreen extends ScreenAdapter {
@@ -32,7 +30,7 @@ public class MainMenuScreen extends ScreenAdapter {
public MainMenuScreen(MainGame game) {
this.game = game;
- texture = new Texture(Gdx.files.internal("src\\main\\resources\\bg.png"));
+ texture = new Texture(Gdx.files.internal("bg.png"));
}
@Override
@@ -46,7 +44,7 @@ public class MainMenuScreen extends ScreenAdapter {
@Override
public void render(float delta) {
- Gdx.gl.glClearColor(0,0,0,0);
+ Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
int mouseX = Gdx.input.getX();
@@ -76,6 +74,7 @@ public class MainMenuScreen extends ScreenAdapter {
game.setScreen(new CharacterSelectScreen(game));
} else if (isTouched(mouseX, mouseY, buttonX, settingsY)) {
Gdx.app.log("Button", "设置按钮被点击!");
+ game.setScreen(new SettingsScreen(game));
} else if (isTouched(mouseX, mouseY, buttonX, networkY)) {
Gdx.app.log("Button", "联网设置按钮被点击!");
game.setScreen(new NetworkSettingsScreen(game));
@@ -92,8 +91,7 @@ public class MainMenuScreen extends ScreenAdapter {
}
private void drawButtonText(int y, String text) {
- float textWidth = font.getRegion().getRegionWidth(); // 粗略估算
- float textX = buttonX + buttonWidth / 2f - text.length() * 20; // 居中估算
+ float textX = buttonX + buttonWidth / 2f - text.length() * 20; // 简单估算居中
float textY = y + buttonHeight / 2f + 20;
font.draw(batch, text, textX, textY);
}
@@ -104,8 +102,11 @@ public class MainMenuScreen extends ScreenAdapter {
@Override
public void dispose() {
- if (batch != null) batch.dispose();
- if (font != null) font.dispose();
- if (shapeRenderer != null) shapeRenderer.dispose();
+ if (batch != null)
+ batch.dispose();
+ if (font != null)
+ font.dispose();
+ if (shapeRenderer != null)
+ shapeRenderer.dispose();
}
}
diff --git a/src/main/java/uno/mloluyu/desktop/NetworkSettingsScreen.java b/src/main/java/uno/mloluyu/desktop/NetworkSettingsScreen.java
index 5428946..f47cca0 100644
--- a/src/main/java/uno/mloluyu/desktop/NetworkSettingsScreen.java
+++ b/src/main/java/uno/mloluyu/desktop/NetworkSettingsScreen.java
@@ -3,7 +3,6 @@ package uno.mloluyu.desktop;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.ScreenAdapter;
import com.badlogic.gdx.graphics.Color;
-import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
@@ -40,7 +39,8 @@ public class NetworkSettingsScreen extends ScreenAdapter {
@Override
public void render(float delta) {
- new ClearScreen();
+ // 使用静态工具方法清屏
+ ClearScreen.clear();
int mouseX = Gdx.input.getX();
int mouseY = Gdx.graphics.getHeight() - Gdx.input.getY();
@@ -64,6 +64,12 @@ public class NetworkSettingsScreen extends ScreenAdapter {
drawButtonText(CREATE_ROOM_Y, "创建房间");
drawButtonText(JOIN_ROOM_Y, "加入房间");
drawButtonText(EXIT_Y, "返回");
+ // 状态信息
+ NetworkManager nm = NetworkManager.getInstance();
+ String id = nm.getLocalPlayerId();
+ font.draw(batch, "本机ID: " + (id == null ? "(未分配)" : id.substring(0, Math.min(8, id.length()))), 50, 200);
+ font.draw(batch, nm.isHost() ? "当前: 房主" : (nm.isConnected() ? "当前: 已连接客户端" : "当前: 未连接"), 50, 160);
+ font.draw(batch, "在线玩家: " + (nm.getPlayerPositions() == null ? 0 : nm.getPlayerPositions().size()), 50, 120);
batch.end();
}
diff --git a/src/main/java/uno/mloluyu/desktop/ScreenManager.java b/src/main/java/uno/mloluyu/desktop/ScreenManager.java
new file mode 100644
index 0000000..ff1e7c2
--- /dev/null
+++ b/src/main/java/uno/mloluyu/desktop/ScreenManager.java
@@ -0,0 +1,25 @@
+package uno.mloluyu.desktop;
+
+/** 简易屏幕管理器,负责切换与异常保护。 */
+public class ScreenManager {
+ private final MainGame game;
+ private BaseScreen current;
+
+ public ScreenManager(MainGame game) {
+ this.game = game;
+ }
+
+ public void set(BaseScreen next) {
+ try {
+ if (current != null) {
+ current.hide();
+ current.dispose();
+ }
+ current = next;
+ game.setScreen(next);
+ } catch (Throwable t) {
+ // 忽略或可加简单 System.err
+ t.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/uno/mloluyu/desktop/SettingsScreen.java b/src/main/java/uno/mloluyu/desktop/SettingsScreen.java
new file mode 100644
index 0000000..46d6142
--- /dev/null
+++ b/src/main/java/uno/mloluyu/desktop/SettingsScreen.java
@@ -0,0 +1,75 @@
+package uno.mloluyu.desktop;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.ScreenAdapter;
+import com.badlogic.gdx.graphics.Color;
+import com.badlogic.gdx.graphics.g2d.BitmapFont;
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
+import uno.mloluyu.util.ClearScreen;
+import static uno.mloluyu.util.Font.loadChineseFont;
+
+/**
+ * 简单设置界面占位:未来可扩展(音量/按键设置)。
+ */
+public class SettingsScreen extends ScreenAdapter {
+ private final MainGame game;
+ private SpriteBatch batch;
+ private BitmapFont font;
+ private ShapeRenderer shapeRenderer;
+
+ private static final int BACK_X = 100; // 返回按钮区域
+ private static final int BACK_Y = 100;
+ private static final int BACK_W = 220;
+ private static final int BACK_H = 70;
+
+ public SettingsScreen(MainGame game) {
+ this.game = game;
+ }
+
+ @Override
+ public void show() {
+ batch = new SpriteBatch();
+ shapeRenderer = new ShapeRenderer();
+ font = loadChineseFont();
+ font.setColor(Color.WHITE);
+ font.getData().setScale(2f);
+ }
+
+ @Override
+ public void render(float delta) {
+ ClearScreen.clear();
+ int mouseX = Gdx.input.getX();
+ int mouseY = Gdx.graphics.getHeight() - Gdx.input.getY();
+
+ // 绘制背景与返回按钮
+ shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
+ shapeRenderer.setColor(Color.DARK_GRAY);
+ shapeRenderer.rect(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
+ boolean backHover = isHovered(mouseX, mouseY, BACK_X, BACK_Y, BACK_W, BACK_H);
+ shapeRenderer.setColor(backHover ? Color.LIGHT_GRAY : Color.GRAY);
+ shapeRenderer.rect(BACK_X, BACK_Y, BACK_W, BACK_H);
+ shapeRenderer.end();
+
+ batch.begin();
+ font.draw(batch, "设置 (占位界面)", 100, Gdx.graphics.getHeight() - 120);
+ font.draw(batch, "此处可添加: 音量 / 按键 / 分辨率 / 语言 等", 100, Gdx.graphics.getHeight() - 180);
+ font.draw(batch, "返回", BACK_X + 50, BACK_Y + 45);
+ batch.end();
+
+ if (Gdx.input.justTouched() && backHover) {
+ game.setScreen(new MainMenuScreen(game));
+ }
+ }
+
+ private boolean isHovered(int x, int y, int bx, int by, int bw, int bh) {
+ return x >= bx && x <= bx + bw && y >= by && y <= by + bh;
+ }
+
+ @Override
+ public void dispose() {
+ batch.dispose();
+ font.dispose();
+ shapeRenderer.dispose();
+ }
+}
diff --git a/src/main/java/uno/mloluyu/desktop/StartScreen.java b/src/main/java/uno/mloluyu/desktop/StartScreen.java
index 3217a97..9d278ef 100644
--- a/src/main/java/uno/mloluyu/desktop/StartScreen.java
+++ b/src/main/java/uno/mloluyu/desktop/StartScreen.java
@@ -1,17 +1,17 @@
package uno.mloluyu.desktop;
import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
+import uno.mloluyu.util.ResourcePaths;
/**
* 启动屏幕类
* 显示游戏Logo并在3秒后切换到主菜单界面
*/
-public class StartScreen implements Screen {
+public class StartScreen extends BaseScreen {
- private MainGame mainGame;
+ private MainGame mainGame; // TODO: 后续可直接用BaseScreen.game
private Texture logoTexture;
private com.badlogic.gdx.graphics.g2d.SpriteBatch batch;
@@ -19,8 +19,9 @@ public class StartScreen implements Screen {
private float deltaSum;
public StartScreen(MainGame mainGame) {
+ super(mainGame);
this.mainGame = mainGame;
- logoTexture = new Texture(Gdx.files.internal("logo.png"));
+ logoTexture = new Texture(Gdx.files.internal(ResourcePaths.LOGO));
batch = new com.badlogic.gdx.graphics.g2d.SpriteBatch();
}
@@ -36,7 +37,6 @@ public class StartScreen implements Screen {
if (deltaSum >= .01F) {
if (mainGame != null) {
mainGame.showGameScreen();
- System.out.println("已经切换到主菜单");
return;
}
}
diff --git a/src/main/java/uno/mloluyu/network/NetworkManager.java b/src/main/java/uno/mloluyu/network/NetworkManager.java
index f5b8a10..826206e 100644
--- a/src/main/java/uno/mloluyu/network/NetworkManager.java
+++ b/src/main/java/uno/mloluyu/network/NetworkManager.java
@@ -73,6 +73,14 @@ public class NetworkManager {
}
}
+ /**
+ * 本地玩家所选角色(仅本地缓存,远程映射存于 playerCharacters)。
+ * 供界面或后续同步逻辑查询。
+ */
+ public String getLocalCharacter() {
+ return localCharacter;
+ }
+
public void receiveMessage(String message) {// 解析消息
if (message.startsWith("POS:")) {
diff --git a/src/main/java/uno/mloluyu/perf/PerfMetrics.java b/src/main/java/uno/mloluyu/perf/PerfMetrics.java
new file mode 100644
index 0000000..35a6151
--- /dev/null
+++ b/src/main/java/uno/mloluyu/perf/PerfMetrics.java
@@ -0,0 +1,20 @@
+package uno.mloluyu.perf;
+
+/** 简单性能指标收集(首版)。 */
+public final class PerfMetrics {
+ private static long frameCount;
+ private static double accumTime;
+ private static double maxFrame = 0;
+
+ public static void frame(double delta) {
+ frameCount++;
+ accumTime += delta;
+ if (delta > maxFrame)
+ maxFrame = delta;
+ }
+
+ public static String summary() {
+ double avg = frameCount == 0 ? 0 : accumTime / frameCount;
+ return String.format("frames=%d avg=%.4f max=%.4f", frameCount, avg, maxFrame);
+ }
+}
diff --git a/src/main/java/uno/mloluyu/util/ClearScreen.java b/src/main/java/uno/mloluyu/util/ClearScreen.java
index 55d3fcd..12fd426 100644
--- a/src/main/java/uno/mloluyu/util/ClearScreen.java
+++ b/src/main/java/uno/mloluyu/util/ClearScreen.java
@@ -3,9 +3,13 @@ package uno.mloluyu.util;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
-public class ClearScreen {
- public ClearScreen() {
+/** 清屏工具:改为静态方法避免每帧 new 对象。 */
+public final class ClearScreen {
+ private ClearScreen() {
+ }
+
+ public static void clear() {
Gdx.gl.glClearColor(0.3F, 0.3F, 0.5F, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/uno/mloluyu/util/GameConstants.java b/src/main/java/uno/mloluyu/util/GameConstants.java
new file mode 100644
index 0000000..3a17828
--- /dev/null
+++ b/src/main/java/uno/mloluyu/util/GameConstants.java
@@ -0,0 +1,32 @@
+package uno.mloluyu.util;
+
+/**
+ * 全局游戏常量集中放置。
+ */
+public final class GameConstants {
+ /**
+ * 地面(空气墙)Y 坐标。抬高后便于更好构图。
+ */
+ public static final float GROUND_Y = 180f; // 可按需要再调
+
+ // 角色移动/物理参数(集中配置便于统一手感调节)
+ // 用户要求:速度 *2,跳跃 *3(基于当前 520 / 1250)
+ public static final float MOVE_SPEED = 1040f; // 520 *2 (最初 ~300)
+ // 调低跳跃:更低高度 + 更短滞空:v0 ↓,同时重力 ↑
+ // 说明:上升时间 t_up = v0 / g,本次取 v0=1500, g=3200 =>
+ // t_up≈0.47s,总滞空≈0.94s,高度≈(v0^2)/(2g)≈351
+ // 若想再更低:JUMP_SPEED 1400 + GRAVITY 3400;再更高一点:JUMP_SPEED 1600 + GRAVITY 3000。
+ public static final float JUMP_SPEED = 1500f;
+ public static final float GRAVITY = 3200f; // 加大重力让落地更快
+
+ // 调试命中盒渲染缩放(=1 表示真实大小;之前放大 3.6 现在回归可控)
+ // 调试盒缩放:1 = 实际大小;若想放大显示结构,可调大。
+ public static final float DEBUG_BOX_SCALE = 1.0f;
+ // 是否按中心放大(true 则保持角色中心位置,不会视觉漂移)
+ public static final boolean DEBUG_SCALE_FROM_CENTER = true;
+
+ // (可选)相机或后续平衡参数也可集中放这里
+
+ private GameConstants() {
+ }
+}
diff --git a/src/main/java/uno/mloluyu/util/ResourcePaths.java b/src/main/java/uno/mloluyu/util/ResourcePaths.java
new file mode 100644
index 0000000..a62800b
--- /dev/null
+++ b/src/main/java/uno/mloluyu/util/ResourcePaths.java
@@ -0,0 +1,12 @@
+package uno.mloluyu.util;
+
+/** 统一资源常量,避免魔法字符串散落。 */
+public final class ResourcePaths {
+ private ResourcePaths() {
+ }
+
+ public static final String LOGO = "logo.png";
+ public static final String FONT_MAIN = "FLyouzichati-Regular-2.ttf";
+ public static final String CHARACTER_ROOT = "character/";
+ public static final String UI_SKIN_JSON = "ui/uiskin.json";
+}
diff --git a/src/main/java/uno/mloluyu/util/TimeStepLimiter.java b/src/main/java/uno/mloluyu/util/TimeStepLimiter.java
new file mode 100644
index 0000000..f8f8fef
--- /dev/null
+++ b/src/main/java/uno/mloluyu/util/TimeStepLimiter.java
@@ -0,0 +1,13 @@
+package uno.mloluyu.util;
+
+/** 限制delta时间,防止窗口拖拽/卡顿后出现物理跳跃。 */
+public final class TimeStepLimiter {
+ private TimeStepLimiter() {
+ }
+
+ private static final float MAX_DELTA = 1f / 30f; // 上限: 相当于最低30FPS
+
+ public static float clamp(float delta) {
+ return delta > MAX_DELTA ? MAX_DELTA : Math.max(delta, 0f);
+ }
+}
diff --git a/src/main/resources/innerbg.png b/src/main/resources/innerbg.png
new file mode 100644
index 0000000..7503a26
Binary files /dev/null and b/src/main/resources/innerbg.png differ
diff --git a/src/test/java/uno/mloluyu/assets/AssetsExistenceTest.java b/src/test/java/uno/mloluyu/assets/AssetsExistenceTest.java
new file mode 100644
index 0000000..71b535f
--- /dev/null
+++ b/src/test/java/uno/mloluyu/assets/AssetsExistenceTest.java
@@ -0,0 +1,22 @@
+package uno.mloluyu.assets;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+public class AssetsExistenceTest {
+ private static final Path RES = Path.of("src", "main", "resources");
+
+ @Test
+ void testCoreAssetsPresent() {
+ List required = List.of("logo.png", "character/alice/alice.png", "character/reimu/reimu-0.png",
+ "ui/uiskin.json");
+ for (String r : required) {
+ Path p = RES.resolve(r);
+ Assertions.assertTrue(Files.exists(p), "缺失资源: " + r);
+ }
+ }
+}
diff --git a/src/test/java/uno/mloluyu/characters/ActionStateTest.java b/src/test/java/uno/mloluyu/characters/ActionStateTest.java
new file mode 100644
index 0000000..211434b
--- /dev/null
+++ b/src/test/java/uno/mloluyu/characters/ActionStateTest.java
@@ -0,0 +1,21 @@
+package uno.mloluyu.characters;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class ActionStateTest {
+ @Test
+ void testLegalTransitionIdleToMove() {
+ SimpleFighter f = new SimpleFighter("Test");
+ f.changeAction(Action.MOVE);
+ Assertions.assertEquals(Action.MOVE, f.getCurrentAction());
+ }
+
+ @Test
+ void testIllegalTransitionDeadToMove() {
+ SimpleFighter f = new SimpleFighter("Test");
+ f.changeAction(Action.DEAD);
+ f.changeAction(Action.MOVE); // 应被拒绝
+ Assertions.assertEquals(Action.DEAD, f.getCurrentAction());
+ }
+}
diff --git a/target/classes/innerbg.png b/target/classes/innerbg.png
new file mode 100644
index 0000000..7503a26
Binary files /dev/null and b/target/classes/innerbg.png differ
diff --git a/target/classes/uno/mloluyu/characters/Action.class b/target/classes/uno/mloluyu/characters/Action.class
index 92cd063..7ea2ac5 100644
Binary files a/target/classes/uno/mloluyu/characters/Action.class and b/target/classes/uno/mloluyu/characters/Action.class differ
diff --git a/target/classes/uno/mloluyu/characters/ActionStateGuard.class b/target/classes/uno/mloluyu/characters/ActionStateGuard.class
new file mode 100644
index 0000000..dcc21b6
Binary files /dev/null and b/target/classes/uno/mloluyu/characters/ActionStateGuard.class differ
diff --git a/target/classes/uno/mloluyu/characters/ActionTransitionMap.class b/target/classes/uno/mloluyu/characters/ActionTransitionMap.class
new file mode 100644
index 0000000..da867dc
Binary files /dev/null and b/target/classes/uno/mloluyu/characters/ActionTransitionMap.class differ
diff --git a/target/classes/uno/mloluyu/characters/AdvancedFighter.class b/target/classes/uno/mloluyu/characters/AdvancedFighter.class
index 102df56..6b749bf 100644
Binary files a/target/classes/uno/mloluyu/characters/AdvancedFighter.class and b/target/classes/uno/mloluyu/characters/AdvancedFighter.class differ
diff --git a/target/classes/uno/mloluyu/characters/FighterAnimationManager.class b/target/classes/uno/mloluyu/characters/FighterAnimationManager.class
index eb5f5a6..cf0ed32 100644
Binary files a/target/classes/uno/mloluyu/characters/FighterAnimationManager.class and b/target/classes/uno/mloluyu/characters/FighterAnimationManager.class differ
diff --git a/target/classes/uno/mloluyu/characters/FighterBase.class b/target/classes/uno/mloluyu/characters/FighterBase.class
new file mode 100644
index 0000000..126da1a
Binary files /dev/null and b/target/classes/uno/mloluyu/characters/FighterBase.class differ
diff --git a/target/classes/uno/mloluyu/characters/SimpleFighter.class b/target/classes/uno/mloluyu/characters/SimpleFighter.class
index dd65ca8..0e8605e 100644
Binary files a/target/classes/uno/mloluyu/characters/SimpleFighter.class and b/target/classes/uno/mloluyu/characters/SimpleFighter.class differ
diff --git a/target/classes/uno/mloluyu/desktop/BaseScreen.class b/target/classes/uno/mloluyu/desktop/BaseScreen.class
new file mode 100644
index 0000000..a6a8708
Binary files /dev/null and b/target/classes/uno/mloluyu/desktop/BaseScreen.class differ
diff --git a/target/classes/uno/mloluyu/desktop/CharacterSelectScreen.class b/target/classes/uno/mloluyu/desktop/CharacterSelectScreen.class
index 97f3dae..b4abd5d 100644
Binary files a/target/classes/uno/mloluyu/desktop/CharacterSelectScreen.class and b/target/classes/uno/mloluyu/desktop/CharacterSelectScreen.class differ
diff --git a/target/classes/uno/mloluyu/desktop/DesktopLauncher.class b/target/classes/uno/mloluyu/desktop/DesktopLauncher.class
index d258f8a..14c04bc 100644
Binary files a/target/classes/uno/mloluyu/desktop/DesktopLauncher.class and b/target/classes/uno/mloluyu/desktop/DesktopLauncher.class differ
diff --git a/target/classes/uno/mloluyu/desktop/GameScreen.class b/target/classes/uno/mloluyu/desktop/GameScreen.class
index 4f63201..4b3f60d 100644
Binary files a/target/classes/uno/mloluyu/desktop/GameScreen.class and b/target/classes/uno/mloluyu/desktop/GameScreen.class differ
diff --git a/target/classes/uno/mloluyu/desktop/MainGame.class b/target/classes/uno/mloluyu/desktop/MainGame.class
index 56c5d61..91fbf91 100644
Binary files a/target/classes/uno/mloluyu/desktop/MainGame.class and b/target/classes/uno/mloluyu/desktop/MainGame.class differ
diff --git a/target/classes/uno/mloluyu/desktop/MainMenuScreen.class b/target/classes/uno/mloluyu/desktop/MainMenuScreen.class
index 0c537df..55edc9f 100644
Binary files a/target/classes/uno/mloluyu/desktop/MainMenuScreen.class and b/target/classes/uno/mloluyu/desktop/MainMenuScreen.class differ
diff --git a/target/classes/uno/mloluyu/desktop/NetworkSettingsScreen$1.class b/target/classes/uno/mloluyu/desktop/NetworkSettingsScreen$1.class
index 283b1c0..32054a2 100644
Binary files a/target/classes/uno/mloluyu/desktop/NetworkSettingsScreen$1.class and b/target/classes/uno/mloluyu/desktop/NetworkSettingsScreen$1.class differ
diff --git a/target/classes/uno/mloluyu/desktop/NetworkSettingsScreen.class b/target/classes/uno/mloluyu/desktop/NetworkSettingsScreen.class
index b845803..14617b8 100644
Binary files a/target/classes/uno/mloluyu/desktop/NetworkSettingsScreen.class and b/target/classes/uno/mloluyu/desktop/NetworkSettingsScreen.class differ
diff --git a/target/classes/uno/mloluyu/desktop/ScreenManager.class b/target/classes/uno/mloluyu/desktop/ScreenManager.class
new file mode 100644
index 0000000..d833a70
Binary files /dev/null and b/target/classes/uno/mloluyu/desktop/ScreenManager.class differ
diff --git a/target/classes/uno/mloluyu/desktop/SettingsScreen.class b/target/classes/uno/mloluyu/desktop/SettingsScreen.class
new file mode 100644
index 0000000..5f8abb7
Binary files /dev/null and b/target/classes/uno/mloluyu/desktop/SettingsScreen.class differ
diff --git a/target/classes/uno/mloluyu/desktop/StartScreen.class b/target/classes/uno/mloluyu/desktop/StartScreen.class
index f60838b..bca2b1d 100644
Binary files a/target/classes/uno/mloluyu/desktop/StartScreen.class and b/target/classes/uno/mloluyu/desktop/StartScreen.class differ
diff --git a/target/classes/uno/mloluyu/network/ConnectClient.class b/target/classes/uno/mloluyu/network/ConnectClient.class
index 3e28e9f..a050295 100644
Binary files a/target/classes/uno/mloluyu/network/ConnectClient.class and b/target/classes/uno/mloluyu/network/ConnectClient.class differ
diff --git a/target/classes/uno/mloluyu/network/ConnectServer.class b/target/classes/uno/mloluyu/network/ConnectServer.class
index 5c99138..c56c7a3 100644
Binary files a/target/classes/uno/mloluyu/network/ConnectServer.class and b/target/classes/uno/mloluyu/network/ConnectServer.class differ
diff --git a/target/classes/uno/mloluyu/network/NetworkManager.class b/target/classes/uno/mloluyu/network/NetworkManager.class
index f836db3..cdd9abd 100644
Binary files a/target/classes/uno/mloluyu/network/NetworkManager.class and b/target/classes/uno/mloluyu/network/NetworkManager.class differ
diff --git a/target/classes/uno/mloluyu/perf/PerfMetrics.class b/target/classes/uno/mloluyu/perf/PerfMetrics.class
new file mode 100644
index 0000000..803cb01
Binary files /dev/null and b/target/classes/uno/mloluyu/perf/PerfMetrics.class differ
diff --git a/target/classes/uno/mloluyu/util/ClearScreen.class b/target/classes/uno/mloluyu/util/ClearScreen.class
index b747ce3..7d173c8 100644
Binary files a/target/classes/uno/mloluyu/util/ClearScreen.class and b/target/classes/uno/mloluyu/util/ClearScreen.class differ
diff --git a/target/classes/uno/mloluyu/util/Font.class b/target/classes/uno/mloluyu/util/Font.class
index d0e69d2..f3d8782 100644
Binary files a/target/classes/uno/mloluyu/util/Font.class and b/target/classes/uno/mloluyu/util/Font.class differ
diff --git a/target/classes/uno/mloluyu/util/GameConstants.class b/target/classes/uno/mloluyu/util/GameConstants.class
new file mode 100644
index 0000000..e35d632
Binary files /dev/null and b/target/classes/uno/mloluyu/util/GameConstants.class differ
diff --git a/target/classes/uno/mloluyu/util/ResourcePaths.class b/target/classes/uno/mloluyu/util/ResourcePaths.class
new file mode 100644
index 0000000..758f2ae
Binary files /dev/null and b/target/classes/uno/mloluyu/util/ResourcePaths.class differ
diff --git a/target/classes/uno/mloluyu/util/SimpleFormatter.class b/target/classes/uno/mloluyu/util/SimpleFormatter.class
index 8c9bab2..84af275 100644
Binary files a/target/classes/uno/mloluyu/util/SimpleFormatter.class and b/target/classes/uno/mloluyu/util/SimpleFormatter.class differ
diff --git a/target/classes/uno/mloluyu/util/TimeStepLimiter.class b/target/classes/uno/mloluyu/util/TimeStepLimiter.class
new file mode 100644
index 0000000..0700958
Binary files /dev/null and b/target/classes/uno/mloluyu/util/TimeStepLimiter.class differ
diff --git a/target/classes/uno/mloluyu/versatile/FighterController.class b/target/classes/uno/mloluyu/versatile/FighterController.class
index f375ecf..9f2fe30 100644
Binary files a/target/classes/uno/mloluyu/versatile/FighterController.class and b/target/classes/uno/mloluyu/versatile/FighterController.class differ
diff --git a/target/game-1.0-SNAPSHOT.jar b/target/game-1.0-SNAPSHOT.jar
new file mode 100644
index 0000000..8f63653
Binary files /dev/null and b/target/game-1.0-SNAPSHOT.jar differ
diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties
new file mode 100644
index 0000000..a1c2e23
--- /dev/null
+++ b/target/maven-archiver/pom.properties
@@ -0,0 +1,3 @@
+artifactId=game
+groupId=uno.mloluyu
+version=1.0-SNAPSHOT
diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
index 59271ad..c994b96 100644
--- a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
+++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
@@ -1,6 +1,7 @@
uno\mloluyu\desktop\StartScreen.class
uno\mloluyu\desktop\NetworkSettingsScreen$1.class
uno\mloluyu\network\NetworkManager.class
+uno\mloluyu\characters\FighterAnimationManager.class
uno\mloluyu\desktop\CharacterSelectScreen.class
uno\mloluyu\versatile\FighterController.class
uno\mloluyu\desktop\MainGame.class
diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
index d01a604..46662ee 100644
--- a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
+++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
@@ -1,17 +1,28 @@
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\characters\Action.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\characters\ActionStateGuard.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\characters\ActionTransitionMap.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\characters\AdvancedFighter.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\characters\FighterAnimationManager.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\characters\FighterBase.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\characters\SimpleFighter.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\desktop\BaseScreen.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\desktop\CharacterSelectScreen.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\desktop\DesktopLauncher.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\desktop\GameScreen.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\desktop\MainGame.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\desktop\MainMenuScreen.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\desktop\NetworkSettingsScreen.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\desktop\ScreenManager.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\desktop\SettingsScreen.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\desktop\StartScreen.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\network\ConnectClient.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\network\ConnectServer.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\network\NetworkManager.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\perf\PerfMetrics.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\util\ClearScreen.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\util\Font.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\util\GameConstants.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\util\ResourcePaths.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\util\SimpleFormatter.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\util\TimeStepLimiter.java
C:\Users\www\Documents\Game\格斗游戏\Game\src\main\java\uno\mloluyu\versatile\FighterController.java
diff --git a/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
new file mode 100644
index 0000000..e69de29
diff --git a/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
new file mode 100644
index 0000000..e0019a5
--- /dev/null
+++ b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
@@ -0,0 +1,2 @@
+C:\Users\www\Documents\Game\格斗游戏\Game\src\test\java\uno\mloluyu\assets\AssetsExistenceTest.java
+C:\Users\www\Documents\Game\格斗游戏\Game\src\test\java\uno\mloluyu\characters\ActionStateTest.java
diff --git a/target/test-classes/uno/mloluyu/assets/AssetsExistenceTest.class b/target/test-classes/uno/mloluyu/assets/AssetsExistenceTest.class
new file mode 100644
index 0000000..7e5bba1
Binary files /dev/null and b/target/test-classes/uno/mloluyu/assets/AssetsExistenceTest.class differ
diff --git a/target/test-classes/uno/mloluyu/characters/ActionStateTest.class b/target/test-classes/uno/mloluyu/characters/ActionStateTest.class
new file mode 100644
index 0000000..7d5a884
Binary files /dev/null and b/target/test-classes/uno/mloluyu/characters/ActionStateTest.class differ