队列任务方案

JAction

JAction是一个队列任务解决方案,可以更好的对队列任务进行管理

提示

比如想要某个函数一直等待到角色死亡,然后显示保存数据,等待2秒后再更新UI,常规写法:

while(!player.dead)
{
  await Task.Delay(1000);//或者yield return new WaitForSecond(1)等做法等待
}
SaveData();//保存数据
await Task.Delay(2000);//或者其他方法等待
UIPanel.Show("DeadPanel");//显示死亡UI

而用JAction能很优雅的解决:

new JAction()
  .Until(player.dead)
  .Do(SaveData)
  .Delay(2)
  .Do(()=>UIPanel.Show("DeadPanel"))
  .Execute();

提示

JAction能干什么?

  • 更少的代码,实现更强大的功能
  • 链式编程
  • 条件等待
  • 延时等待
  • 次数循环
  • 条件循环
  • 取消队列
  • 同步异步运行
  • 可主线程运行
  • 内部包含对象池

使用

  1. 引入以下命名空间

    using JEngine.Core;
    
  2. 创建新的JAction对象

    JAction j = new JAction();
    

    开源版v0.7.3或Pro1.3后也可以使用JAction j = new JAction("任务名");,来给JAction起名

  3. 给JAction分配任务

    j.Do(() => Log.Print("Hello from JAction!"))
      .Do(() => Log.Print("Bye from JAction"))
    
  4. 让JAction执行(必备):

    j.Execute();
    
  5. 恭喜!成功使用!(记得第四步,让JAction执行)

链式编程

JAction j
  .Do(xxx)
  .Repeat(xxx,times,frequecny)
  .Delay(duration)
  .Do(xxx)
  .Execute();

执行

警告

同一个JAction不能被同时执行,若需要同时执行同一个JAction多次,请调用接口Parallel()

  • 同步不阻塞执行

    public JAction Execute(bool onMainThread = false)
    

    可传是否主线程执行的参数,传true代表主线程执行,false代表子线程执行

  • 异步回调执行(不阻塞)

    public JAction ExecuteAsyncParallel(Action callback = null, bool onMainThread = false)
    

    可传执行完毕后的回调

    可传是否主线程执行的参数,传true代表主线程执行,false代表子线程执行

  • 异步执行

    public async ET.ETTask<JAction> ExecuteAsync(bool onMainThread = false)
    

    可传是否主线程执行的参数,传true代表主线程执行,false代表子线程执行

    警告

    需要用await ExecuteAsync()执行,或者ExecuteAsync().Coroutine(),后者会变为同步不阻塞执行

复用

在通过Dispose接口释放掉一个JAction后,该JAction实际上会清除数据后进入内部对象池,而下一个创建的JAction会从对象池中取出一个被清空数据的JAction直接使用,减少new的开销,所以建议不用了的JAction就释放掉

重置

如果需要对JAction的任务进行重置,不建议再去new一个JAction而造成GC和性能浪费,建议直接调用Reset接口

警告

请确保JAction已被取消,或没有在执行状态,再去进行Reset,不然会导致之前的任务还在继续执行

接口

/// <summary>
/// 使同一个JAction可以同时被多次Execute
/// </summary>
/// <returns></returns>
public JAction Parallel()
/// <summary>
/// 执行Action(会被同步执行)
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public JAction Do(Action action)
/// <summary>
/// 执行Task(可异步)
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public JAction Do(Task action)
/// <summary>
/// 延迟time秒后执行后续任务
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public JAction Delay(float time)
/// <summary>
/// 延迟frame帧后执行后续任务
/// </summary>
/// <param name="frame"></param>
/// <returns></returns>
public JAction DelayFrame(int frame)
/// <summary>
/// 等待到condition = true, 每frequency秒检测一次,当timeout>-1时,如果超过timeout秒condition还是false就超时了
/// </summary>
/// <param name="condition"></param>
/// <param name="frequency"></param>
/// <param name="timeout"></param>
/// <returns></returns>
public JAction Until(Func<bool> condition, float frequency = 0.5f, float timeout = -1)
/// <summary>
/// 当condition是true时每frequency秒执行一次action, timeout大于-1时会在执行timeout秒后超时
/// </summary>
/// <param name="action"></param>
/// <param name="condition"></param>
/// <param name="frequency"></param>
/// <param name="timeout"></param>
/// <returns></returns>
public JAction RepeatWhen(Action action, Func<bool> condition, float frequency = 0.5f, float timeout = -1)
/// <summary>
/// 当condition是false时每frequency秒执行一次action, timeout大于-1时会在执行timeout秒后超时
/// </summary>
/// <param name="action"></param>
/// <param name="condition"></param>
/// <param name="frequency"></param>
/// <param name="timeout"></param>
/// <returns></returns>
public JAction RepeatUntil(Action action, Func<bool> condition, float frequency = 0.5f, float timeout = -1)
/// <summary>
/// 重复执行action counts次,每次间隔duration秒
/// </summary>
/// <param name="action"></param>
/// <param name="counts"></param>
/// <param name="duration"></param>
/// <returns></returns>
public JAction Repeat(Action action, int counts, float duration = 0)
/// <summary>
/// 被取消时回调
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public JAction OnCancel(Action action)
/// <summary>
/// 取消JAction
/// </summary>
/// <returns></returns>
public JAction Cancel()
/// <summary>
/// 重置JAction(不force的时候如果在执行就不会重置)
/// </summary>
/// <param name="force"></param>
/// <returns></returns>
public JAction Reset(bool force = true)
/// <summary>
/// 释放JAction接口,释放后会把JAction任务队列加入对象池
/// </summary>
public void Dispose()

