All Projects → ChevyRay → Coroutines

ChevyRay / Coroutines

Licence: mit
A simple system for running nested coroutines in C#.

Projects that are alternatives of or similar to Coroutines

Kotlin Flow Extensions
Extensions to the Kotlin Flow library.
Stars: ✭ 404 (+304%)
Mutual labels:  async, coroutines
Recoil
Asynchronous coroutines for PHP 7.
Stars: ✭ 765 (+665%)
Mutual labels:  async, coroutines
Asyncawait
async/await for Android built upon coroutines introduced in Kotlin 1.1
Stars: ✭ 410 (+310%)
Mutual labels:  async, coroutines
Creed
Sophisticated and functionally-minded async with advanced features: coroutines, promises, ES2015 iterables, fantasy-land
Stars: ✭ 265 (+165%)
Mutual labels:  async, coroutines
May
rust stackful coroutine library
Stars: ✭ 909 (+809%)
Mutual labels:  async, coroutines
Amp
A non-blocking concurrency framework for PHP applications. 🐘
Stars: ✭ 3,457 (+3357%)
Mutual labels:  async, coroutines
Swiftcoroutine
Swift coroutines for iOS, macOS and Linux.
Stars: ✭ 690 (+590%)
Mutual labels:  async, coroutines
Fooproxy
稳健高效的评分制-针对性- IP代理池 + API服务,可以自己插入采集器进行代理IP的爬取,针对你的爬虫的一个或多个目标网站分别生成有效的IP代理数据库,支持MongoDB 4.0 使用 Python3.7(Scored IP proxy pool ,customise proxy data crawler can be added anytime)
Stars: ✭ 195 (+95%)
Mutual labels:  async, coroutines
Kotlinx.coroutines
Library support for Kotlin coroutines
Stars: ✭ 10,194 (+10094%)
Mutual labels:  async, coroutines
Runtimepermission
Simpliest way to ask runtime permissions on Android, no need to extend class or override permissionResult method, choose your way : Kotlin / Coroutines / RxJava / Java7 / Java8
Stars: ✭ 860 (+760%)
Mutual labels:  async, coroutines
Rsocket Kotlin
RSocket Kotlin multi-platform implementation
Stars: ✭ 256 (+156%)
Mutual labels:  async, coroutines
Handle Path Oz
Android Library to handle multiple Uri's(paths) received through Intents.
Stars: ✭ 36 (-64%)
Mutual labels:  async, coroutines
React Coroutine
Make your async components compact and descriptive by leveraging the power of the language features
Stars: ✭ 246 (+146%)
Mutual labels:  async, coroutines
Swoole Src
🚀 Coroutine-based concurrency library for PHP
Stars: ✭ 17,175 (+17075%)
Mutual labels:  async, coroutines
Vertx Lang Kotlin
Vert.x for Kotlin
Stars: ✭ 215 (+115%)
Mutual labels:  async, coroutines
Groupco
PHP的服务化框架。适用于Api、Http Server、Rpc Server;帮助原生PHP项目转向微服务化。出色的性能与支持高并发的协程相结合
Stars: ✭ 473 (+373%)
Mutual labels:  async, coroutines
Unityfx.async
Asynchronous operations (promises) for Unity3d.
Stars: ✭ 143 (+43%)
Mutual labels:  async, coroutines
Minicoro
Single header asymmetric stackful cross-platform coroutine library in pure C.
Stars: ✭ 164 (+64%)
Mutual labels:  async, coroutines
Kotlin Coroutines Retrofit
Kotlin Coroutines await() extension for Retrofit Call
Stars: ✭ 812 (+712%)
Mutual labels:  async, coroutines
Ktx
LibKTX: Kotlin extensions for LibGDX games and applications
Stars: ✭ 913 (+813%)
Mutual labels:  async, coroutines

Coroutines

A simple system for running nested coroutines in C#. Just drop Coroutines.cs into your project and you're ready to go.

What is a coroutine?

C# has a feature called "enumerators" which are functions that can be suspended during their execution. They do this by using yield return, rather than regular return. When you use yield, you effectively pause the function, and at any time you can resume it and it will continue after the most recent yield.

In this context, a "coroutine" is basically one of these functions, but wrapped up in a nice little package and a few extra features:

  • A container that will automatically update several coroutines for you
  • A simple syntax for nesting coroutines so they can yield to others
  • The ability to yield a floating point number, which will pause the routine for a desired amount of time
  • Handles to routines are provided to make tracking them easier

Example usage

To use the system, you need to create a CoroutineRunner and update it at regular intervals (eg. in a game loop). You also need to tell it a time interval.

CoroutineRunner runner = new CoroutineRunner();

void UpdateGame(float deltaTime)
{
    runner.Update(deltaTime);
}

Now you can run coroutines by calling Run(). Here's a simple coroutine that counts:

