侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

unity3d支持typescript开发(五)

2023-01-21 星期六 / 0 评论 / 0 点赞 / 87 阅读 / 10177 字

目录unity3d支持typescript开发(一)unity3d支持typescript开发(二)unity3d支持typescript开发(三)unity3d支持typescript开发(四)un

目录

  1. unity3d支持typescript开发(一)
  2. unity3d支持typescript开发(二)
  3. unity3d支持typescript开发(三)
  4. unity3d支持typescript开发(四)
  5. unity3d支持typescript开发(五)
  6. unity3d支持typescript开发(六)

前言

上一篇文章原本是要完成加载场景的,但是由于完成prefab界面元素成员绑定的篇幅已经过长了,因此此篇文章首先完成上一篇的遗留.

加载进度

控制器

为了达到显示进度的效果,需要在_view.push推送视图数据之后延迟一定的时间,然后再次推送即可,代码大致如下:

class TSControllerLoading {    public onStart(): void {        // 略        _view.push({ ... }, () => {            setTimeout(this.onStart, 100);        });    }}

定时器

为了让C#端支持定时器,可以使用untiy的帧,那么定时器需要继承自MonoBehaviour,不存在的时候则动态创建,定时器使用单例模式+观察者模式,当需要使用定时器的地方,则可以通过定时器单例增加观察者,根据setTimeout的需求,这里只需要增加一个只执行一次的延后观察者,然后在update内遍历所有观察者并把已经完结的观察者移除掉,这里会出现一个问题,那就是有可能出现增加观察者的时候正好也在删除,那就会有锁的问题了,为了尽量避免用锁,可以分配一个专门增加列表,然后在update内将增加的列表合并到总列表,然后清空增加列表,大致代码如下:

class TimerSubject : MonoBehaviour{    private readonly List<OnceTimerObserver> m_Observers = new List<OnceTimerObserver>();    private readonly List<OnceTimerObserver> m_ObserversToAdd = new List<OnceTimerObserver>();    private static TimerSubject s_Instnace;    public static TimerSubject Instance    {        get        {            if (s_Instnace == null)            {                s_Instnace = FindObjectOfType<TimerSubject>() ?? new GameObject(                    typeof(TimerSubject).Name                ).AddComponent<TimerSubject>();            }            return s_Instnace;        }    }    public void AddObserver(OnceTimerObserver observer)    {        this.m_ObserversToAdd.Add(observer);    }    private void Update()    {        if (this.m_ObserversToAdd.Count > 0)        {            this.m_Observers.AddRange(this.m_ObserversToAdd);            this.m_ObserversToAdd.Clear();        }        foreach (var item in this.m_Observers)            item.Update();        this.m_Observers.RemoveAll(r => r.IsDone);    }}class OnceTimerObserver{    private readonly float m_StartTime = Time.time;    private bool m_IsDone = false;    public Action Action { private get; set; }    public float Interval { private get; set; }    public void Update()    {        if (this.m_IsDone || Time.time < this.GetFireTime())            return;        this.m_IsDone = true;        this.Action();    }    private float GetFireTime()    {        return this.m_StartTime + this.Interval;    }}

WindowInstance

有了定时器就可以创建Jint对象了,代码如下:

class WindowInstance : ObjectInstance{    public WindowInstance(Engine engine) : base(engine)    {        engine.SetValue(            "setTimeout",            new ClrFunctionInstance(this.Engine, this.SetTimeout)        );    }    public JsValue SetTimeout(JsValue thisObject, JsValue[] arguments)    {        TimerSubject.Instance.AddObserver(new OnceTimerObserver        {            Action = () => arguments[0].Invoke(),            Interval = (float)(arguments[1].AsNumber() / 1000)        });        return null;    }}

支持Promise

控制器

由于Jint暂时还不支持Promise,因此需要自己扩展来支持,那么首先应该将代码改为async/await方式的,大致代码如下:

// index.d.tsinterface View {    push(viewModel: object): Promise<void>;    // 略}class TSControllerLoading {    public async onStart(): Promise<void> {        while (true) {            // 略            await _view.push({ ... });            await new Promise(s => {                setTimeout(s, 100);            });        }    }}

Jint构造函数/对象/原型

Jint中,有3种对象:

