Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batch Async utils #3151

Open
Geokureli opened this issue May 28, 2024 · 3 comments
Open

Batch Async utils #3151

Geokureli opened this issue May 28, 2024 · 3 comments

Comments

@Geokureli
Copy link
Member

Geokureli commented May 28, 2024

FlxTweens have tween.then(otherTween) which allow chaining, but timers do not have anything like this. Would be nice to have batch timers like the one created for FNF by cyn0x8 in FunkinCrew/Funkin#2391.

Even more so it would be nice if there was an interface or protocol shared by FlxTimer, FlxTween or any other async event that allowed them to be laid out in a single sequence, I.E.

new FlxSequence
(
    [
        FlxTween.tween(obj, {x: targetX }, 2.5, obj.doThing),
        FlxTween.flicker(1.0),// no callback
        FlxTween.tween(obj, {x: targetX }, 2.5, obj.doThing),
        FlxTimer().wait(1.0, doThing2),
        FlxG.camera.shake(0.05, 0.5),
        obj.startAsyncProcess(1.0)
    ],
    onSequenceComplete
)

the above would run each process in sequence, and then call onSequenceComplete

@ninjamuffin99
Copy link
Member

for fnf i had a lil thing that I was prototyping for a sorta queue/chain system.

Note: This was made for our lil FNF wrapper class thats on top of FlxAnimate (which is on top of FlxSprite) so some api might be slightly different, but here was the gist of what I had for that.

So usage would be like

// setup our "fullAttack" chain
spr.animationChain.queueAnimation("attack1", "fullAttack");
spr.animationChain.queueAnimation("attackFollowThrough1", "fullAttack");
spr.animationChain.queueWaitInFrames(10, "fullAttack");
spr.animationChain.queueAnimation("idle", "fullAttack");

// when we want to play our chain, which will play each animation in sequence
spr.animationChain.playChain("fullAttack"); 

lil code implementation I had. Food for thought

package funkin.graphics.adobeanimate;

import flixel.util.FlxTimer;

/**
 * A helper class for making queued / chained animations easier to manage.
 * Generally should be used via `spr.animationChain.queueAnimation()` a la `spr.animation.add()` flixel api
 * however this is meant for FlxAtlasSprite rather than FlxSprite
 */
class AtlasAnimationChain
{
  var chains:Map<String, Array<String>>;

  var parent:FlxAtlasSprite;

  public function new(parent:FlxAtlasSprite)
  {
    this.parent = parent;
    chains = new Map();
  }

  /**
   * Add an animation to the end of a chain. If a chain doesn't exist, it will be created.
   * @param name The animation name to be added to a chain.
   * @param chain Which "chain" to add the animation to. A chain will be created if it doesn't already exist
   */
  public function queueAnimation(name:String, chain:String):Void
  {
    if (!chains.exists(chain)) chains.set(chain, []);
    trace('Adding ${name} to chain ${chain}');
    chains.get(chain).push(name);
  }

  /**
   * Queues a "wait" in the queue, which will hold our current animation for a certain time.
   * In frames at 24fps.
   * @param wait How many frames to wait, at 24fps.
   * @param chain Which "chain" to add the wait to. A chain will be created if it doesn't already exist
   */
  public function queueWaitInFrames(wait:Int, chain:String):Void
  {
    if (!chains.exists(chain)) chains.set(chain, []);
    trace('Adding wait(${wait}) to chain ${chain}');

    chains.get(chain).push('chain_wait:' + wait);
  }

  /**
   * Begins playing a chain of animations
   * @param chain String name of the chain to play
   */
  public function playChain(chain:String):Void
  {
    if (!chains.exists(chain)) return;

    var chainArr:Array<String> = chains.get(chain);

    var currentIndex:Int = 0;

    // Cute little recursive function to play the next animation in the chain once our current one is done
    // Done in this way so we don't have a bunch of potentially dangling callbacks if we need to cancel the chain
    // (dangling callbacks may or may not happen... FlxAtlasSprite and FlxAnimate have many moving parts... careful...)
    var playNext:Void->Void;
    playNext = () -> {
      if (currentIndex < chainArr.length)
      {
        // mini parser for our wait command
        if (chainArr[currentIndex].startsWith('chain_wait:'))
        {
          var waitFrames = Std.parseInt(chainArr[currentIndex].split(':')[1]);
          currentIndex++;
          new FlxTimer().start(waitFrames / 24, _ -> playNext());
          return;
        }

        trace('Playing ${chainArr[currentIndex]} from chain ${chain} (${currentIndex + 1}/${chainArr.length})');
        parent.playAnimation(chainArr[currentIndex], true, false, false);
        parent.anim.onComplete.add(() -> {
          currentIndex++;
          playNext();
        });
      }
    }

    playNext();
  }
}

@Vortex2Oblivion
Copy link
Contributor

new FlxSequence

(

    [

        FlxTween.tween(obj, {x: targetX }, 2.5, obj.doThing),

        FlxTween.flicker(1.0),// no callback

        FlxTween.tween(obj, {x: targetX }, 2.5, obj.doThing),

        FlxTimer().wait(1.0, doThing2),

        FlxG.camera.shake(0.05, 0.5),

        obj.startAsyncProcess(1.0)

    ],

    onSequenceComplete

)

This would be so useful to have

@ninjamuffin99
Copy link
Member

also some food for thought, i wonder if we can yoink some stuff from FlxTaskManager to make the usage more core in flixel. It seems like it might be what we want to do?

https://api.haxeflixel.com/flixel/addons/plugin/taskManager/FlxTaskManager.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants