这是使用LibGdx构建游戏系列的第二部分。 在开始第二部分之前,请确保已阅读第一部分 。 以下文章将涉及很多内容,因此我将尝试将其分解为更易消化的大小。 我们离开了一个基本的世界,鲍勃在使用箭头键或触摸屏幕时来回滑动。 让我们为运动添加一些真实感,并在角色移动时对其进行动画处理。
角色动画
要为Bob制作动画,我们将使用最简单的技术,称为Sprite animation 。 动画无非是按设定的时间间隔显示的一系列图像以创建
运动的错觉。 以下图像序列用于创建正在运行的动画。
。 我通过多次玩Star Guard并分析其运行顺序来使用Gimp来创建运行角色。 创建动画非常简单。 我们要在一定时间内显示每一帧,然后切换到下一张图像。 当我们到达序列的结尾时,我们再次开始。 这称为循环 。 我们需要确定帧持续时间 ,即显示帧的时间。 假设我们以60 FPS渲染游戏,这意味着我们每1/60 = 0.016 s渲染一帧。 我们只有5帧可以动画整步。 考虑到典型的运动员节奏为180,我们可以计算出每个帧显示多少时间才能使跑步更加逼真。
跑步的数学
节奏为180表示每分钟180步。 要计算每秒的步数,我们有180/60 =3。因此,我们每秒必须采取3步。 我们的5帧构成了整整一个步骤,因此我们需要每秒显示3 * 5 = 15帧以模拟职业运动员的跑步情况。 顺便说一下,这不是冲刺。 我们的帧持续时间将是1/15 = 0.066秒。 那是66毫秒。
优化图像
在将其添加到游戏中之前,我们将优化图像。 目前,该项目在star-assault-android
项目中的assets/images
目录下将图像作为单独的png文件assets/images
。 我们目前正在使用block.png
和bob_01.png
。 还有更多图像,即bob_02 - 06.png
。 这些图像组成了动画序列。 因为libgdx在后台使用OpenGL,所以最好不要给框架提供大量图像作为纹理来使用。 我们将要做的是创建一个所谓的Texture Atlas
。 纹理图集只是一个足以容纳其上所有图像的图像,并且它具有一个描述符,其中包含每个单独图像的名称,在图集中的位置和大小。 单个图像在地图集中称为区域 。 它有很多图像,图集可以有多个页面 。 每个页面都作为单一图像加载到内存中,并且这些区域用作单独的图像。 不需要了解所有这一切,但这会使应用程序更加优化,加载速度更快,运行更流畅。 Libgdx具有一个名为TexturePacker2的实用程序来创建这些地图集。 它可以从命令行运行或以编程方式使用。 要从Java运行它,请使用以下程序:
package net.obviam.starassault.utils;
import com.badlogic.gdx.tools.imagepacker.TexturePacker2;
public class TextureSetup {
public static void main(String[] args) {
TexturePacker2.process('/path-to-star-guard-assets-images/', 'path-to-star-guard-assets-images', 'textures.pack');
}
}
确保将gdx-tools.jar
添加到您的libs
目录中。 更改process
方法的属性,使其指向资产所在的目录。
注意:
另外,还要对包含下划线“ _”字符的文件进行重命名,因为TexturePacker2会将其用作定界符,而我们目前不需要。 将下划线字符替换为连字符“-”。 处理目录中的图像应生成2个文件: textures.png
和textures.pack
。 纹理图集应类似于下图
现在我们已经确定了动画的效果,帧持续时间并优化了资源,让我们将其添加到游戏中。 我们将首先修改Bob.java
因为这是最小的位
public class Bob {
// ... omitted ... //
float stateTime = 0;
// ... omitted ... //
public void update(float delta) {
stateTime += delta;
position.add(velocity.tmp().mul(delta));
}
}
我们添加了一个名为stateTime
的属性。 这将跟踪Bob在特定状态下的时间。 我们将使用它来提供Bob在游戏中花费的时间。 动画确定要显示的帧很重要。 现在不用担心。 如果您真的想了解,请将动画的每个帧都视为一个状态。 鲍勃经历了state_frame_1,state_frame_2等。 这些状态中的每个状态持续0.066秒。 一旦状态时间超过0.066秒,Bob便进入下一个状态。 动画类知道要为当前状态显示的图像。 也称为关键帧 。 WorldRenderer.java
遭受的更改最多。 以下代码段包含所有更改。
public class WorldRenderer {
// ... omitted ... //
private static final float RUNNING_FRAME_DURATION = 0.06f;
/** Textures **/
private TextureRegion bobIdleLeft;
private TextureRegion bobIdleRight;
private TextureRegion blockTexture;
private TextureRegion bobFrame;
/** Animations **/
private Animation walkLeftAnimation;
private Animation walkRightAnimation;
// ... omitted ... //
private void loadTextures() {
TextureAtlas atlas = new TextureAtlas(Gdx.files.internal('images/textures/textures.pack'));
bobIdleLeft = atlas.findRegion('bob-01');
bobIdleRight = new TextureRegion(bobIdleLeft);
bobIdleRight.flip(true, false);
blockTexture = atlas.findRegion('block');
TextureRegion[] walkLeftFrames = new TextureRegion[5];
for (int i = 0; i < 5; i++) {
walkLeftFrames[i] = atlas.findRegion('bob-0' + (i + 2));
}
walkLeftAnimation = new Animation(RUNNING_FRAME_DURATION, walkLeftFrames);
TextureRegion[] walkRightFrames = new TextureRegion[5];
for (int i = 0; i < 5; i++) {
walkRightFrames[i] = new TextureRegion(walkLeftFrames[i]);
walkRightFrames[i].flip(true, false);
}
walkRightAnimation = new Animation(RUNNING_FRAME_DURATION, walkRightFrames);
}
private void drawBob() {
Bob bob = world.getBob();
bobFrame = bob.isFacingLeft() ? bobIdleLeft : bobIdleRight;
if(bob.getState().equals(State.WALKING)) {
bobFrame = bob.isFacingLeft() ? walkLeftAnimation.getKeyFrame(bob.getStateTime(), true) : walkRightAnimation.getKeyFrame(bob.getStateTime(), true);
}
spriteBatch.draw(bobFrame, bob.getPosition().x * ppuX, bob.getPosition().y * ppuY, Bob.SIZE * ppuX, Bob.SIZE * ppuY);
}
// ... omitted ... //
}
#05 –声明RUNNING_FRAME_DURATION常数,该常数控制跑步/步行周期中帧的显示时间
#08 –#11 – Bob的不同状态的TextureRegion
。 bobFrame
–将保存将在当前循环中显示的区域。 #14-#15-两个Animation
对象,用于在行走/跑步时为Bob设置动画。
从TextureAtlas
加载图像
#19 –新的loadTextures()
方法
#20 –从内部文件中加载TextureAtlas。 这是TexturePacker2
的.pack
文件。 #21 –分配名为“ bob-01?”的区域 (这是不带扩展名的实际png名称-请参见TexturePacker2)到bobIdleLeft
变量。 #22 –#23 –创建一个新的TextureRegion
(注意使用副本构造函数,我们需要一个副本,而不是引用),并在X轴上翻转它,以便我们具有相同的图像,但针对Bob的空闲状态进行镜像,但是当面对右侧时。 翻转非常有用,因为我们不需要加载额外的图像,而是从现有图像中创建一个。 #24 –将相应区域分配给块 #25 –#28 –我们创建一个TextureRegion
数组,它们将组成动画。 我们知道有5个帧及其名称: bob-02, bob-03, bob-04, bob-05
和bob-06
。 为了方便起见,我们使用for循环。 #29 –在此处定义向左行走状态的动画。 第一个参数是序列中以秒(0.06)表示的序列中每个帧的持续时间,第二个参数采用组成动画的帧的有序列表。 #31 –#38 –为步行右状态创建动画。 它是左行走状态动画的副本,但每帧均被翻转。 重要的是要复制框架,而不要翻转框架,因为原稿也会翻转。 #40 –更改后的drawBob()
方法。 #42 –根据Bob的朝向,将活动帧设置为空闲帧之一 #44 –如果Bob处于步行状态,则根据Bob的当前状态时间为步行序列之一提取相应的帧,并将其分配给将被绘制到屏幕上的bobFrame。 运行StarAssaultDesktop
应用程序,我们应该看到Bob动画在StarAssaultDesktop
。 它看起来应该像这样:
该项目的源代码可以在这里找到: https : //github.com/obviam/star-assault 。 您需要检出分支part2 。 要使用git进行检查: git clone -b part2 git@github.com:obviam/star-assault.git
。 您也可以将其下载为zip文件 。
参考: 使用libgdx进行Android游戏开发–动画,来自JCG合作伙伴 Impaler的第2部分,网址为Against the Grain博客。
翻译自: https://www.javacodegeeks.com/2013/02/android-game-development-with-libgdx-animation-part-2.html