关于Unity启动时间过长(启动黑屏时间长)的问题

2023-10-29

好吧,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,只是加载的时间还是比其他引擎慢了,不过也能接受,因为很快的 就开到了我们的启动动画界面,等待加载到游戏场景。

最后贴点代码上来。。。。

[java]  view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. package com.u3d.plugins;  
  2.   
  3. import java.util.Locale;  
  4.   
  5. import android.annotation.SuppressLint;  
  6. import android.content.Context;  
  7. import android.graphics.drawable.AnimationDrawable;  
  8. import android.media.AudioManager;  
  9. import android.media.AudioManager.OnAudioFocusChangeListener;  
  10. import android.os.Bundle;  
  11. import android.os.Handler;  
  12. import android.os.Looper;  
  13. import android.util.DisplayMetrics;  
  14. import android.util.Log;  
  15. import android.view.LayoutInflater;  
  16. import android.view.View;  
  17. import android.widget.ImageView;  
  18.   
  19. import com.unity3d.player.UnityPlayerActivity;  
  20.   
  21. public class MainActivity extends UnityPlayerActivity   
  22. {  
  23.     static final String TAG = "com.u3d.plugins";  
  24.     private ImageView bgView = null;  
  25.     private View view = null;  
  26.     AnimationDrawable animationDrawable = null;  
  27.       
  28.     @SuppressLint("NewApi"@Override  
  29.     protected void onCreate(Bundle arg0)   
  30.     {  
  31.         super.onCreate(arg0);  
  32.                   
  33.         bgView=new ImageView(this);  
  34.         String lanStr=Locale.getDefault().getLanguage();  
  35.         String bgName="splash_bg_en";  
  36.         if(lanStr.equals("zh"))  
  37.         {  
  38.             bgName="splash_bg_zh";  
  39.         }  
  40.         Log.d(TAG, "System Lan:"+bgName);  
  41.         int splash_bg=getResources().getIdentifier(bgName, "drawable", getPackageName());  
  42.         bgView.setBackgroundResource(splash_bg);  
  43. //      this.addContentView(bgView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));  
  44.         mUnityPlayer.addView(bgView);  
  45.           
  46.         DisplayMetrics dm = new DisplayMetrics();  
  47.         getWindowManager().getDefaultDisplay().getMetrics(dm);  
  48.         float scaleX=dm.widthPixels/1024f;  
  49.         float scaleY=dm.heightPixels/600f;  
  50.         Log.d(TAG, "Screen Width:"+dm.widthPixels+";Screen Height:"+dm.heightPixels);  
  51.         LayoutInflater flater = LayoutInflater.from(this);   
  52.         int layoutID=getResources().getIdentifier("activity_splash""layout", getPackageName());  
  53.         view = flater.inflate(layoutID, null);  
  54.               
  55.         int frame_id=view.getResources().getIdentifier("splash_frame""id", getPackageName());  
  56.         ImageView frameView=(ImageView)view.findViewById(frame_id);//new ImageView(this);  
  57.         frameView.setBackgroundResource(R.anim.splash_gif);  
  58. //      this.addContentView(view, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));  
  59.         mUnityPlayer.addView(view);  
  60.           
  61.         frameView.setScaleX(scaleX);  
  62.         frameView.setScaleY(scaleY);  
  63.           
  64. //      frameView=new ImageView(this);  
  65. //      frameView.setBackgroundResource(R.anim.splash_gif);  
  66. //        
  67. //      LinearLayout ll=new LinearLayout(this);  
  68. //      LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);  
  69. //      params.leftMargin=scaleX*620;  
  70. //      ll.setLayoutParams(params);  
  71. //      ll.addView(frameView);  
  72. //      mUnityPlayer.addView(ll);  
  73.           
  74.         animationDrawable = (AnimationDrawable) frameView.getBackground();  
  75.         animationDrawable.start();  
  76.     }  
  77.     public void HideSplash()  
  78.     {  
  79.         Log.d(TAG, "HideSplash");  
  80.         new Handler(Looper.getMainLooper()).post(new Runnable()  
  81.         {  
  82.             @Override  
  83.             public void run()  
  84.             {  
  85.                 Log.d(TAG, "HideSplash run");  
  86.                 animationDrawable.stop();  
  87.                 mUnityPlayer.removeView(bgView);  
  88.                 mUnityPlayer.removeView(view);  
  89. //              ((ViewGroup)bgView.getParent()).removeView(bgView);  
  90. //              ((ViewGroup)view.getParent()).removeView(view);  
  91.                 bgView=null;  
  92.                 view=null;  
  93.                 animationDrawable=null;  
  94.             }  
  95.         });  
  96.     }  
  97.     @Override  
  98.     protected void onRestart() {  
  99.         // TODO Auto-generated method stub  
  100.         super.onRestart();  
  101.         Log.d(TAG, "onRestart");  
  102.         new Handler(Looper.getMainLooper()).post(new Runnable()  
  103.         {  
  104.             @Override  
  105.             public void run()  
  106.             {  
  107.                 muteAudioFocus(MainActivity.this,true);  
  108.             }  
  109.         });  
  110.     }  
  111.     @Override  
  112.     protected void onResume() {  
  113.         // TODO Auto-generated method stub  
  114.         super.onResume();  
  115.     }  
  116.     @Override  
  117.     protected void onPause()   
  118.     {  
  119.         // TODO Auto-generated method stub  
  120.         super.onPause();  
  121.     }  
  122.     @Override  
  123.     protected void onDestroy() {  
  124.         // TODO Auto-generated method stub  
  125.         super.onDestroy();  
  126.     }  
  127.     @Override  
  128.     protected void onStop() {  
  129.         // TODO Auto-generated method stub  
  130.         super.onStop();  
  131.         Log.d(TAG, "onStop");  
  132.         new Handler(Looper.getMainLooper()).post(new Runnable()  
  133.         {  
  134.             @Override  
  135.             public void run()  
  136.             {  
  137.                 muteAudioFocus(MainActivity.this,false);  
  138.             }  
  139.         });  
  140.     }  
  141.     @Override  
  142.     protected void onStart() {  
  143.         // TODO Auto-generated method stub  
  144.         super.onStart();  
  145.         Log.d(TAG, "onStart");  
  146.         new Handler(Looper.getMainLooper()).post(new Runnable()  
  147.         {  
  148.             @Override  
  149.             public void run()  
  150.             {  
  151.                 muteAudioFocus(MainActivity.this,true);  
  152.             }  
  153.         });  
  154.     }  
  155.     /**@param bMute 值为true时为关闭背景音乐。*/  
  156.     public boolean muteAudioFocus(Context context, boolean bMute)   
  157.     {  
  158.         if(context == null)  
  159.         {  
  160.             Log.d(TAG, "context is null.");  
  161.             return false;  
  162.         }  
  163.         boolean bool = false;  
  164.         AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);  
  165.         if(bMute)  
  166.         {  
  167.             int result = am.requestAudioFocus(afChangeListener,AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN);  
  168.             bool = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;  
  169.         }  
  170.         else  
  171.         {  
  172.             int result = am.abandonAudioFocus(afChangeListener);  
  173.             bool = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;  
  174.         }  
  175.         Log.d(TAG, "pauseMusic bMute="+bMute +" result="+bool);  
  176.         return bool;  
  177.     }  
  178.     OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener()   
  179.     {    
  180.         public void onAudioFocusChange(int focusChange)   
  181.         {    
  182.             Log.d(TAG, "focusChange:"+focusChange);  
  183.             if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT)  
  184.             {    
  185.                 // Pause playback     
  186.             }  
  187.             else if (focusChange == AudioManager.AUDIOFOCUS_LOSS)   
  188.             {    
  189.                 muteAudioFocus(MainActivity.this,false);  
  190.                 // Stop playback     
  191.             }   
  192.             else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK)  
  193.             {    
  194.                 // Lower the volume     
  195.             }   
  196.             else if (focusChange == AudioManager.AUDIOFOCUS_GAIN)  
  197.             {    
  198.                 // Resume playback or Raise it back to normal     
  199.             }    
  200.         }    
  201.     };    
  202. }  

