標籤:des android blog http java 使用 os io
本文轉自:http://www.cnblogs.com/Z-XML/p/3349518.html
引言:我們使用cocos2d-x引擎製作了一款飛行射擊遊戲,其中創新性地融入了手勢識別功能。但是我們在移植過程中遇到了很多的問題,同時也發現網上的資料少而不全。所以在項目行將結束的時候,我們特地寫了這篇文章來完整記錄我們整個移植的過程,紀念我們項目的成功完成,更以此來表達對協助過我們的人的感謝。移植過程中我們在網上得到了很多協助,更要感謝黃楊學長在最後時刻協助我們突破難關!
0、開發平台
系統:win8 profession 64bit
IDE:vs2012 rtm, eclipse
cocos2d-x版本:2.1.2
1、移植準備
在windows下移植我們需要如下環境支援:Android SDK、 NDK、 Eclipse、 Cygwin.
1.1下載Cygwin安裝程式
在Cygwin官網上找(http://cygwin.com/install.html)到線上安裝程式,下載對應版本。這裡我選擇 windows 64bit版本。
1.2 Cygwin安裝過程
開啟下載好的setup-x86_64.exe,可一路單擊下一步(篇幅所限,太過細節的問題就不一一闡述了),直到如下頁面:
選擇下載的網站,正確選擇網站之後下載會很快。我們(在北航)選擇了ftp://mirrors.neusoft.edu.cn,速度還是挺快的。這裡要提醒大家注意,並不是所有網站的下載都是完整的!Rylynn(部落格名)選擇的好幾個網站都下載不完整,大家如果遇到這個問題,可嘗試不同的網站。
選擇完網站之後將出現如上介面,這是要選擇安裝包。為了使Cywin能夠編譯器,我們需要選擇一些必要的組件。在不改動預設選擇的前提下,我們需要保證在Devel分支裡如下包已經被選中:binutils, gcc-c++,gcc-core,gdb,make,mingw-gcc-core,mingw-gcc-c++。安裝成功後,運行Cygwin,可以在Cygwin視窗中分別輸入gcc+ -v, g++ -version, make -v, gdb -v等命令並斷行符號,如果看到視窗輸出了各組件的版本資訊,那麼說明安裝成功。如果輸入某條命令,視窗輸出 command not found,那麼就需要重新開啟安裝程式並安裝對應的組件,不需要全部重新安裝。
1.3 安裝Eclipse、Android SDK、 Android NDK
這裡提供網站連結,大家可自行下載和安裝。NDK下載後解壓即可。Eclipse的安裝和環境配置,請大家參考相應的文章,在此不再贅述。
Android SDK:http://developer.android.com/sdk/index.html
Android NDK:http://developer.android.com/tools/sdk/ndk/index.html
Eclipse:http://www.eclipse.org/downloads/
1.4 編輯create-android-project指令碼
在cocos2d-x引擎的根目錄下,可以找到create-android-project指令碼。在windows下,對應的是"create-android-project.bat",這個指令碼用於產生遊戲的android工程。
使用任何支援unix風格換行的編輯器(我們選擇了Ultra Editor)開啟指令檔,找到如下語句,並進行修改。
set _CYGBIN = e:\cygwin\bin
set _ANDROIDTOOLS =e:\android\andoird-sdk\tools
set _NDKROOT = e:\android\android-ndk-r8d
其中將_CYGBIN設定為Cygwin安裝目錄下的"bin"檔案夾路徑,_ANDROIDTOOLS設定為Andoird SDK安裝路徑下"tools"檔案夾路徑,_NDKROOT設定為NDK的解壓路徑。
完成設定後,在Cygwin中運行"create-android-project"指令碼(可直接將檔案拖入Cygwin視窗後斷行符號)。若提示如下,則修改成功:
Input package path. For example: org.cocos2dx.example:
2、產生項目
接下來我們執行create-android-project指令碼。用Cygwin運行"create-android-project.bat",看到如下提示:
Input package path. For example: org.cocos2dx.example:
此時輸入我們想要建立的程式包名(程式包的命名應遵守Andoird命名規範)。我們輸入:"org.cocofish.skyline"(我們這個項目的隊名叫cocofish,項目叫做skyline。大家可隨意選擇,只要記住就好)。斷行符號後,視窗輸出:
Input project name:
我們輸入了"Skyline"
斷行符號後,視窗會列出電腦中安裝的所有Android SDK版本,大家可以根據需要自行選擇。我們輸入了"1",即選擇android 4.1.2的版本。在Lmeng(部落格名)的電腦裡,整個過程視窗輸出的內容貼在下方:
1 Please enter your package path. For example: org.cocos2dx.example:org.cocofish.skyline 2 Please enter your project name:Skyline 3 "Now cocos2d-x suppurts Android 2.1-update1, 2.2, 2.3 & 3.0" 4 "Other versions have not tested." 5 Available Android targets: 6 ---------- 7 id: 1 or "android-16" 8 Name: Android 4.1.2 9 Type: Platform10 API level: 1611 Revision: 412 Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, W13 XGA720, WXGA800, WXGA800-7in14 ABIs : armeabi-v7a, mips, x8615 ----------16 id: 2 or "Google Inc.:Google APIs:16"17 Name: Google APIs18 Type: Add-On19 Vendor: Google Inc.20 Revision: 321 Description: Android + Google APIs22 Based on Android 4.1.2 (API level 16)23 Libraries:24 * com.google.android.media.effects (effects.jar)25 Collection of video effects26 * com.android.future.usb.accessory (usb.jar)27 API for USB Accessories28 * com.google.android.maps (maps.jar)29 API for Google Maps30 Skins: WVGA854, WQVGA400, WSVGA, WXGA800-7in, WXGA720, HVGA, WQVGA432, WVGA31 (default), QVGA, WXGA80032 ABIs : armeabi-v7a33 ----------34 id: 3 or "android-17"35 Name: Android 4.2.236 Type: Platform37 API level: 1738 Revision: 239 Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, W40 XGA720, WXGA800, WXGA800-7in41 ABIs : armeabi-v7a, mips, x8642 ----------43 id: 4 or "Google Inc.:Google APIs:17"44 Name: Google APIs45 Type: Add-On46 Vendor: Google Inc.47 Revision: 348 Description: Android + Google APIs49 Based on Android 4.2.2 (API level 17)50 Libraries:51 * com.google.android.media.effects (effects.jar)52 Collection of video effects53 * com.android.future.usb.accessory (usb.jar)54 API for USB Accessories55 * com.google.android.maps (maps.jar)56 API for Google Maps57 Skins: WVGA854, WQVGA400, WSVGA, WXGA800-7in, WXGA720, HVGA, WQVGA432, WVGA58 (default), QVGA, WXGA80059 ABIs : armeabi-v7a60 Please input target id:1
完成之後,指令碼會在根目錄下建立"Skyline"的目錄,並在此目錄裡產生Android專案檔。新建立的專案檔中有Helloworld的項目,大家接著可直接跳到從"執行build_native.sh"繼續後續操作,通過完成這樣一個預設的項目的移植來檢測整個配置和操作過程的正確性。這裡將繼續自己項目的移植。
開啟新建立的項目目錄(我們這裡是"Skyline"),可以看到"Classes"和"Resources"目錄,指令碼會在這兩個目錄下建立預設的Helloworld代碼和資源檔,我們把它們全部刪除。接著,把我們自己的項目源碼和資源複製到這兩個目錄裡。通常,我們將原始碼(.cpp和.h)複製到"Classes"目錄下,把資源檔(圖片,音樂等)複製到"Resources"目錄下。操作完成後,進入下一步。
重要!在建立的項目後,proj.android\jni\hellocpp下,有個main.cpp,是整個項目的入口。直接點擊,會彈出"拒絕訪問"。如果想要查看裡面的內容的話,要先修改它的屬性-安全-進階,在許可權條目裡將使用權限設定為"完全控制"(雙擊後可修改)。main.cpp的內容,一般情況下不需要做修改。
3、編譯
完成上述操作後,我們要對項目進行編譯,並產生.so檔案(unix的動態連結程式庫,與windows的.dll類似)。
3.1 修改"Android.mk"
"Android.mk"檔案位於項目的"proj.android\jni"目錄下,它記錄了項目所包含的源碼檔案資訊。利用編輯器(如Ultra Editor)開啟此檔案,參照下面的檔案進行修改。/*...*/裡的內容是筆者加上的注釋
1 LOCAL_PATH := $(call my-dir) /*不改動*/ 2 3 include $(CLEAR_VARS) /*不改動*/ 4 5 LOCAL_MODULE := sky_shared /*預設為game_sharred,如果改動,請一定記住*/ 6 7 LOCAL_MODULE_FILENAME := libsky /*預設為libgame,如果改動,請一定記住。*/ 8 9 LOCAL_SRC_FILES := hellocpp/main.cpp \ 10 ../../Classes/AppDelegate.cpp 11 ../../Classes/其他源檔案.cpp /*添加上自己項目裡所有的源檔案,結尾的‘\‘是串連符,如果下一行還有內容,請不要漏掉.而且‘\‘後應直接斷行符號*/ 12 13 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes 14 $(LOCAL_PATH)/../../../cocos2dx/platform/third_party/win32 15 $(LOCAL_PATH)/../../../extensions /*添加上自己項目裡標頭檔所在的目錄。後兩行是筆者因為項目而單獨添加的,前一個是為線程,後一個是為 控制項類引入的標頭檔所在的目錄*/16 17 LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static cocosdenshion_static cocos_extension_static /*以下均不作改動*/18 19 include $(BUILD_SHARED_LIBRARY)20 21 $(call import-module,CocosDenshion/android) 22 $(call import-module,cocos2dx) 23 $(call import-module,extensions)
重要!出錯點!筆者在這一步遇到很多問題,所以也請讀者加以重視。
(1)對LOCAL_MODULE與LOCAL_MODULE_FILENAME修改後請務必記住自己所修改的名字。比如筆者將它們改為skyline_shared和libskyline。因為這裡的skyline將會在匯入eclipse那一步之後用到。我們需要將在通過執行“create-android-project”建立的專案檔夾裡的"<你的項目名>.java”(比如"skyline.java")這個檔案裡System.loadLibrary("game")的“game”改成自己所修改的名字,在筆者這裡就是"skyline",否則就是黑屏。估計是無法載入產生的libskyline.so(後面會提到)。筆者因為這個問題糾結了很久!最後才發現原來就一個字串的事情!!如果不改動前面的LOCAL_MODULE和LOCAL_MODULE_FILENAME,因為預設的是"game",那就不會有問題。
(2)如果你在項目裡引入了線程和控制項類,可參考筆者這個代碼框裡的LOCAL_C_INCLUDES。對於線程,請注意:將你引入線程的那個檔案裡"#include ‘pthread/pthread.h‘"改為"#include‘pthread.h‘",以使編譯能夠通過。(筆者不知道原因,也許沒有這麼麻煩,但是在筆者電腦裡成功了。也希望明白的人告知~)
3.2 執行"build_native.sh"
接下來就啟動編譯了。進入android項目路徑下,使用Cygwin執行"build_native.sh"指令碼(tip:可直接將檔案拖入Cygwin視窗),如果順利,我們可以在Cygwin視窗輸出的最後發現“Install : libsky.so => libs/armeabi/libsky.so”,並且在libs/armeabi目錄下找到編譯獲得的"libskyline.so"(注意到了嗎,這是上一步設定的LOCAL_MODULE_FILENAME)。
然而,事情往往不那麼順利!
重要!出錯點!很大可能你會看到Cygwin輸出一大堆亂七八糟的東西,而且在中途停下。這時候就是編譯出錯了。但是千萬不要著急,一點點調。雖然出錯了,但是報錯點還是很準確的。所以請大家從最上面往下一行一行找。發現有"error"的這行,這就是報錯點。仔細看這行的內容,它很明確地告訴你是哪個檔案哪一行出了錯。這時候去找到那個出錯的位置,根據報錯的資訊,尋找一些資料,加上自己的判斷和嘗試,把錯誤處理掉。然後再編譯一遍。如果有錯誤,繼續處理。不要看一堆字母感覺煩躁(看著就像亂碼的感覺),這時候你最需要的就是慢慢來。而且這個錯誤可能來自於引擎代碼本身!!
比如筆者遇到這樣幾個錯誤:
(1)使用了未聲明的"itoa"。於是我去查Classes目錄下的props_number_shower.cpp第27行,確實調用了itoa這個方法。雖然這個在vs2012裡運行沒問題,但是這裡並不支援。於是我從網上找了一個替代itoa功能的函數原始碼,加入到這個源檔案中,編譯就通過了。
(2)格式問題。同樣的思路,找到CocosDenshion/android/SimpleAudioEngine.cpp第77行。發現了LOGD(deviceModel)()。上網查了下發現好像linux對格式要求比較嚴格,於是筆者嘗試把這行改為LOGD("%s", deviceModel);發現編譯通過。在編譯的過程中發現非常多類似的報錯,大家如果看到報錯資訊如,找到指定位置修改即可。
(3)檔案流。筆者對c++檔案流是否能在Cygwin中編譯通過沒有做足夠的測試。但是筆者將fstream換成c的FILE操作的時候就不報錯了,如果大家在這裡遇到問題,可以嘗試著改改。但是對於移植到android上,還應采CCFileUtils。範例如下:
1 string fullPath=CCFileUtils::sharedFileUtils()->getWritablePath()+"rank.txt"; /*"rank.txt"是自己使用的資源檔,其他的不用改動。此行用於獲得檔案位置*/2 unsigned long file_size; /*聲明變數,在下一行中使用,用於接收檔案內容大小*/3 char *filedata=(char*)CCFileUtils::sharedFileUtils()->getFileData(fullPath.c_str(),"r",&file_size); /*取得檔案指標*/4 if(filedata==NULL)... /*對於檔案指標的用法,與C++一樣*/
如果遇到其他的錯誤,讀者可按照以上解決問題的思路自行解決問題。
4、匯入Eclipse
4.1建立項目
開啟Eclipse,一次開啟"File"-"New"-"Project"-"Android"-"Android Project from Existing Code"項目,在隨後出現的介面中點擊browser,後找到遊戲項目的"proj.android"並確認,此時即從原有代碼中建立了安卓項目。
4.2複製必要檔案
4.2.1將cocos2d-2.1rc0-x-2.1.2(根目錄)\cocos2dx\platform\android\java\src下的檔案複製到Sky(遊戲項目根目錄)\proj.android\src裡,並在eclipse中手動匯入
4.2.2如果Sky(遊戲項目根目錄)\proj.android\assets裡沒有資源檔,將Sky(遊戲項目根目錄)\Resources下你的所有資源檔複製到assets中,並在eclipse中手動匯入
4.3 做必要的修改
4.3.1 在Sky(遊戲根目錄)\src\<項目名>裡的Sky.java檔案裡,所標示的那行中,請記得將loadLibrary("xxx");裡的字串改為先前修改過的LOCAL_MODULE_FILENAME的值(去掉lib),如筆者改為sky。注意!這在上面已經強調過,如果這裡的字串和LOCAL_MODULE_FILENAME(去掉lib)的不匹配,結果很慘烈!看不見介面!筆者在這裡費了很多時間!
4.3.2 其他簡單的錯誤,比如所示:找不到drawable/icon,可在eclipse工程中res裡加入一個icon.png檔案即可。當然也可將icon改名成其他以存在於工程的圖片檔案(一般為png檔案)
5、調試
虛擬機器十分卡,而且好像並不支援opengl,所以建議使用真機進行調試(使用方法這裡就不詳細展開,大家可在網上查閱相關資料)。調試過程中難免發生問題,這裡將列舉出筆者在調試過程中遇到的問題,探討解決的思路。
5.1 檔案許可權問題。在調試過程中我們在logcat message視窗看到這樣一個錯誤,意思是某個檔案許可權不夠。如果這時候大家複製這麼長串的看起來像目錄的東西去搜尋,是找不到的。因為他們畢竟不是目錄名。這個時候,大家可以選去關鍵詞去搜尋。比如這張圖片裡,我們認為"shader"是關鍵詞,果然在項目安卓工程裡找到了"shaders"檔案夾,將裡面所有檔案的許可權修改成“完全控制”,發現調試不再報錯,可以認為修改成功!
5.2檔案讀寫問題
某種意義上筆者並不願意把它稱作檔案讀寫問題。後面將做解釋。
如果讀者還記得的話,上面已經提到過讀寫問題。如果單純採用C的檔案讀寫寫法,工程就會找不到資源檔。因此將它改成上述的CCFileUtils,將解決此類問題。
1 string fullPath=CCFileUtils::sharedFileUtils()->getWritablePath()+"rank.txt"; /*"rank.txt"是自己使用的資源檔,其他的不用改動。此行用於獲得檔案位置*/2 unsigned long file_size; /*聲明變數,在下一行中使用,用於接收檔案內容大小*/3 char *filedata=(char*)CCFileUtils::sharedFileUtils()->getFileData(fullPath.c_str(),"r",&file_size); /*取得檔案指標*/4 if(filedata==NULL)...
5.3 如何調試
之所以說讀者不願意把“5.2檔案讀寫問題”稱作“檔案讀寫問題”,是因為讀者在解決這類問題的時候使用的方法其實是告訴了我們如何進行調試。筆者在完成5.1那一步之後發現真機上還是沒有顯示出任何內容。黑屏!這個時候我們著急了,曾經已經將helloword顯示在手機上了,為什麼這個項目就不可以?!學長提示我們是不是主菜單載入不成功,並知道我們對每一個關鍵區段加上一個輸出,通過在控制台的輸出查看哪一步出了問題!比如我們在主菜單"mainmenu.cpp"的"init()"裡每一個載入操作後加上了CCLOG("%s","init() xxx;--From MainMenu")("xxx"這裡改成特定的值,用於確定出錯位置)。也是通過這個方法,我們才確定了所有的“檔案讀寫問題”。因此,如果大家遇到問題,請大家不要氣餒,一點點地去判斷出錯位置,然後修改,嘗試。
6、解析度適配
最後一個問題就是解析度適配了。在網上翻看了相關資料後,總算解決了問題。其實就是一行代碼的事情。
在 AppDelegate.cpp的 bool AppDelegate::applicationDidFinishLaunching() 方法裡,加上
CCEGLView::sharedOpenGLView()->setDesignResolutionSize(576,324,kResolutionNoBorder);即可解決解析度適配問題。
其中,576,324 是筆者在win32設計遊戲時採用的寬度和高度,大家改為自己所設定的寬高即可。kResolutionNoBorder是指在螢幕展開時採用的其中一種策略,保證展開後無邊界,但是設計時介面的邊緣部分可能在最後被遮蓋。筆者通過vs2012的 "go to definition"操作找到了如下的定義。以下即是全部的適配策略了。
1 enum ResolutionPolicy 2 { 3 // The entire application is visible in the specified area without trying to preserve the original aspect ratio. 4 // Distortion can occur, and the application may appear stretched or compressed. 5 kResolutionExactFit, 6 // The entire application fills the specified area, without distortion but possibly with some cropping, 7 // while maintaining the original aspect ratio of the application. 8 kResolutionNoBorder, 9 // The entire application is visible in the specified area without distortion while maintaining the original10 // aspect ratio of the application. Borders can appear on two sides of the application.11 kResolutionShowAll,12 13 kResolutionUnKnown,14 };
參考資料:參考的資料較為零碎,多為網上的文章。因為比較繁亂,沒有記錄下來。另外參考了《Cocos2d-x進階開發教程》的移植部分。
總結:
筆者和隊友在整個移植過程中備受煎熬,幾近絕望。但是始終相信既然別人能夠移植成功,我們也一定可以!最終我們用了兩天多的時間終於讓我們的遊戲成功運行在手機上!那個興奮感、那種絕處逢生的快感到現在還十分難忘!所以請各位cocos2d-x的戰友們不要氣餒,問題都是可以解決的,一點一點來,不要著急,給自己信心。先把helloworld顯示出來,然後再把自己的項目慢慢調出來。堅持下去,總會成功的!
Here is our game <SkyLine Beta1.0>, Please download it to support us!!!
http://pan.baidu.com/s/13O4dT
希望這篇文章能夠幫到困擾在cocosd-x移植android過程中的朋友們。如果文章內容與錯誤或者某些部分有更好的解法,也請留言。我們很希望和大家交流經驗!謝謝!