IEnumerator CountTo(int num, float delay)
{
    for (int i = 1; i <= num; ++i)
    {
        yield return delay;
        Console.WriteLine(i);
    }
}
void StartGame()
{
    //Count to 10, pausing 1 second between each number
    runner.Run(CountTo(10, 1.0f));
}

When you yield a floating-point number, it will pause the coroutine for that many seconds.

You can also nest coroutines by yielding to them. Here we will have a parent routine that will run several sub-routines:

IEnumerator DoSomeCounting()
{
    Console.WriteLine("Counting to 3 slowly...");
    yield return CountTo(3, 2.0f);
    Console.WriteLine("Done!");

    Console.WriteLine("Counting to 5 normally...");
    yield return CountTo(5, 1.0f);
    Console.WriteLine("Done!");

    Console.WriteLine("Counting to 99 quickly...");
    yield return CountTo(99, 0.1f);
    Console.WriteLine("Done!");
}

void StartGame()
{
    runner.Run(DoSomeCounting());
}

You can also stop any running routines:

//Stop all running routines
runner.StopAll();

//Start a routine and store a handle to it
CoroutineHandle myRoutine = runner.Run(SomeRoutine());

//Stop a specific routine
myRoutine.Stop();

Other tips and tricks

A coroutine can run infinitely as well by using a loop. You can also tell the routine to "wait for the next update" by yielding null:

IEnumerator RunThisForever()
{
    while (true)
    {
        yield return null;
    }
}

Coroutines are very handy for games, especially for sequenced behavior and animations, acting sort of like behavior trees. For example, a simple enemy's AI routine might look like this:

IEnumerator EnemyBehavior()
{
    while (enemyIsAlive)
    {
        yield return PatrolForPlayer();
        yield return Speak("I found you!");
        yield return ChaseAfterPlayer();
        yield return Speak("Wait... where did you go!?");
        yield return ReturnToPatrol();
    }
}

Sometimes you might want to run multiple routines in parallel, and have a parent routine wait for them both to finish. For this you can use the return handle from Run():

IEnumerator GatherNPCs(Vector gatheringPoint)
{
    //Make three NPCs walk to the gathering point at the same time
    var move1 = runner.Run(npc1.WalkTo(gatheringPoint));
    var move2 = runner.Run(npc2.WalkTo(gatheringPoint));
    var move3 = runner.Run(npc3.WalkTo(gatheringPoint));

    //We don't know how long they'll take, so just wait until all three have finished
    while (move1.IsPlaying || move2.IsPlaying || move3.IsPlaying)
        yield return null;

    //Now they've all gathered!
}

Here is a more complicated example where I show how you can use coroutines in conjunction with asynchronous functions (in this case, to download a batch of files and wait until they've finished):

IEnumerator DownloadFile(string url, string toFile)
{
    //I actually don't know how to download files in C# so I just guessed this, but you get the point
    bool done = false;
    var client = new WebClient();
    client.DownloadFileCompleted += (e, b, o) => done = true;
    client.DownloadFileAsync(new Uri(url), toFile);
    while (!done)
        yield return null;
}

//Download the files one-by-one in sync
IEnumerator DownloadOneAtATime()
{
    yield return DownloadFile("http://site.com/file1.png", "file1.png");
    yield return DownloadFile("http://site.com/file2.png", "file2.png");
    yield return DownloadFile("http://site.com/file3.png", "file3.png");
    yield return DownloadFile("http://site.com/file4.png", "file4.png");
    yield return DownloadFile("http://site.com/file5.png", "file5.png");
}

//Download the files all at once asynchronously
IEnumerator DownloadAllAtOnce()
{
    //Start multiple async downloads and store their handles
    var downloads = new List<CoroutineHandle>();
    downloads.Add(runner.Run(DownloadFile("http://site.com/file1.png", "file1.png")));
    downloads.Add(runner.Run(DownloadFile("http://site.com/file2.png", "file2.png")));
    downloads.Add(runner.Run(DownloadFile("http://site.com/file3.png", "file3.png")));
    downloads.Add(runner.Run(DownloadFile("http://site.com/file4.png", "file4.png")));
    downloads.Add(runner.Run(DownloadFile("http://site.com/file5.png", "file5.png")));

    //Wait until all downloads are done
    while (downloads.Count > 0)
    {
        yield return null;
        for (int i = 0; i < downloads.Count; ++i)
            if (!downloads[i].IsRunning)
                downloads.RemoveAt(i--);
    }
}

Why coroutines?

I use coroutines a lot in my games, as I find them great for organizing actor behavior and animations. As opposed to an async callback-based system, coroutines allow you to write your behaviors line-by-line, like how you would naturally write code, and result in very clean and easy to understand sequences.

There are good and bad times to use them, and you will get better at distinguishing this as you use them more. For many of my games, coroutines have been completely priceless, and have helped me organize and maintain very large and complicated systems that behave exactly in the order I wish them to.

NOTE: Not all languages have built-in support for coroutine systems like this. If you plan on porting your code to other languages, it may not be worth the pain of porting if your target language does not have a reliable means of implementing coroutines.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].