Merge remote-tracking branch 'origin/test' into test
This commit is contained in:
71
dependency-reduced-pom.xml
Normal file
71
dependency-reduced-pom.xml
Normal file
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>uno.mloluyu</groupId>
|
||||
<artifactId>game</artifactId>
|
||||
<name>game</name>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<description>LibGDX Desktop Game</description>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
<release>${maven.compiler.source}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<configuration>
|
||||
<mainClass>${exec.mainClass}</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>true</createDependencyReducedPom>
|
||||
<minimizeJar>false</minimizeJar>
|
||||
<shadedArtifactSet />
|
||||
<transformers>
|
||||
<transformer>
|
||||
<mainClass>${exec.mainClass}</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Build-Time>${maven.build.timestamp}</Build-Time>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<exec.mainClass>uno.mloluyu.desktop.DesktopLauncher</exec.mainClass>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<gdx.version>1.12.1</gdx.version>
|
||||
<maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss</maven.build.timestamp.format>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
</project>
|
||||
@@ -12,15 +12,15 @@ public class AdvancedFighter extends SimpleFighter {
|
||||
switch (attackType.toLowerCase()) {
|
||||
case "light":
|
||||
changeAction(Action.ATTACK);
|
||||
System.out.println(getName() + " 发起轻攻击!");
|
||||
// System.out.println(getName() + " 发起轻攻击!");
|
||||
break;
|
||||
case "heavy":
|
||||
changeAction(Action.ATTACK);
|
||||
System.out.println(getName() + " 发起重攻击!");
|
||||
// System.out.println(getName() + " 发起重攻击!");
|
||||
break;
|
||||
case "special":
|
||||
changeAction(Action.ATTACK);
|
||||
System.out.println(getName() + " 发动特殊技能!");
|
||||
// System.out.println(getName() + " 发动特殊技能!");
|
||||
break;
|
||||
default:
|
||||
super.attack(attackType); // 默认调用父类攻击逻辑
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package uno.mloluyu.characters;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
// 注意:本类使用的是包 uno.mloluyu.characters 下的 Action (IDLE, JUMP, MOVE, ATTACK, DEFEND, HIT, DEAD)
|
||||
// 避免与 uno.mloluyu.characters.character.Action (ATTACK1/2/3...) 混淆
|
||||
|
||||
// 简化:去除内部按键时长跟踪,统一由 FighterController 负责
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
@@ -16,7 +18,6 @@ import com.badlogic.gdx.math.Rectangle;
|
||||
public class SimpleFighter {
|
||||
|
||||
private String name; // 角色名称
|
||||
private final Map<Integer, Float> keyPressDuration = new HashMap<>();
|
||||
|
||||
private Action currentAction = Action.IDLE; // 当前动作状态(待机、攻击、受击等)
|
||||
private float verticalSpeed = 0f; // 垂直速度(可用于跳跃或下落)
|
||||
@@ -28,36 +29,60 @@ public class SimpleFighter {
|
||||
|
||||
private float speed = 300f; // 移动速度(像素/秒)
|
||||
private int health = 100; // 当前生命值
|
||||
private int attackPower = 10; // 攻击力(暂未使用)
|
||||
|
||||
private boolean isAttacking = false; // 是否正在攻击(攻击状态标志)
|
||||
private boolean attackJustStarted = false; // 攻击刚开始的标记,避免第一帧被减掉
|
||||
private int attackInvokeCount = 0; // 调试:attack()调用次数
|
||||
|
||||
private SimpleFighter fighter; // 添加 fighter 的声明
|
||||
// 攻击持续时间(秒)
|
||||
private float attackTimer = 0f;
|
||||
private static final float ATTACK_DURATION = 0.15f; // 攻击判定显示时间
|
||||
|
||||
private Iterable<Integer> pressedKeys = new HashMap<Integer, Float>().keySet(); // 初始化 pressedKeys
|
||||
private static boolean debugEnabled = true; // F3 开关
|
||||
|
||||
public static void toggleDebug() {
|
||||
debugEnabled = !debugEnabled;
|
||||
}
|
||||
|
||||
public static boolean isDebugEnabled() {
|
||||
return debugEnabled;
|
||||
}
|
||||
|
||||
public SimpleFighter(String name) {
|
||||
this.name = name; // 构造函数,初始化角色名称
|
||||
this.fighter = this; // 初始化 fighter 为当前实例
|
||||
}
|
||||
|
||||
public void update(float deltaTime) {
|
||||
updateAttackbox();
|
||||
// 自愈:动作是 ATTACK 但标记丢失
|
||||
if (currentAction == Action.ATTACK && attackTimer > 0f && !isAttacking) {
|
||||
isAttacking = true;
|
||||
attackJustStarted = false;
|
||||
}
|
||||
|
||||
// 攻击只持续一帧
|
||||
// 攻击计时
|
||||
if (isAttacking) {
|
||||
isAttacking = false;
|
||||
changeAction(Action.IDLE);
|
||||
if (attackJustStarted) {
|
||||
attackJustStarted = false; // 第一帧不扣时间
|
||||
} else {
|
||||
attackTimer -= deltaTime;
|
||||
}
|
||||
if (attackTimer <= 0f) {
|
||||
isAttacking = false;
|
||||
attackTimer = 0f;
|
||||
if (currentAction == Action.ATTACK)
|
||||
changeAction(Action.IDLE);
|
||||
if (debugEnabled)
|
||||
System.out.println("[ATTACK-END]");
|
||||
}
|
||||
} else {
|
||||
// 空闲/移动状态下保持一个默认攻击盒(便于调试观察)
|
||||
updateAttackbox("light");
|
||||
}
|
||||
for (int keycode : pressedKeys) {
|
||||
keyPressDuration.put(keycode, keyPressDuration.getOrDefault(keycode, 0f) + deltaTime); // 更新持续时间
|
||||
fighter.handleInput(keycode, true); // 持续按下的键
|
||||
}
|
||||
// 垂直移动(跳跃或重力)
|
||||
if (!isGrounded) {
|
||||
verticalSpeed -= 980 * deltaTime; // 简单重力模拟
|
||||
hitbox.y += verticalSpeed * deltaTime;
|
||||
|
||||
// 垂直运动 & 重力
|
||||
if (!isGrounded) {
|
||||
verticalSpeed -= 2500 * deltaTime;
|
||||
hitbox.y += verticalSpeed * deltaTime;
|
||||
if (hitbox.y <= 0) {
|
||||
hitbox.y = 0;
|
||||
verticalSpeed = 0;
|
||||
@@ -67,50 +92,59 @@ public class SimpleFighter {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void render(SpriteBatch batch, ShapeRenderer shapeRenderer) {
|
||||
batch.end(); // 暂停 SpriteBatch 渲染,切换到 ShapeRenderer
|
||||
System.out.println("人物状态" + currentAction);
|
||||
boolean isAttacking = currentAction == Action.ATTACK;
|
||||
shapeRenderer.begin(ShapeRenderer.ShapeType.Line); // 开始绘制线框
|
||||
batch.end();
|
||||
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
|
||||
renderDebug(shapeRenderer);
|
||||
shapeRenderer.end();
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
shapeRenderer.setColor(Color.BLUE); // 设置颜色为蓝色
|
||||
shapeRenderer.rect(hitbox.x, hitbox.y, hitbox.width, hitbox.height); // 绘制碰撞盒
|
||||
public void renderSprite(SpriteBatch batch) {
|
||||
/* 预留贴图渲染入口 */ }
|
||||
|
||||
public void renderDebug(ShapeRenderer sr) {
|
||||
if (!debugEnabled)
|
||||
return;
|
||||
sr.setColor(Color.BLUE);
|
||||
sr.rect(hitbox.x, hitbox.y, hitbox.width, hitbox.height);
|
||||
if (isAttacking) {
|
||||
shapeRenderer.setColor(Color.RED); // 设置颜色为红色
|
||||
shapeRenderer.rect(attackbox.x, attackbox.y, attackbox.width, attackbox.height); // 绘制攻击盒
|
||||
// 只画轮廓;填充在 GameScreen 专门的 Filled pass 中画
|
||||
sr.setColor(Color.RED);
|
||||
sr.rect(attackbox.x, attackbox.y, attackbox.width, attackbox.height);
|
||||
}
|
||||
|
||||
shapeRenderer.end(); // 结束 ShapeRenderer 渲染
|
||||
batch.begin(); // 恢复 SpriteBatch 渲染
|
||||
// 朝向箭头
|
||||
float arrowX = isFacingRight ? hitbox.x + hitbox.width + 5 : hitbox.x - 15;
|
||||
sr.setColor(Color.YELLOW);
|
||||
sr.line(arrowX, hitbox.y + hitbox.height * 0.7f, arrowX + (isFacingRight ? 10 : -10),
|
||||
hitbox.y + hitbox.height * 0.7f);
|
||||
}
|
||||
|
||||
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()); // 向左移动
|
||||
move(-1, Gdx.graphics.getDeltaTime());
|
||||
} else if (keycode == Input.Keys.RIGHT || keycode == Input.Keys.D) {
|
||||
move(1, Gdx.graphics.getDeltaTime()); // 向右移动
|
||||
}
|
||||
if (keycode == Input.Keys.Z || keycode == Input.Keys.J) {
|
||||
attack(""); // 普通攻击
|
||||
} else if (keycode == Input.Keys.X || keycode == Input.Keys.K) {
|
||||
attack(""); // 重攻击(暂未区分)
|
||||
} else if (keycode == Input.Keys.SPACE || keycode == Input.Keys.UP || keycode == Input.Keys.W) {
|
||||
attack(""); // 跳跃(暂未实现跳跃逻辑)
|
||||
} else if (keycode == Input.Keys.SHIFT_LEFT || keycode == Input.Keys.SHIFT_RIGHT) {
|
||||
attack(""); // 防御(暂未实现防御逻辑)
|
||||
move(1, Gdx.graphics.getDeltaTime());
|
||||
}
|
||||
if (keycode == Input.Keys.SPACE || keycode == Input.Keys.UP || keycode == Input.Keys.W) {
|
||||
System.out.println("点击了跳跃");
|
||||
jump();
|
||||
}
|
||||
|
||||
// 攻击按键
|
||||
if (!isAttacking) {
|
||||
if (keycode == Input.Keys.Z || keycode == Input.Keys.J) {
|
||||
attack("light");
|
||||
} else if (keycode == Input.Keys.X || keycode == Input.Keys.K) {
|
||||
attack("heavy");
|
||||
} else if (keycode == Input.Keys.SHIFT_LEFT || keycode == Input.Keys.SHIFT_RIGHT) {
|
||||
attack("special");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 松开防御键时恢复待机状态
|
||||
if ((keycode == Input.Keys.SHIFT_LEFT || keycode == Input.Keys.SHIFT_RIGHT) &&
|
||||
getCurrentAction() == Action.DEFEND) {
|
||||
if ((keycode == Input.Keys.LEFT || keycode == Input.Keys.RIGHT || keycode == Input.Keys.A
|
||||
|| keycode == Input.Keys.D) &&
|
||||
getCurrentAction() == Action.MOVE) {
|
||||
changeAction(Action.IDLE);
|
||||
}
|
||||
}
|
||||
@@ -120,16 +154,6 @@ public class SimpleFighter {
|
||||
handleInput(keycode, isPressed, 0f); // 调用已有方法,补充默认持续时间
|
||||
}
|
||||
|
||||
public void handleRelease(int keycode, float duration) {
|
||||
// 处理按键释放逻辑
|
||||
System.out.println("按键释放: " + keycode + ", 持续时间: " + duration);
|
||||
keyPressDuration.remove(keycode);
|
||||
if (keycode == Input.Keys.LEFT || keycode == Input.Keys.RIGHT || keycode == Input.Keys.A
|
||||
|| keycode == Input.Keys.D) {
|
||||
changeAction(Action.IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
public Action getCurrentAction() {
|
||||
return currentAction; // 获取当前动作状态
|
||||
}
|
||||
@@ -140,8 +164,9 @@ public class SimpleFighter {
|
||||
|
||||
public void jump() {
|
||||
if (isGrounded) {
|
||||
verticalSpeed = 600f;
|
||||
verticalSpeed = 1000f;
|
||||
isGrounded = false;
|
||||
System.out.println("跳跃高度: " + verticalSpeed);
|
||||
changeAction(Action.JUMP);
|
||||
}
|
||||
}
|
||||
@@ -156,9 +181,45 @@ public class SimpleFighter {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAttackbox(String attackType) {
|
||||
float offsetX;
|
||||
float offsetY = 20; // 默认偏移量
|
||||
float width = 80;
|
||||
float height = 80;
|
||||
|
||||
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;
|
||||
break;
|
||||
case "special":
|
||||
offsetX = isFacingRight ? hitbox.width + 20 : -attackbox.width - 20;
|
||||
offsetY = 50;
|
||||
width = 120;
|
||||
height = 60;
|
||||
break;
|
||||
default:
|
||||
offsetX = isFacingRight ? hitbox.width - 10 : -attackbox.width + 10;
|
||||
}
|
||||
|
||||
attackbox.setPosition(hitbox.x + offsetX, hitbox.y + offsetY);
|
||||
attackbox.setSize(width, height);
|
||||
}
|
||||
|
||||
public void attack(String attackType) {
|
||||
isAttacking = true; // 设置攻击状态
|
||||
changeAction(Action.ATTACK); // 切换为攻击动作
|
||||
isAttacking = true;
|
||||
attackTimer = ATTACK_DURATION;
|
||||
attackJustStarted = true;
|
||||
changeAction(Action.ATTACK);
|
||||
updateAttackbox(attackType);
|
||||
attackInvokeCount++;
|
||||
if (debugEnabled)
|
||||
System.out.println("[ATTACK] type=" + attackType + " count=" + attackInvokeCount);
|
||||
}
|
||||
|
||||
public void takeHit(int damage) {
|
||||
@@ -174,12 +235,6 @@ public class SimpleFighter {
|
||||
return isAttacking; // 判断是否处于攻击状态
|
||||
}
|
||||
|
||||
private void updateAttackbox() {
|
||||
// 根据朝向更新攻击盒位置,使其位于角色前方
|
||||
float offsetX = isFacingRight ? hitbox.width - 10 : -attackbox.width + 10;
|
||||
attackbox.setPosition(hitbox.x + offsetX, hitbox.y + 20);
|
||||
}
|
||||
|
||||
// 常用访问器
|
||||
public Rectangle getHitbox() {
|
||||
return hitbox; // 获取碰撞盒
|
||||
@@ -200,4 +255,21 @@ public class SimpleFighter {
|
||||
public void setPosition(float x, float y) {
|
||||
hitbox.setPosition(x, y); // 设置角色位置
|
||||
}
|
||||
|
||||
public void debugPrintState() {
|
||||
if (debugEnabled)
|
||||
System.out.println("[STATE] action=" + currentAction + ", atk=" + isAttacking + ", t=" + attackTimer);
|
||||
}
|
||||
|
||||
public float getAttackTimer() {
|
||||
return attackTimer;
|
||||
}
|
||||
|
||||
public float getAttackTimerPercent() {
|
||||
return isAttacking ? attackTimer / ATTACK_DURATION : 0f;
|
||||
}
|
||||
|
||||
public int getAttackInvokeCount() {
|
||||
return attackInvokeCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public abstract class Fighter implements Disposable {
|
||||
return;
|
||||
|
||||
switch (currentAction) {
|
||||
case ATTACK1, ATTACK2, ATTACK3, SPECIAL1, SPECIAL2, HIT -> changeAction(Action.IDLE);
|
||||
case ATTACK1, ATTACK2, ATTACK3, ATTACK4, SPECIAL1, SPECIAL2, HIT -> changeAction(Action.IDLE);
|
||||
case JUMP -> changeAction(Action.FALL);
|
||||
default -> {
|
||||
}
|
||||
|
||||
@@ -3,11 +3,9 @@ package uno.mloluyu.characters.character;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
|
||||
import uno.mloluyu.characters.character.Fighter.Action;
|
||||
|
||||
public class Reimu extends Fighter {
|
||||
public Reimu() {
|
||||
super(new TextureAtlas(Gdx.files.internal("src\\main\\resources\\character\\reimu\\reimu.atlas")));
|
||||
super("Reimu", new TextureAtlas(Gdx.files.internal("src/main/resources/character/reimu/reimu.atlas")));
|
||||
|
||||
// 设置角色属性
|
||||
speed = 350f; // 更快的移动速度
|
||||
@@ -18,27 +16,27 @@ public class Reimu extends Fighter {
|
||||
|
||||
@Override
|
||||
protected void loadAnimations() {
|
||||
// TODO Auto-generated method stub
|
||||
// 加载基础动作动画
|
||||
loadAnimationFromAtlas(Action.IDLE, "other/stand", 9, true);
|
||||
loadAnimationFromAtlas(Action.WALK, "other/walkFront", 9, true);
|
||||
loadAnimationFromAtlas(Action.JUMP, "other/jump", 8, false);
|
||||
loadAnimationFromAtlas(Action.FALL, "other/hitSpin", 5, false);
|
||||
// 基础动作 (looping)
|
||||
animationManager.loadLooping(Action.IDLE, "other/stand", 9);
|
||||
animationManager.loadLooping(Action.WALK, "other/walkFront", 9);
|
||||
// 一次性动作 (one-shot)
|
||||
animationManager.loadOneShot(Action.JUMP, "other/jump", 8);
|
||||
animationManager.loadOneShot(Action.FALL, "other/hitSpin", 5);
|
||||
|
||||
// 加载攻击动作动画
|
||||
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);
|
||||
// 攻击动作
|
||||
animationManager.loadOneShot(Action.ATTACK1, "attackAa/attackAa", 6);
|
||||
animationManager.loadOneShot(Action.ATTACK2, "attackAb/attackAb", 6);
|
||||
animationManager.loadOneShot(Action.ATTACK3, "attackAc/attackAc", 6);
|
||||
animationManager.loadOneShot(Action.ATTACK4, "attackAd/attackAd", 6);
|
||||
|
||||
// 加载受击动画
|
||||
loadAnimationFromAtlas(Action.HIT, "hitSpin/hitSpin", 5, false);
|
||||
// 受击
|
||||
animationManager.loadOneShot(Action.HIT, "hitSpin/hitSpin", 5);
|
||||
|
||||
// 设置帧间隔(动作速度)
|
||||
setFrameDuration(Action.IDLE, 0.04f);
|
||||
setFrameDuration(Action.WALK, 0.08f);
|
||||
setFrameDuration(Action.ATTACK1, 0.07f);
|
||||
setFrameDuration(Action.SPECIAL2, 0.06f);
|
||||
// 帧间隔
|
||||
animationManager.setFrameDuration(Action.IDLE, 0.04f);
|
||||
animationManager.setFrameDuration(Action.WALK, 0.08f);
|
||||
animationManager.setFrameDuration(Action.ATTACK1, 0.07f);
|
||||
animationManager.setFrameDuration(Action.SPECIAL2, 0.06f);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,9 +3,13 @@ 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.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import uno.mloluyu.characters.Action;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -22,6 +26,8 @@ public class GameScreen extends ScreenAdapter {
|
||||
|
||||
private SpriteBatch batch;
|
||||
private ShapeRenderer shapeRenderer;
|
||||
private OrthographicCamera camera; // 添加摄像机
|
||||
private com.badlogic.gdx.graphics.g2d.BitmapFont debugFont; // 添加 debugFont 字段
|
||||
|
||||
public GameScreen(MainGame game, SimpleFighter player) {
|
||||
this.player = player;
|
||||
@@ -30,8 +36,13 @@ public class GameScreen extends ScreenAdapter {
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||
camera.position.set(player.getHitbox().x, player.getHitbox().y, 0); // 初始化摄像机位置
|
||||
camera.update();
|
||||
|
||||
batch = new SpriteBatch();
|
||||
shapeRenderer = new ShapeRenderer();
|
||||
debugFont = new com.badlogic.gdx.graphics.g2d.BitmapFont(); // 初始化 debugFont
|
||||
Gdx.input.setInputProcessor(controller);
|
||||
}
|
||||
|
||||
@@ -39,55 +50,109 @@ public class GameScreen extends ScreenAdapter {
|
||||
public void render(float delta) {
|
||||
new ClearScreen();
|
||||
|
||||
// 输入 / 逻辑
|
||||
player.update(delta);
|
||||
controller.update(delta);
|
||||
|
||||
if (NetworkManager.getInstance().isConnected()) {
|
||||
NetworkManager.getInstance().sendPosition(player.getHitbox().x, player.getHitbox().y);
|
||||
}
|
||||
|
||||
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
|
||||
|
||||
renderFighter(player, Color.BLUE);
|
||||
if (player.isAttacking()) renderAttackBox(player, Color.RED);
|
||||
|
||||
Map<String, float[]> positions = NetworkManager.getInstance().getPlayerPositions();
|
||||
if (positions != null) {
|
||||
for (Map.Entry<String, float[]> entry : positions.entrySet()) {
|
||||
String id = entry.getKey();
|
||||
float[] pos = entry.getValue();
|
||||
if (pos == null) continue;
|
||||
SimpleFighter remote = otherPlayers.computeIfAbsent(id, k -> new SimpleFighter("Remote-" + k));
|
||||
remote.setPosition(pos[0], pos[1]);
|
||||
remote.update(delta);
|
||||
renderFighter(remote, Color.GREEN);
|
||||
Map<String, float[]> positions = NetworkManager.getInstance().getPlayerPositions();
|
||||
if (positions != null) {
|
||||
for (Map.Entry<String, float[]> entry : positions.entrySet()) {
|
||||
float[] pos = entry.getValue();
|
||||
if (pos == null)
|
||||
continue;
|
||||
SimpleFighter remote = otherPlayers.computeIfAbsent(entry.getKey(),
|
||||
k -> new SimpleFighter("Remote-" + k));
|
||||
remote.setPosition(pos[0], pos[1]);
|
||||
remote.update(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// F3 调试切换
|
||||
if (Gdx.input.isKeyJustPressed(com.badlogic.gdx.Input.Keys.F3)) {
|
||||
SimpleFighter.toggleDebug();
|
||||
}
|
||||
|
||||
// 摄像机跟随
|
||||
camera.position.lerp(new Vector3(player.getHitbox().x, player.getHitbox().y, 0), 0.1f);
|
||||
camera.update();
|
||||
batch.setProjectionMatrix(camera.combined);
|
||||
shapeRenderer.setProjectionMatrix(camera.combined);
|
||||
|
||||
// 混合
|
||||
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);
|
||||
boolean showPlayerAttack = player.isAttacking()
|
||||
|| (player.getCurrentAction() == Action.ATTACK && player.getAttackTimer() > 0);
|
||||
if (showPlayerAttack)
|
||||
drawAttackBox(player, 1f, 0f, 0f, 0.35f);
|
||||
for (SimpleFighter remote : otherPlayers.values()) {
|
||||
drawHitbox(remote, Color.GREEN);
|
||||
if (remote.isAttacking())
|
||||
drawAttackBox(remote, 1f, 0f, 0f, 0.25f);
|
||||
}
|
||||
shapeRenderer.end();
|
||||
|
||||
// -------- Sprite / HUD pass --------
|
||||
batch.begin();
|
||||
player.renderSprite(batch);
|
||||
if (SimpleFighter.isDebugEnabled()) {
|
||||
debugFont.setColor(Color.WHITE);
|
||||
debugFont.draw(batch,
|
||||
"ACTION:" + player.getCurrentAction() +
|
||||
" atk=" + player.isAttacking() +
|
||||
" timer=" + String.format("%.2f", player.getAttackTimer()) +
|
||||
" atkInvoke=" + player.getAttackInvokeCount(),
|
||||
10, Gdx.graphics.getHeight() - 10);
|
||||
}
|
||||
batch.end();
|
||||
|
||||
// -------- Debug line pass --------
|
||||
if (SimpleFighter.isDebugEnabled()) {
|
||||
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
|
||||
player.renderDebug(shapeRenderer);
|
||||
for (SimpleFighter remote : otherPlayers.values())
|
||||
remote.renderDebug(shapeRenderer);
|
||||
shapeRenderer.setColor(Color.WHITE);
|
||||
shapeRenderer.rect(0, 0, 1000, 1000);
|
||||
shapeRenderer.end();
|
||||
}
|
||||
|
||||
// 控制台状态输出(保持以便继续诊断)
|
||||
player.debugPrintState();
|
||||
if (SimpleFighter.isDebugEnabled() && player.isAttacking()) {
|
||||
Rectangle ab = player.getAttackbox();
|
||||
System.out.println("[DEBUG] AttackBox: x=" + ab.x + ", y=" + ab.y + ", w=" + ab.width + ", h=" + ab.height
|
||||
+ ", timer=" + player.getAttackTimer());
|
||||
}
|
||||
}
|
||||
|
||||
private void renderFighter(SimpleFighter fighter, Color color) {
|
||||
private void drawHitbox(SimpleFighter fighter, Color color) {
|
||||
shapeRenderer.setColor(color);
|
||||
Rectangle r = fighter.getHitbox();
|
||||
shapeRenderer.rect(r.x, r.y, r.width, r.height);
|
||||
}
|
||||
|
||||
private void renderAttackBox(SimpleFighter fighter, Color color) {
|
||||
shapeRenderer.setColor(color);
|
||||
Rectangle a = fighter.getAttackbox();
|
||||
shapeRenderer.rect(a.x, a.y, a.width, a.height);
|
||||
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);
|
||||
}
|
||||
|
||||
// private void checkPlayerAttacks() {
|
||||
// if (!player.isAttacking()) return;
|
||||
// if (!player.isAttacking()) return;
|
||||
|
||||
// for (SimpleFighter target : otherPlayers.values()) {
|
||||
// if (target.isAlive() && player.getAttackbox().overlaps(target.getHitbox())) {
|
||||
// target.takeHit(player.getAttackPower()); // 使用访问器方法
|
||||
// System.out.println("命中远程玩家:" + target.getName());
|
||||
// }
|
||||
// }
|
||||
// for (SimpleFighter target : otherPlayers.values()) {
|
||||
// if (target.isAlive() && player.getAttackbox().overlaps(target.getHitbox())) {
|
||||
// target.takeHit(player.getAttackPower()); // 使用访问器方法
|
||||
// System.out.println("命中远程玩家:" + target.getName());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,10 +33,10 @@ public class StartScreen implements Screen {
|
||||
public void render(float delta) {
|
||||
deltaSum += delta;
|
||||
|
||||
if (deltaSum >= 3.0F) {
|
||||
if (deltaSum >= .01F) {
|
||||
if (mainGame != null) {
|
||||
mainGame.showGameScreen();
|
||||
System.out.println("已经切换到主菜单");
|
||||
System.out.println("已经切换到主菜单");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
package uno.mloluyu.versatile;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
|
||||
/**
|
||||
* 按钮资源管理类:统一管理按钮枚举和图集资源
|
||||
*/
|
||||
public class ButtonActions {
|
||||
|
||||
private static TextureAtlas atlas;
|
||||
|
||||
// 初始化图集(建议在游戏启动或Screen加载时调用一次)
|
||||
public static void loadAtlas(String atlasPath) {
|
||||
if (atlas == null) {
|
||||
atlas = new TextureAtlas(Gdx.files.internal(atlasPath));
|
||||
}
|
||||
}
|
||||
|
||||
// 获取图集区域
|
||||
public static TextureRegion getRegion(Button button) {
|
||||
if (atlas == null) {
|
||||
throw new IllegalStateException("按钮图集尚未加载,请先调用 ButtonActions.loadAtlas()");
|
||||
}
|
||||
TextureRegion region = atlas.findRegion(button.getRegionName());
|
||||
if (region == null) {
|
||||
throw new IllegalArgumentException("图集中未找到区域: " + button.getRegionName());
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
// 释放资源(建议在Screen dispose时调用)
|
||||
public static void dispose() {
|
||||
if (atlas != null) {
|
||||
atlas.dispose();
|
||||
atlas = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按钮枚举:统一定义所有按钮区域名
|
||||
*/
|
||||
public enum Button {
|
||||
CONFIRM("confirm"), // 确认按钮
|
||||
BACK("back"), // 返回按钮
|
||||
WARRIOR("warrior"), // 战士角色按钮
|
||||
MAGE("mage"), // 法师角色按钮
|
||||
ARCHER("archer"); // 弓箭手角色按钮
|
||||
|
||||
private final String regionName;
|
||||
|
||||
Button(String regionName) {
|
||||
this.regionName = regionName;
|
||||
}
|
||||
|
||||
public String getRegionName() {
|
||||
return regionName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,36 +29,42 @@ public class FighterController extends InputAdapter {
|
||||
return;
|
||||
|
||||
for (int keycode : pressedKeys) {
|
||||
fighter.handleInput(keycode, true); // 持续按下的键
|
||||
float currentDuration = keyPressDuration.getOrDefault(keycode, 0f);
|
||||
currentDuration += deltaTime;
|
||||
keyPressDuration.put(keycode, currentDuration);
|
||||
fighter.handleInput(keycode, true, currentDuration); // 持续按下的键,传递持续时间
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyDown(int keycode) {
|
||||
// System.out.println("按键按下: " + keycode);
|
||||
if (fighter == null)
|
||||
return false;
|
||||
|
||||
if (!pressedKeys.contains(keycode, false)) {
|
||||
pressedKeys.add(keycode);
|
||||
keyPressDuration.put(keycode, 0f); // 初始化按键持续时间
|
||||
}
|
||||
|
||||
fighter.handleInput(keycode, true); // 按下事件
|
||||
fighter.handleInput(keycode, true, 0f); // 按下事件,初始持续时间为 0
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyUp(int keycode) {
|
||||
if (fighter == null)
|
||||
return false;
|
||||
@Override
|
||||
public boolean keyUp(int keycode) {
|
||||
// System.out.println("按键松开: " + keycode);
|
||||
|
||||
float duration = keyPressDuration.getOrDefault(keycode, 0f);
|
||||
pressedKeys.removeValue(keycode, false);
|
||||
keyPressDuration.remove(keycode);
|
||||
if (fighter == null)
|
||||
return false;
|
||||
|
||||
// 传给角色:按键松开 + 按下时长
|
||||
fighter.handleRelease(keycode, duration);
|
||||
return true;
|
||||
}//松开事件
|
||||
float duration = keyPressDuration.getOrDefault(keycode, 0f);
|
||||
pressedKeys.removeValue(keycode, false);
|
||||
keyPressDuration.remove(keycode);
|
||||
|
||||
fighter.handleInput(keycode, false, duration); // 按键松开事件,传递持续时间
|
||||
return true;
|
||||
}// 松开事件
|
||||
|
||||
public SimpleFighter getFighter() {
|
||||
return fighter;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,13 +1,3 @@
|
||||
uno\mloluyu\network\ConnectServer$1$1.class
|
||||
uno\mloluyu\network\ConnectServer$1.class
|
||||
uno\mloluyu\network\CreateServer$1.class
|
||||
uno\mloluyu\characters\FighterList.class
|
||||
uno\mloluyu\network\CreateServer.class
|
||||
uno\mloluyu\desktop\Launcher.class
|
||||
uno\mloluyu\characters\Fighter$Action.class
|
||||
uno\mloluyu\desktop\GameCore.class
|
||||
uno\mloluyu\characters\Fighter.class
|
||||
uno\mloluyu\characters\Alice.class
|
||||
uno\mloluyu\Controller\FighterController.class
|
||||
uno\mloluyu\network\ConnectServer.class
|
||||
uno\mloluyu\characters\character\Fighter$1.class
|
||||
uno\mloluyu\util\SimpleFormatter.class
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\characters\Alice.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\characters\Fighter.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\characters\FighterList.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\Controller\FighterController.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\desktop\GameCore.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\desktop\Launcher.java
|
||||
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\AdvancedFighter.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\characters\character\Action.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\characters\character\Alice.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\characters\character\Fighter.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\characters\character\FighterAnimationManager.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\characters\character\FighterList.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\characters\character\Reimu.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\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\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\CreateServer.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\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\SimpleFormatter.java
|
||||
C:\Users\www\Documents\Game\Game\src\main\java\uno\mloluyu\versatile\FighterController.java
|
||||
|
||||
BIN
target/original-game-1.0-SNAPSHOT.jar
Normal file
BIN
target/original-game-1.0-SNAPSHOT.jar
Normal file
Binary file not shown.
Reference in New Issue
Block a user