Unity的启动场景代码:

[csharp]  view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class Launcher : MonoBehaviour  
  5. {  
  6.     public string loadScene;  
  7.     void Awake()  
  8.     {  
  9.         Debug.Log("Launcher Awake");  
  10.         DontDestroyOnLoad(gameObject);  
  11.     }  
  12.     void Start()  
  13.     {  
  14.         Debug.Log("Launcher Start");  
  15.         StartCoroutine(LoadSence());  
  16.     }  
  17.     IEnumerator LoadSence()  
  18.     {  
  19.         if (!string.IsNullOrEmpty(loadScene))  
  20.         {  
  21.             Application.LoadLevelAsync(loadScene);  
  22.         }  
  23.         else  
  24.         {  
  25.             int levelCount = Application.levelCount;  
  26.             int curLevel = Application.loadedLevel;  
  27.             if (curLevel + 1 < levelCount)  
  28.                 Application.LoadLevelAsync(curLevel + 1);  
  29.         }  
  30.         yield return 0;  
  31.         Invoke("OnFinish", 0.5f);  
  32.         //OnFinish();  
  33.     }  
  34.     void OnFinish()  
  35.     {  
  36.         if (Application.platform.Equals(RuntimePlatform.Android))  
  37.         {  
  38.             using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))  
  39.             {  
  40.                 using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity"))  
  41.                 {  
  42.                     jo.Call("HideSplash");  
  43.                 }  
  44.   
  45.             }  
  46.         }  
  47.         Destroy(gameObject);  
  48.     }  
  49. }  
