1. 概述
    在游戏开发中通常需要读取许多图片加载为纹理,每创建一个图片纹理对象都要经过读取图片并解码图片的过程,如果频繁创建纹理会消耗性能降低效率。为了优化这个问题,可以将多张图片合成一张大图,在游戏启动时只读取一次合成的这一张大图加载为一个纹理图集(TextureAtlas),当需要使用到其中具体的某个小图时再通过纹理图集查找出小图对应的纹理区域。使用这样的纹理图集,不但能提高效率、加快速度,还能减少内存的消耗。

  2. gdx-tools 工具
    要使用纹理图集首先要将多张小图合成一张大图,LibGDX 提供了一个 TexturePacker 类,该类提供了将本地指定文件夹中的小图合成一张大图的静态方法。TexturePacker 类在下载的 LibGDX 开发包的扩展文件夹(extensions)中的 gdx-tools.jar 中,如下图所示:

(1) 准备图片

为了演示,我在网上找了下面这 5 个图片:

将这 5 个图片保存到本地,分别命名为: button_1.png,button_2.png,flower.png,man.png,mushroom.png。

为了方便演示,我在 C 盘根目录创建一个 atlas 文件夹,然后在 atlas 文件夹中创建 input 和 output 两个文件夹分别用于存放待合成的所有小图和合成后的文件输出路径,把所有小图复制到 input 文件夹中,结果如下图:

(2) 创建 Java 工程合成图片

在 Eclipse 中新建一个 Java 工程,命名为 MyPacker,在工程根目录下创建 libs 文件夹,把 gdx-tools.jar 和 gdx.jar 这两个 jar 包拷贝到 libs 文件夹中,鼠标选中这两个 jar 包,右键 -> Build Path -> Add to Build Path,创建一个包含 main 方法的类 MyPacker。结果如下图:

MyPacker 类代码如下:

package com.libgdx.mypacker;

import com.badlogic.gdx.tools.texturepacker.TexturePacker;

public class MyPacker {

    public static void main(String[] args) {

        String inputDir = "C:/atlas/input";       // 所有小图存放的文件夹
        String outputDir = "C:/atlas/output"; // 合成后的文件输出路径
        String packFileName = "myatlas";      // 合成后的文件的名称

        // 进行图片合成
        TexturePacker.process(inputDir, outputDir, packFileName);
    }

}

运行代码,在 C:/atlas/output 目录中便生成两个文件,如下图所示:

myatlas.png:由多个小图合成的一个大图;
myatlas.atlas:一个文本文件,记了录大图 myatlas.png 的位置,以及所有小图在大图中的具体位置(纹理区域),可以用记事本打开查看。

到了这里图片的合成就完成了,然后将 myatlas.png 和 myatlas.atlas 这两个文件复制到 LibGDX 项目的 assets 资源文件夹中就可以在代码中使用了。

(3) 使用命令行合成图片

gdx-tools 工具除了用上面创建工程的合成图片方法,还可以通过命令行直接运行命令合成图片。实际上在 gdx-tools.jar 中的 TexturePacker 类本身就是一个命令行应用(包含了 main 方法),因此可以不用另外创建工程,直接使用命令行运行 TexturePacker 类中的 main 方法并传入相应的参数即可进行合成图片。

要使用 TexturePacker 类通过命令合成图片,首先打开命令行终端,进入到 LibGDX 开发包目录(即 gdx.jar 文件所在目录,目录不能进错,这非常重要)。

在不同操作系统中的命令格式如下所示:

// Windows
java -cp gdx.jar;extensions/gdx-tools/gdx-tools.jar com.badlogic.gdx.tools.texturepacker.TexturePacker inputDir outputDir packFileName

// OS X / Linux
java -cp gdx.jar:extensions/gdx-tools/gdx-tools.jar com.badlogic.gdx.tools.texturepacker.TexturePacker inputDir outputDir packFileName

命令有点长,先把命令复制到记事本,然后替换掉最后的三个参数(小图所在文件夹/inputDir,合成文件输出路径/outputDir,合成文件的名称/packFileName),其中前两个是目录参数最好将目录字符串用双引号引起来,避免目录中含空格被认为是多个参数(带空格的字符串参数都应该引起来,因为命令中的参数是用空格分隔的),最终的命令如下所示:

// Windows
java -cp gdx.jar;extensions/gdx-tools/gdx-tools.jar com.badlogic.gdx.tools.texturepacker.TexturePacker "C:/atlas/input" "C:/atlas/output" myatlas

// OS X / Linux
java -cp gdx.jar:extensions/gdx-tools/gdx-tools.jar com.badlogic.gdx.tools.texturepacker.TexturePacker "~/atlas/input" "~/atlas/output" myatlas

将替换好参数的命令复制到终端运行,运行完后查看 C:/atlas/output 目录便可生成两个文件 myatlas.png 和 myatlas.atlas 文件。

  1. gdx-texturepacker-gui 工具
    前面介绍的是通过代码或命令来合成图片。有 LibGDX 爱好者对 gdx-tools 工具中的图片合成代码封装成了图形界面,即 gdx-texturepacker-gui 工具,这是一个标准 JavaSE 编写的工具,通过命令即可运行。

