Hãy suy nghĩ về cách thức foreach
hoạt động:
foreach (var number in Enumerable.Range(1, 1000000))
{
if (number > 10) break;
}
Kiểm soát lặp lại là trên người gọi - nếu bạn dừng lặp lại (ở đây với break
), đó là nó.
Các yield
từ khóa là một cách đơn giản để thực hiện một đếm được trong C #. Tên gợi ý về điều này - yield return
mang lại quyền kiểm soát cho người gọi (trong trường hợp này là của chúng tôi foreach
); đó là người gọi quyết định khi nào sẽ tiếp tục mục tiếp theo. Vì vậy, bạn có thể thực hiện một phương pháp như thế này:
IEnumerable<int> ToInfinity()
{
var i = 0;
while (true) yield return i++;
}
Điều này trông ngây thơ như nó sẽ chạy mãi mãi; nhưng trong thực tế, nó phụ thuộc hoàn toàn vào người gọi. Bạn có thể làm một cái gì đó như thế này:
var range = ToInfinity().Take(10).ToArray();
Điều này có thể hơi khó hiểu nếu bạn không quen với khái niệm này, nhưng tôi hy vọng cũng rõ ràng đây là một tài sản rất hữu ích. Đó là cách đơn giản nhất mà bạn có thể mang lại sự kiểm soát để người gọi của bạn, và khi người gọi quyết định để theo dõi, nó chỉ có thể thực hiện bước tiếp theo (nếu Unity đã được thực hiện ngày hôm nay, nó có lẽ sẽ sử dụng await
thay vì yield
; nhưng await
đã không tồn tại trở lại sau đó).
Tất cả những gì bạn cần để thực hiện các coroutines của riêng bạn (không cần phải nói, các coroutines ngu ngốc đơn giản nhất) là đây:
List<IEnumerable> continuations = new List<IEnumerable>();
void StartCoroutine(IEnumerable coroutine) => continuations.Add(coroutine);
void MainLoop()
{
while (GameIsRunning)
{
foreach (var continuation in continuations.ToArray())
{
if (!continuation.MoveNext()) continuations.Remove(continuation);
}
foreach (var gameObject in updateableGameObjects)
{
gameObject.Update();
}
}
}
Để thêm một cách WaitForSeconds
thực hiện rất đơn giản , bạn chỉ cần một cái gì đó như thế này:
interface IDelayedCoroutine
{
bool ShouldMove();
}
class Waiter: IDelayedCoroutine
{
private readonly TimeSpan time;
private readonly DateTime start;
public Waiter(TimeSpan time)
{
this.start = DateTime.Now;
this.time = time;
}
public bool ShouldMove() => start + time > DateTime.Now;
}
Và mã tương ứng trong vòng lặp chính của chúng tôi:
foreach (var continuation in continuations.ToArray())
{
if (continuation.Current is IDelayedCoroutine dc)
{
if (!dc.ShouldMove()) continue;
}
if (!continuation.MoveNext()) continuations.Remove(continuation);
}
Ta-da - đó là tất cả một hệ thống coroutine đơn giản cần. Và bằng cách mang lại quyền kiểm soát cho người gọi, người gọi có thể quyết định bất kỳ số lượng nào; họ có thể có một bảng sự kiện được sắp xếp thay vì lặp qua tất cả các coroutines trên mỗi khung; họ có thể có các ưu tiên hoặc phụ thuộc. Nó cho phép thực hiện rất đơn giản của đa tác vụ hợp tác. Và chỉ cần nhìn vào cách đơn giản này, nhờ yield
:)
"Fire1"
, đó có phải là thứ bạn có thể thiết lập trong công cụ để cho phép sửa lỗi thay vì gõ raKeycode.Foo
không?