"no such file or directory" 在预加载器中

"no such file or directory" in preloader

我正在为大型应用程序制作预加载器。今天发生错误 "no such file or directory"。此错误仅发生在 Android 设备上。在计算机上(在模拟器中)工作正常。所有文件名和目录都小写。

代码:

---------------------------------------------
---------------- Прелоадер ------------------
-- Сервис по загрузке текстур, звука --------
---------------------------------------------

TEXTURES = {} -- место в оперативной памяти для текстур
SOUNDS = {} -- место в оперативной памяти для звука

local Preloader = {}
local path = {
    animations = "assets/images/animations/",
    army_run = "assets/images/animations/army_run/",
    area = "assets/images/area/",
    access = "assets/images/area/access/",
    artefacts = "assets/images/artefacts/",
    castles = "assets/images/building/castles/",
    mining = "assets/images/building/mining/",
    flags = "assets/images/flags/",
    interface = "assets/images/interface/",
    marker = "assets/images/interface/marker/",
    items = "assets/images/items/",
    raw = "assets/images/raw/",
}

-- Место для путей к текстурам
Preloader.texture = {}

-- Место для путей к звуку
Preloader.sound = {}

-- Загрузка текстур в оперативную память
Preloader.loadingTextures = function(arr)
    TEXTURES[arr.id] = {}
    for i = 1, #arr do
        local name = string.gsub(arr[i], '.*(.*)/', '')
        TEXTURES[arr.id][name] = graphics.newTexture( { type="image", filename = arr[i] } )
        TEXTURES[arr.id][name]:preload()
    end
end

-- Загрузка звука в оперативную память
Preloader.loadingSounds = function()
    for i = 1, #Preloader.sound do
        sounds[Preloader.sound[i]] = audio.loadSound( "snd/"..Preloader.sound[i] )
    end
end

-- Таймер
Preloader.getTimer = function()
    return system.getTimer()
end

-- Окно загрузки
Preloader.screenLoader = nil
Preloader.loaderShow = function()
    if(Preloader.screenLoader)then
        return false
    end 

    Preloader.screenLoader = display.newGroup()
    Preloader.screenLoader.x = _W/2
    Preloader.screenLoader.y = _H/2

    local screen = display.newRect( 0, 0, _W, _H )
    screen:setFillColor( 0, 0, 0 )
    Preloader.screenLoader:insert(screen)

    local imgLoad = "assets/images/animations/army_run/150.png"
    local sheetLoad = graphics.newImageSheet( imgLoad, { width = 224, height = 224, numFrames = 8 } )

    local animLoad = display.newSprite( Preloader.screenLoader, sheetLoad, { start = 1, count = 8, time = 800, loopCount=0 } )
    animLoad.xScale, animLoad.yScale = _H*.001, _H*.001
    animLoad.x, animLoad.y = 0, _H*-.07
    animLoad:play()

    -- Загрузка в процентах
    tfLoader = display.newText( TEXTS.Preloader.loading..": 0%", 0, _H*.08, font, _H*.035 )
    tfLoader:setTextColor( 1,1,1) 
    Preloader.screenLoader:insert(tfLoader)
    Preloader.screenLoader.tf = tfLoader

    -- Загрузка в этапах
    stepLoader = display.newText( TEXTS.Preloader.start_load, 0, _H*.125, font, _H*.022 )
    stepLoader:setTextColor( 160/255, 160/255, 160/255 ) 
    Preloader.screenLoader:insert(stepLoader)
    Preloader.screenLoader.step = stepLoader
end

-- Создание массивов с путями
Preloader.createPath = function()
    for k, v in pairs(path) do
        local i = 0
        Preloader.texture[k] = { id = k }
        for l in lfs.dir(v) do
            if ( l ~= "." and l ~= ".." and l ~= "..." ) then
                i = i + 1
                Preloader.texture[k][i] = v..l
            end
        end
    end
end

