Unity与C#学习记录 - 13

14 篇文章 0 订阅

01 Splash Screen

对Unity Splash Screen使用进行简单记录,主要是针对安卓的。

第一点,只设置Static Splash Image,效果非常好,就是显示该启动图片:

第二点,用Splash Screen,启用的话就能用Preview直接预览启动效果,可以选择是否显示Unity的logo,可以设置动画模式,可以添加多个logo,设置持续时间等。这里注意,logo就是小的图片,它需要在背景图之上,且动画效果控制其变大淡入淡出效果。而且为了凸显logo,清晰背景图会被unity模糊化,如果想以此来替代Static Splash Image则会得到模糊化的启动图效果。

第三点,我开发的VR应用,开启unity的xr支持,sdk选择一个Cardboard甚至None,就会发现Splash无效了。然后我注意到Virtual Reality Splash Image,对其进行设置,并取消Splash Screen和Static Splash Image,还是未得到启动图效果。这可能很少有人用到过,我觉得可能我设置不正确或者Unity有bug,这里unity是2017.4版本。因此,对于安卓VR应用的Splash,我用了第二点中的做法,背景被自动模糊了,其实并不是我想要的,我想要的是VR应用Splash像普通应用Static Splash Image那样。

02 Unity序列化代码.NET4.6运行时安卓平台kernel32报错问题

这里记录一个少见的问题,有关于安卓平台序列化kernel32.dll找不到的问题。

首先是示例代码:

using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;
using UnityEngine;

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }

    [XmlIgnore] //此属性不被序列化,System.Xml.Serialization.XmlIgnoreAttribute
    public bool Gender { get; set; }
}

public class TestSer2 : MonoBehaviour
{
	void Start ()
	{
        Serializer(Application.persistentDataPath + "/test.xml");
        List<Person> people = Deserializer(Application.persistentDataPath + "/test.xml");
        Debug.Log(people[0].Age);
	}

    public List<Person> Deserializer(string path)
    {
        List<Person> list = new List<Person>();
        XmlSerializer xmlSer = new XmlSerializer(typeof(List<Person>));

        using (System.IO.FileStream fs = System.IO.File.OpenRead(path))
        {
            list = (List<Person>)xmlSer.Deserialize(fs);
        }

        return list;
    }

    public void Serializer(string path)
    {
        List<Person> list = new List<Person>();
        Person p1 = new Person() { ID = 1, Name = "张三", Age = 18 };
        Person p2 = new Person() { ID = 2, Name = "李四", Age = 20 };
        list.Add(p1);
        list.Add(p2);

        //xml序列化,System.Xml.Serialization.XmlSerializer
        XmlSerializer xmlSer = new XmlSerializer(typeof(List<Person>));

        using (System.IO.FileStream fs = System.IO.File.OpenWrite(path))
        {
            xmlSer.Serialize(fs, list);
        }
    }
}

这个代码直接创建简单的xml并写入两个人的信息,如下:

<?xml version="1.0"?>
<ArrayOfPerson xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Person>
    <ID>1</ID>
    <Name>张三</Name>
    <Age>18</Age>
  </Person>
  <Person>
    <ID>2</ID>
    <Name>李四</Name>
    <Age>20</Age>
  </Person>
</ArrayOfPerson>

然后反序列化读取第一个人的年龄信息。

Windows上没有任何问题,而安卓上则出现了问题。首先Unity版本是2.17.4.15f1,编译安卓的时候,选择Scripting Runtime Version未Stable(.NET 3.5 Equivalent),编译运行没有问题。出问题的是在选择4.6的时候,手机上就报错:

Unable to find kernel32.dll

不过不得不说,这个报错虽然有,但是解析还是解析出来了,让人疑惑。

接着,由于我Unity2019.1正式版已经出来了,它的4.6运行时已经不是实验版了,我用它做了同样的测试,报错依旧(Api Compatibility Level选的是.NET 4.x)。不过我继续尝试,发现2019版本Unity选择4.6的运行时版本的时候,仍然可以选择Api Compatibility Level为.NET Standard 2.0,用该版本进行编译,发现不会报错。这边说的都是Mono后端,没涉及IL2CPP。

因此序列化的操作考虑跨平台问题,还是需要2.0的Api兼容等级。如果用了异步等操作,还需要4.x的运行时,那么二者都要,可能就不得不用2019版本的Unity了(2018.3在选择了4.x运行时的情况下也可以选择2.0的Api兼容等级,而不像2017.4长期支持版那样选择了4.x后就只能用4.x的Api兼容等级,毕竟这里的4.x还是实验版本)。

03 Unity DLL平台设置