  • Constructor: 构造函数,包含实例化Instance的方法,继承自FunctionInstance``IConstructor
  • Instance: 对象(实例),在该对象上增加的方法相当于静态方法,例如: console.log,继承自ObjectInstance
  • Prototype: 原型链对象(不了解的可以网上查询相关的文章),继承自Instance

由于Promise的实现比较复杂,该篇文章只为了满足以上业务的需求,因此只给出了Promise.then实现,至于其他方法,大家可以自己实现.

PromiseInstance

从控制器中的代码可以看出,我们会使用到Promise的构造函数以及Promise实例中的then方法,当该方法被调用的时候代表异步结束,因此只需要在PromiseInstance上创建一个委托属性Action<JsValue, JsValue>,该委托属性上的两个参数分别代表Promiseresolve``reject回调函数,大致代码如下:

class PromiseInstance : ObjectInstance{    public override string Class => "Promise";    public Action<JsValue, JsValue> ReadyAction { get; set; }    public PromiseInstance(Engine engine) : base(engine) { }    public override string ToString()    {        return this.Class;    }}

PromisePrototype

由于控制器中使用到的是Promise实例化后的then方法,因此该方法需要定义在Prototype上,当调用then的时候则调用PromiseInstance.ReadyAction,另外由于编译后的代码中会使用到instanceof,因此必须要在原型对象上定义constructor属性,大致代码如下:

class PromisePrototype : PromiseInstance{    private PromisePrototype(Engine engine) : base(engine) { }    public void Configure()    {        this.FastAddProperty(            "then",            new ClrFunctionInstance(Engine, this.Then),            true,            false,            true        );    }    private JsValue Then(JsValue thisValue, JsValue[] args)    {        thisValue.As<PromiseInstance>().ReadyAction(args[0], JsValue.Undefined);        return null;    }    public static PromisePrototype New(Engine engine, GlobalPromiseConstructor ctor)    {        var obj = new PromisePrototype(engine)        {            Extensible = true,            Prototype = engine.Object.PrototypeObject,        };        obj.FastAddProperty("constructor", ctor, true, false, true);        return obj;    }}

PromiseConstructor

该对象主要的作用就是实例化PromiseInstance以及将Promise注入到js代码中,大致代码如下:

class PromiseConstructor : FunctionInstance, IConstructor{    public PromisePrototype PrototypeObject { get; set; }    private PromiseConstructor(Engine engine) : base(engine, null, null, false) { }    public override JsValue Call(JsValue thisObject, JsValue[] arguments)    {        return null;    }    public void Configure()    {    }    public ObjectInstance Construct(JsValue[] arguments)    {        return this.New(            (s, f) => arguments[0].Invoke(s, f)        );    }    public PromiseInstance NewInstance(Action<JsValue, JsValue> taskAction)    {        return new PromiseInstance(Engine)        {            Extensible = true,            Prototype = this.PrototypeObject,            ReadyAction = taskAction        };    }    public static PromiseConstructor New(Engine engine)    {        var obj = new PromiseConstructor(engine)        {            Extensible = true,            Prototype = engine.Function.PrototypeObject        };        obj.PrototypeObject = PromisePrototype.New(engine, obj);        obj.FastAddProperty("length", 1, false, false, false);        obj.FastAddProperty("prototype", obj.PrototypeObject, false, false, false);        return obj;    }}

重构

修改ViewInstance.Push让其返回PromiseInstance实例并不够,因为instanceof的判断不正确,因为PromiseInstance.PrototypeObject来自不同的实例导致的,因此需要在DemoCanvas上增加PromiseConstructor的属性,然后ViewInstance.Push内用PromiseConstructor.NewInstance来创建PromiseInstance,大致代码如下:

// ViewInstanceclass ViewInstance : ObjectInstance{    public JsValue Push(JsValue thisObject, JsValue[] arguments)    {        return this.m_Canvas.Promise.NewInstance((s, _) =>        {            this.m_Canvas.Notify(                arguments[0].AsObject()            );            arguments[1].Invoke()        });'    }    // 略}// DemoCanvasclass DemoCanvas : MonoBehaviour{    public PromiseConstructor Pormise { get; private set; }    public DemoCanvas()    {        this.Promise = PromiseConstructor.New(this.m_Engine);        this.m_Engine.SetValue("Promise", this.Promise);    }    // 略}

结尾

那么今天就到这里了,如果文章中有任何错误或者疑问欢迎提问,我会尽快回复的,如果文章对你有帮助也欢迎打赏,谢谢.

广告 广告

评论区