上周二拿到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都没能令我更开心。