cocos2d-x android 直接加载下载到sd的zip里的资源文件(二)

来源:互联网 发布:数据分析师的工资待遇 编辑:程序博客网 时间:2024/05/01 23:23

上一节 解决了读文件的问题,游戏也跑起来了,可是音效和背景音乐,死活播放不出来。回想一下,的确没有考虑到游戏的音效问题。让我们再折腾一下,播放zip里的音效问题。cocos-x 安卓的背景音乐处理交给了Cocos2dxMusic.java,音效处理交给了Cocos2dxSound.java。别的我们不看,就关注声音资源加载的地方。

先分析一下Cocos2dxMusic.java 的声音资源加载方法

private MediaPlayer createMediaplayer(final String pPath) ;

这个方法就是啦。大概就是判断fullpath路径是否 '/'开头,如果是就加载sd卡声音资源,否则加载apk里的资源。


/** * create mediaplayer for music *  * @param pPath *            the pPath relative to assets * @return */private MediaPlayer createMediaplayer(final String pPath) {MediaPlayer mediaPlayer = new MediaPlayer();try {//加载sd卡里的声音资源if (pPath.startsWith("/")) {final FileInputStream fis = new FileInputStream(pPath);mediaPlayer.setDataSource(fis.getFD());fis.close();} else {//加载apk里的声音资源final AssetFileDescriptor assetFileDescritor = this.mContext.getAssets().openFd(pPath);mediaPlayer.setDataSource(assetFileDescritor.getFileDescriptor(), assetFileDescritor.getStartOffset(), assetFileDescritor.getLength());}mediaPlayer.prepare();mediaPlayer.setVolume(this.mLeftVolume, this.mRightVolume);} catch (final Exception e) {mediaPlayer = null;Log.e(Cocos2dxMusic.TAG, "error: " + e.getMessage(), e);}return mediaPlayer;}

在分析一下Cocos2dxSound.java的声音资源加载方法

->public int playEffect(final String pPath, final boolean pLoop)

->public int preloadEffect(final String pPath)

->public int createSoundIDFromAsset(final String pPath)

也是是判断fullpath路径是否 '/'开头,如果是就加载sd卡声音资源,否则加载apk里的资源。


public int createSoundIDFromAsset(final String pPath) {int soundID = Cocos2dxSound.INVALID_SOUND_ID;try {if (pPath.startsWith("/")) {//加载sd卡声音资源soundID = this.mSoundPool.load(pPath, 0);} else {//加载apk里的声音资源soundID = this.mSoundPool.load(this.mContext.getAssets().openFd(pPath), 0);}} catch (final Exception e) {soundID = Cocos2dxSound.INVALID_SOUND_ID;Log.e(Cocos2dxSound.TAG, "error: " + e.getMessage(), e);}// mSoundPool.load returns 0 if something goes wrong, for example a file does not existif (soundID == 0) {soundID = Cocos2dxSound.INVALID_SOUND_ID;}return soundID;}

回想起来,我们已经有fullpath ,我们要像读取向下面的资源

fullpath = /storage/emulated/0/DonutABC/unitRes/game_22.zip#/res/pub_element/L1U1/audio/pub_unit1_blue_audio.wav


有两种方法:

方法1:直接读取zip里的声音流 让播放器们播放

InputStream 这样的东西java 程序猿们太熟悉不过了,何况是ZipInputStream。我们先将对应的文件用ZipInputStream 读出,然后直接让MediaPlayer 或SoundPool 加载播放流不就可以了吗?可是童话都是骗人的。突然想起邓超演的《美人鱼》,我实在是想不通。好好的白富美在身边不要,偏偏去要一条上半身是人,下半身是鱼的人鱼。没有接口下半辈子能幸福吗!!!实在是想不通。在这个问题上,也是遇到了这样的人鱼。MediaPlayer 和 SoundPool 都没有直接播放流的方法 ,MediaPlayer的setDataSource方法。SoundPool的load方法 都没有播放流的接口。下半辈子不幸福,感觉不会再爱了。好吧换第二个方法

方法2:将zip对应的声音文件临时解压到sd卡里, 然后返回fullpath给 Cocos2dxMusic.java或Cocos2dxSound.java 的加载方法。

新欢没有接口,我们找旧爱。旧爱的接口就是要个声音文件的fullpath吗,太容易满足了。让我们动手改改 

Cocos2dxMusic.java 的 createMediaplayer

/** * create mediaplayer for music * * @param pPath *            the pPath relative to assets * @return */private MediaPlayer createMediaplayer(final String pPath) {MediaPlayer mediaPlayer = new MediaPlayer();try {if (pPath.startsWith("/")) {//改了这里String ppPath = PathUtils.getZipFilePath(pPath);final FileInputStream fis = new FileInputStream(ppPath);mediaPlayer.setDataSource(fis.getFD());fis.close();} else {final AssetFileDescriptor assetFileDescritor = this.mContext.getAssets().openFd(pPath);mediaPlayer.setDataSource(assetFileDescritor.getFileDescriptor(), assetFileDescritor.getStartOffset(), assetFileDescritor.getLength());}mediaPlayer.prepare();mediaPlayer.setVolume(this.mLeftVolume, this.mRightVolume);} catch (final Exception e) {mediaPlayer = null;Log.e(Cocos2dxMusic.TAG, "error: " + e.getMessage(), e);}return mediaPlayer;}

 Cocos2dxSound.java 的createSoundIDFromAsset

public int createSoundIDFromAsset(final String pPath) {int soundID = Cocos2dxSound.INVALID_SOUND_ID;try {if (pPath.startsWith("/")) {//改了下面的String ppPath = PathUtils.getZipFilePath(pPath);soundID = this.mSoundPool.load(ppPath, 0);} else {soundID = this.mSoundPool.load(this.mContext.getAssets().openFd(pPath), 0);}} catch (final Exception e) {soundID = Cocos2dxSound.INVALID_SOUND_ID;Log.e(Cocos2dxSound.TAG, "error: " + e.getMessage(), e);}// mSoundPool.load returns 0 if something goes wrong, for example a file does not existif (soundID == 0) {soundID = Cocos2dxSound.INVALID_SOUND_ID;}return soundID;}


解压的方法 getZipFilePath

/*** * 获得路径 也许是zip里面的的路径 * @param pPath * @return * @throws ZipException * @throws IOException     */public static String getZipFilePath(String pPath) throws ZipException, IOException {String zipfilepath = "";String filename = "";int index = pPath.indexOf("#");String ppPath = pPath;//是否在zip里if(index != -1){zipfilepath = pPath.substring(0,index);filename = pPath.substring(index+2);Log.d("RecordManager","zipfilepath:"+ zipfilepath + "--filename:" + filename);String filesavename = filename.replaceAll("/","_");ppPath = PathUtils.getTempPath() +filesavename+".temp";File filetemp = new File(ppPath);//是否有临时解压文件 避免重复解压if(!filetemp.exists()){filetemp.createNewFile();ZipFile file = new ZipFile(zipfilepath);FileHeader fileHeader = file.getFileHeader(filename);net.lingala.zip4j.io.ZipInputStream zipInputStream =  file.getInputStream(fileHeader);FileOutputStream fo =  new FileOutputStream(ppPath);byte[] b = new byte[4096];int readLine = -1;while ((readLine = zipInputStream.read(b)) != -1) {fo.write(b,0,readLine);}fo.close();zipInputStream.close();}}return ppPath;}

注:我用了开源的zip操作库 zip4j ,我git上有提交 。

好啦。我们这就跑起来。欧啦!声音出来了。这个方案凑合着用,如有更高明的方法,请回复我。


解压方法 c++版


static std::string getZipFilePath(const std::string& fullPath,const std::string& saveDir);static unsigned char* getFileDataFromZip(const char* pszZipFilePath, const char* pszFileName, unsigned long * pSize);

#include "support/zip_support/ZipUtils.h"#include "platform/CCCommon.h"#include "support/zip_support/unzip.h"#include "platform/CCFileUtils.h"


/** * fullpath 音效的绝对路径 * saveDir  解压到的地方 * return  解压后的资源返回的路径 **/std::string JNItools::getZipFilePath(const std::string& fullPath,const std::string& saveDir){    unsigned char * pBuffer = NULL;    unsigned long pSize = 0;    std::string savepath = fullPath;    std::string pszFileNameTemp = "";    std::string pszZipFilePath = "";
    size_t pos = fullPath.find_last_of("#");    if (pos != std::string::npos)    {                    // file_path = /storage/emulated/0/DonutABC/unitRes/game_22.zip        pszZipFilePath = fullPath.substr(0, pos);            // file = res/pub_element/L1U1/audio/pub_unit1_blue_audio.wav        pszFileNameTemp = fullPath.substr(pos+2);//        CCLOG("pszZipFilePath:%s,pszFileNameTemp:%s",pszZipFilePath.c_str(),pszFileNameTemp.c_str());                //替换‘/'        std::string filename = pszFileNameTemp;        std::string old_value = "/";        std::string new_value = "_";                for(string::size_type   pos(0);   pos!=string::npos;   pos+=new_value.length()){            if((pos=filename.find(old_value,pos))!=string::npos)                filename.replace(pos,old_value.length(),new_value);            else                break;        }//        CCLOG("filename:%s",filename.c_str());                savepath =  saveDir + filename + ".temp";               const char* output = savepath.c_str();        CCLOG("filename:%s",output);                   //文件如果存在就不解压了        int i = access(savepath.c_str(), 0);        CCLOG("filename:%d",i);                if( i == -1){            pBuffer = JNItools::getFileDataFromZip(pszZipFilePath.c_str(),pszFileNameTemp.c_str(),&pSize);                                     FILE *savefile = fopen(output, "wb");            fwrite(pBuffer, 1, (size_t)pSize, savefile);            fflush(savefile);            fclose(savefile);                        delete pBuffer;        }                                            }        return savepath;    }/** * 解压zip 获得资源数据 **/unsigned char* JNItools::getFileDataFromZip(const char* pszZipFilePath, const char* pszFileName, unsigned long * pSize){    unsigned char * pBuffer = NULL;    unzFile pFile = NULL;    *pSize = 0;        do    {//        CCLOG("1");        CC_BREAK_IF(!pszZipFilePath || !pszFileName);//         CCLOG("11");        CC_BREAK_IF(strlen(pszZipFilePath) == 0);//         CCLOG("1111");        pFile = unzOpen(pszZipFilePath);        CC_BREAK_IF(!pFile);//         CCLOG("2");        int nRet = unzLocateFile(pFile, pszFileName, 1);        CC_BREAK_IF(UNZ_OK != nRet);//         CCLOG("3");        char szFilePathA[260];        unz_file_info FileInfo;        nRet = unzGetCurrentFileInfo(pFile, &FileInfo, szFilePathA, sizeof(szFilePathA), NULL, 0, NULL, 0);        CC_BREAK_IF(UNZ_OK != nRet);//         CCLOG("4");        nRet = unzOpenCurrentFile(pFile);        CC_BREAK_IF(UNZ_OK != nRet);//         CCLOG("5");        pBuffer = new unsigned char[FileInfo.uncompressed_size];        int CC_UNUSED nSize = unzReadCurrentFile(pFile, pBuffer, FileInfo.uncompressed_size);        CCAssert(nSize == 0 || nSize == (int)FileInfo.uncompressed_size, "the file size is wrong");//         CCLOG("6");        *pSize = FileInfo.uncompressed_size;        unzCloseCurrentFile(pFile);    } while (0);        if (pFile)    {        unzClose(pFile);    }        return pBuffer;}


调方法

public static native  String getZipFilePath(String pPath,String saveDir);

    /**     * jni 调用     */    jstring Java_org_cocos2dx_lib_PathUtils_getZipFilePath(JNIEnv*  env, jobject thiz,jstring path,jstring savedir)    {//         CCLOG("filename:%s","Java_org_cocos2dx_lib_PathUtils_getZipFilePath");        std::string char_path = JniHelper::jstring2string(path);        std::string char_savedir = JniHelper::jstring2string(savedir);        std::string str_path = JNItools::getZipFilePath(char_path,char_savedir);//         CCLOG("----getPath:%s",str_path.c_str());        env->DeleteLocalRef(path);        env->DeleteLocalRef(savedir);        return (env)->NewStringUTF(str_path.c_str());            }


Cocos2dSound.java 修改的地方

public int createSoundIDFromAsset(final String pPath) {int soundID = Cocos2dxSound.INVALID_SOUND_ID;try {if (pPath.startsWith("/")) {String ppPath = PathUtils.getZipFilePath(pPath,PathUtils.getTempPath());soundID = this.mSoundPool.load(ppPath, 0);} else {soundID = this.mSoundPool.load(this.mContext.getAssets().openFd(pPath), 0);}} catch (final Exception e) {soundID = Cocos2dxSound.INVALID_SOUND_ID;Log.e(Cocos2dxSound.TAG, "error: " + e.getMessage(), e);}// mSoundPool.load returns 0 if something goes wrong, for example a file does not existif (soundID == 0) {soundID = Cocos2dxSound.INVALID_SOUND_ID;}return soundID;}

Cocos2dxMusic.java 修改

/** * create mediaplayer for music * * @param pPath *            the pPath relative to assets * @return */private MediaPlayer createMediaplayer(final String pPath) {MediaPlayer mediaPlayer = new MediaPlayer();try {if (pPath.startsWith("/")) {String ppPath = PathUtils.getZipFilePath(pPath,PathUtils.getTempPath());final FileInputStream fis = new FileInputStream(ppPath);mediaPlayer.setDataSource(fis.getFD());fis.close();} else {final AssetFileDescriptor assetFileDescritor = this.mContext.getAssets().openFd(pPath);mediaPlayer.setDataSource(assetFileDescritor.getFileDescriptor(), assetFileDescritor.getStartOffset(), assetFileDescritor.getLength());}mediaPlayer.prepare();mediaPlayer.setVolume(this.mLeftVolume, this.mRightVolume);} catch (final Exception e) {mediaPlayer = null;Log.e(Cocos2dxMusic.TAG, "error: " + e.getMessage(), e);}return mediaPlayer;}


整体来看效率没什么提高,就是不用 zip4j 解压了。


还是老样子。下载完整的改动

{{{{{{{{{github传送门}}}}}}}}

本文出处

http://blog.csdn.net/frabbit_on_fire/article/details/51538300

0 0