Merge remote-tracking branch 'origin/master'
# Conflicts: # src/main/java/uno/mloluyu/characters/Alice.java # src/main/java/uno/mloluyu/desktop/GameCore.java # src/main/java/uno/mloluyu/desktop/Launcher.java # target/classes/uno/mloluyu/characters/Alice.class # target/classes/uno/mloluyu/characters/Fighter$Action.class # target/classes/uno/mloluyu/characters/Fighter.class # target/classes/uno/mloluyu/desktop/GameCore.class # target/classes/uno/mloluyu/desktop/Launcher.class
16
pom.xml
@@ -10,6 +10,14 @@
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<gdx.version>1.12.1</gdx.version>
|
||||
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -29,7 +37,6 @@
|
||||
<classifier>natives-desktop</classifier>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
@@ -72,10 +79,5 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<gdx.version>1.12.1</gdx.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
||||
127
src/main/java/uno/mloluyu/Controller/FighterController.java
Normal file
@@ -0,0 +1,127 @@
|
||||
package uno.mloluyu.Controller;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.InputAdapter;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import uno.mloluyu.characters.Fighter;
|
||||
|
||||
/**
|
||||
* 角色控制器,处理玩家输入并映射到角色动作
|
||||
*/
|
||||
public class FighterController extends InputAdapter {
|
||||
private final Fighter fighter;
|
||||
private final Array<Integer> pressedKeys = new Array<>();
|
||||
|
||||
// 输入缓冲时间(防止快速按键导致的重复触发)
|
||||
private static final float INPUT_DELAY = 0.2f;
|
||||
private float attackCooldown = 0;
|
||||
private float jumpCooldown = 0;
|
||||
|
||||
public FighterController(Fighter fighter) {
|
||||
this.fighter = fighter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新控制器状态和冷却时间
|
||||
* @param deltaTime 帧间隔时间
|
||||
*/
|
||||
public void update(float deltaTime) {
|
||||
// 更新冷却时间
|
||||
if (attackCooldown > 0) attackCooldown -= deltaTime;
|
||||
if (jumpCooldown > 0) jumpCooldown -= deltaTime;
|
||||
|
||||
// 处理移动输入
|
||||
handleMovement();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理移动输入
|
||||
*/
|
||||
private void handleMovement() {
|
||||
float moveX = 0;
|
||||
|
||||
// 左右移动控制(支持方向键和WSAD)
|
||||
if (isKeyPressed(Input.Keys.RIGHT) || isKeyPressed(Input.Keys.D)) {
|
||||
moveX += 1;
|
||||
}
|
||||
if (isKeyPressed(Input.Keys.LEFT) || isKeyPressed(Input.Keys.A)) {
|
||||
moveX -= 1;
|
||||
}
|
||||
|
||||
// 调用角色移动方法
|
||||
fighter.move(moveX, Gdx.graphics.getDeltaTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理按键按下事件
|
||||
*/
|
||||
@Override
|
||||
public boolean keyDown(int keycode) {
|
||||
if (!pressedKeys.contains(keycode, false)) {
|
||||
pressedKeys.add(keycode);
|
||||
}
|
||||
|
||||
// 普通攻击(Z键或J键)
|
||||
if ((keycode == Input.Keys.Z || keycode == Input.Keys.J) && attackCooldown <= 0) {
|
||||
fighter.attack(1);
|
||||
attackCooldown = INPUT_DELAY;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 第二攻击(X键或K键)
|
||||
if ((keycode == Input.Keys.X || keycode == Input.Keys.K) && attackCooldown <= 0) {
|
||||
fighter.attack(2);
|
||||
attackCooldown = INPUT_DELAY;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 跳跃(空格、上方向键或W键)
|
||||
if ((keycode == Input.Keys.SPACE || keycode == Input.Keys.UP || keycode == Input.Keys.W) && jumpCooldown <= 0) {
|
||||
// 这里假设你已经实现了跳跃方法
|
||||
// fighter.jump();
|
||||
jumpCooldown = INPUT_DELAY;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 防御(左Shift或右Shift)
|
||||
if (keycode == Input.Keys.SHIFT_LEFT || keycode == Input.Keys.SHIFT_RIGHT) {
|
||||
fighter.changeAction(Fighter.Action.DEFEND);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理按键释放事件
|
||||
*/
|
||||
@Override
|
||||
public boolean keyUp(int keycode) {
|
||||
pressedKeys.removeValue(keycode, false);
|
||||
|
||||
// 释放防御键时恢复到 idle 状态
|
||||
if ((keycode == Input.Keys.SHIFT_LEFT || keycode == Input.Keys.SHIFT_RIGHT) &&
|
||||
fighter.getCurrentAction() == Fighter.Action.DEFEND) {
|
||||
fighter.changeAction(Fighter.Action.IDLE);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查按键是否处于按下状态
|
||||
*/
|
||||
private boolean isKeyPressed(int keycode) {
|
||||
return pressedKeys.contains(keycode, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前控制的角色
|
||||
*/
|
||||
public Fighter getFighter() {
|
||||
return fighter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
package uno.mloluyu.characters;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
|
||||
/**
|
||||
* 角色类,继承自Fighter父类
|
||||
*/
|
||||
public class Alice extends Fighter {
|
||||
private TextureAtlas atlas;
|
||||
|
||||
public Alice(TextureAtlas atlas) {
|
||||
super(atlas);
|
||||
public Alice() {
|
||||
super(new TextureAtlas(Gdx.files.internal("src\\main\\resources\\character\\alice\\精灵1.2.atlas")));
|
||||
speed = 350f; // 速度更快
|
||||
maxHealth = 90; // 生命值较低
|
||||
health = maxHealth;
|
||||
attackPower = 12; // 攻击力中等
|
||||
name = "alice";
|
||||
attackPower = 12; // 攻击力中等\
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -30,6 +32,7 @@ public class Alice extends Fighter {
|
||||
loadAnimationFromAtlas(Action.HIT, "hitSpin/hitSpin", 5, false);
|
||||
|
||||
// 为特定动作设置帧间隔
|
||||
setFrameDuration(Action.IDLE, 0.04f);
|
||||
setFrameDuration(Action.WALK, 0.08f); // 行走更快
|
||||
setFrameDuration(Action.ATTACK1, 0.07f); // 攻击更快
|
||||
setFrameDuration(Action.SPECIAL2, 0.06f); // 特殊技能2非常快
|
||||
@@ -54,8 +57,4 @@ public class Alice extends Fighter {
|
||||
protected boolean canAttack() {
|
||||
return super.canAttack() || currentAction == Action.JUMP || currentAction == Action.FALL;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
117
src/main/java/uno/mloluyu/characters/AliceAnimationTest.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package uno.mloluyu.characters;
|
||||
|
||||
import com.badlogic.gdx.ApplicationAdapter;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.utils.viewport.FitViewport;
|
||||
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||
|
||||
import uno.mloluyu.characters.Alice;
|
||||
import uno.mloluyu.characters.Fighter;
|
||||
|
||||
public class AliceAnimationTest extends ApplicationAdapter {
|
||||
|
||||
private SpriteBatch batch;
|
||||
private OrthographicCamera camera;
|
||||
private Viewport viewport;
|
||||
|
||||
private Alice alice;
|
||||
|
||||
private float stateTimer; // 用于切换动作测试
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
// 初始化相机和批处理
|
||||
camera = new OrthographicCamera();
|
||||
viewport = new FitViewport(800, 600, camera);
|
||||
batch = new SpriteBatch();
|
||||
|
||||
// 创建 Alice 实例
|
||||
alice = new Alice();
|
||||
|
||||
// 初始位置
|
||||
alice.getHitbox().setPosition(
|
||||
viewport.getWorldWidth() / 2 - alice.getHitbox().width / 2,
|
||||
viewport.getWorldHeight() / 2 - alice.getHitbox().height / 2
|
||||
);
|
||||
|
||||
stateTimer = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
// 清屏
|
||||
Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// 更新状态时间
|
||||
float delta = Gdx.graphics.getDeltaTime();
|
||||
stateTimer += delta;
|
||||
|
||||
// 控制 Alice 执行不同动作,测试动画切换
|
||||
controlAliceActions();
|
||||
|
||||
// 更新 Alice
|
||||
alice.update(delta);
|
||||
|
||||
// 绘制
|
||||
batch.setProjectionMatrix(camera.combined);
|
||||
batch.begin();
|
||||
alice.render(batch);
|
||||
batch.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动切换 Alice 动作,测试各种动画
|
||||
*/
|
||||
private void controlAliceActions() {
|
||||
// 每2秒切换一个动作
|
||||
if (stateTimer < 2) {
|
||||
alice.changeAction(Fighter.Action.IDLE);
|
||||
} else if (stateTimer < 4) {
|
||||
alice.move(1, Gdx.graphics.getDeltaTime()); // 向右走
|
||||
} else if (stateTimer < 6) {
|
||||
alice.changeAction(Fighter.Action.JUMP);
|
||||
} else if (stateTimer < 8) {
|
||||
alice.attack(1); // 普通攻击1
|
||||
} else if (stateTimer < 10) {
|
||||
alice.attack(2); // 普通攻击2
|
||||
} else if (stateTimer < 12) {
|
||||
alice.attack(3); // 普通攻击3
|
||||
} else if (stateTimer < 14) {
|
||||
alice.takeHit(10); // 受击
|
||||
} else {
|
||||
// 循环
|
||||
stateTimer = 0;
|
||||
alice.getHitbox().setPosition(
|
||||
viewport.getWorldWidth() / 2 - alice.getHitbox().width / 2,
|
||||
viewport.getWorldHeight() / 2 - alice.getHitbox().height / 2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height) {
|
||||
viewport.update(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
batch.dispose();
|
||||
alice.dispose();
|
||||
}
|
||||
|
||||
// 直接运行这个 main 方法即可启动测试
|
||||
// public static void main(String[] args) {
|
||||
// Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
|
||||
// config.setTitle("Alice Animation Test");
|
||||
// config.setWindowedMode(800, 600);
|
||||
// config.setForegroundFPS(60);
|
||||
// config.useVsync(true);
|
||||
// new Lwjgl3Application(new AliceAnimationTest(), config);
|
||||
// }
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package uno.mloluyu.characters;
|
||||
|
||||
import uno.mloluyu.util.SimpleFormatter;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.g2d.Animation;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
@@ -13,7 +15,6 @@ import com.badlogic.gdx.utils.Disposable;
|
||||
* 格斗角色父类,封装所有角色共有的动画和状态管理逻辑
|
||||
*/
|
||||
public abstract class Fighter implements Disposable {
|
||||
// 动作类型枚举 - 所有角色共用的基础动作
|
||||
public enum Action {
|
||||
IDLE, WALK, JUMP, FALL,
|
||||
ATTACK1, ATTACK2, ATTACK3, ATTACK4,
|
||||
@@ -23,7 +24,7 @@ public abstract class Fighter implements Disposable {
|
||||
}
|
||||
protected String name;
|
||||
|
||||
// 动画帧间隔(秒)
|
||||
// 画帧间隔(秒)
|
||||
protected static final float DEFAULT_FRAME_DURATION = 0.1f;
|
||||
protected float[] frameDurations;
|
||||
|
||||
@@ -48,38 +49,35 @@ public abstract class Fighter implements Disposable {
|
||||
|
||||
// 精灵图表
|
||||
protected TextureAtlas atlas;
|
||||
// 缩放比例
|
||||
protected float scaleX = 1.0f;
|
||||
protected float scaleY = 1.0f;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Fighter(TextureAtlas atlas) {
|
||||
this.atlas = atlas;
|
||||
int actionCount = Action.values().length;
|
||||
|
||||
// 初始化动画数组和帧间隔数组
|
||||
animations = new Animation[actionCount];
|
||||
frameDurations = new float[actionCount];
|
||||
|
||||
// 设置默认帧间隔
|
||||
for (int i = 0; i < actionCount; i++) {
|
||||
frameDurations[i] = DEFAULT_FRAME_DURATION;
|
||||
}
|
||||
|
||||
// 初始化碰撞框
|
||||
hitbox = new Rectangle(0, 0, 64, 128);
|
||||
attackbox = new Rectangle(0, 0, 80, 80);
|
||||
|
||||
// 初始化默认属性(子类可以重写)
|
||||
speed = 300f;
|
||||
maxHealth = 100;
|
||||
health = maxHealth;
|
||||
attackPower = 10;
|
||||
|
||||
// 初始状态
|
||||
isFacingRight = true;
|
||||
currentAction = Action.IDLE;
|
||||
stateTime = 0;
|
||||
isAnimationFinished = false;
|
||||
|
||||
// 加载动画(由子类实现具体的动画帧)
|
||||
loadAnimations();
|
||||
}
|
||||
|
||||
@@ -98,25 +96,33 @@ public abstract class Fighter implements Disposable {
|
||||
*/
|
||||
protected void loadAnimationFromAtlas(Action action, String regionPrefix,
|
||||
int frameCount, boolean loop) {
|
||||
if (atlas == null) {
|
||||
throw new IllegalStateException("TextureAtlas 未初始化!");
|
||||
}
|
||||
if (frameCount <= 0) {
|
||||
throw new IllegalArgumentException("帧数必须大于0: " + frameCount);
|
||||
}
|
||||
|
||||
if (frameDurations == null || frameDurations.length <= action.ordinal()) {
|
||||
throw new IllegalStateException("frameDurations 未初始化或大小不足");
|
||||
}
|
||||
|
||||
Array<TextureRegion> frames = new Array<>();
|
||||
|
||||
// 从精灵图表中获取所有帧
|
||||
for (int i = 0; i < frameCount; i++) {
|
||||
// 生成带三位前导零的序号(000, 001, 002...)
|
||||
String formattedIndex = SimpleFormatter.addLeadingZeros(i, 3);
|
||||
// 拼接完整的区域名称(如"stand/stand" + "000" → "stand/stand000")
|
||||
String regionName = regionPrefix + formattedIndex;
|
||||
|
||||
TextureRegion region = atlas.findRegion(regionName);
|
||||
|
||||
if (region == null) {
|
||||
throw new IllegalArgumentException("精灵图表中未找到区域: " + regionName);
|
||||
throw new IllegalArgumentException("精灵图表中未找到区域: " + regionName +
|
||||
" (前缀: " + regionPrefix + ", 索引: " + i + ")");
|
||||
}
|
||||
|
||||
frames.add(region);
|
||||
}
|
||||
|
||||
// 创建动画
|
||||
Animation<TextureRegion> animation = new Animation<>(
|
||||
frameDurations[action.ordinal()],
|
||||
frames);
|
||||
@@ -130,7 +136,6 @@ public abstract class Fighter implements Disposable {
|
||||
protected void setFrameDuration(Action action, float duration) {
|
||||
frameDurations[action.ordinal()] = duration;
|
||||
|
||||
// 如果动画已加载,更新它
|
||||
if (animations[action.ordinal()] != null) {
|
||||
animations[action.ordinal()].setFrameDuration(duration);
|
||||
}
|
||||
@@ -143,10 +148,8 @@ public abstract class Fighter implements Disposable {
|
||||
stateTime += deltaTime;
|
||||
isAnimationFinished = animations[currentAction.ordinal()].isAnimationFinished(stateTime);
|
||||
|
||||
// 处理动画完成后的状态转换
|
||||
handleAnimationTransitions();
|
||||
|
||||
// 更新碰撞框位置
|
||||
updateHitboxes();
|
||||
}
|
||||
|
||||
@@ -156,7 +159,6 @@ public abstract class Fighter implements Disposable {
|
||||
protected void handleAnimationTransitions() {
|
||||
Animation<TextureRegion> currentAnim = animations[currentAction.ordinal()];
|
||||
|
||||
// 检查非循环动画是否已完成
|
||||
if (currentAnim.getPlayMode() != Animation.PlayMode.LOOP && isAnimationFinished) {
|
||||
switch (currentAction) {
|
||||
case ATTACK1:
|
||||
@@ -164,18 +166,14 @@ public abstract class Fighter implements Disposable {
|
||||
case ATTACK3:
|
||||
case SPECIAL1:
|
||||
case SPECIAL2:
|
||||
// 攻击动作完成后回到 idle
|
||||
changeAction(Action.IDLE);
|
||||
break;
|
||||
case HIT:
|
||||
// 受击后回到 idle
|
||||
changeAction(Action.IDLE);
|
||||
break;
|
||||
case JUMP:
|
||||
// 跳跃后进入下落状态
|
||||
changeAction(Action.FALL);
|
||||
break;
|
||||
// 其他默认转换逻辑
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,31 +182,62 @@ public abstract class Fighter implements Disposable {
|
||||
* 绘制角色
|
||||
*/
|
||||
public void render(SpriteBatch batch) {
|
||||
TextureRegion currentFrame = animations[currentAction.ordinal()].getKeyFrame(stateTime, true);
|
||||
|
||||
// 绘制角色,考虑方向翻转
|
||||
float x = hitbox.x;
|
||||
float y = hitbox.y;
|
||||
float width = hitbox.width;
|
||||
float height = hitbox.height;
|
||||
|
||||
if (isFacingRight) {
|
||||
batch.draw(currentFrame, x, y, width, height);
|
||||
} else {
|
||||
batch.draw(currentFrame, x + width, y, -width, height);
|
||||
Animation<TextureRegion> currentAnimation = animations[currentAction.ordinal()];
|
||||
if (currentAnimation == null) {
|
||||
Gdx.app.error("Fighter", "动画未初始化: " + currentAction);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean loop = currentAnimation.getPlayMode() == Animation.PlayMode.LOOP;
|
||||
TextureRegion currentFrame = currentAnimation.getKeyFrame(stateTime, loop);
|
||||
|
||||
if (currentFrame == null) {
|
||||
Gdx.app.error("Fighter", "动画帧为空: " + currentAction);
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 计算缩放后的帧尺寸(保持原始比例)
|
||||
float frameWidth = currentFrame.getRegionWidth() * scaleX;
|
||||
float frameHeight = currentFrame.getRegionHeight() * scaleY;
|
||||
|
||||
// 2. 计算绘制位置:始终以hitbox为基准,水平居中、底部对齐(关键!)
|
||||
// 无论是否翻转,x/y坐标都基于hitbox计算,保证位置锚点一致
|
||||
float drawX = hitbox.x + (hitbox.width - frameWidth) / 2; // 水平居中(hitbox中心和帧中心对齐)
|
||||
float drawY = hitbox.y; // 底部对齐(hitbox底部和帧底部对齐)
|
||||
|
||||
// 3. 处理翻转:用TextureRegion的flip方法,避免手动偏移x坐标
|
||||
// 先记录原始flip状态(防止影响其他地方复用该帧)
|
||||
boolean wasFlippedX = currentFrame.isFlipX();
|
||||
// 根据朝向设置翻转(只翻转X轴,Y轴不变)
|
||||
currentFrame.flip(!isFacingRight && !wasFlippedX, false); // 正向→不翻,反向→翻
|
||||
currentFrame.flip(isFacingRight && wasFlippedX, false); // 修复原始已翻转的情况
|
||||
|
||||
// 4. 绘制:缩放中心为帧的中心,确保翻转/旋转时围绕自身中心
|
||||
batch.draw(
|
||||
currentFrame,
|
||||
drawX, // 绘制X(基于hitbox的居中位置,固定不变)
|
||||
drawY, // 绘制Y(基于hitbox的底部,固定不变)
|
||||
frameWidth / 2, // 缩放/旋转中心X(帧的中心)
|
||||
frameHeight / 2, // 缩放/旋转中心Y(帧的中心)
|
||||
frameWidth, // 缩放后的宽度(已乘scaleX)
|
||||
frameHeight, // 缩放后的高度(已乘scaleY)
|
||||
1f, // X轴额外缩放(这里已提前计算,设为1避免重复缩放)
|
||||
1f, // Y轴额外缩放(同上)
|
||||
0f // 旋转角度
|
||||
);
|
||||
|
||||
// 5. 恢复帧的原始flip状态(关键!避免影响后续绘制)
|
||||
currentFrame.flip(wasFlippedX != currentFrame.isFlipX(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 改变角色动作
|
||||
*/
|
||||
public boolean changeAction(Action newAction) {
|
||||
// 某些动作不能被打断
|
||||
if (isActionUninterruptible(currentAction)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果是新动作,重置状态时间
|
||||
if (currentAction != newAction) {
|
||||
currentAction = newAction;
|
||||
stateTime = 0;
|
||||
@@ -229,7 +258,6 @@ public abstract class Fighter implements Disposable {
|
||||
* 更新碰撞框位置
|
||||
*/
|
||||
protected void updateHitboxes() {
|
||||
// 根据角色朝向更新攻击框位置
|
||||
if (isFacingRight) {
|
||||
attackbox.setPosition(hitbox.x + hitbox.width - 10, hitbox.y + 20);
|
||||
} else {
|
||||
@@ -242,16 +270,12 @@ public abstract class Fighter implements Disposable {
|
||||
*/
|
||||
public void move(float x, float deltaTime) {
|
||||
if (x != 0) {
|
||||
// 改变朝向
|
||||
isFacingRight = x > 0;
|
||||
|
||||
// 移动位置
|
||||
hitbox.x += x * speed * deltaTime;
|
||||
|
||||
// 处理移动状态转换
|
||||
handleMoveState();
|
||||
} else if (currentAction == Action.WALK) {
|
||||
// 如果停止移动且当前是行走状态,切换到 idle
|
||||
changeAction(Action.IDLE);
|
||||
}
|
||||
}
|
||||
@@ -260,7 +284,6 @@ public abstract class Fighter implements Disposable {
|
||||
* 处理移动状态转换,子类可重写
|
||||
*/
|
||||
protected void handleMoveState() {
|
||||
// 如果不是攻击或特殊动作,切换到行走动画
|
||||
if (currentAction != Action.ATTACK1 && currentAction != Action.ATTACK2 &&
|
||||
currentAction != Action.ATTACK3 && currentAction != Action.SPECIAL1 &&
|
||||
currentAction != Action.SPECIAL2 && currentAction != Action.JUMP &&
|
||||
@@ -273,7 +296,6 @@ public abstract class Fighter implements Disposable {
|
||||
* 执行攻击
|
||||
*/
|
||||
public boolean attack(int attackType) {
|
||||
// 只能在允许攻击的状态下攻击
|
||||
if (!canAttack()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3,58 +3,44 @@ package uno.mloluyu.desktop;
|
||||
import com.badlogic.gdx.ApplicationListener;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
|
||||
import com.badlogic.gdx.utils.viewport.ExtendViewport;
|
||||
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||
import uno.mloluyu.Controller.FighterController;
|
||||
import uno.mloluyu.characters.Alice;
|
||||
import uno.mloluyu.characters.FighterList;
|
||||
|
||||
public class GameCore implements ApplicationListener {
|
||||
private SpriteBatch batch;
|
||||
private Viewport viewport;
|
||||
private Gaming gaming;
|
||||
private Texture texture;
|
||||
private Alice alice1;
|
||||
private FighterController controller;
|
||||
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
viewport = new ExtendViewport(Launcher.width, Launcher.width);
|
||||
texture = new Texture(Gdx.files.internal("src\\main\\resources\\backgrounds\\bg.png"));
|
||||
batch = new SpriteBatch();
|
||||
gaming = new Gaming(new Alice(FighterList.aliceAtlas), new Alice(FighterList.aliceAtlas));
|
||||
gaming.create();
|
||||
alice1= new Alice();
|
||||
controller = new FighterController(alice1);
|
||||
Gdx.input.setInputProcessor(controller);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
Gdx.gl.glClearColor(150, 150, 150, 1);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
viewport.apply();
|
||||
|
||||
alice1.update(Gdx.graphics.getDeltaTime());
|
||||
controller.update(Gdx.graphics.getDeltaTime());
|
||||
batch.begin();
|
||||
batch.draw(texture, 0, 0);
|
||||
// alice1.update(Gdx.graphics.getDeltaTime());
|
||||
// batch.begin();
|
||||
// alice1.render(batch);
|
||||
// batch.end();
|
||||
gaming.render();
|
||||
alice1.render(batch);
|
||||
batch.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
gaming.dispose();
|
||||
alice1.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height) {
|
||||
float screenAspectRatio = (float) width / (float) height;
|
||||
|
||||
float newWorldWidth = Launcher.height * screenAspectRatio;
|
||||
float newWorldHeight = Launcher.width / screenAspectRatio;
|
||||
|
||||
// 应用新的视口设置
|
||||
viewport.update((int)newWorldWidth, (int)newWorldHeight, true); // 第三个参数 true 表示相机居中
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
|
Before Width: | Height: | Size: 4.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
BIN
src/main/resources/character/alice/精灵1.2-0.png
Normal file
|
After Width: | Height: | Size: 5.0 MiB |
BIN
src/main/resources/character/alice/精灵1.2-1.png
Normal file
|
After Width: | Height: | Size: 5.2 MiB |
BIN
src/main/resources/character/alice/精灵1.2-2.png
Normal file
|
After Width: | Height: | Size: 3.9 MiB |
1078
src/main/resources/character/alice/精灵1.2.atlas
Normal file
BIN
src/main/resources/character/alice/精灵1.2.png
Normal file
|
After Width: | Height: | Size: 3.8 MiB |
|
Before Width: | Height: | Size: 4.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
BIN
target/classes/character/alice/精灵1.2-0.png
Normal file
|
After Width: | Height: | Size: 5.0 MiB |
BIN
target/classes/character/alice/精灵1.2-1.png
Normal file
|
After Width: | Height: | Size: 5.2 MiB |
BIN
target/classes/character/alice/精灵1.2-2.png
Normal file
|
After Width: | Height: | Size: 3.9 MiB |
1078
target/classes/character/alice/精灵1.2.atlas
Normal file
BIN
target/classes/character/alice/精灵1.2.png
Normal file
|
After Width: | Height: | Size: 3.8 MiB |