このクラスを継承して、Executeだけをオーバーライドして使うようなクラス作って、Executeからはまるでコンソールアプリケーションみたいな感覚でコードが書ける。アドベンチャーゲームのシナリオなんかには便利なのではないだろうか。
さらには、トランスパイラの類を書けば他の直列に記述するスクリプトからこの関数を作るのもそう難しいことではないだろう。昔のBASICみたいな環境を作ったり、NScripterやら吉里吉里っぽいスクリプトやらを動かせるようになるかも知れない。
C#の(C++でもCでもJavaでも、多分どんな言語でも可能だが)関数の実行を途中で中断して保存・復帰する方法についてはアイデアがある(ソースの自動生成が前提だけど)。また次の記事で。組み合わせれば高速で単純で柔軟なノベルゲームエンジン作れると思う。
なお、残念なことにこのコードはWebGLでは機能しない。UnityのWebGLではスレッドを作れないようなので。PCとAndroidで動くのは確認済み。他は持ってないので試せない……PS系とかSwitchとか気になるよね。
using System.Collections; using System.Collections.Generic; using UnityEngine.UI; using UnityEngine; using System.Threading; public class ThreadTest : MonoBehaviour { delegate void InvokeDelegate(); static Object lockObject=new Object(); List(追記:バグを修正しました。)invokeList=new List (); private bool _b; public bool canInvoke { get { lock (lockObject) { return _b; } } set { lock (lockObject) { _b = value; } } } Thread thread; //描画用 public Text text; // Use this for initialization void Start() { canInvoke = true; thread = new Thread(Execute); thread.Start(); } // Update is called once per frame void Update() { if (canInvoke) { lock (lockObject) { foreach (var data in invokeList) { data(); } invokeList.Clear(); } } } void InvokeWait() { while (true) { lock(lockObject) { if (!canInvoke) { Debug.Log("canInvoke=falseの時にInvokeWaitを実行してはいけません。"); } if (invokeList.Count == 0) break; } Thread.Sleep(8); } } void ClickWait() { bool isMouseDown = false; while (!isMouseDown) { InvokeMainThread(()=> { if (Input.GetMouseButtonDown(0)) { isMouseDown = true; } }); InvokeWait(); } } void InvokeMainThread(InvokeDelegate f) { lock (lockObject) { invokeList.Add(f); } } void PutText(string s) { InvokeMainThread(()=> { text.text = s; }); } void Execute() { PutText("てきすと1"); ClickWait(); PutText("てきすと2"); ClickWait(); PutText("直列で実行できてる?"); //ここでは使ってないけど /* canInvoke=false; Load1(); Load2(); Setting1(); canInvoke=true; こう書けば、canInvoke=falseのあいだの命令実行中にInvokeしたものが実行されないことが保証され、正確に同じフレームで実行できる。 */ } }