UniRx คือการ Re-Implement Reactive Extensions (ReactiveX) ของ .Net Frameswork เพื่อไว้สำหรับใช้งานใน Unity โดยคนที่นำมา Re-Implement เพื่อให้เราได้ใช้งานกันนั้นคือ Yoshifumi Kawai โปรแกรมเมอร์ชาวญี่ปุ่นซึ่งเป็น Microsoft MVP ของ Visual C#. โดยในบทความฉบับนี้ ทางผู้เขียนจะพาท่านผู้อ่านไปเรียนรู้ทำความเข้าใจถึงพื้นฐานและสิ่งที่ควรรู้เกี่ยวกับ UniRx เช่น Reactive Extensions คืออะไร ข้อจำกัดของ Coroutine ที่ทำให้เราควรเปลี่ยนมาใช้ UniRx เพื่อให้ผู้อ่านมีความเข้าใจที่ถูกต้องก่อนที่จะลงลึกไปถึงวิธีการใช้งาน UniRx ใช้งานในแบบต่างๆ
Reactive Extensions หรือ Rx คือ library สำหรับการเขียน asynchronous และ event-based programs โดยใช้ observable sequences และ LINQ-style query operators. เพื่อจัดการกับ asynchronous data ต่างๆ โดย reactive extensions จะ represents Data ในรูปแบบของ observable เพื่อให้ตัว program , game หรือ application ของเรา สามารถ subscribe กับ observable นั้นๆ เพื่อรับ Notification เมื่อมี Data ใหม่ๆเข้ามา
โดยปกติแล้วเวลาที่เราเขียนโปรแกรมที่เป็น asynchronous เช่น การรับส่งข้อมูลของผู้เล่นกับ Server เรามักจะใช้ Class ที่ชื่อ WWW ควบคู่กับ Coroutine กัน แต่การใช้ Coroutine นั้นจริงๆแล้วไม่ใช่ practice ที่ดีสำหรับการเขียนโปรแกรมที่เป็น asynchronous อันเนื่องมาจากปัญหาต่างๆ
เช่น
ทำให้การที่เราจะเขียนโปรแกรมที่เป็น asynchronous ภายใน Unity ค่อนข้างลำบากอันเนื่องมาจากเราไม่สามารถหลีกเหลี่ยงการใช้ Coroutine เพราะ Unity เองนั้นเป็น singlethread.
Ex1. ตัวอย่างการใช้ UniRx แทน Class WWW ของ Unity ในการยิง API
ObservableWWW.Get("http://google.co.jp/")
.Subscribe(
x => Debug.Log(x.Substring(0, 100)),
ex => Debug.LogException(ex));
Ex2. ตัวอย่างการใช้ UniRx แทน Class WWW ของ Unity ในการยิง Chain API แบบ Concatinate
var query = from google in ObservableWWW.Get("http://google.com/")
from bing in ObservableWWW.Get("http://bing.com/")
select new { google, bing };
var cancel = query.Subscribe(x => Debug.Log(x.google.Substring(0, 100) + ":" + x.bing.Substring(0, 100)));
cancel.Dispose();
Ex3. ตัวอย่างการใช้ UniRx แทน Class WWW ของ Unity ในการยิง API แบบ parallel
var parallel = Observable.WhenAll(
ObservableWWW.Get("http://google.com/"),
ObservableWWW.Get("http://bing.com/"),
ObservableWWW.Get("http://unity3d.com/"));
parallel.Subscribe(xs =>
{
Debug.Log(xs[0].Substring(0, 100)); // google
Debug.Log(xs[1].Substring(0, 100)); // bing
Debug.Log(xs[2].Substring(0, 100)); // unity
});
Ex4. ตัวอย่างการ handler download progress ของ UniRx
var progressNotifier = new ScheduledNotifier<float>();
progressNotifier.Subscribe(x => Debug.Log(x));
ObservableWWW.Get("http://google.com/", progress: progressNotifier).Subscribe();
Ex5. ตัวอย่างการ handle error ของ UniRx
ObservableWWW.Get("http://www.google.com/404")
.CatchIgnore((WWWErrorException ex) =>
{
Debug.Log(ex.RawErrorMessage);
if (ex.HasResponse)
{
Debug.Log(ex.StatusCode);
}
foreach (var item in ex.ResponseHeaders)
{
Debug.Log(item.Key + ":" + item.Value);
}
}).Subscribe();