最后把我们的Android项目生成jar包供Unity使用

anim文件夹放了动画得的配置文件,layout布局文件。

[html]  view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     package="com.unity3d.player"  
  5.     android:installLocation="preferExternal"  
  6.     android:versionCode="1"  
  7.     android:versionName="1.0">  
  8.     <supports-screens  
  9.         android:smallScreens="true"  
  10.         android:normalScreens="true"  
  11.         android:largeScreens="true"  
  12.         android:xlargeScreens="true"  
  13.         android:anyDensity="true"/>  
  14.   
  15.     <application  
  16.         android:theme="@android:style/Theme.NoTitleBar.Fullscreen"  
  17.         android:icon="@drawable/launcher_icon"  
  18.         android:label="@string/app_name"  
  19.         android:debuggable="true">  
  20.         <activity android:name="com.u3d.plugins.MainActivity"  
  21.                   android:label="@string/app_name">  
  22.             <intent-filter>  
  23.                 <action android:name="android.intent.action.MAIN" />  
  24.                 <category android:name="android.intent.category.LAUNCHER" />  
  25.             </intent-filter>  
  26.             <meta-data android:name="unityplayer.UnityActivity" android:value="true" />  
  27.         </activity>  
  28.     </application>  
  29. </manifest>  


[html]  view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:id="@+id/splash_bg"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent"  
  6.     android:orientation="horizontal" >  
  7.   
  8.     <LinearLayout  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="match_parent"  
  11.         android:layout_weight="6.3"  
  12.         android:orientation="horizontal" />  
  13.   
  14.   <LinearLayout  
  15.         android:layout_width="wrap_content"  
  16.         android:layout_height="match_parent"  
  17.                 android:layout_weight="3.7"  
  18.         android:orientation="vertical" >  
  19.     <LinearLayout  
  20.         android:layout_width="wrap_content"  
  21.         android:layout_height="wrap_content"  
  22.         android:layout_weight="7.86"  
  23.         android:orientation="horizontal" />  
  24.         <LinearLayout  
  25.         android:layout_width="wrap_content"  
  26.         android:layout_height="wrap_content"  
  27.         android:layout_weight="2.14"  
  28.         android:orientation="horizontal" >  
  29.                 <ImageView  
  30.         android:id="@+id/splash_frame"  
  31.         android:layout_width="wrap_content"  
  32.         android:layout_height="wrap_content"/>  
  33.             </LinearLayout>  
  34.     </LinearLayout>  
  35.   
  36. </LinearLayout>  