下载地址: https://code.google.com/p/libgdx-texturepacker-gui/downloads/list

国内可能无法访问 Google,我已把它下载下来上传到了 CSDN,

CSDN 下载地址: http://download.csdn.net/detail/xietansheng/9235265

这里我下载当前的最新版 gdx-texturepacker-3.2.0.zip,如下图所示:

下载到本地后进行解压缩,结果如下:

启动命令终端,进入到 gdx-texturepacker.jar 所在目录,

运行打开该工具的命令:java -jar gdx-texturepacker.jar

打开结果如下:

合成图片步骤:

点击左上角的 “New pack” 输入包名称(mypack)创建一个包;
选择小图所在文件夹 / Input directory(C:/atlas/input);
选择合成文件输出路径 / Output directory(C:/atlas/output);
输入合成文件的名称 / File name(myatlas);
点击 “Pack’em all” 进行合成图片。
个人建议:先准备好图片和 input、output 文件夹,然后拼接命令直接用命令行合成图片即可。

  1. 代码示例: 纹理图集 TextureAtlas 类的使用
    创建 LibGDX 工程,将图片合成后生成的文件 myatlas.png 和 myatlas.atlas 复制到 assets 文件夹中,这里我在 assets 中单独创建一个 atlas 文件夹用于存放在两个文件。结果如下图所示:

TextureAtlas 类的使用,游戏主程序的启动入口类:

package com.libgdx.test;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

/**
 * 游戏主程序的启动入口类
 */
public class MainGame extends ApplicationAdapter {

    private SpriteBatch batch;

    // 纹理图集
    private TextureAtlas atlas;

    // 每个小图在在纹理图集中对应的名称常量(实际上就是小图的原文件名,定义在 myatlas.atlas 文件中)
    public static final String MAN = "man";             // 人
    public static final String MUSHROOM = "mushroom";   // 蘑菇
    public static final String FLOWER = "flower";       // 鲜花
    public static final String BUTTON = "button";       // 按钮

    // 小图对应的 纹理区域 或 精灵
    private TextureRegion manRegion;        // 人
    private Sprite mushroomSprite;          // 蘑菇
    private Sprite flowerSprite;            // 鲜花
    private TextureRegion button1Region;    // 按钮 1
    private TextureRegion button2Region;    // 按钮 2

    @Override
    public void create() {
        // 创建 SpriteBatch
        batch = new SpriteBatch();

        // 读取 myatlas.atlas 文件创建纹理图集
        atlas = new TextureAtlas(Gdx.files.internal("atlas/myatlas.atlas"));

        // 根据名称从纹理图集中获取纹理区域
        manRegion = atlas.findRegion(MAN);

        // 也可以根据名称直接由纹理图集创建精灵
        mushroomSprite = atlas.createSprite(MUSHROOM);
        flowerSprite = atlas.createSprite(FLOWER);

        /*
         * 根据 名称 和 索引 从纹理图集中获取纹理区域
         * 
         * 特别说明: 
         *     纹理图集中的小图名称一般就是小图的原文件名, 但可以给小图加上一个索引(index)属性, 就是在文件名后
         * 面加上下划线和表示索引的数字(name_index.png), 例如 button_1.png 和 button_2.png 这两个小图文件, 
         * gdx-tools 在合成纹理图集时会使用相同的名称(button)分别加上对应的索引值(1 和 2)表示。这样有助于对
         * 业务相同的图片进行统一命名。纹理图集对小图的描述定义在 myatlas.atlas 文件中, 这是一个文本文件, 可以用
         * 记事本打开查看。
         * 
         * 因此下面获取按钮的纹理区域时使用 "button" 作为名称并加上对应的索引值来获取。
         */
        button1Region = atlas.findRegion(BUTTON, 1);
        button2Region = atlas.findRegion(BUTTON, 2);

        /* 给精灵设置位置属性 */
        flowerSprite.setPosition(190, 80);
        mushroomSprite.setPosition(190, 290);
    }

    @Override
    public void render() {
        // 黑色清屏
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        // 开始绘制
        batch.begin();

        // 绘制精灵
        mushroomSprite.draw(batch);         // 蘑菇
        flowerSprite.draw(batch);           // 鲜花

        // 绘制纹理区域
        batch.draw(manRegion, 30, 70);      // 人
        batch.draw(button1Region, 30, 340); // 按钮 1
        batch.draw(button2Region, 30, 286); // 按钮 2

        // 绘制结束
        batch.end();
    }

    @Override
    public void dispose() {
        // 当应用退出时释放资源
        if (batch != null) {
            batch.dispose();
        }
        // 纹理图集关联了一张合成的大图, 应用退出时需要释放纹理图集资源
        if (atlas != null) {
            atlas.dispose();
        }
    }

}

运行结果:


作者:xietansheng
来源:CSDN
原文:https://blog.csdn.net/xietansheng/article/details/50187651
版权声明:本文为博主原创文章,转载请附上博文链接!

发表评论

邮箱地址不会被公开。 必填项已用*标注