关于Unity启动时间过长(启动黑屏时间长)的问题
Unity启动确实比其他引擎生成的游戏包慢些,关键是你启动的时候还要等上一段时间才显示Splash那个logo图,那么有什么办法可以解决启动时间过长(启动黑屏时间长)的这个问题呢?下面就通过一个具体的项目案例给大家做介绍。
最近项目有个蛋疼得需求,需要在启动界面加进度帧动画。。我也是醉了。
刚开始的思路:用Unity单独做个启动场景,让Splash那张图用成纯黑。那么问题来了,除了Unity刚启动的黑屏 显示Splash的黑图,再到显示loading动画界面至游戏场景加载出来,这时间都在十多秒以上了,。项目要求游戏从启动到显示游戏场景不能超过5秒。。哎。。太难为我了。好长一段时间都没能解决这个问题。
中间还想到一个方案就是用Android做一个插件的启动Activity场景,然后把这个场景设置成启动场景,之后再到Unity的场景。但是这个问题是无法绕过Unity的启动Splash。。无奈放弃。
因为不熟悉Android开发,所以。。。
我分析了Unity生成Android,对就是从Unity的UnityPlayerActivity入手。既然绕不过,那就不绕过,思路:
1、Unity生成的Android应用必然要从这个UnityPlayerActivity启动,那么他的启动Splash view必然显示在这个activity里面;
2、那么我可以继承UnityPlayerActivity,然后在onCreate方法里面在创建一个view来覆盖Splash,是的。这是可行的。激动。。。。。。
3、那这个启动界面上我们也同样可以做动画咯,O(∩_∩)O哈哈~现在的问题是当Unity Splash显示完毕之后,或者初始化完成之后怎么来隐藏我们所创建的View和动画。
4、现在我们要在Unity建一个空场景用来加载我们的第一个游戏场景,当加载完成之后通知我们的自定义Activity移除我们创建的界面和动画,是不是很完美呢?
现在不用看黑屏了,也绕过了Unity的Splash,只是加载的时间还是比其他引擎慢了,不过也能接受,因为很快的 就开到了我们的启动动画界面,等待加载到游戏场景。
最后贴点代码上来。。。。
package com.u3d.plugins; import java.util.Locale; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.drawable.AnimationDrawable; import android.media.AudioManager; import android.media.AudioManager.OnAudioFocusChangeListener; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import com.unity3d.player.UnityPlayerActivity; public class MainActivity extends UnityPlayerActivity { static final String TAG = "com.u3d.plugins"; private ImageView bgView = null; private View view = null; AnimationDrawable animationDrawable = null; @SuppressLint("NewApi") @Override protected void onCreate(Bundle arg0) { super.onCreate(arg0); bgView=new ImageView(this); String lanStr=Locale.getDefault().getLanguage(); String bgName="splash_bg_en"; if(lanStr.equals("zh")) { bgName="splash_bg_zh"; } Log.d(TAG, "System Lan:" bgName); int splash_bg=getResources().getIdentifier(bgName, "drawable", getPackageName()); bgView.setBackgroundResource(splash_bg); // this.addContentView(bgView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); mUnityPlayer.addView(bgView); DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); float scaleX=dm.widthPixels/1024f; float scaleY=dm.heightPixels/600f; Log.d(TAG, "Screen Width:" dm.widthPixels ";Screen Height:" dm.heightPixels); LayoutInflater flater = LayoutInflater.from(this); int layoutID=getResources().getIdentifier("activity_splash", "layout", getPackageName()); view = flater.inflate(layoutID, null); int frame_id=view.getResources().getIdentifier("splash_frame", "id", getPackageName()); ImageView frameView=(ImageView)view.findViewById(frame_id);//new ImageView(this); frameView.setBackgroundResource(R.anim.splash_gif); // this.addContentView(view, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); mUnityPlayer.addView(view); frameView.setScaleX(scaleX); frameView.setScaleY(scaleY); // frameView=new ImageView(this); // frameView.setBackgroundResource(R.anim.splash_gif); // // LinearLayout ll=new LinearLayout(this); // LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT); // params.leftMargin=scaleX*620; // ll.setLayoutParams(params); // ll.addView(frameView); // mUnityPlayer.addView(ll); animationDrawable = (AnimationDrawable) frameView.getBackground(); animationDrawable.start(); } public void HideSplash() { Log.d(TAG, "HideSplash"); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { Log.d(TAG, "HideSplash run"); animationDrawable.stop(); mUnityPlayer.removeView(bgView); mUnityPlayer.removeView(view); // ((ViewGroup)bgView.getParent()).removeView(bgView); // ((ViewGroup)view.getParent()).removeView(view); bgView=null; view=null; animationDrawable=null; } }); } @Override protected void onRestart() { // TODO Auto-generated method stub super.onRestart(); Log.d(TAG, "onRestart"); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { muteAudioFocus(MainActivity.this,true); } }); } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); } @Override protected void onStop() { // TODO Auto-generated method stub super.onStop(); Log.d(TAG, "onStop"); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { muteAudioFocus(MainActivity.this,false); } }); } @Override protected void onStart() { // TODO Auto-generated method stub super.onStart(); Log.d(TAG, "onStart"); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { muteAudioFocus(MainActivity.this,true); } }); } /**@param bMute 值为true时为关闭背景音乐。*/ public boolean muteAudioFocus(Context context, boolean bMute) { if(context == null) { Log.d(TAG, "context is null."); return false; } boolean bool = false; AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); if(bMute) { int result = am.requestAudioFocus(afChangeListener,AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN); bool = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED; } else { int result = am.abandonAudioFocus(afChangeListener); bool = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED; } Log.d(TAG, "pauseMusic bMute=" bMute " result=" bool); return bool; } OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() { public void onAudioFocusChange(int focusChange) { Log.d(TAG, "focusChange:" focusChange); if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) { // Pause playback } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { muteAudioFocus(MainActivity.this,false); // Stop playback } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { // Lower the volume } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { // Resume playback or Raise it back to normal } } }; }
using UnityEngine; using System.Collections; public class Launcher : MonoBehaviour { public string loadScene; void Awake() { Debug.Log("Launcher Awake"); DontDestroyOnLoad(gameObject); } void Start() { Debug.Log("Launcher Start"); StartCoroutine(LoadSence()); } IEnumerator LoadSence() { if (!string.IsNullOrEmpty(loadScene)) { Application.LoadLevelAsync(loadScene); } else { int levelCount = Application.levelCount; int curLevel = Application.loadedLevel; if (curLevel 1 < levelCount) Application.LoadLevelAsync(curLevel 1); } yield return 0; Invoke("OnFinish", 0.5f); //OnFinish(); } void OnFinish() { if (Application.platform.Equals(RuntimePlatform.Android)) { using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity")) { jo.Call("HideSplash"); } } } Destroy(gameObject); } }
anim文件夹放了动画得的配置文件,layout布局文件。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.unity3d.player" android:installLocation="preferExternal" android:versionCode="1" android:versionName="1.0"> <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true"/> <application android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:icon="@drawable/launcher_icon" android:label="@string/app_name" android:debuggable="true"> <activity android:name="com.u3d.plugins.MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="unityplayer.UnityActivity" android:value="true" /> </activity> </application> </manifest>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@ id/splash_bg" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="6.3" android:orientation="horizontal" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="3.7" android:orientation="vertical" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="7.86" android:orientation="horizontal" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="2.14" android:orientation="horizontal" > <ImageView android:id="@ id/splash_frame" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> </LinearLayout> </LinearLayout>
<?xml version="1.0" encoding="UTF-8"?> <animation-list android:oneshot="false" xmlns:android="http://schemas.android.com/apk/res/android"> <item android:duration="300" android:drawable="@drawable/loading_1" /> <item android:duration="300" android:drawable="@drawable/loading_2" /> <item android:duration="300" android:drawable="@drawable/loading_3" /> </animation-list>