使用TexturePacker高效打包各类游戏图集格式的脚本Bash+Python详解

在游戏开发、UI 设计等领域,图集打包是一项常见且重要的工作。合理的图集打包可以减少内存占用,提高资源加载效率。今天,我们就来介绍一款强大的图集打包工具 ——texture_packer,它由texture_packer.bat和texture_packer.py两个文件组成,能帮助我们快速完成图集打包任务。

工具要点

主要功能
  • 多格式支持:支持生成 Cocos 2d 的 plist 格式、JSON 格式以及 Unity 的 TPSheet 格式的元数据。
  • 灵活配置:可以设置是否删除原图集文件、是否扁平化路径和生成其对应游戏格式数据等。
  • 递归处理:能够递归处理目录结构,对多个子目录进行批量打包。
  • 可扩展:文末列举了TexturePacker所有支持生成对应格式的api可供扩展

texture_packer.bat

这是一个 Windows 批处理脚本,主要用于设置参数和调用 Python 脚本。

主要功能
  • 参数设置:可以通过命令行参数指定输入路径、输出路径,以及是否删除原图集文件、是否扁平化路径、是否生成需要的游戏格式的元数据。
  • 路径验证:检查输入路径是否存在,如果不存在则输出错误信息并退出。
  • 执行打包:调用 texture_packer.py 脚本进行图集打包。
@echo off
setlocal enabledelayedexpansion
chcp 65001 >nul

::输入文件路径
set DEFAULT_INPUT=C:\Users\13294\Desktop\danny\图集1
::输出目标路径
set DEFAULT_OUTPUT=C:\Users\13294\Desktop\danny\tar
::是否删除原图集文件
set DELETE_FLAG=true
::是否扁平化路径
set FLATTEN_FLAG=true
::是否生成Cocos 2d的plist格式的元数据
set COCOS_FLAG=true
::是否生成JSON格式的元数据
set JSON_FLAG=true
:: 是否生成Unity的TPSheet格式的元数据
set UNITY_FLAG=true

:: 参数解析
set "INPUT_PATH=%~1"        :: 文件路径
set "OUTPUT_PATH=%~2"       :: 图集存储路径

:: 遍历所有参数,查找标识
for %%a in (%*) do (
    if /i "%%a"=="-D" (
        set DELETE_FLAG=true
    ) else if /i "%%a"=="-F" (
        set FLATTEN_FLAG=true
    ) else if /i "%%a"=="-J" (
        set JSON_FLAG=true
    ) else if /i "%%a"=="-U" (
        set UNITY_FLAG=true
    ) else if /i "%%a"=="-C" (
        set COCOS_FLAG=true
    )
)

:: 设置默认值(当无参数时)
if "%~1"=="" (
    set "INPUT_PATH=%DEFAULT_INPUT%"
    set "OUTPUT_PATH=%DEFAULT_OUTPUT%"
    set "DELETE_FLAG=%DELETE_FLAG%"
    set "FLATTEN_FLAG=%FLATTEN_FLAG%"
    set "JSON_FLAG=%JSON_FLAG%"
    set "UNITY_FLAG=%UNITY_FLAG%"
    set "COCOS_FLAG=%COCOS_FLAG%"
)

:: 输入路径验证
if not exist "%INPUT_PATH%" (
    echo [ERROR] Invalid input path: "%INPUT_PATH%"
    exit /b 1
)

:: 自动生成输出文件名
for %%A in ("%INPUT_PATH%") do set "OUTPUT_NAME=%%~nxA"

:: 显示执行参数
echo [INFO] Runtime parameters:
echo -----------------------------------
echo Input Path   : "%INPUT_PATH%"
echo Output Path  : "%OUTPUT_PATH%"
echo Delete Flag  : %DELETE_FLAG%
echo Flatten Flag : %FLATTEN_FLAG%
echo COCOS FLAG   : %COCOS_FLAG%
echo JSON Flag    : %JSON_FLAG%
echo UNITY FLAG   : %UNITY_FLAG%
echo -----------------------------------

:: 执行打包命令
python texture_packer.py "%INPUT_PATH%" "%OUTPUT_PATH%" %DELETE_FLAG% %FLATTEN_FLAG% %COCOS_FLAG% %JSON_FLAG% %UNITY_FLAG%

:: 保持窗口打开
echo [INFO] Process completed
pause
endlocal

texture_packer.py

这是一个 Python 脚本,主要负责具体的图集打包操作。

主要功能
  • 日志记录:使用 logging 模块记录操作过程中的信息和错误。
  • 文件处理:删除原有图集文件、检查残留文件、获取有效图片文件。
  • 图集打包:使用 subprocess 模块调用 TexturePacker 命令进行图集打包,并生成 JSON 和 Cocos2d PLIST 格式的元数据文件。
  • 递归处理:递归地处理输入目录下的所有子目录。
