无法加载声音文件LibGdx。

4
我希望能够通过使用AssetManager直接从扩展OBB文件中加载文件。我实现了自己的FileHandleResolver
public class CustomFileHandleResolver implements FileHandleResolver
{
    @Override
    public FileHandle resolve(String fileName) {
        return new CustomFileHandle(fileName);
    }
}

我将其设置为我的AssetManager。我创建了自己的FileHandle并覆盖了read()函数。

@Override
public InputStream read()
{
    InputStream input = null;

    try {           
        input = GameInfo.expansionFile.getInputStream(file.getPath().replace('\\', '/'));
    } catch (IOException e) {
        e.printStackTrace();
    }   

    return input;
}

它加载所有像 .PNG、.PACK、.FNT 这样的文件,但不包括 .OGG 文件,因此我猜测所有音频文件都无法被加载。 我收到了以下错误信息:
com.badlogic.gdx.utils.GdxRuntimeException: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: SFx/button_click.ogg

这是一个错误提示信息:
com.badlogic.gdx.utils.GdxRuntimeException: java.lang.ClassCastException: com.solidgamesstudio.threedefendersn.framework.CustomFileHandle cannot be cast to com.badlogic.gdx.backends.android.AndroidFileHandle

我看到zip文件无法压缩。 我在7zip中选择了“存储”压缩,这样就完全没有被压缩,但仍然出现此问题。
我浏览了文件加载时发生的情况,发现AssetManager调用我的CustomFileHandleResolver,它创建CustomFileHandle。对于每个不是.OGG的文件,它调用InputStream read()。在此函数中,它从zip文件中加载文件,一切正常。但是如我所说,当它要加载.OGG时,它不会调用此函数。所以它甚至还没有尝试从zip中获取文件。问题是,为什么.OGG文件不在CustomFileHandle()中调用InputStream read()?
更新
我更详细地查看后发现它无法从FileHandle创建声音。 这表明无法从OGG文件中创建声音。
CustomFileHandle cannot be cast to AndroidFileHandle

为了创建一个声音,你需要传递 fileHandle。

public Sound newSound (FileHandle fileHandle);

这是从SoundLoader调用的。

@Override
public void loadAsync (AssetManager manager, String fileName, FileHandle file, SoundParameter parameter) {
    sound = Gdx.audio.newSound(file);
}

我使用了自定义的文件处理器CustomFileHandleResolver作为soundLoader。我不知道声音文件是否与其他文件类型有所不同,但默认情况下,AssetManager会使用

public class InternalFileHandleResolver implements FileHandleResolver {
    @Override
    public FileHandle resolve (String fileName) {
        return Gdx.files.internal(fileName);
    }
}

我无法访问Gdx.files.internal以查看是否有任何特殊处理声音的方法。

更新:

进一步分析使我得出结论,正如之前所提到的那样,主要问题在于这个问题。

CustomFileHandle cannot be cast to AndroidFileHandle

我不知道为什么在加载OGG文件时它会把我的FileHandle转换成AndroidFileHandle。如果它可以正常加载其他类型的文件,那可能意味着它不会对它们进行强制类型转换。这意味着OGG是特殊的,并且需要进行类型转换。有任何线索吗?


为什么要创建自己的自定义FileHandleResolver?你只需要执行assetManager.load("SFx/button_click.ogg", Sound.class)Sound sound = assetManager.get("SFx/button_click.ogg", Sound.class)。这是libgdx的所有标准功能。 - noone
我在拼写“直接从扩展OGG”时犯了错误,应该是“OBB”。为了澄清,我有自己的OBB扩展文件,其中包含所有资产。我需要从中加载所有文件。我正在使用AssetManager来完成这个任务。因此,我需要自己的FileHandler来指向zip文件中的特定资产文件。而且我需要自己的FileHandleResolver来使用我的FileHandler。 - draziw
这是一个有趣的问题。如果您自己找到了解决方案,请在此处发布。 - noone
3个回答

0

嗯,我目前正在做这个。每当您需要获取真正的FileHandle以便使声音加载机制工作(或在任何其他情况下,强制转换为AndroidFileHandle让您感到困扰),请将该文件解压缩到本地目录并在需要时重复使用:

    public static FileHandle getRealFileHandle(String zipEntryPath, ZipFile zipFile) {
    if (Gdx.files.local(zipEntryPath).exists()) {
        return Gdx.files.local(zipEntryPath);
    } else {
        Gdx.app.log(TAG, "Unzipping file '" + zipEntryPath + "'...");
        try {
            FileHandle unzippedFile;
            ZipEntry entry = zipFile.getEntry(zipEntryPath);
            if (entry != null) {
                unzippedFile = Gdx.files.local(zipEntryPath);
                InputStream is = zipFile.getInputStream(entry);
                byte[] buffer = new byte[65536];
                int readLength;
                while ((readLength = is.read(buffer)) >= 0) {
                    unzippedFile.writeBytes(buffer, 0, readLength, true);
                }
                return unzippedFile;
            } else {
                Gdx.app.error(TAG, "Entry '" + zipEntryPath + "' not found inside zip file.");
            }
        } catch (IOException ioe) {
            Gdx.app.error(TAG, "A problem occurred while writing to the local file.");
        }
    }
    return null;
}

