Merge remote-tracking branch 'origin/test' into test
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user