Unity与C#学习记录 - 01

14 篇文章 0 订阅

前面一段时间学习了一些AI的东西,目测接下来的一年要围绕Unity和C#做事情了。由于以前Unity与C#学习的就只是入门水平,且一年多没碰,基本都忘了,而现在突然又要承担起Unity开发的重任,Unity引擎和C#编程语言就需要多多学习了。由于我自己一个人处理这方面的事情,所以预计会记录学习各种情况,比较繁杂或者基础的,毕竟不是资深程序员带着我,基本导师靠学习网上教程等。

学习一些就会记录更新一些,并不会像书籍一样按照各个系统进行详细学习介绍,主要还是依据工作中的需要和解决问题过程进行学习和总结。有新的要记录积累的东西我会更新文章,如果太长了就重新开一篇继续。下面就准备进入正题吧。

        01 协程中调用异步方法

如我有一个异步方法,需要下载一些东西比较费时,如下:

async Task LoadAudio()
{
    InitSDK();
    await GetDataFromUrl(url);
}

那么在协程中调用可以用如下方法:

IEnumerator LoadPrefab()
{
    var task = LoadAudio();
    yield return new WaitUntil(() => task.IsCompleted || task.IsFaulted || task.IsCanceled);
    yield return new WaitForSeconds(0.3f);
}

如果该任务调用混乱,可是试着用:

yield return new WaitUntil(() => isLoadAudioFinished == true);

这里LoadAudio完成后设置标志位为true,保证完成后才执行后面的内容。

02 音频加密

音频加密的需求很多时候会遇到,如果用C#的加密供应商进行流加密会耗费较多时间。尝试验证后,发现对音频混入一些byte即可对音频加密,如:

        byte[] tmp = File.ReadAllBytes(path);

        byte[] enc = new byte[tmp.Length + 64];

        for(int i = 0; i < 64; i++)
        {
            enc[i] = tmp[i];
        }

        for(int i = 64; i < 128; i++)
        {
            enc[i] = byte.MinValue;
        }

        Array.Copy(tmp, 64, enc, 128, tmp.Length - 64);

        File.WriteAllBytes(pathNew, enc);

这里对ogg格式音频,拷贝前64个字节后自己加入64个字节,然后再加入剩余内容。这样即可实现简单加密,不过要注意不同格式音频的解析不同,这种方法对wav格式音频却无法加密,wav格式加密可以在文件头直接加两个字节。

03 AVPro播放流媒体

Unity上视频播放插件可能有不少,AVPro算是大名鼎鼎了,我也是主要用到这个。在播放流媒体的时候,遇到一个问题。PC平台上,AVPro可以边缓冲边播放,IsBuffering和IsPlaying可以都是true。安卓平台由于没有选择ExoPlayer,默认用了Media Player这套视频播放API,出现的问题是,第一次加载视频,可以较快从http服务器获取视频数据,缓冲好了就播放。但是其播放过程中无法同时缓冲,导致播放完成一段后会停止,然后继续缓冲。这还不是主要的,主要问题是第二次缓冲加载视频的时候很快速度降到0,GetBufferingProgress也就停止了。这里我用的AVPro是最新的1.9.4,安卓是8.1版本,视频来自http协议mp4格式文件。

在后续学习中得知,ExoPlayer这套API更合适:

实际使用中,换成了ExoPlayer后解决了以上问题。也就是,播放过程中,仍然可以进行缓冲。如果速度慢,视频停止播放,后续缓冲不会像Media Player的那样没速度而一直卡着。

另外,AVPro播放在线mp4文件获取缓冲进度是正确的,但是m3u8文件在线播放却无法获取正确的缓冲进度。虽然都缓冲好播放了,但是GetBufferingProgress却是0,IsBuffering也是true。

关于ExoPlayer和Media Player的比较如下:

04 C# 委托Action等

C#有个委托是Action,该委托是没有返回值的。那么其参数呢,可以有也可以没有。

比如这样一段代码:

public void ResetTransform<T>(List<T> animList, Action endAction) where T : AnimNode
{
    if (animList.Count == 0) return;
    animList.ForEach((a) =>
    {
        a.ResetTransform();
    });
    if (endAction != null)
        endAction();
}

这里Action是无参的,我们直接执行endAction()即可。where在这里就起到了基类约束的作用,也就是泛型T必须是以AnimNode为基类才行。

Action委托可以有参数的,如:

public List<Action<bool, PointerEventData>> onClickEventList = new List<Action<bool, PointerEventData>>();

这里就是有参数的委托,而且是俩参数,其实最多可以传16个参数。那么用的时候就是这样的:

onClickEventList.ForEach(e => e(IsActived, eventData));

ForEach()本身需要传一个委托,比如有一个void函数Print()和一个List<String> names,可以用names.ForEach(Print)来输出该List的内容。如果不想写Print,那就用匿名方法(来自C#2.0),如:

names.ForEach(delegate(String name){Console.WriteLine(name);});

这里delegate部分可以简写为 (x) => { ... },这个也就是lambda表达式了,括号里面的是参数。没有参数就是 () => 的形式,多个参数就是 (x, y, z) => 的形式。前面的代码中出现的e是个参数,单个参数可以写成括号包含的形式,也可以不加括号。所以前面的 e => 就是 (e) => 。另外由于e这个参数是个委托,所以直接就是e(x, y)这样的方式使用。

普通使用委托,如:

public delegate void MyDelegate(string name);
public MyDelegate myDelegate;

就和类差不多,先定义后实例化。Action就会方便一些,如:

void Start(){Action action = test; action();}

void test(){Debug.Log("test");}

这里直接用Action替代了前面的定义,也就是系统已经帮我们定义好的委托了。

基于Action或者委托,就可以做事件Handler了,如:

public event Action<SwipeDir> SwipeEventHandler;

那么别的类可以订阅该事件:

Test_SceneMgr.Instance.SwipeEventHandler += Instance_SwipeEventHandler;

private void Instance_SwipeEventHandler(Test_SceneMgr.SwipeDir obj){}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值