将精灵表中的精灵存储在数组 Libgdx 中

Store sprites from spritesheet in array Libgdx

我在 Libgdx android 资产中将 960x960 spritesheet 存储为 png。在 class 中,我指定要初始化用于我的游戏的 sprite,我试图做到这一点,以便从 spritesheet 中切割出一个 120x120 的 sprite(因此数组中应该有 64 个项目)。我怎么能做到这一点?这是我在类似情况下尝试过的方法:

public static Texture spritesheet;
public static Sprite[] textures = new Sprite[64];
...
    //inside method that gets called once to initialize variables
    spritesheet = new Texture(
            Gdx.app.getType() == Application.ApplicationType.Android ?
                    "...Spritesheet.png" :
                    "android/assets/...Spritesheet.png"
    );
    spritesheet.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);

    for (int x = 0; x < 64; x ++) {
        textures[x] = new Sprite(spritesheet, x, (x%8), 64, 64);
        textures[x].flip(false, true);
    }

然后我在其他 classes 中渲染精灵:

batch.draw(Assets.textures[0 /*this can be any number*/], (float) x, (float) y, 108, 108);

当我这样做时,它的行为真的很奇怪。它说数组中填充了元素,但仍然存在数组索引越界异常或精灵只是疯狂渲染。总的来说,这是行不通的。我想做的是做到这一点,这样我就不必分别初始化 64 个不同的精灵,并且做到这一点,这样我就可以通过更改渲染精灵时输入的索引来轻松更改精灵,这样我以后就可以做一些其他的事情上,像动画。我该怎么做呢?

我认为你的 for 循环应该是这样的

for(int x = 0; x < 64; x ++){
    textures[x] = new Sprite(
        spritesheet, 
        (x%8)*64, //where x=3, (3%8)*64 = 3*64 = 192px sourceX
        (x/8)*64, //where x=3, (int)(3/8)*64 = 0*64 = 0px sourceY
        64, //source width
        64 //source height
    );


Another test case where x=20;
(20%8)*64 = 4*64 = 256px SourceX
(20/8)*64 = 2*64 = 128px SourceY

您应该为此目的使用 TextureAtlas。图集是由 LibGDX TexturePacker 从单独的图像自动生成的文件。它存储从 sheet 中的图像边界到 NinePatch 信息的所有内容。您需要做的就是将单独的图像放在一个文件夹中,然后 运行 该文件夹中的 TexturePacker。这将为您创建一个 sheet 和一个可以轻松加载的 .atlas/.pack 文件。

如果您对命令行有困难,可以使用 TexturePackerGui,但我建议您使用命令行,甚至在您的应用程序中使用它。

我通常做的是在开发时即时创建这些 sheet。我可以轻松地覆盖单独的图像,并且在我再次 运行 我的应用程序后它们会立即生效。我首先在项目的根目录下创建一个新文件夹 images。然后为我需要的每个包创建另一个文件夹。对于此示例,我在 images 中创建文件夹 tileset。在 DesktopLauncher 中,我将设置此文件夹以从图像生成图集。

    TexturePacker.Settings settings = new TexturePacker.Settings();
    settings.maxWidth = 1024;
    settings.maxHeight = 1024;

设置文件指定了关于您的地图集的所有内容。单个 sheet 的最大尺寸,如果它应该从图像、填充、旋转等中去除透明度。它们都非常简单,您可以在文档中查看这些。使用这些设置,您可以创建地图集。

    TexturePacker.process(settings, 
            "../../images/tileset", //where to find the images to be packed.
            "../../android/assets/tileset/", //where to store the atlas and sheet
            "tileset"); //what filename to use

现在您可以打开 .atlas 文件,您会看到它使用文件名作为别名。此别名用于查找它们,但让我们先加载图集。

TextureAtlas atlas = new TextureAtlas("tileset/tileset.atlas");

通过仅将一个字符串传递给构造函数,它默认在您的本地路径中查找,而本地路径又默认在 android/assets/ 中。现在我们可以要求atlas交出我们在sheet.

的资产

atlas.findRegion("alias"); //移交 sheet 上名为 "alias"

的图像

查找这样的纹理有点昂贵。您不想在每次更新时都查找很多这样的纹理,因此您仍然需要将它们存储在某个地方。

如果您将图像序列命名为 image_01.pngimage_02.pngimage_03.png,它会将它们全部存储在相同的名称下,并在图集中对它们进行排序,但它是 index.所以如果你想要一个单独的特定纹理数组,你可以用 _xx 命名它们并一次性获得它们:

atlas.findRegions("alias");

这对 Animation 来说特别方便。只需将您的图像序列复制到一个文件夹并指定要打包即可。正确命名您的序列并将区域指定给动画。一切都会马上开始。

使用 AssetManager 加载 TextureAtlas 与普通 Texture 几乎相同,只是您指定它来自 TextureAtlas.class。你总是加载 .atlas ,它又会处理你的图像。

我总是使用 AssetDescriptor 来加载我的资产。如果我在你那里,我会摆脱静态 Assets.textures[] since that will get you into trouble sooner or later.

//None static AssetManager with getter
private AssetManager manager = new AssetManager();
public AssetManager getManager() { return manager; }

//Specify a descriptor for the atlas, this is static so I can acces it anywhere. 
//It's just a descriptor of the asset so this is safe.
public static final AssetDescriptor<TextureAtlas> TileSet = new AssetDescriptor<TextureAtlas>("tileset/tileset.atlas", TextureAtlas.class);

//then just load everything
public void load()
{
    manager.load(tileSet);
    //... load other stuff
}

现在只需将 AssetManager 对象传递到您需要访问资产的任何地方,您就可以像这样加载任何资产:

TextureAtlas tileset = assetManager.get(Assets.TileSet);