.Net的Task写起来太TM爽了

上周二拿到PvE的需求,开始搞起来了。

地形用新的TileMap搞了一下,先用着再管美术问题。

摇杆就用EasyTouch的,结果还是发现确实没法满足右摇杆的需求,于是就开始纠结怎么办了。

结果纠结了一下午之后,完美解决了。

RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, screenPosition, null, out localPosition);

获取实际点击位置,分辨率无关。顺便再重构了一下InputController,逻辑非常清晰,很满意。

主角状态有意没有用很复杂的结构,先简单写了一些行为,然后对输入做绑定。前期需求还不明确的情况下设计逻辑架构感觉其实还是挺不合算的。子弹也是一样,简单写了个实现。

上周基本就是这样。

其实整个框架一直都有一个严重的问题,就是基于协程的异步接口一直令人非常难受。主要的点在于,协程不能返回值啊!!!一溜烟写一串那确实是挺爽的,但是一旦需要返回值那就直接火葬场。框架服务启动的时候会涉及AssetBundle加载,肯定涉及异步,代码写起来的感觉啊,真的是拆东墙补西墙,一个地方改改一堆地方都要跪。今天一早来,改到中午,好不容易把View的加载改好了(本来是Resources.Load),结果好了,这里不阻塞了,直接服务启动速度快了很多,导致整个服务都启动好了,主角还没被加载出来,然后一加载敌人,找不到主角,跪了。

虽然这个问题可以简单的靠敌人做一下null判断就可以解决的事情,但是总是心里非常的不爽。明明弄了这么一套服务框架,出发点就是让执行顺序可以得到保证,而且明明大部分情况都是可以的,但是最后的一点问题总是不好解决,非常的难受。

而主要的问题,就是协程不能返回值啊!!!要让我把所有代码都写成一个Request形式的,也太难受了,而且这样,其实说到底还是得在一个协程里完成,只是可以把这个协程往上推,根本不解决实际问题。

崩溃,这个问题想了很久很久,感觉实在没法想出什么写法可以完美解决这个问题的。

最后,我也不记得是怎么想起来的,用.Net 4.6 Framework试一下Task。

随便Google了一下,找到了个以及作者的博客。Asset Store也有,但是不是最新提交,于是git clone了一份下来。在经历了导进去删掉再导进去再删掉最后还是导了进去之后,终于搞清楚是怎么回事了。

于是我在办公室里喊了一下午:“太爽了!!!”

所以就不能怪大家今天一直用奇怪的眼神看我了……

大家直接理解为,新的语法可以把任何一个函数变成异步的(只需要加上async关键字),然后,可以随意返回值!!!

写出来类似这样:

public class AsyncExample : MonoBehaviour
{
    public async void Start()
    {
        // Wait one second
        await new WaitForSeconds(1.0f);
 
        // Wait for IEnumerator to complete
        await CustomCoroutineAsync();
 
        await LoadModelAsync();
 
        // You can also get the final yielded value from the coroutine
        var value = (string)(await CustomCoroutineWithReturnValue());
        // value is equal to "asdf" here
 
        // Open notepad and wait for the user to exit
        var returnCode = await Process.Start("notepad.exe");
 
        // Load another scene and wait for it to finish loading
        await SceneManager.LoadSceneAsync("scene2");
    }
 
    async Task LoadModelAsync()
    {
        var assetBundle = await GetAssetBundle("www.my-server.com/myfile");
        var prefab = await assetBundle.LoadAssetAsync<GameObject>("myasset");
        GameObject.Instantiate(prefab);
        assetBundle.Unload(false);
    }
 
    async Task<AssetBundle> GetAssetBundle(string url)
    {
        return (await new WWW(url)).assetBundle
    }
 
    IEnumerator CustomCoroutineAsync()
    {
        yield return new WaitForSeconds(1.0f);
    }
 
    IEnumerator CustomCoroutineWithReturnValue()
    {
        yield return new WaitForSeconds(1.0f);
        yield return "asdf";
    }
}

这是这个库的官方样例,再次感叹拓展方法真的太神奇,可以和协程完美互相结合。

我只能说,谁用谁知道。

很快把项目所有异步接口都改写成Task,服务和游戏逻辑完全保证执行顺序,完美达成目的不说,关键写起来是真的优雅,真的爽。

开心,晚饭汉堡王30-20都没能令我更开心。