关于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   
	        }  
	    }  
	};  
}

Unity的启动场景代码:

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);
    }
}
最后把我们的Android项目生成jar包供Unity使用

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>


Unity开发的Android应用程序进入黑屏时间可能有多个原因。 1.资源加载时间Unity应用程序启动时,需要加载各种资源,例如游戏场景、纹理、音频、脚本等。如果资源较多或者资源文件较大,加载时间就会变,导致进入黑屏时间。 2.编译和打包时间:在Unity中,将应用程序编译和打包成Android应用需要一定时间。如果项目代码较多或者有复杂的逻辑,编译和打包的时间就会增加,从而导致黑屏时间。 3.设备性能不足:如果用户的Android设备性能较低,如处理器速度慢、内存较小,那么启动Unity应用程序的时间可能会比较。这是因为设备性能不足导致Unity引擎初始化和资源加载速度变慢。 4.其他耗时操作:除了资源加载和编译打包,还可能有其他耗时操作导致进入黑屏时间,例如初始化插件、网络请求、加载广告等。这些操作都可能会增加进入黑屏时间。 解决这个问题可以从以下几个方面入手: 1.优化资源加载:合理使用资源压缩和分包技术,减小资源文件大小,降低加载时间。另外,可以进行异步加载,避免阻塞主线程。 2.优化代码逻辑:简化代码结构,减少不必要的计算和操作,提高应用程序的启动速度。 3.兼容性测试和优化:针对不同的Android设备进行兼容性测试,发现性能较低的设备并进行相应的优化。 4.使用启动图或进度提示:可以在应用程序启动时显示一张启动图或者添加一个进度提示,从而让用户感知到应用程序正在加载,减少黑屏时间的影响。 综上所述,Unity Android应用程序进入黑屏时间可能是由于资源加载时间、编译和打包时间、设备性能不足以及其他耗时操作等原因造成的。通过优化资源加载、代码逻辑、兼容性测试和增加启动图或进度提示等方式可以减少黑屏时间
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值