You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

libGDX实现精灵表纹理拆分算法异常问题求助

精灵表切割逻辑修复方案

你的代码核心问题是循环遍历子纹理索引时完全没有用x/y变量计算坐标,所有子纹理的坐标都写死为和spritesX/spritesY相关的常量,所以最终只会得到同一个位置的纹理区域。此外还有逻辑分支冗余、坐标规则适配错误、全局映射意外重置的问题,修复后的完整代码如下:

import com.badlogic.gdx.Gdx
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.TextureRegion
import java.lang.Exception

lateinit var AssetMap: MutableMap<String, Texture>
// 初始化改为懒加载,避免每次加载精灵表清空之前的内容
lateinit var SheetAssets: MutableMap<String, MutableMap<String, TextureRegion>>
object Assets {
    lateinit var fileHandle: FileHandle
    fun loadAssets()
    {
        loadAssets(DefaultAssetDirectory)
    }
    fun loadAssets(directory: String)
    {
        AssetMap = mutableMapOf() // 当前实现会在加载时重置映射
        fileHandle = Gdx.files.local(directory)
        val fileList = fileHandle.list()
        for(file in fileList)
        {
            if(file.extension() == "png")
                try
                {
                    AssetMap[file.nameWithoutExtension()] = Texture(directory+file.name())
                }
                catch(e: Exception) {
                    Gdx.app.error("Assets", "加载纹理失败: ${file.name()}", e)
                }
        }
    }

    /**
     * 适用于非常基础的精灵表
     * 该函数无需传入名称列表,子纹理将按索引命名
     * 函数默认从左上角(0,0)位置开始扫描
     * @param directoryToSheet 精灵表的本地存储路径
     * @param spaceBetweenX 仅为纹理之间的横向间隔,不包含纹理与边框的间隔
     * @param spaceBetweenY 仅为纹理之间的纵向间隔,不包含纹理与边框的间隔
     */
    fun loadSheetAtlas(directoryToSheet: String, width: Int, height: Int, spaceBetweenX: Int, spaceBetweenY: Int, spritesX: Int, spritesY: Int)
    {
        loadSheetAtlas(directoryToSheet, null, width, height, spaceBetweenX, spaceBetweenY, spritesX, spritesY)
    }

    /**
     * 适用于非常基础的精灵表
     * @param directoryToSheet 精灵表的本地存储路径
     * @param names 子纹理名称列表,若为null则子纹理按索引命名
     * @param spaceBetweenX 仅为纹理之间的横向间隔,不包含纹理与边框的间隔
     * @param spaceBetweenY 仅为纹理之间的纵向间隔,不包含纹理与边框的间隔
     */
    fun loadSheetAtlas(directoryToSheet: String, names: List<String?>?, width: Int, height: Int, spaceBetweenX: Int, spaceBetweenY: Int, spritesX: Int, spritesY: Int)
    {
        // 仅在首次调用时初始化全局映射,避免清空之前加载的精灵表
        if (!::SheetAssets.isInitialized) {
            SheetAssets = mutableMapOf()
        }
        val nameToConvert = Gdx.files.local(directoryToSheet).nameWithoutExtension()
            .replace(' ', '-')
            .lowercase()
        // 已加载过的精灵表直接跳过
        if (SheetAssets.containsKey(nameToConvert)) return
        
        val sheet = Texture(directoryToSheet)
        val regionMap = mutableMapOf<String, TextureRegion>()
        var nameIndex = 0

        for(y in 0 until spritesY) {
            for(x in 0 until spritesX) {
                val key = if (!names.isNullOrEmpty() && names[nameIndex] != null) {
                    names[nameIndex]!!
                } else {
                    nameIndex.toString()
                }
                // 计算子纹理坐标,适配libGDX纹理左下角为原点的规则
                val xPos = x * (width + spaceBetweenX)
                // 从左上角开始计算,转换为libGDX的y坐标
                val yPos = sheet.height - (y + 1) * height - y * spaceBetweenY
                regionMap[key] = TextureRegion(sheet, xPos, yPos, width, height)
                nameIndex++
            }
        }
        SheetAssets[nameToConvert] = regionMap
    }
}

关键修改说明

  • 移除了冗余的x == spritesX - 1分支逻辑,统一用循环变量计算坐标
  • 横向坐标直接按索引*(子纹理宽度+横向间隔)计算,符合边框无偏移的要求
  • 纵向坐标适配libGDX左下角为原点的规则,转换了左上角排列的精灵表坐标
  • 修复了每次调用loadSheetAtlas都会清空所有已加载精灵表的问题
  • 增加了异常日志输出,避免加载失败静默报错

内容的提问来源于stack exchange,提问作者random person

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 02:30:02