0
我解决了这个问题,将zip文件提取到特定的文件夹中,然后从该外部文件夹中读取。
提取zip文件的方法如下:
    public void extract(){
    String packageName = getPackageName();
    File root = Environment.getExternalStorageDirectory();
    File expPath = new File(root.toString() + "/Android/obb/" + packageName);

    if (expPath.exists()) {
        String strMainPath = null;
        try {
            strMainPath = expPath + File.separator + "main."
                    + getPackageManager().getPackageInfo(
                            getPackageName(), 0).versionCode + "."
                            + packageName + ".obb";


            Log.e("Extract File path", "===>"+strMainPath);

            File f=new File(strMainPath);
            if(f.exists()){
                Log.e("Extract From File path", "===> not exist");
            }
            else
            {
                Log.e("Extract From File path", "===> exist");
            }

            String pathToExtract = Environment.getExternalStorageDirectory()+"/"+Cons.FOLDERNAME;
            Log.e("Extract to path", "===>"+pathToExtract);
            flag = extractZip(strMainPath,pathToExtract);

            Log.e("After Extract Zip", "===>"+flag);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }

    }

}


private boolean extractZip(String pathOfZip,String pathToExtract)
{
    int BUFFER_SIZE = 1024;
    int size;
    byte[] buffer = new byte[BUFFER_SIZE];


    try {
        File f = new File(pathToExtract);
        if(!f.isDirectory()) {
            f.mkdirs();
        }
        ZipInputStream zin = new ZipInputStream(new BufferedInputStream(new FileInputStream(pathOfZip), BUFFER_SIZE));
        fileNum=0;
        try {
            ZipEntry ze = null;
            while ((ze = zin.getNextEntry()) != null) {
                String path = pathToExtract  +"/"+ ze.getName();

                if (ze.isDirectory()) {
                    File unzipFile = new File(path);
                    if(!unzipFile.isDirectory()) {
                        unzipFile.mkdirs();
                    }
                }
                else {
                    updateFileNum();
                    FileOutputStream out = new FileOutputStream(path, false);
                    BufferedOutputStream fout = new BufferedOutputStream(out, BUFFER_SIZE);
                    try {
                        while ( (size = zin.read(buffer, 0, BUFFER_SIZE)) != -1 ) {
                            fout.write(buffer, 0, size);
                        }

                        zin.closeEntry();
                    }catch (Exception e) {
                        Log.e("Exception", "Unzip exception 1:" + e.toString());
                    }
                    finally {
                        fout.flush();
                        fout.close();
                    }
                }
            }
        }catch (Exception e) {
            Log.e("Exception", "Unzip exception2 :" + e.toString());
        }
        finally {
            zin.close();
        }
        return true;
    }
    catch (Exception e) {
        Log.e("Exception", "Unzip exception :" + e.toString());
    }
    return false;

}

注意:将其提取到.Android文件夹中,否则用户将直接访问资产。例如,他们将在图库应用程序中看到图像。

0

我还没有找到一种从zip文件中加载音频文件的方法。问题在于AssetManager与其他文件类型不同地加载声音文件。问题在于它将FileHandle转换为AndroidFileHandle,而由于CustomFileHandle扩展了FileHandle,因此无法将其转换为AndroidFileHandle。我找不到绕过这个问题的方法,因为它已经深入根本了。

CustomFileHandle cannot be cast to AndroidFileHandle

在这种情况下,我不得不从OBB文件中取出所有声音文件,并将它们与应用程序放在一起。我创建了另一个AssetManager实例,专门用于加载声音。因此,声音可以像使用AssetManager一样正常加载,而对于任何其他类型的文件,我使用了使用自己的FileHandlerResolver的AssetManager,该FileHandlerResolver使用我的自己的FileHandle类从zip中返回文件。这种方法的唯一问题是,您仅限于拥有最多50 MB的声音文件。

嘿 @user2974885,你能帮我吗? 你是如何至少加载图片的? 我遇到了同样的错误:“无法加载资产的依赖项:” 怎么回事?你是如何让它工作的? - chelo_c
你好 chelo_c。你是否正在尝试从OBB文件中加载图像?如果不是,那么你不需要覆盖任何内容,只需创建AssetManager实例,然后使用AssetManager.load()函数来加载图像、声音等即可。 - draziw
1
如果您正在尝试从扩展文件中加载图像,则我在此线程中为您提供了答案:https://dev59.com/an_aa4cB1Zd3GeqPzilO#23388998 - draziw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接