1. 程式人生 > >Unity3D遊戲開發之“重寫Unity Android Splash,實現啟動無黑屏”

Unity3D遊戲開發之“重寫Unity Android Splash,實現啟動無黑屏”

轉自:http://www.manew.com/thread-98428-1-1.html

Splash設定相信搞unity的朋友都知道這個東西,就是遊戲啟動的時候的啟動畫面,在unity中如果不設定splash的話我們就能夠看到unity遊戲啟動的時候就會出現一張unity預設的帶有Unity標誌的splash啟動頁,如果我們需要換成自己的啟動頁就需要在打包的時候把splash設定成自己的圖片。
那麼Unity為什麼會有啟動頁這麼一個東西呢?
其實在我們遊戲啟動的時候unity或者我們自己會有一系列的資源載入或者初始化的東西,而這些操作都需要時間來完成,如果沒有splash的話就會造成一種卡機的假象。當unity所有的初始化都完成並載入第一個場景完成,unity就會自動的隱藏splash。




那麼可能有很多朋友就有疑問了,既然unity自帶了splash的設定我們為什麼還要重寫splash呢?
答案:不知道大家有沒有注意到,在我們啟動unity遊戲的時候會出現一段時間的黑屏然後才出現我們設定好的splash,如果機器配置越差,黑屏時間就越長。為了解決這個黑屏時間,我們重寫了splash功能,讓我們遊戲一啟動就出現我們的splash啟動頁。


接下來我們說一說重寫splash的流程:
重寫splash會涉及到好4個流程,1、編寫JAVA層splash載入和處理程式碼  2、設定Unity中的splash  3、編寫unity層隱藏splash程式碼  4、splash圖片資源路徑設定

1、編寫JAVA層splash載入和處理程式碼 

在這一流程中我們首先需要編寫我們自己的程式啟動Activity,此Activity繼承UnityPlayerActivity,因為我們需要在主Activity onCreate()的時候顯示我們JAVA層的splash。
再寫一個專門管理splash載入、顯示和隱藏的類。這個類的職責就是負責splash的載入、顯示、隱藏。
在載入了splash圖片新建view後我們需要把他加到Unity的View中,並且設定我們新建view的長寬為我們的Unity檢視的長寬這樣才能保證我們載入的splash跟unity中設定的splash一樣而不會變形。


2、設定Unity中的splash
這個過程是必要的,因為unity載入第一個場景的時候是需要時間的,而這段時間unity會使用splash來進行覆蓋,而且還會涉及到隱藏splash時機的
問題


3、編寫unity層隱藏splash程式碼
第二點說了一下隱藏時機的問題,可能大部分人都會認為unity splash消失後才會執行啟動場景中的Awake。但是我很確定的告訴你,並不是你想想的那樣。
其實在Awake執行後splash才會消失,而這段時間是不可預估的,所以如果我們不設定Unity自帶的splash頁面就會造成我們無法知道的splash什麼時候去隱藏他。
所以設定了unity的自帶splash後我們就能光明正大的把隱藏的程式碼放到啟動場景的Awake中去執行了。


4、splash圖片資源路徑設定
如果明白了上面的思路,那麼最後一步就是設定我們的splash資源路徑了。而這一步我們要設定2個地方的資源,一個是Android層載入的splash的位置,一個是Unity層設定的splash的位置。
可能你要問,unity層的splash設定不就是直接把圖片拖到設定面板中麼,但是這次我們不這樣做,其實搞懂了unity設定的splash最後在Android包中哪個位置那麼你就瞭解我要怎麼做了。
注意:splash圖片必須是png圖片並且名字是splash.png

Android層的splash設定:放入Assets\Plugins\Android\res\drawable中
Unity層的splash設定:放入Assets\Plugins\Android\assets\bin\Data中,不需要再設定面板中去設定splash,所以大家明白了unity設定的splash最後就是在assets\bin\Data中。
一般Android層和unity層的splash應該是同一張圖片,當然你也可以不一樣。

有朋友推薦了一篇部落格:http://blog.csdn.net/u012169685/article/details/52068809我抽空看了一下他的做法,基本的做法沒有什麼區別,最大的區別是我增加了一步就是設定unity的自身啟屏頁。我來解釋一下為什麼要這麼做。
在上面部落格的程式碼中我們可以看到最後他隱藏splsh的程式碼是在start裡面Invoke("OnFinish", 0.5f),這就說明他延遲了0.5s來隱藏splash,但是我很明確的是他這個做法是不準確的,因為unity隱藏splash的時機是不確定的,這種做法會導致splash提前或者延後隱藏,這完全取決於機器的效能。
我的做法是在啟動場景awake之前是靠Android層的splash覆蓋unitysplash,Awake之後就是顯示的unity自己的splash,最後隱藏是unity的自身行為,這種方式保證了unity的百分百準確隱藏splash。

例項程式碼:

package com.zwwx.jsws;



import com.unity3d.player.UnityPlayer;

import android.annotation.SuppressLint;

import android.app.Activity;

import android.os.Bundle;

import android.widget.ImageView;

import android.widget.ImageView.ScaleType;



public class Splash extends SDKBase{

        private ImageView bgView = null;

        private UnityPlayer mUnityPlayer = null;



        private static Splash mInstance;

        public static Splash getInstance() {

                if (null == mInstance) {

                        synchronized (Splash.class) {

                                if (null == mInstance) {

                                        mInstance = new Splash();

                                }

                        }

                }

                return mInstance;

        }



        @Override

        public void onCreate(Activity activity, Bundle savedInstanceState) {

                // TODO Auto-generated method stub

                super.onCreate(activity, savedInstanceState);

                mUnityPlayer = ((ZWWXActivity)mActivity).getUnityPlayer();

                onShowSplash();

        }

        

        @Override

        public void onDestroy() {

                // TODO Auto-generated method stub

                super.onDestroy();

                onHideSplash();

        }

        



        @SuppressLint("NewApi")

        public void onShowSplash() {        

                if (bgView != null)

                        return;



                try {Resources r = UnityPlayer.currentActivity.getResources();

                        bgView = new ImageView(UnityPlayer.currentActivity);

                        int splash_bg = r.getIdentifier("splash", "drawable",

                                                        UnityPlayer.currentActivity.getPackageName());

                        bgView.setBackgroundResource(splash_bg);

                        bgView.setScaleType(ScaleType.CENTER);

                        mUnityPlayer.addView(bgView,r.getDisplayMetrics().widthPixels,

                                        r.getDisplayMetrics().heightPixels);

                } catch (Exception e) {

                        error("[onShowSplash]"+e.toString());

                }

        }



        public void onHideSplash() {

                try {

                        if(bgView == null)

                                return;

                        UnityPlayer.currentActivity.runOnUiThread(new Runnable() {

                                public void run() {

                                        mUnityPlayer.removeView(bgView);

                                        bgView = null;

                                }

                        });

                } catch (Exception e) {

                        error("[onHideSplash]"+e.toString());

                }

        }

}