使用示范

v0.7.3或Pro1.3及以后

public async static void RunGame()
{
  /*
            * ====================================
            *           JAction EXAMPLE
            * ====================================
            */

  //for(int i = 0; i < 100; i++)
  //{
  //    new JAction();
  //}

  int num = 0;
  int repeatCounts = 3;
  float repeatDuration = 0.5f;
  float timeout = 10f;

  //Simple use
  JAction j = new JAction("j0测试");
  j.Do(() => Log.Print("[j] Hello from JAction!"))
    .Execute();

  //Until
  JAction j1 = new JAction("j1测试");
  j1.Until(() => true)
    .Do(() => Log.Print("[j1] until condition has done"))
    .Execute();

  //Repeat
  JAction j2 = new JAction("j2测试");
  j2.Repeat(() =>
            {
              num++;
              Log.Print($"[j2] num is: {num}");
            }, repeatCounts, repeatDuration)
    .Execute();

  //Repeat when
  JAction j3 = new JAction("j3测试");
  j3.RepeatWhen(() =>
                {
                  Log.Print($"[j3] num is more than 0, num--");
                  num--;
                }, () => num > 0, repeatDuration, timeout)
    .Execute();

  //Repeat until
  JAction j4 = new JAction("j4测试");
  j4.RepeatUntil(() =>
                 {
                   Log.Print($"[j4] num is less than 3, num++");
                   num++;
                 }, () => num < 3, repeatDuration, timeout)
    .Execute(true);

  //Delay
  JAction j5 = new JAction("j5测试");
  j5.Do(() => Log.Print("[j5] JAction will do something else in 3 seconds"))
    .Delay(3.0f)
    .Do(() => Log.Print("[j5] Bye from JAction"))
    .Execute();

  //Execute Async
  JAction j6 = new JAction("j6测试");
  j6.Do(() => Log.Print("[j6] This is an async JAction"))
    .ExecuteAsyncParallel(() =>
                          {
                            Log.Print("[j6] on complete callback");
                            //dispose JAction
                            j6.Dispose();
                          });

  //Execute Async Parallel
  JAction j7 = new JAction();
  await j7.Do(() => Log.Print("[j7] This is an async JAction but runs parallel, callback will be called after it has done"))
    .ExecuteAsync();

  //Cancel a JAction
  JAction j8 = new JAction();
  j8.RepeatWhen(() => Log.Print("[j8] I am repeating!!!"), () => true, 1, timeout)
    .ExecuteAsync().Coroutine();
  //You can either add a cancel callback
  j8.OnCancel(() =>
              {
                Log.Print("[j8] has been cancelled!");

                //Reset a JAction
                //j8.Reset();
              });

  JAction j9 = new JAction();
  j9.Delay(5)
    .Do(() =>
        {
          j8.Cancel();
          Log.Print("[j9] cancelled j8");
        })
    .Execute();
}

开源版v0.7.2或Pro1.2及以前

public async static void RunGame()
{
  /*
  * ====================================
  *           JAction EXAMPLE
  * ====================================
  */
  int num = 0;
  int repeatCounts = 3;
  float repeatDuration = 0.5f;
  float timeout = 10f;

  //Simple use
  JAction j = new JAction();
  j.Do(() => Log.Print("[j] Hello from JAction!"))
    .Execute();

  //Until
  JAction j1 = new JAction();
  j1.Until(() => true)
    .Do(() => Log.Print("[j1] until condition has done"))
    .Execute();

  //Repeat
  JAction j2 = new JAction();
  j2.Repeat(() =>
            {
              num++;
              Log.Print($"[j2] num is: {num}");
            }, repeatCounts, repeatDuration)
    .Execute();

  //Repeat when
  JAction j3 = new JAction();
  j3.RepeatWhen(() =>
                {
                  Log.Print($"[j3] num is more than 0, num--");
                  num--;
                }, () => num > 0, repeatDuration, timeout)
    .Execute();

  //Repeat until
  JAction j4 = new JAction();
  j4.RepeatUntil(() =>
                 {
                   Log.Print($"[j4] num is less than 3, num++");
                   num++;
                 }, () => num < 3, repeatDuration, timeout)
    .Execute();

  //Delay
  JAction j5 = new JAction();
  j5.Do(() => Log.Print("[j5] JAction will do something else in 3 seconds"))
    .Delay(3.0f)
    .Do(() => Log.Print("[j5] Bye from JAction"))
    .Execute();

  //Execute Async
  JAction j6 = new JAction();
  j6.Do(() => Log.Print("[j6] This is an async JAction"))
    .ExecuteAsyncParallel(() =>
                          {
                            Log.Print("[j6] on complete callback");
                            //dispose JAction
                            j6.Dispose();
                          });

  //Execute Async Parallel
  JAction j7 = new JAction();
  await j7.Do(() => Log.Print("[j7] This is an async JAction but runs parallel, callback will be called after it has done"))
    .ExecuteAsync();

  //Cancel a JAction
  JAction j8 = new JAction();
  j8.RepeatWhen(() => Log.Print("[j8] I am repeating!!!"), () => true, 1, timeout)
    .ExecuteAsync().Coroutine();
  //You can either add a cancel callback
  j8.OnCancel(() =>
              {
                Log.Print("[j8] has been cancelled!");
              });

  JAction j9 = new JAction();
  j9.Delay(5)
    .Do(() =>
        {
          j8.Cancel();
          //Reset a JAction
          j8.Reset();
          Log.Print("[j9] cancelled j8");
        })
    .Execute();
}