import sys
import os
import subprocess
import logging

# 配置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 排除的图集文件扩展名(避免循环打包)
EXCLUDE_EXTENSIONS = {'.json', '.plist', '.atlas', '.db','.tpsheet'}

def delete_existing_files(base_path):
    """删除原有图集文件"""
    json_file = f"{base_path}.json"
    plist_file = f"{base_path}.plist"
    png_file = f"{base_path}.png"
    unity_file = f"{base_path}.tpsheet"
    for file in [json_file, plist_file, png_file,unity_file]:
        try:
            if os.path.exists(file):
                os.remove(file)
                logging.info(f"删除原有文件:{file}")
        except Exception as e:
            logging.error(f"删除失败:{file} - {str(e)}")

def check_residual_files(base_path):
    """检查残留文件"""
    json_file = f"{base_path}.json"
    plist_file = f"{base_path}.plist"
    png_file = f"{base_path}.png"
    unity_file = f"{base_path}.tpsheet"
    return any(os.path.exists(f) for f in [json_file, plist_file, png_file,unity_file])

def get_valid_files(input_dir):
    """获取当前目录的有效图片文件"""
    valid_files = []
    for entry in os.listdir(input_dir):
        full_path = os.path.join(input_dir, entry)
        #logging.info(f"发现文件: {full_path}")
        if os.path.isfile(full_path):
            ext = os.path.splitext(entry)[1].lower()
            if ext not in EXCLUDE_EXTENSIONS:
                valid_files.append(full_path)
    logging.info(f"检查目录 {input_dir} 中有效文件数量: {len(valid_files)}")
    return valid_files

def run_texture_packer(common_params, format_type, data_file):
    """运行TexturePacker命令"""
    try:
        subprocess.run(
            [*common_params, "--format", format_type, "--data", data_file],
            check=True,
            capture_output=True,
            text=True,
            encoding='gbk',  # 关键修复:指定GBK编码适配Windows环境
            errors='replace'  # 替换无法解码的字符避免报错
        )
        logging.info(f"生成 {format_type} 格式成功")
    except subprocess.CalledProcessError as e:
        logging.error(f"生成 {format_type} 格式失败:{e.stderr}")
    except Exception as e:
        logging.error(f"未知错误:{str(e)}")

def process_directory(
    input_dir: str, 
    output_base: str, 
    delete_existing: bool,
    flatten_output: bool,
    root_input_dir: str,
    cocos_flag: bool,
    json_flag: bool,
    unity_flag: bool
):
    """处理单个目录的打包逻辑,支持自定义输出路径和扁平化模式"""
    # 计算相对路径用于非扁平化模式
    if not flatten_output:
        relative_path = os.path.relpath(input_dir, root_input_dir)
        final_output_path = os.path.join(output_base, relative_path)
    else:
        final_output_path = output_base
    
    os.makedirs(final_output_path, exist_ok=True)
    final_output_name = os.path.basename(input_dir)
    
    base_path = os.path.join(final_output_path, final_output_name)

    # 删除原有图集文件(如果需要)
    if delete_existing:
        delete_existing_files(base_path)

    # 检查残留文件
    if check_residual_files(base_path):
        logging.info(f"跳过打包:存在残留文件 - {input_dir}")
        return

    # 获取有效图片文件
    valid_files = get_valid_files(input_dir)

    if not valid_files:
        logging.info(f"跳过打包:无有效图片文件 - {input_dir}")
        return

    # 通用TexturePacker参数
    common_params = [
        "TexturePacker",
        "--sheet", f"{base_path}.png",
        "--opt", "RGBA8888",
        "--trim-mode", "None",
        "--disable-rotation",
        *valid_files  # 只传入当前目录的有效文件
    ]

    logging.info(f"\n开始处理:{input_dir}")
    logging.info(f"输出位置:{final_output_path}")
    logging.info(f"图集名称:{final_output_name}")
    logging.info(f"有效文件:{len(valid_files)} 个")

    if json_flag:
        # 生成JSON格式
        run_texture_packer(common_params, "json", f"{base_path}.json")
    if unity_flag:
        # 生成UNITY TPSHEEP格式
        run_texture_packer(common_params, "unity", f"{base_path}.tpsheet")
    if cocos_flag:
        # 生成Cocos2d PLIST格式
        run_texture_packer(common_params, "cocos2d", f"{base_path}.plist")
    logging.info(f"✅ 打包完成 - {input_dir}")

