移动和待机动画

This commit is contained in:
2025-09-19 15:36:50 +08:00
parent ffaa54b339
commit 566d570074
6 changed files with 143 additions and 52 deletions

View File

@@ -16,11 +16,16 @@ public class GameCore implements ApplicationListener {
@Override
public void create() {
alice1.create();
}
@Override
public void render() {
Gdx.gl.glClearColor(150, 150, 150, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
alice1.update(Gdx.graphics.getDeltaTime());
alice1.render();
}

View File

@@ -1,112 +1,179 @@
package uno.mloluyu.desktop.character;
import uno.mloluyu.util.SimpleFormatter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
public class Alice {
private SpriteBatch batch;
private Sprite playerSprite;
private Texture playerTexture;
private Animation<TextureRegion> walkAnimation; // 行走动画
private Animation<TextureRegion> idleAnimation; // idle动画
private TextureRegion currentFrame; // 当前显示的帧
private float stateTime; // 动画播放时间
private String path = "character/alice/";
private String textureFileName = "attackAa000.png";
private final float MOVEMENT_SPEED = 200f;
private Vector2 position;
private float width; // 角色宽度
private float height; // 角色高度
private boolean isMoving = false; // 是否在移动
private boolean isFacingRight = true; // 是否面朝右
public void create(){
public void create() {
batch = new SpriteBatch();
// 验证文件是否存在
String fullPath = path + textureFileName;
if (!Gdx.files.internal(fullPath).exists()) {
Gdx.app.error("Alice", "图片文件不存在: " + fullPath);
Gdx.app.error("Alice", "请检查文件是否放在 assets/" + fullPath);
return;
}
try {
// 加载纹理并添加错误处理
playerTexture = new Texture(Gdx.files.internal(fullPath));
Gdx.app.log("Alice", "成功加载纹理: " + fullPath);
} catch (Exception e) {
Gdx.app.error("Alice", "加载纹理失败: " + e.getMessage());
e.printStackTrace();
return;
}
// 从纹理创建精灵
playerSprite = new Sprite(playerTexture);
// 初始化位置向量
position = new Vector2();
setSpriteToCenter(playerSprite);
// 设置精灵的原点为中心
playerSprite.setOriginCenter();
// 加载动画帧
loadAnimations();
// 初始化位置(屏幕中心)
setToCenter();
}
private void setSpriteToCenter(Sprite sprite) {
if (sprite == null) return; // 防止空指针
float x = (Gdx.graphics.getWidth() - sprite.getWidth()) / 2f;
float y = (Gdx.graphics.getHeight() - sprite.getHeight()) / 2f;
sprite.setPosition(x, y);
/**
* 加载动画帧序列
*/
private void loadAnimations() {
try {
// 1. 加载静止动画
Array<TextureRegion> idleFrames = new Array<>();
for (int i = 0; i < 16; i++) {
Texture texture = new Texture(Gdx.files.internal(path + "stand" + SimpleFormatter.addLeadingZeros(i,3) + ".png")); //文件路径
System.out.println(texture);
idleFrames.add(new TextureRegion(texture));
}
idleAnimation = new Animation<>(0.1f, idleFrames, Animation.PlayMode.LOOP); // 每帧时间
// 2. 加载行走动画
Array<TextureRegion> walkFrames = new Array<>();
for (int i = 0; i < 5; i++) {
Texture texture = new Texture(Gdx.files.internal(path + "walkFront" + SimpleFormatter.addLeadingZeros(i,3) + ".png"));
System.out.println("调试代码"+texture);
walkFrames.add(new TextureRegion(texture));
}
walkAnimation = new Animation<>(0.1f, walkFrames, Animation.PlayMode.LOOP);
// 设置角色尺寸
width = idleFrames.get(0).getRegionWidth();
height = idleFrames.get(0).getRegionHeight();
Gdx.app.log("Alice", "动画加载成功");
} catch (Exception e) {
Gdx.app.error("Alice", "动画加载失败: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 设置角色到屏幕中心
*/
private void setToCenter() {
float x = (Gdx.graphics.getWidth() - width) / 2f;
float y = (Gdx.graphics.getHeight() - height) / 2f;
position.set(x, y);
}
/**
* 更新逻辑和动画
*/
public void update(float deltaTime) {
if (playerSprite == null) return; // 资源未加载则不更新
if (idleAnimation == null) return;
stateTime += deltaTime;
handleMovement(deltaTime);
if (isMoving) {
currentFrame = walkAnimation.getKeyFrame(stateTime);
} else {
currentFrame = idleAnimation.getKeyFrame(stateTime);
}
if ((isFacingRight && currentFrame.isFlipX()) ||
(!isFacingRight && !currentFrame.isFlipX())) {
currentFrame.flip(true, false);
}
}
/**
* 处理移动逻辑
*/
private void handleMovement(float deltaTime) {
float moveX = 0;
float moveY = 0;
isMoving = false;
// 方向键控制
if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
moveY += MOVEMENT_SPEED * deltaTime;
isMoving = true;
}
if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
moveY -= MOVEMENT_SPEED * deltaTime;
isMoving = true;
}
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
moveX += MOVEMENT_SPEED * deltaTime;
isMoving = true;
isFacingRight = true; // 朝右
}
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
moveX -= MOVEMENT_SPEED * deltaTime;
isMoving = true;
isFacingRight = false; // 朝左
}
// 更新位置并限制在屏幕内
position.add(moveX, moveY);
clampPosition();
playerSprite.setPosition(position.x, position.y);
}
/**
* 限制在屏幕范围内
*/
private void clampPosition() {
if (playerSprite == null) return;
float maxX = Gdx.graphics.getWidth() - playerSprite.getWidth();
float maxY = Gdx.graphics.getHeight() - playerSprite.getHeight();
float maxX = Gdx.graphics.getWidth() - width;
float maxY = Gdx.graphics.getHeight() - height;
position.x = Math.max(0, Math.min(position.x, maxX));
position.y = Math.max(0, Math.min(position.y, maxY));
}
/**
* 渲染角色和动画
*/
public void render() {
if (batch == null || playerSprite == null) return; // 资源未准备好则不渲染
if (batch == null || currentFrame == null) return;
batch.begin();
playerSprite.draw(batch);
batch.draw(currentFrame, position.x, position.y);
batch.end();
}
/**
* 释放资源
*/
public void dispose() {
if (batch != null) {
batch.dispose();
batch = null;
}
if (playerTexture != null) {
playerTexture.dispose();
playerTexture = null;
if (idleAnimation != null) {
for (TextureRegion region : idleAnimation.getKeyFrames()) {
region.getTexture().dispose();
}
}
if (walkAnimation != null) {
for (TextureRegion region : walkAnimation.getKeyFrames()) {
region.getTexture().dispose();
}
}
playerSprite = null;
}
}

View File

@@ -0,0 +1,19 @@
package uno.mloluyu.util;
public class SimpleFormatter {
/**
* 简化版:数字补前导零
* @param number 要格式化的数字如1, 10
* @param digits 保留的位数如3位
* @return 带前导零的字符串1→"001"10→"010"
*/
public static String addLeadingZeros(int number, int digits) {
return String.format("%0" + digits + "d", number);
}
// 测试
public static void main(String[] args) {
for (int i = 1; i <= 15; i++) {
System.out.println(addLeadingZeros(i, 3));
}
}
}

Binary file not shown.