標籤:
cocos2dx一個跨移動(平板)平台的遊戲引擎,支援2d和3d,基於c/c++,網上介紹多在此不詳敘。
我們本篇關心的是跨平台那些事,自然而然就找到platform目錄。好傢夥,支援的操作平台還真不少,最吸引我們關注的可能就是字母順序排列的頭二個平台,android和apple。然後順帶會看一看winrt和linux。platform這個目錄,物如其名,就是一些使用到平台服務的東西(封裝)。platform目錄下各平檯子目錄封裝的平台服務都大同小異,唯android目錄特殊還多了jni和java兩個目錄。因為在android平台下做應用,用c/c++的話還跨了語言。至於iOS,c/c++和oc混搭是很自然的事。所以我們來看android平台的跨語言那些事。
cocos/platform/android/jni,不用解釋,就是java native interface。包含了從java到c/c++和從c/c++到java的調用協定。
這個目錄最主要的就是JniHelper相關的頭和源兩個檔案了。它主要負責協助c/c++代碼層完成對java代碼層的靜態方法的調用。而其它代碼檔案則是,特定為某個java類提供c/c++到java靜態方法調用協助,或是java到c/c++函數調用的協助。
所以這個目錄主要用來協助c/c++代碼調用java代碼,而c/c++跨平台為java提供的功能(或服務)的函數,一般來說都分散到了具體模組的目錄裡,當需要支援跨平台的代碼時,會將平台相關代碼,寫到如某個類的`-android.cpp`檔案去。
另一個目錄就是cocos/platform/android/java。沒錯就是java代碼的目錄。裡麵包含了一些專為cocos引擎層,也就是為讓c/c++代碼層使用到java庫,或用java庫實現功能的組件。可以通過java代碼使用到android平台提供的服務。對於apple平台(iOS和mac)來說,c/c++代碼與oc類混合使用是很自然的事;而winrt平台,平台提供的服務自然就是c/c++,或許以COM的形式;至於linux,第三方庫都是c/c++庫。因此除android以外的其它平台的子目錄,並沒有做太多的周折(相對於android來說)。
下面請看一下這樣的比較:
// jnijclass _clazz = (jclass) env->CallObjectMethod(jobj, loadclassMethod_ID, jstrClassName);jclass _clazz = env->FindClass(_cstrClassName);// iOSClass _clazz = NSClassFromNSString(_nsstrClassName);Class _clazz = [ClassName class];
// jnijmethodID methodID = env->GetMethodID(_clazz, cstrMethodName, cstrParamCode);// iOSSEL _selector = NSSelectorFromString(_nsstrSELName);IMP imp = class_getMethodImplementation(_clazz, _selector);
// jnienv->CallObjectMethod(jobj, methodID /**, (jobject*)arg1, ... */);// iOSobjc_msgSend(obj, sel /**, arg1, arg2, ... */);
可以看到java和oc之間還有共通,現在從java看oc,還是從oc看java,都不會感到完全的陌生,反而有幾分親近。
有一點要注意的是,java的類名是全路徑的,在代碼中以點引用的方式對包引用,在名字中則以‘/‘為節點分隔的路徑。java將方法拆分開方法名和原型描述。原型描述包含參數列表以及傳回型別,參數列表以‘()‘包含放在前面,後面才是傳回型別。對於java物件類型的描述包含在‘L;‘配對之中,java物件類型自然是類名的全路徑了。‘[‘表示的是數組。
jni從java調用c/c++代碼也就可能這麼一回事。java中只有類靜態方法和成員方法,所以java要調用c/c++函數,就必須在java層有對應的方法入口(或者說可以讓java代碼調用的等價物,methodID),這樣就將成員方法聲明為native。從上面c/c++調用java的函數CallObjectMethod可以看出,java調用成員方法時也是根據methodID找對應的代碼入口,jni產生的c/c++函式宣告也就是java中對應聲明為native的成員方法的methodID的映射。
當跨越jni時,相應也產生了損耗,其中原因只能去看jvm的代碼了。在這裡我只是試著猜想,可能c/c++函數和methodID不是直接映射,中間可能要做路由還是適配,或者是還有幾層的處理,構建跨語言的棧幀環境等。另外可能就是,c/c++函數不是位元組碼指令的東西,不利於虛擬機器對代碼的最佳化,就好像處理器在分支預測失敗的時候,要清空預裝載的指令重新裝入指令分支。
從cocos2dx原始碼看android和iOS跨平台那些事