前面的一篇博客记录了VS添加条件编译符号的操作,这里还有一些别的设置需要Unity中完成,记录如下。

创建Plugins目录,下面根据平台创建Android和x86目录,如下:

分别放入VS编译的DLL,安卓下的dll已经自动默认平台为Android,且没有其他设置:

x86下面的则默认为全平台,这里设置为Windows:

且可以继续设置CPU和OS类型,且可以区分Editor和Standalone模式。

根据测试,Editor模式中,切换平台为Windows,那么自然调用的是x86下面的dll。切换为安卓,发现仍然调用x86下面的dll。真正编译运行在安卓平台上的时候,则调用了Android目录下的dll。所以说,要编译一个安卓平台的dll,想要调用的话,还需要一个Windows版本的dll,这样Edito模式中才能运行起来不报错。

04 Unity Movie Texture报错问题

本来的一个工程写了www.GetMovieTexture()的代码,虽然没用到,但是这也导致安卓平台上报错

Windows平台则是可以的,也不报错。为了测试,我写了下面的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestGetMovieTexture : MonoBehaviour
{
    void Start ()
    {
        StartCoroutine(TestMovieTexture(Application.persistentDataPath + "test.txt"));
    }
    
    IEnumerator TestMovieTexture(string path)
    {
        string prefix = "file://";
        UnityEngine.Object obj;
        WWW www = new WWW(prefix + path);

        while(!www.isDone)
        {
            yield return null;
        }

        if(path.Contains("mp4"))
        {
            obj = www.GetMovieTexture();
        }

        else
        {
            Debug.Log("Not supported");
        }

        www.Dispose();
    }
}

Windows平台则能输出我预设的“Not supported”,切换到安卓平台编译,本来还想重现原来的问题,这次居然编译不过了:

error CS1061: Type `UnityEngine.WWW' does not contain a definition for `GetMovieTexture' and no extension method `GetMovieTexture' of type `UnityEngine.WWW' could be found. Are you missing an assembly reference?

真是怪事。网上也有关于安卓上movie texture的问题,且unity已经不太支持用这个了:

而且我本来也用不到,只是一行代码写道了GetMovieTexture(),反而让我浪费许多时间查找问题。

05 Awake函数执行时机

再强调一下,Awake执行与自身脚本激活状态无关,但是与其所在游戏对象激活状态有关。一般都知道,如果脚本不激活,运行的时候Awake也会自动执行。但是要注意,如果其所在游戏对象一开始就是非激活状态,那么Awake是要等到启用该游戏对象的时候才会执行的。

06 Unity使用AVPro的时候进行Application.Quit()问题

Unity使用Application.Quit()可以退出应用,回到前一个activity,而不是回到主界面。比如,用下面的启动器来拉起一个Unity应用:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    TextView textView = (TextView)this.findViewById(R.id.textView);
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
    Date date = new Date(System.currentTimeMillis());
    textView.append(simpleDateFormat.format(date));


    Button button = (Button)this.findViewById(R.id.button);
    button.setOnClickListener(
            new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = getPackageManager().getLaunchIntentForPackage("com.hu.sic");
                    if (intent != null) {
                        {
                            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                        }
                    }
                }
            }
    );
}

那么在Application.Quit()后,unity应用关闭了,回到了该启动器界面,该启动器界面上的时间字符串还是一开始的时间,证明启动器没有被关闭。

但是,如果unity中用:

System.Diagnostics.Process.GetCurrentProcess().Kill();

来结束程序,那么会关闭应用,并回到主界面,而无法回到启动器一开始的activity。

所以用quit的方式是比较好的,但是由于我工程中用了avpro这个视频播放插件,它有点bug。quit的时候,程序实际并没有完全关闭,继续启动它的时候会发现它的进程id没变。当然,如果是kill的方式,那就完全清掉了进程。所以quit这种方式,导致avpro不会再次初始化,无法播放视频,就一直黑屏,具体问题如下:

https://github.com/RenderHeads/UnityPlugin-AVProVideo/issues/37

所以用下面的方法来改进:

public static void QuitApp()
{
#if UNITY_ANDROID
    AndroidJavaClass player = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    AndroidJavaObject androidActivity = player.GetStatic<AndroidJavaObject>("currentActivity");
    if (androidActivity != null)
    {
        androidActivity.Call("finishAffinity");
        AndroidJavaClass system = new AndroidJavaClass("java.lang.System");
        system.CallStatic("exit", new object[] { 0 });
    }
#else
    Application.Quit();
#endif
}

这样,程序会正常关闭,关闭的时候会回到上一个activity而不是退到主界面;另外,它也可以避免avpro初始化问题,不会再黑屏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值