[Unity3D]Unity3D遊戲開發之在Android視圖中嵌入Unity視圖,unity3dandroid
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
喜歡我的部落格請記住我的名字:秦元培,我部落格地址是blog.csdn.net/qinyuanpei。
轉載請註明出處,本文作者:秦元培,本文出處:http://blog.csdn.net/qinyuanpei/article/details/39380717
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
大家好,我是秦元培,歡迎大家關注我的部落格,我的部落格地址是blog.csdn.net/qinyuanpei。最近博主發現博主的文章被很多的網站(如遊戲蠻牛)等非法轉載,在轉載的過程中博主原來的文章出處和連結均被去掉,更讓博主覺得生氣的事情是某些人將博主的文章複製一部分以原創文章的形式發表在CSDN上,這樣CSDN在根據Tag推薦相關文章的時候,就會將一部分文章串連到博主部落格以外的地方,博主並不是一個小氣的人,只是這些部落格都是傾注了博主自己心血而寫成的,如此作踐難免讓博主本人心寒。從今天起,博主所有的文章、配圖都會加上連結,希望以此告誡那些非法轉載博主文章的人懂得自重、懂得尊重博主的勞動成果。
好了,這些人我暫且不去理會,今天我們繼續來研究Unity在Android平台上的擴充,通過昨天的學習,大家已經知道Unity和Android是可以互相調用的,可是相信大家從昨天的文章中可以看出,如果單純地從調用Android介面的角度來看,我們已經可以實現這一目的。可是從實際開發的角度來看,我們只是邁出了很小的一步。為什麼這麼說呢,因為在實際的開發中可能我們不僅需要從介面上實現與Unity的對接,而且需要從介面上實現與Unity的對接。比如,現在主流的網遊都會在遊戲開始的時候給玩家一個選擇建立角色的過程,通常介面上會顯示各種類型的角色設定,玩家可以通過介面瞭解每種類型的角色的特點,從而選擇合適自己的角色。從技術上來講,這一部分我們可以完全使用Unity3D的GUI系統來實現,不過本文的目的在於探討Unity和Android的對接問題,因此我們可以假定Android在整個對接過程中扮演著介面渲染的角色,而Unity則負責遊戲邏輯的維護。那麼,這樣就誕生了我們今天的問題,能不能將Unity作為Android介面的一部分嵌入到Android應用中呢?答案當然是肯定的。
一、為Unity編寫Android外掛程式
首先,我們來看Unity中為Android提供的類檔案UnityPlayerNativeActivity.java,該檔案位於如下位置:
D:\ProgramFiles\Unity\Editor\Data\PlaybackEngines\androidplayer\com\unity3d\player(在不同的電腦上可能會有所不同,大家靈活運用即可)
package com.unity3d.player;import android.app.NativeActivity;import android.content.res.Configuration;import android.graphics.PixelFormat;import android.os.Bundle;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.View;import android.view.Window;import android.view.WindowManager;public class UnityPlayerNativeActivity extends NativeActivity{protected UnityPlayer mUnityPlayer;// don't change the name of this variable; referenced from native code// Setup activity layout@Override protected void onCreate (Bundle savedInstanceState){requestWindowFeature(Window.FEATURE_NO_TITLE);super.onCreate(savedInstanceState);getWindow().takeSurface(null);setTheme(android.R.style.Theme_NoTitleBar_Fullscreen);getWindow().setFormat(PixelFormat.RGB_565);mUnityPlayer = new UnityPlayer(this);if (mUnityPlayer.getSettings ().getBoolean ("hide_status_bar", true))getWindow ().setFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);setContentView(mUnityPlayer);mUnityPlayer.requestFocus();}// Quit Unity@Override protected void onDestroy (){mUnityPlayer.quit();super.onDestroy();}// Pause Unity@Override protected void onPause(){super.onPause();mUnityPlayer.pause();}// Resume Unity@Override protected void onResume(){super.onResume();mUnityPlayer.resume();}// This ensures the layout will be correct.@Override public void onConfigurationChanged(Configuration newConfig){super.onConfigurationChanged(newConfig);mUnityPlayer.configurationChanged(newConfig);}// Notify Unity of the focus change.@Override public void onWindowFocusChanged(boolean hasFocus){super.onWindowFocusChanged(hasFocus);mUnityPlayer.windowFocusChanged(hasFocus);}// For some reason the multiple keyevent type is not supported by the ndk.// Force event injection by overriding dispatchKeyEvent().@Override public boolean dispatchKeyEvent(KeyEvent event){if (event.getAction() == KeyEvent.ACTION_MULTIPLE)return mUnityPlayer.injectEvent(event);return super.dispatchKeyEvent(event);}// Pass any events not handled by (unfocused) views straight to UnityPlayer@Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); }@Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); }@Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); }/*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); }}
熟悉Android開發的朋友一定對這個類覺得眼熟吧,NativeActivity是Google在Android3.0後推出的,其目的是為了讓開發人員使用C/C++在NDK環境下管理Activity的生存周期,於是我們可以大膽的猜測Unity之所以可以和Android進行互動是因為NDK提供了方便之門,果然,博主在Unity的目錄下找到了
libmain.so、libunity.so、libmono.so這三個檔案,這證實我們的猜想是正確的。在這個類中,我們可以看到Unity做了大量的初始化工作,並且重寫了NativeActvity的相關方法。不知道大家還記不記得我們在前一篇文章中定義主Activity時,我們是讓它繼承自UnityPlayerActivity而不是Android的Activity。那麼,這個UnityPlayerActivity是什麼呢?我們開啟它的檔案:
package com.unity3d.player;/** * @deprecated Use UnityPlayerNativeActivity instead. */public class UnityPlayerActivity extends UnityPlayerNativeActivity { }
這時候我相信大家和博主一樣都有一種恍然大悟的感覺,原來它是繼承自UnityPlayerNativeActivity的,換句話說Unity在Android這部分其實做了兩件事,即初始化Activity和重寫相關的方法。我們注意到代碼中的注釋提示這個類已經deprecated建議我們使用UnityPlayerNativeActivity,這點我們暫時不用管,我們依然使用UnityPlayerActivity,因為它和UnityPlayerNativeActivity本質上是一樣的。好了,到目前為止,如果大家已經理解了這裡所有的內容,那麼我們可以浩浩蕩蕩地沖向Eclipse開始編寫Android項目了。
和昨天一樣,我們建立一個Android項目並將其設為庫,這裡我們將其包名設為com.android.unityview4android。這個名稱很重要,我們在Unity中將繼續使用這個名字。首先我們來建立一個Android的布局檔案activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <Button android:id="@+id/BtnPre" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:text="@string/BtnPre" /> <LinearLayout android:id="@+id/UnityView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/BtnNext" android:layout_below="@+id/BtnPre" android:orientation="vertical" > </LinearLayout> <Button android:id="@+id/BtnNext" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="@string/BtnNext" /></RelativeLayout>
這裡我們放置了兩個Button按鈕,分別用來控制Unity向前、向後切換模型,在螢幕中間有一個叫做UnityView的線性布局,它將作為Unity視圖的父控制項,即我們會將Unity的視圖放到這個控制項裡。我們注意到在UnityPlayerNativeActivity.java類中有一個UnityPlayer類型的變數mUnityPlayer,該類型博主目前沒有找到官方的相關說明,博主推測它應該是負責Unity介面渲染的一個類吧,在這個類中有一個getView()方法,它將返回一個View類型的值,我們便可以通過這種方法將其添加到Android視圖裡,因為我們已經準備好了一個UnityView的父控制項,所以這一切實現起來變得相當地容易:
package com.android.unityview4android;/*匯入Unity提供的類*/import com.unity3d.player.UnityPlayer;import com.unity3d.player.UnityPlayerActivity;import android.os.Bundle;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.LinearLayout;public class MainActivity extends UnityPlayerActivity {private Button BtnPre,BtnNext;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//設定當前布局檔案setContentView(R.layout.activity_main);//擷取顯示Unity視圖的父控制項LinearLayout mParent=(LinearLayout)findViewById(R.id.UnityView);//擷取Unity視圖View mView=mUnityPlayer.getView();//將Unity視圖添加到Android視圖中mParent.addView(mView);//上一個BtnPre=(Button)findViewById(R.id.BtnPre);BtnPre.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {UnityPlayer.UnitySendMessage("GameObject", "ShowPrevious", "");}});//下一個BtnNext=(Button)findViewById(R.id.BtnNext);BtnNext.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {UnityPlayer.UnitySendMessage("GameObject", "ShowNext", "");}});}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}
好了,這樣我們就完成了Jar庫的編寫,我們只要將Jar庫匯入到Unity中,並且按照上一篇文章中所述的方法構建Android外掛程式目錄組織相關資源就可以了。最後我們給出AndroidManifest.xml檔案:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.unityview4android" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.android.unityview4android.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application></manifest>
二、建立Unity項目
好了,現在我們來建立Unity項目,我們這裡建立一個簡單地情境,情境中只有一個空遊戲體和攝像機,我們將通過指令碼的形式來控制Unity渲染,主要的指令碼代碼如下:
using UnityEngine;using System.Collections;public class ModelManager : MonoBehaviour {//模型public GameObject[] Models;//當前索引private int index=0;//當前對象private GameObject mObject;void Start () {this.name="GameObject";//產生第一個物體mObject=(GameObject)Instantiate(Models[index]);}public void ShowNext(){ //使索引增加 index+=1; //範圍控制 if(index>Models.Length-1){index=0; } //銷毀原來物體 Destroy(mObject); //產生新物體 mObject=(GameObject)Instantiate(Models[index]);}public void ShowPrevious(){//使索引減少index-=1;//範圍控制if(index<0){index=Models.Length-1;}//銷毀原來物體Destroy(mObject);//產生新物體mObject=(GameObject)Instantiate(Models[index]);}}
這段指令碼我們綁定到這個空的遊戲體上,指令碼的兩個方法ShowNext()和ShowPrevious()相對應,通過UnitySendMessage()實現通訊。好了,我們來運行項目,:
我們可以注意到當程式開啟的那一瞬間,是Android視圖先載入、然後Unity視圖才載入的,給人整體的感覺就是在Activity裡面嵌套了一個Activity。可是博主馬上就發現了一個問題,這Android視圖中的按鈕無法取得焦點啊,點擊事件無效。這是為什麼呢?後來博主找到的解決方案是在AndroidManifest.xml檔案中的activity子節點下增加如下兩行代碼:
<meta-data android:name="android.app.lib_name" android:value="unity" /> <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />
這樣問題是解決了,可是我們得搞懂為什麼吧,在Unity官方文檔中,我們找到了答案:
請注意,NativeActivity在Android2.3以後被引入而且不支援該版本以下的裝置。因為觸摸/運動事件處理在機器碼,Java視圖通常不會看到這些事件。然而,在統一轉寄機制允許將事件傳播到DalvikVM。為了使用這個機制,您需要修改manifest檔案如下:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product"> <application android:icon="@drawable/app_icon" android:label="@string/app_name"> <activity android:name=".OverrideExampleNative" android:label="@string/app_name"> <meta-data android:name="android.app.lib_name" android:value="unity" /> <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application></manifest>
這段話的意思就是說Android的事件是運行在機器碼中的,Java視圖是看不到這些事件的,然而我們可以通過Unity提供的統一轉寄機制將這些事件發送到Android虛擬機器,為了使用這個機制,我們必須修改Android的AndroidManifest.xml檔案。博主感覺Android外掛程式這塊官方目前做得不是很好,總是給人一種雲裡霧裡的感覺,而且通過各種語言相互調用增加了調試的難度,關於Android更多的內容,大家可以參考官方的文檔:點擊這裡.好了,今天的內容就是這樣啦,希望大家喜歡。最後再來看看程式啟動並執行效果吧
每日箴言:這年頭連夢想都是有期限的。有想法就去做,即使失敗了都比沒做來得好,因為失敗至少給了你經驗,沒做只會帶給你懊悔。——朱德庸
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
喜歡我的部落格請記住我的名字:秦元培,我部落格地址是blog.csdn.net/qinyuanpei。
轉載請註明出處,本文作者:秦元培,本文出處:http://blog.csdn.net/qinyuanpei/article/details/39348677
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Unity3D開發的遊戲發布到android手機上後中文不可以顯示,怎解決?源碼
我記得U吧裡面有關於植入廣告的解決方案..摟主看下 unity3d8.com/...%AA%A4
[Unity3D]手機3D遊戲開發:怎使用Unity3D中內建的重力感應
汪 汪海的實驗室 海的實驗室- - 各種圖形學實驗和資料結構實驗以及其他一切瑣碎雜亂的小筆記們都相遇在此齊聚一堂共同守候 0 - - 各種圖形學實驗和資料結構實驗以及其他一切瑣碎雜亂的小筆記們都相遇在此齊聚一堂共同守候 0error(s), 0 warning(s) 這神奇時刻的到來 error(s), 0 warning(s) 這神奇時刻的到來學習Unity指令碼推薦:Unity3D官網索引重力感應在手機遊戲的開發中非常常見。Unity3D本身集合了重力感應的相關內容。一個簡單的JS指令碼示範一下重力感應的使用。CSDNGravity.js://物體的貼圖var round : Texture2D;//物體在螢幕中顯示的X Y座標var x = 0;var y = 0;//物體螢幕顯示的最大 X Y 範圍var cross_x = 0;var cross_y = 0;function Start(){//初始化賦值cross_x = Screen.width - round.width;cross_y = Screen.height - round.height;}function OnGUI () {//整體顯示 x y z 重力感應的重力分量GUI.Label(Rect(0,0,480,100),"position is " + Input.acceleration);//繪製物體GUI.DrawTexture(Rect(x,y,256,256),round);}function Update(){//根據重力分量修改物體的位置這裡乘以30的意思是讓物體移動的快一些x += Input.acceleration.x * 30;y += -Input.acceleration.y * 30;//避免物體超出螢幕if(x < 0){x = 0;}else if(x > cross_x){x = cross_x;}if(y < 0){y = 0;}else if(y > cross_y){y = cross_y;}}這裡的Input是指Unity中的輸入,acceleration便是其重力了,x和y分別代表其重力分量。建立完畢之後只需要添加紋理圖片即可:12