LibGdx - 我怎么能不在每一帧都加载我的纹理?
LibGdx - How can I not load my textures every single frame?
我对 Java 和 LibGdx 有点陌生,但对于我的学校项目,我需要为 Player-Sprite 设置动画。
对于每个玩家只有一个动画,使用我为此制作的 Methode 一切顺利,但现在我还需要一个行走、空闲和战斗动画。我设法让动画切换,但现在的问题是,每个动画只显示一帧。经过一些研究后,我知道我需要停止每帧更新我的纹理,但我不知道该怎么做。
到目前为止,我在更新之前尝试了一个简单的计时器,但这看起来很奇怪。
这是我的代码:
public Player(){
img3 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_idle_anim_strip_4.png");
img = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_idle_anim_strip_4.png");
img1 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_run_anim_strip_6.png");
img2 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_sword_attack_anim_strip_4.png");
animation();
changeCharacter();
}
public static void animation(){
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
img3 = img2;
amount = 3;
tileWidth = 32;
}else if(Gdx.input.isKeyPressed(Input.Keys.D) || Gdx.input.isKeyPressed(Input.Keys.A)){
img3 = img1;
tileWidth = 16;
amount = 3;
}else{
img3 = img;
amount = 3;
tileWidth = 16;
}
}
public static void changeCharacter(){
batch = new SpriteBatch();
regions = TextureRegion.split(img3, tileWidth, 16);
sprite = new Sprite(regions[0][0]);
sprite.setPosition(x,y);
Timer.schedule(new Timer.Task() {
@Override
public void run() {
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
}, 0, 1 / 12f);
}
在 render() 中调用了方法“animation”和“changeCharacter”。
我知道 LibGdx 中有更简单的解决方案,但我的其余代码都基于此,我基本上必须重写整个项目...
如果您需要任何其他 类,请询问。我可能会问一个非常简单的问题,但我不知道该怎么做。
您需要先重命名。
img3
看起来它的作用是作为指向 currentTextureSet 的指针。因此,当您在 Player()
中初始化时,您可能希望将 img3
重命名为 currentTextureSet
然后,而不是重复加载 herochar_idle_anim_strip_4.png
,设置
currentTextureSet = img;
后
(您可能还想将 img
、img1
、img2
重命名为 idleTextureSet
、runTextureSet
和 swordAttackTextureSet
)。
除此之外,
绝对摆脱你从 render 调用的 Timer.schedule 将 运行 在你不想要的后台线程中。
在这里查看资产包 https://o-lobster.itch.io/platformmetroidvania-pixel-art-asset-pack?download 如果这是同一个,则应选择图像 从左到右 即 x
应递增不是 y
。但是,您似乎增加了 y
...
sprite.setRegion(regions[0][frame]);
并且不正确的数组访问被吞没了,因为在后台计时器任务中,您唯一可以访问的 textureRegion 是 [0][0]
,即您只看到一个帧。
所以扔掉这个
Timer.schedule(new Timer.Task() {
@Override
public void run() {
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
}, 0, 1 / 12f);
并替换为
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[frame][0]);
*编辑
所以这意味着你的帧随着每次渲染而更新,这太快了。所以 - 简单易碎的方式 - (不是最好的 deltaTime 请阅读这篇优秀的文章 https://gafferongames.com/post/fix_your_timestep/ )。在没有时间的情况下,简单的方法不是最好的方法是声明
long renderCallCount =0;
将上面的内容放在声明框架的位置,然后在您的渲染方法中
renderCallCount++; //One more render call
if (renderCallCount % 60 == 0) { //Should I update frame?
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
因此,每当使用 mod 运算符 https://www.edureka.co/blog/mod-method-in-java/ 时 renderCallCount
被 60
整除,如果您的刷新率为 60hz,则每秒一次,那么您的帧递增。要每秒切换帧两次,请将 60
更改为 30
。
这假设您的显示器仅在 60hz 时达到 运行。我认为您的应用程序可能取决于位置更新刷新率的时间,因此您可能希望根据本文的一些想法在将来更新它。在具有更快帧速率的显示器上,一切都会加速(一致)。
我只是把一些东西按正确的顺序放好,现在可以用了!我真的不明白为什么 mod 运算符之后的数字需要这么小,否则它看起来就不对。我也知道你不应该在 render() 中创建 Spritebatch,但是当我在构造函数中创建它时,程序会因为缺少 Spritebatch 而崩溃???但感谢您的帮助 :) 这是任何对此感兴趣的人的工作代码:
public static void animation(){
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT) && InfoGame.cl.isGrounded() && current > Enemy.lastDmg + Enemy.dmgCool){
currentTextureSet = attackTexture;
amount = 3;
tileWidth = 32;
}else if(Gdx.input.isKeyPressed(Input.Keys.D) || Gdx.input.isKeyPressed(Input.Keys.A)){
currentTextureSet = runTexture;
tileWidth = 16;
amount = 3;
}else{
currentTextureSet = idleTexture;
amount = 3;
tileWidth = 16;
}
}
public static void changeCharacter(){
batch = new SpriteBatch();
regions = TextureRegion.split(currentTextureSet, tileWidth, 16);
sprite = new Sprite(regions[0][0]);
sprite.setPosition(x,y);
sprite.setOrigin(8,8);
if (renderCallCount % 6 == 0) {
frame++;
if (frame > amount) {
frame = 0;
}
}
sprite.setRegion(regions[0][frame]);
}
我对 Java 和 LibGdx 有点陌生,但对于我的学校项目,我需要为 Player-Sprite 设置动画。 对于每个玩家只有一个动画,使用我为此制作的 Methode 一切顺利,但现在我还需要一个行走、空闲和战斗动画。我设法让动画切换,但现在的问题是,每个动画只显示一帧。经过一些研究后,我知道我需要停止每帧更新我的纹理,但我不知道该怎么做。 到目前为止,我在更新之前尝试了一个简单的计时器,但这看起来很奇怪。 这是我的代码:
public Player(){
img3 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_idle_anim_strip_4.png");
img = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_idle_anim_strip_4.png");
img1 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_run_anim_strip_6.png");
img2 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_sword_attack_anim_strip_4.png");
animation();
changeCharacter();
}
public static void animation(){
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
img3 = img2;
amount = 3;
tileWidth = 32;
}else if(Gdx.input.isKeyPressed(Input.Keys.D) || Gdx.input.isKeyPressed(Input.Keys.A)){
img3 = img1;
tileWidth = 16;
amount = 3;
}else{
img3 = img;
amount = 3;
tileWidth = 16;
}
}
public static void changeCharacter(){
batch = new SpriteBatch();
regions = TextureRegion.split(img3, tileWidth, 16);
sprite = new Sprite(regions[0][0]);
sprite.setPosition(x,y);
Timer.schedule(new Timer.Task() {
@Override
public void run() {
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
}, 0, 1 / 12f);
}
在 render() 中调用了方法“animation”和“changeCharacter”。 我知道 LibGdx 中有更简单的解决方案,但我的其余代码都基于此,我基本上必须重写整个项目... 如果您需要任何其他 类,请询问。我可能会问一个非常简单的问题,但我不知道该怎么做。
您需要先重命名。
img3
看起来它的作用是作为指向 currentTextureSet 的指针。因此,当您在 Player()
中初始化时,您可能希望将 img3
重命名为 currentTextureSet
然后,而不是重复加载 herochar_idle_anim_strip_4.png
,设置
currentTextureSet = img;
后
(您可能还想将 img
、img1
、img2
重命名为 idleTextureSet
、runTextureSet
和 swordAttackTextureSet
)。
除此之外, 绝对摆脱你从 render 调用的 Timer.schedule 将 运行 在你不想要的后台线程中。
在这里查看资产包 https://o-lobster.itch.io/platformmetroidvania-pixel-art-asset-pack?download 如果这是同一个,则应选择图像 从左到右 即 x
应递增不是 y
。但是,您似乎增加了 y
...
sprite.setRegion(regions[0][frame]);
并且不正确的数组访问被吞没了,因为在后台计时器任务中,您唯一可以访问的 textureRegion 是 [0][0]
,即您只看到一个帧。
所以扔掉这个
Timer.schedule(new Timer.Task() {
@Override
public void run() {
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
}, 0, 1 / 12f);
并替换为
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[frame][0]);
*编辑 所以这意味着你的帧随着每次渲染而更新,这太快了。所以 - 简单易碎的方式 - (不是最好的 deltaTime 请阅读这篇优秀的文章 https://gafferongames.com/post/fix_your_timestep/ )。在没有时间的情况下,简单的方法不是最好的方法是声明
long renderCallCount =0;
将上面的内容放在声明框架的位置,然后在您的渲染方法中
renderCallCount++; //One more render call
if (renderCallCount % 60 == 0) { //Should I update frame?
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
因此,每当使用 mod 运算符 https://www.edureka.co/blog/mod-method-in-java/ 时 renderCallCount
被 60
整除,如果您的刷新率为 60hz,则每秒一次,那么您的帧递增。要每秒切换帧两次,请将 60
更改为 30
。
这假设您的显示器仅在 60hz 时达到 运行。我认为您的应用程序可能取决于位置更新刷新率的时间,因此您可能希望根据本文的一些想法在将来更新它。在具有更快帧速率的显示器上,一切都会加速(一致)。
我只是把一些东西按正确的顺序放好,现在可以用了!我真的不明白为什么 mod 运算符之后的数字需要这么小,否则它看起来就不对。我也知道你不应该在 render() 中创建 Spritebatch,但是当我在构造函数中创建它时,程序会因为缺少 Spritebatch 而崩溃???但感谢您的帮助 :) 这是任何对此感兴趣的人的工作代码:
public static void animation(){
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT) && InfoGame.cl.isGrounded() && current > Enemy.lastDmg + Enemy.dmgCool){
currentTextureSet = attackTexture;
amount = 3;
tileWidth = 32;
}else if(Gdx.input.isKeyPressed(Input.Keys.D) || Gdx.input.isKeyPressed(Input.Keys.A)){
currentTextureSet = runTexture;
tileWidth = 16;
amount = 3;
}else{
currentTextureSet = idleTexture;
amount = 3;
tileWidth = 16;
}
}
public static void changeCharacter(){
batch = new SpriteBatch();
regions = TextureRegion.split(currentTextureSet, tileWidth, 16);
sprite = new Sprite(regions[0][0]);
sprite.setPosition(x,y);
sprite.setOrigin(8,8);
if (renderCallCount % 6 == 0) {
frame++;
if (frame > amount) {
frame = 0;
}
}
sprite.setRegion(regions[0][frame]);
}