-- Запуск прелоадера и контроль процесса загрузки
Preloader.start = function() 
    -- Создаём шаги для загрузки
    local loading_steps = {}

    -- Шаг 1 - Загрузка путей
    table.insert(loading_steps, function()
        Preloader.createPath()
        Preloader.screenLoader.step.text = TEXTS.Preloader.path_load..'...'
    end)

    -- Шаг 2 - Загрузка текстур интерфейса
    table.insert(loading_steps, function()
        Preloader.loadingTextures(Preloader.texture.interface)
        Preloader.loadingTextures(Preloader.texture.marker)
        Preloader.screenLoader.step.text = TEXTS.Preloader.interface_load..'...'
    end)

    -- Шаг 3 - Загрузка анимаций
    table.insert(loading_steps, function()
        Preloader.loadingTextures(Preloader.texture.animations)
        Preloader.loadingTextures(Preloader.texture.army_run)
        Preloader.screenLoader.step.text = TEXTS.Preloader.animations_load..'...'
    end)

    -- Шаг 4 - Создание карты
    table.insert(loading_steps, function()
        Preloader.loadingTextures(Preloader.texture.area)
        Preloader.loadingTextures(Preloader.texture.access)
        Preloader.loadingTextures(Preloader.texture.castles)
        Preloader.loadingTextures(Preloader.texture.mining)
        Preloader.screenLoader.step.text = TEXTS.Preloader.map_load..'...'
    end)

    -- Шаг 5 - Загрузка ресурсов
    table.insert(loading_steps, function()
        Preloader.loadingTextures(Preloader.texture.raw)
        Preloader.loadingTextures(Preloader.texture.items)
        Preloader.loadingTextures(Preloader.texture.artefacts)
        Preloader.screenLoader.step.text = TEXTS.Preloader.res_load..'...'
    end)

    -- Шаг 6 - Загрузка параметров игрока
    table.insert(loading_steps, function()
        Preloader.loadingTextures(Preloader.texture.flags)
        Preloader.screenLoader.step.text = TEXTS.Preloader.res_load..'...'
    end)

    local loading_steps_max = #loading_steps+1
    local st = Preloader.getTimer()
    Preloader.loaderShow()

    local function mainHandler(e)
        if(#loading_steps>0)then
            loading_steps[1]()
            table.remove(loading_steps, 1)

            if(Preloader.screenLoader)then
                local loading_p = math.floor((loading_steps_max - #loading_steps)*100/loading_steps_max)
                Preloader.screenLoader.tf.text = TEXTS.Preloader.loading..': '..loading_p..'%'
            end
            return true
        end
        Preloader.loaderClose()
        print('Time load: '..(Preloader.getTimer()-st)..'ms')

        Runtime:removeEventListener("enterFrame", mainHandler)
    end
    Runtime:addEventListener("enterFrame", mainHandler)
end

-- Окончание загрузки
Preloader.loaderClose = function()
    if(Preloader.screenLoader)then
        if(Preloader.screenLoader.removeSelf)then
            Preloader.screenLoader:removeSelf()
        end
    end
    Preloader.screenLoader = nil

    -- Переход на стартовую сцену
    composer.gotoScene( start_scene, "fade", 0 )
end

-- Сборщик мусора
Preloader.garbage_collector = function()
    for key in pairs(TEXTURES) do
        for i=1, #TEXTURES[key] do
            TEXTURES[key][i]:releaseSelf()
        end
    end
    TEXTURES = {}
end

return Preloader

这就是我在舞台上展示图像的方式:

M.dial = display.newImageRect( M.gr, TEXTURES.interface["btn_compas_comp.png"].filename, TEXTURES.interface["btn_compas_comp.png"].baseDir, 272, 272 )
M.dial.x, M.dial.y = X, Y

在此先感谢朋友们。

1) All file names and directories to lowercase - 我建议仔细检查这一点,因为 Android 文件系统区分大小写。

2) 同时检查您的 build.settings 以确保 excludeFiles 部分不包含您代码中的任何目录

编辑: 另一个基于 corona lfs doc 的想法 - 在加载之前尝试以下操作:

local resourcesPath = system.pathForFile( "", system.ResourceDirectory )

-- Change current working directory
local success = lfs.chdir( resourcesPath )  --returns true on success

我猜默认情况下 lfs 不指向资源目录。您的所有资产都应在此目录中,但不要尝试修改它们 - For security reasons, this directory is read-only and enforced by the operating system, not by Corona.

编辑2:不依赖当前目录的解决方案

Preloader.createPath = function()
  for k, v in pairs(path) do
    local i = 0
    local pathForDirectory = system.pathForFile(v, system.ResourceDirectory)
    Preloader.texture[k] = { id = k }
    for l in lfs.dir(pathForDirectory) do
        if ( l ~= "." and l ~= ".." and l ~= "..." ) then
            i = i + 1
            Preloader.texture[k][i] = v..l
        end
    end
  end
end