def batch_process(
    input_path: str, 
    output_base: str, 
    delete_existing: bool,
    flatten_output: bool,
    cocos_flag: bool,
    json_flag: bool,
    unity_flag: bool
):
    """递归处理目录结构,支持扁平化输出"""
    input_abs_path = os.path.abspath(input_path)
    
    if not os.path.exists(input_abs_path):
        logging.error(f"错误:输入路径不存在 - {input_abs_path}")
        return

    logging.info(f"开始处理:{input_abs_path}")
    logging.info(f"输出基准路径:{output_base}")
    logging.info(f"删除模式:{'启用' if delete_existing else '禁用'}")
    logging.info(f"扁平化模式:{'启用' if flatten_output else '禁用'}")
    logging.info(f"COCOS模式:{'启用' if cocos_flag else '禁用'}")
    logging.info(f"JSON模式:{'启用' if json_flag else '禁用'}")
    logging.info(f"UNITY模式:{'启用' if unity_flag else '禁用'}")

    def process_recursive(current_dir):
        # 处理当前目录
        process_directory(
            current_dir,
            output_base=output_base,
            delete_existing=delete_existing,
            flatten_output=flatten_output,
            root_input_dir=input_abs_path,
            cocos_flag=cocos_flag,
            json_flag=json_flag,
            unity_flag=unity_flag
        )
        # 递归处理子目录
        for entry in os.listdir(current_dir):
            subdir_path = os.path.join(current_dir, entry)
            if os.path.isdir(subdir_path):
                process_recursive(subdir_path)

    process_recursive(input_abs_path)

    logging.info("\n所有处理完成!")

if __name__ == "__main__":
    args = sys.argv[1:]
    input_path = args[0] if len(args) > 0 else None
    output_path = args[1] if len(args) > 1 else None
    delete_flag = args[2].lower() == 'true' if len(args) > 2 else False
    flatten_flag = args[3].lower() == 'true' if len(args) > 3 else False
    cocos_flag = args[4].lower() == 'true' if len(args) > 4 else False
    json_flag = args[5].lower() == 'true' if len(args) > 5 else False
    unity_flag = args[6].lower() == 'true' if len(args) > 6 else False

    if not input_path:
        logging.error("错误:必须指定输入路径")
        sys.exit(1)

    # 处理默认输出路径:如果未指定则使用输入路径的父目录
    final_output_base = output_path or os.path.dirname(os.path.abspath(input_path))
    batch_process(
        input_path,
        output_base=final_output_base,
        delete_existing=delete_flag,
        flatten_output=flatten_flag,
        cocos_flag=cocos_flag,
        json_flag=json_flag,
        unity_flag=unity_flag
    )

    

使用方法

  1. 确保 TexturePacker已安装:这两个脚本依赖 TexturePacker工具进行图集打包,因此需要先安装该工具,并确保其可在命令行中调用。
  2. 运行批处理脚本:在命令行中运行 texture_packer.bat 脚本,并根据需要指定参数。例如:
texture_packer.bat "C:\path\to\input" "C:\path\to\output" -C -D -F -J
其中,-D表示删除原图集文件,-F表示扁平化路径,-J表示生成 JSON 格式的元数据,-U表示生成 Unity 的 TPSheet 格式的元数据,-C表示生成 Cocos 2d 的 plist 格式的元数据。除了路径其他参数不分先后

或者在texture_packer.bat脚本内替换默认参数,直接双击该脚本

可扩展性 

添加新的元数据格式:如果需要支持其他格式的元数据,可以在texture_packer.py文件中添加新的处理逻辑。例如,添加对XML格式的支持,只需在process_directory函数中添加相应的调用代码: 

if xml_flag:
    # 生成XML格式
    run_texture_packer(common_params, "xml", f"{base_path}.xml")

同时,在texture_packer.bat文件中添加对应的参数解析逻辑。

TexturePacker支持生成的格式:

使用TexturePacker高效打包各类游戏图集格式的脚本Bash+Python详解_第1张图片

优化打包算法

  • 可以根据实际需求对TexturePacker的参数进行调整,例如修改--opt参数来改变图片的优化模式,以达到更好的打包效果。

总结

texture_packer是一款功能强大、灵活配置的图集打包工具,通过批处理文件和 Python 脚本的结合,实现了高效的图集打包任务。同时,它具有良好的可扩展性,可以根据实际需求进行定制和优化。希望本文能帮助你更好地使用该工具,提高工作效率。

        如果喜欢我的文章,欢迎关注、点赞、转发、评论,大家的支持是我最大的动力

        如有疑问或BUG,请加入QQ群一起交流探讨!!!

        技术交流QQ群:1011399921!!!

你可能感兴趣的:(Cocos,Creator,linux,cocos2d,unity,python,bash)