[html]  view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <animation-list android:oneshot="false"  
  3.   xmlns:android="http://schemas.android.com/apk/res/android">  
  4.     <item android:duration="300" android:drawable="@drawable/loading_1" />  
  5.     <item android:duration="300" android:drawable="@drawable/loading_2" />  
  6.     <item android:duration="300" android:drawable="@drawable/loading_3" />  
  7. </animation-list>  
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于Unity启动时间过长(启动黑屏时间长)的问题 的相关文章

随机推荐

  • java实现文件下载功能

    目录 单个下载 流 1 设置响应类型和头信息 2 实现文件输出 单个下载 本地文件 1 文件读取 2 设置响应类型和头信息 3 实现文件输出 单个下载 网络文件 1 与服务器建立连接 2 设置响应类型和头信息 3 实现文件输出 压缩ZIP下
  • 第十二届蓝桥杯大赛模拟赛(网上最后一题题解大部分是错的)

    第十题 问题描述 小蓝在一个 n 行 m 列的方格图中玩一个游戏 开始时 小蓝站在方格图的左上角 即第 1 行第 1 列 小蓝可以在方格图上走动 走动时 如果当前在第 r 行第 c 列 他不能走到行号比 r 小的行 也不能走到列号比 c 小
  • 2020年,为什么你该学PHP?!!

    1676对于编程初学者来说一个开发顺手的代码编辑器很重要 可大多数人不了解代码编辑器有哪些 网上有很多种代码编辑器推荐 但是不知道这些代码编辑器哪个好用 所以 今天php中文网就为初学者推荐2020最好用的8个代码编辑器 代码编辑器排行榜
  • 聚类算法——KMeans算法(机器学习)

    KMeans算法 一 输入参数 n clusters 数据集将被划分成 n clusters个 簇 即k值以及 int optional default 8 一般需要选取多个k值进行运算 并用评估标准判断所选k值的好坏 以获得较好的聚类效果
  • 基于消息中间件解决分布式事务的开源框架Myth

    基于消息中间件的解决分布式事务框架 https github com yu199195 myth 1 rpc框架支持 dubbo motan springcloud 2 消息中间件支持 jms activimq amqp rabbitmq
  • uboot启动——lowlevel_init函数详解

    1 将lr寄存器中的值压栈 push lr lr寄存器保存的是函数返回地址 每个模式下只有一个lr寄存器 如果涉及多重函数调用 则lr寄存器会被覆盖 导致返回地址丢失 在之前已经初始化栈 所以这里可以将lr寄存器压栈 将来函数返回的时候再弹
  • 【网络】初识网络

    Linux初识网络 文章目录 Linux初识网络 网络 协议 协议分层 OSI七层模型 TCP IP五层 四层 模型 网络传输基本流程 数据包封装和分用 网络中的地址管理 IP地址 MAC地址 网络 协议 协议 是一种约定 计算机之间的传输
  • 基于YOLOv3算法的交通标志识别系统实现流程(个人学习笔记,仅当参考!!)

    总流程 安装darknet 本文利用linux操作系统上安装的Darknet开源轻型深度学习框架 为了提高训练速度利用CUDA和OPENCV 进行编译 完成对YOLO v3算法LISA数据集中四类不同的交通标志的训练及测试 实现对视频中运动
  • C#开发环境准备

    开发准备 1 安装visual studio code vscode 2 然后vscode的插件库安装 C Dev Kit 该插件会自动安装 C extension 和 IntelliCode for C Dev Kit 该插件需要安装 N
  • BeautifulSoup库的基本使用

    BeautifulSoup库的基本使用 1 库的基本使用 1 1 安装库 1 2 导入库 1 3 不同文件操作 2 获取html结构化数据 3 节点操作 3 1 获取子节点 3 2 获取节点内容 3 2 1 单个内容 3 2 2 多个内容
  • 华为OD机试真题 Java 实现【最多几个直角三角形】【2023Q1 100分】

    一 题目描述 有 N 条线段 长度分别为 a 1 a n 现要求你计算这 N 条线段最多可以组合成几个直角三角形 每条线段只能使用一次 每个三角形包含三条线段 二 输入描述 第一行输入一个正整数 T 1 lt T lt 100 表示有组测试
  • 多线程实现一分钟插入1000万条数据

    首先我们需要建立一个线程类 继承Thread类 并实现run方法 1 获取数据库连接 2 编写插入的sql语句 3 关闭自动提交 conn setAutoCommit false 4 编写for循环 跟着那个的插入方法一样 5 将注入的信息
  • L1-025 正整数A+B(java)

    1 题目详情 题的目标很简单 就是求两个正整数A和B的和 其中A和B都在区间 1 1000 稍微有点麻烦的是 输入并不保证是两个正整数 输入格式 输入在一行给出A和B 其间以空格分开 问题是A和B不一定是满足要求的正整数 有时候可能是超出范
  • 历史辩证唯物主义下的金融业发展的思考*

    历史辩证唯物主义下的金融业发展的思考 摘要 从历史唯物主义的角度来 金融是人类生产力发展到一定阶段的产物 金为黄金 融意味着分开流通之意 金融不是纯主观知识体系 而是基于客观经济规律的产物 是在不断的金融创新和协调金融风险的矛盾中逐渐完善
  • YOLOv5区域入侵检测【附完整代码以及视频演示】

    一 前期准备 首先你需要有一份yolov5的官方源码 并且能够找到其中的detect py文件即可 在检测过程中 有些项目不需要我们检测所有的区域 比如禁止区域的入侵检测 只需要检测制定规划出来的区域就可以 例如下图所示这样 在网上随便找的
  • 【word】使用VBA代码,自定义页面数拆分大Word文件为多个小文档并指定名称保存

    使用VBA代码 自定义页面数拆分大Word文件为多个小文档并指定名称保存 alt F11打开开发选项 gt 选择 插入 gt 模块 gt 弹出代码编辑窗口 插入下面代码 按照需要修改页数和要重命名的每个文档按顺序的名字 gt 按F5运行代码
  • 利用Qt Assistant 定制帮助文档

    为了将Qt Assistant定制为自己应用程序的帮助文档浏览器 需要完成以下几步 一 导入HTML格式的帮助文档 1 首先 针对自己的应用程序创建HTML格式的帮助文档 请参见 Doxygen生成HTML文件 下面示例假设HTML文件已经
  • 迷你世界物品查询代码lua

    迷你世界物品查询 local A local B local n 0 local s 0 local function add2 for j 1 500 do 等待1秒 threadpool wait 2 i n 1 500 j local
  • 刷脸支付数据积累价值将超越支付服务本身

    产业生态圈的角度来看 支付服务和在此基础之上所延伸出的产业支付生态 未来都将成为各个生态圈的基础设施 未来 随着产业数字化转型深入 某一场景下的终端客户 内部经营管理 上下游供应商等要逐步实现在线化 在这一过程中 产业各方参与者需要链接 支
  • 关于Unity启动时间过长(启动黑屏时间长)的问题

    好吧 Unity启动确实比其他引擎生成的游戏包慢些 关键是你启动的时候还要等上一段时间才显示Splash那个logo图 最近项目有个蛋疼得需求 需要在启动界面加进度帧动画 我也是醉了 刚开始的思路 用Unity单独做个启动场景 让Splas