說一下需求擅腰,因?yàn)樽罱麬R有點(diǎn)火蟋恬,大BOSS從手機(jī)淘寶發(fā)現(xiàn)了一個(gè)AR游戲,在“我的淘寶”右上角
有一個(gè)“抓喵喵”的游戲趁冈,好像是AR實(shí)現(xiàn)的(本人小白歼争,不確定是不是AR。箱歧。矾飞。囧!)呀邢,點(diǎn)進(jìn)去就是一個(gè)游戲,如下圖:
所以大BOSS發(fā)話了豹绪,也要弄一個(gè)出來价淌,就集成到我們自己的App里,于是開干瞒津。蝉衣。。巷蚪。病毡。。先介紹一下大體功能屁柏,點(diǎn)擊進(jìn)入游戲啦膜,先是一個(gè)加載頁有送,這個(gè)我沒上圖,就是一張介紹游戲規(guī)則的圖片加一個(gè)進(jìn)度條僧家,說一下游戲場景里的功能雀摘,首先是一個(gè)地圖,看左下角八拱。阵赠。。肌稻。清蚀。高德地圖 這里用到了地圖和定位功能,主角定位的位置就是我當(dāng)前位置爹谭,主角少女旁邊有很多怪物(喵喵)轧铁,點(diǎn)擊喵喵,就進(jìn)入捕怪場景了(這些就屬于游戲部分了旦棉,具體功能大家可以下載或更新手機(jī)淘寶體驗(yàn)一下)齿风,抓捕到喵后就能獲取優(yōu)惠券折扣之類的。
本來的安排是游戲這塊是交給Unity開發(fā)做的绑洛,我們移動(dòng)端只需要在app上留個(gè)入口救斑,然后加載Unity游戲就行,所以任務(wù)下來了后就了解了一個(gè)Android和Unity交互這塊的知識(shí)點(diǎn)真屯,這個(gè)網(wǎng)上太多了脸候,我這里就不多說了,主要說一下绑蔫,在嵌入U(xiǎn)nity過程中遇到的各種問題
Android 中嵌入U(xiǎn)nity
關(guān)于Android和Unity集成运沦,網(wǎng)上有兩種方案,一種是把Android打包成jar配深,集成到Unity中携添,Unity中還要引入Android的SDK,另一種就是把Unity打包篓叶,然后解壓烈掠,把相關(guān)的jar包、資源文件引入Android項(xiàng)目中缸托,我采用的是第二種左敌,具體步驟我就不寫了(主要是懶。俐镐。矫限。。),找了兩個(gè)叼风,大家可以看看 (交互步驟兩位作者都寫的十分清楚取董,贊!):
說一下我的問題咬扇,Unity開發(fā)大哥甲葬,寫了Demo,打包發(fā)給我懈贺,我照著網(wǎng)上的步驟先試著往項(xiàng)目里集成经窖,一切都很OK,很輕松梭灿。然后問題來了画侣,本來這個(gè)游戲場景是Unity做的,但是Unity那邊集成地圖出現(xiàn)了無法解決的問題堡妒,所以地圖這塊兒需要移動(dòng)端來做了配乱,我有點(diǎn)忐忑,因?yàn)橐郧皬臎]集成過地圖皮迟,于是咬著牙硬上了搬泥,花了一天時(shí)間(囧!7帷7揲荨),把地圖弄出來了爆阶,剛開始用的是百度地圖燥透,但是要求中心點(diǎn)不在地圖正中心(中心點(diǎn)不在地圖中心還叫中心點(diǎn)嗎?),弄半天沒弄出來辨图,然后iOS哥們用的高德地圖班套,可以把中心點(diǎn)偏移出中心位置,于是建議我也用高德故河,好吧吱韭,換吧,正好統(tǒng)一下忧勿,換成高德地圖杉女,OK,都弄好了鸳吸,開始往里面集成Unity了,如下簡單布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<com.amap.api.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.amap.api.maps.MapView>
<FrameLayout
android:id="@+id/fl_unity_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
<ImageView
android:id="@+id/iv_unity_loading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/unity_loading"
android:scaleType="fitXY"/>
</RelativeLayout>
這里的mapView就是高德地圖速勇,F(xiàn)rameLayout 就是Unity場景的父布局了晌砾,最后的那個(gè)ImageView就是最開始游戲加載的圖片。當(dāng)前的Activity須得繼承UnityPlayerActivity烦磁,代碼:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_catch_layout);
//高德地圖
root = View.inflate(CatchActivity.this, R.layout.activity_catch_layout, null);
mMapView = (MapView) findViewById(R.id.mapView);
mMapView.onCreate(savedInstanceState);// 此方法必須重寫
//Unity 父布局
fl_unity_layout = (FrameLayout) findViewById(R.id.fl_unity_layout);
//把Unity游戲加載進(jìn)來
fl_unity_layout.addView(mUnityPlayer.getView());
//游戲加載圖片
iv_unity_loading = (ImageView) findViewById(R.id.iv_unity_loading);
//下面省略地圖初始化和定位設(shè)置养匈。哼勇。。呕乎。
}
我按上面代碼跑了一下积担,發(fā)現(xiàn)Unity場景怎么也出不來,之前單獨(dú)加載Unity可是OK的猬仁,咋回事帝璧?而且我的Unity可是放在地圖上面的,后來查了一下湿刽,地圖的MapView和Unity都涉及到了OpenGL中的glsurfaceview的烁,所以沖突了,想具體了解的可以看看OpenGL和glSurfaceView诈闺,于是我把這里的MapView換成了TextureMapView渴庆,解決了Unity不顯示的問題
Unity背景不透明問題
解決了Unity不顯示問題后,出現(xiàn)了另一個(gè)問題雅镊,那就是Unity場景的背景色是一片漆黑色的襟雷,即便Unity那邊設(shè)置了背景透明,打包后集成到Android中后也是漆黑一片仁烹,這就坑了耸弄,于是Android和Unity兩邊找解決辦法,各種找答案
https://forum.unity.com/threads/transparency-on-android.456736/
https://stackoverflow.com/questions/17705364/unityplayer-as-a-subview-with-transparent-background-unity-game-engine
http://www.geekyhamster.com/2013/07/unityplayer-as-subview-with-transparent.html
硬著頭皮看了幾篇英文文章晃危,都遇到了這個(gè)問題叙赚,發(fā)現(xiàn)只有Unity開發(fā)版本降到4.2才行,這叫一個(gè)坑A欧埂U鸲!!沒辦法鳍鸵,現(xiàn)在Unity開發(fā)大哥的Unity開發(fā)版本是2017的苇瓣,最后把版本降到了4.9,沒解決偿乖,再降到4.2击罪,搞到了半夜,還是沒弄出來贪薪,回家媳禁。。画切。竣稽。。第二天早上,稍改了一下毫别,試跑了一下娃弓,居然可以了,當(dāng)時(shí)激動(dòng)的岛宦,這個(gè)問題搞了兩天台丛,終于好了。砾肺。挽霉。。解決辦法是參照上面第三個(gè)鏈接改好的债沮,但是只能Unity 4.2版本打的包有效果炼吴,其他版本都不行,操蛋R唏谩9璞摹!
Unity-class.jar 混淆問題
解決了背景透明問題闷煤,心情大好童芹,想看看集成了Unity游戲后apk有多大,于是準(zhǔn)備打個(gè)release包看看鲤拿,但是假褪,一打release包就報(bào)錯(cuò),但是debug包沒問題啊近顷,也能直接在手機(jī)上運(yùn)行生音,錯(cuò)誤如下:
Warning:Exception while processing task java.io.IOException: Can't read [D:\****\app\libs\untiy-classes.jar(;;;;;;**.class)] (Can't process class [org/fmod/FMODAudioDevice.class] (256))
在網(wǎng)上查了一下,好像是混淆的時(shí)候出的問題窒升,在build.gradle 文件里一看缀遍,debug版沒有進(jìn)行混淆,所以沒有問題饱须,但是release混淆就出問題了域醇,所以,很明顯蓉媳,就是untiy-class.jar 這個(gè)包混淆時(shí)出問題了譬挚,于是照著網(wǎng)上的方案,將proguard-rules.pro 文件里的混淆規(guī)則改了一下
-dontwarn com.unity3d.player.**
-dontwarn org.fmod.**
-dontwarn bitter.jnibridge.**
-keep class com.unity3d.player.** {*;}
-keep class org.fmod.** {*;}
-keep class bitter.jnibridge.** {*;}
再打包酪呻。减宣。。玩荠。還是報(bào)錯(cuò)蚪腋,還是這個(gè)問題丰歌,摔桌姨蟋。屉凯。。眼溶。悠砚。
再搜。堂飞。灌旧。。
找到了遇到這個(gè)問題的解決方案:
android引入unity-classes.jar之后進(jìn)行混淆的問題解決
作者遇到的問題和我的簡直一毛一樣啊绰筛,興奮枢泰。。铝噩。衡蚂。。照著作者的方案骏庸,把ProGuard 的源文件改了毛甲,使用ant 重新編譯了,然后再打包具被。玻募。。一姿。七咧。還是報(bào)一樣的錯(cuò),再摔桌叮叹。艾栋。。衬横。裹粤。
再發(fā)幾個(gè)相同解決方案的鏈接:
http://www.cnblogs.com/huangbei1990/p/6097782.html
http://bbs.csdn.net/topics/392084419?list=lz
http://blog.csdn.net/vinomvp/article/details/58614043
http://blog.csdn.net/tianyutaizi/article/details/41698933
https://sourceforge.net/p/proguard/bugs/420/?page=0
https://stackoverflow.com/questions/22165902/proguard-returned-with-error-code-1-proguard-errors-with-untiy-classes-jar
http://glblong.blog.51cto.com/3058613/1435941
https://sourceforge.net/p/proguard/bugs/420/
然而,都沒解決我的問題蜂林,有點(diǎn)小絕望了遥诉。。噪叙。矮锈。
最后仔細(xì)想想,應(yīng)該是版本的問題睁蕾,幾位作者的帖子大都是三四年前的了苞笨,可能版本更新后债朵,有的問題就不能照原辦法解決了,問題卡這兒了瀑凝。序芦。。粤咪。
這個(gè)打包的問題還沒解決谚中,另一個(gè)問題又來了,4.2版本的Unity打包的程度在app上陀螺儀失效了寥枝,在這個(gè)游戲里宪塔,用戶是可以拿著手機(jī)移動(dòng)方位的,效果就是地圖也會(huì)隨著屏幕旋轉(zhuǎn)囊拜,而且游戲中的人物也會(huì)隨著屏幕旋轉(zhuǎn)的某筐,比如,上圖中冠跷,有一只喵在少女的后面南誊,沒顯示出來,需要用戶拿著手機(jī)轉(zhuǎn)個(gè)身蔽莱,將身后的怪物顯示在屏幕當(dāng)中弟疆,這里的Unity中有陀螺儀效果,喵喵會(huì)隨著屏幕旋轉(zhuǎn)而出現(xiàn)/隱藏于屏幕中盗冷,在iOS中是可以的怠苔,但是到了Android里就不行了,地圖可以旋轉(zhuǎn)仪糖,但是Unity中的模型動(dòng)不了柑司。。锅劝。攒驰。。
android端開發(fā)頓時(shí)卡住了故爵,而Unity開發(fā)大哥因?yàn)閍ndroid這方面的問題就先顧iOS去了玻粪,先把iOS搞出來,再來解決android問題
替換方案
android這邊兩個(gè)問題最終還是沒解決诬垂,一個(gè)是4.2版本的打包問題(2017版Unity的可以打包)劲室,另一個(gè)就是陀螺儀失效問題。结窘。很洋。。
最后技術(shù)老大拍板拿了方案隧枫,地圖和怪物顯示都android來做喉磁,Unity只負(fù)責(zé)打怪場景(Unity開發(fā)版本用2017版)谓苟,當(dāng)然,只是android端协怒。涝焙。〗锛ィ苦逼
只能在地圖上動(dòng)手腳了纱皆,要在地圖上顯示怪物,只能看自定義 Marker芭商,我是拿到當(dāng)前位置的經(jīng)緯度,然后通過隨機(jī)數(shù)搀缠,在當(dāng)前位置上隨機(jī)增加或減少經(jīng)度和緯度铛楣,將怪物分布到當(dāng)前位置的附近,再設(shè)置MarkerOption來顯示怪物的圖片
//隨機(jī)生成經(jīng)緯度
double demonLongitude = currentLongitude + ((random.nextDouble() + 0.01) * (random.nextInt() > 0.5 ? 0.002 : -0.002));
double demonLatitude = currentLatitude + ((random.nextDouble() + 0.01) * (random.nextInt() > 0.5 ? 0.002 : -0.002));
LatLng latlng = new LatLng(demonLatitude, demonLongitude);
MarkerOptions markerOption = new MarkerOptions().icon(BitmapDescriptorFactory.fromResource(demonList[db.getMonster_id()-1]))
.position(latlng)
.draggable(true);
aMap.addMarker(markerOption);
當(dāng)然這個(gè)效果和iOS端用Unity實(shí)現(xiàn)的效果比起來就差多了艺普,但是我暫時(shí)沒其他解決辦法了簸州。。歧譬。岸浑。一個(gè)是怪物不能動(dòng),不像Unity實(shí)現(xiàn)的那樣能夠動(dòng)而且是3D效果的瑰步,地圖上只有一張圖片矢洲,第二個(gè)就是圖片還是固定大小的,不能設(shè)置缩焦,想把怪物顯示大一點(diǎn)都不行读虏,若是哪位同學(xué)對(duì)高德地圖API里設(shè)置marker這塊比較熟悉的話望告知,謝謝
Unity退出問題
這里還有個(gè)坑爹問題袁滥,就是Unity退出的時(shí)候盖桥,會(huì)將整個(gè)進(jìn)程殺掉,導(dǎo)致app重啟题翻。揩徊。。嵌赠。
Unity中退出使用的是 mUnityPlayer.quit() 方法塑荒,但是我們看看這個(gè)方法的代碼:
public void quit() {
if(this.r != null) {
this.r.b();
}
this.o = true;
if(!this.e.e()) {
this.pause();
}
this.a.a();
try {
this.a.join(4000L);
} catch (InterruptedException var1) {
this.a.interrupt();
}
if(this.g != null) {
this.l.unregisterReceiver(this.g);
}
this.g = null;
if(j.c()) {
this.removeAllViews();
}
//這里是關(guān)鍵
this.kill();
g();
}
關(guān)鍵代碼是在倒數(shù)第三行 this.kill(); 下面是kill()方法:
protected void kill() {
Process.killProcess(Process.myPid());
}
殺死進(jìn)程啊,有木有猾普。袜炕。。初家。偎窘。所以APP就重啟了啊乌助。。陌知。他托。
網(wǎng)上千篇一律的都說加個(gè)按鈕調(diào)用mUnityPlayer.quity() 方法,或是在onBackPress方法中調(diào)用mUnityPlayer.quity() 方法仆葡,這樣和直接調(diào)用 mUnityPlayer.quity()有什么不一樣么赏参,都重啟app了,或許我用的方法不對(duì)沿盅?
稍靠譜點(diǎn)的就是android端調(diào)用Unity方法把篓,Unity端執(zhí)行退出,另一個(gè)方案就是將Unity單獨(dú)放另一個(gè)進(jìn)程里腰涧,這樣退出的話就不會(huì)殺死app所在的進(jìn)程了韧掩。
但是這兩種方案我都試過了,第一種窖铡,Unity端退出執(zhí)行的還是quity() 方法疗锐,最后還是把進(jìn)程給殺了,第二種試了也沒效果费彼。滑臊。。
最后想了個(gè)笨方法箍铲,就是用戶點(diǎn)返回按鈕或是退出這個(gè)繼承 UnityPlayerActivity的Activity時(shí)雇卷,不將這個(gè)Activity 關(guān)閉,而是將這個(gè)Activity的啟動(dòng)模式設(shè)置為singleInstance虹钮,即每次打開的時(shí)候?qū)⑵鋯为?dú)放在一個(gè)任務(wù)棧里(因?yàn)閍pp主頁是singleTask模式聋庵,進(jìn)入主頁時(shí),會(huì)將其上面的activity都清除出棧芙粱,為了避免UnityPlayerActivity子類被清除祭玉,所以將其設(shè)置為singleInstance,作為一個(gè)單例)春畔,這樣這個(gè)包含Unity游戲的Activity就不會(huì)finish掉脱货,同時(shí)也解決了每次加載Unity游戲時(shí)時(shí)間過長的問題,就第一次加載時(shí)花費(fèi)一些時(shí)間律姨,下次就不用再花時(shí)間來加載了振峻。。择份。扣孟。。我們Unity加載時(shí)間得幾十秒鐘荣赶,得等十一過后凤价,Unity開發(fā)大哥來解決這個(gè)問題了鸽斟。
其他要注意的問題
1、Unity調(diào)用Android是在子線程中運(yùn)行的利诺,所以如果涉及到UI操作富蓄,記得切換到主線程
/**
* 供Unity端調(diào)用
* 接收Unity傳遞過來的數(shù)據(jù)
*
* @param MessageData
*/
public void getUnityMessage(int messageType, String MessageData) {
switch (messageType) {
case 2://獲取怪物列表
runOnUiThread(new Runnable() {
@Override
public void run() {
//隱藏加載中圖片和Unity場景,顯示地圖
iv_unity_loading.setVisibility(View.GONE);
fl_unity_layout.setVisibility(View.GONE);
//若未授權(quán)定位慢逾,則提示用戶去設(shè)置
if (!isGrant) {
showFinishActivityDialog();
}
}
});
break;
case 3://打怪結(jié)果
String[] result = MessageData.split("/");
handleCatchResult(result[0],result[1],result[2]);
break;
}
}
2立倍、Unity端調(diào)用android 方法
AndroidJavaClass jc = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject> ("currentActivity");
jo.Call ("makePauseUnity");
上面的三個(gè)參數(shù),前兩個(gè)是固定不變的侣滩,即"com.unity3d.player.UnityPlayer"和"currentActivity" 這兩個(gè)參數(shù)是固定 不變的口注,之前,Unity開發(fā)那邊胜卤,換成了我們app的包名和 Unity所在的Activity名稱疆导,發(fā)現(xiàn)怎么也調(diào)用不了。
上面就是在Android中嵌入U(xiǎn)nity時(shí)葛躏,我遇到的一些坑,暫時(shí)只想到了這么多悠菜,后面想起來了再加上舰攒,同時(shí)如果有遇到同樣問題的同學(xué)可以提問,力所能及的話就幫著解決悔醋。同時(shí)摩窃,如果有對(duì)我上面遇到的問題有更好的解決辦法的,也請(qǐng)?jiān)谙旅媪粞苑医荆嘀x多謝猾愿!
另外想學(xué)習(xí)Unity的同學(xué)可以去這位大神博客看看,挺詳細(xì)的
廢話:第一次在簡書寫博客账阻,主要是太懶了蒂秘。。淘太。姻僧。明天就十一了,同事都下班了蒲牧,國慶好好休息撇贺,這半個(gè)月累壞了,天天到家十二點(diǎn)冰抢、一點(diǎn)的松嘶,腦仁兒疼,下班走人挎扰。翠订。巢音。
更新:最后Unity退出還是用mUnityPlayer.quit()方法退出,不過Unity所在的Activity設(shè)置process屬性蕴轨,單獨(dú)一個(gè)進(jìn)程港谊,這樣退出時(shí)就會(huì)退出Unity所在的進(jìn)程,而不會(huì)退出我們自己的app了