Skip to content

FlxTimer - Add function to complete the callback early.#3575

Open
Vulpicula wants to merge 5 commits intoHaxeFlixel:devfrom
Vulpicula:dev
Open

FlxTimer - Add function to complete the callback early.#3575
Vulpicula wants to merge 5 commits intoHaxeFlixel:devfrom
Vulpicula:dev

Conversation

@Vulpicula
Copy link
Copy Markdown

Small feature. First time contributing, so this may not be up to normal standards.
Seems to work based on testing, although I don't know if any additional work is required.

Needed for a personal use-case, was told to give contributing to the main source code a go.
Copy link
Copy Markdown
Member

@Geokureli Geokureli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a little test to try this out (I always recommend doing this)

package states;

import flixel.FlxG;
import flixel.FlxSprite;
import flixel.group.FlxSpriteGroup;
import flixel.text.FlxBitmapText;
import flixel.ui.FlxButton;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;

class FinishTimerTestState extends flixel.FlxState
{
    var timer:FlxTimer;
    var barBg:FlxSprite;
    var barFg:FlxSprite;
    var text:FlxBitmapText;
    var finishBtn:FlxButton;
    var startBtn:FlxButton;
    var loopBtn:FlxButton;
    
    override function create()
    {
        super.create();
        FlxG.camera.bgColor = FlxColor.WHITE;

        
        final ui = new FlxSpriteGroup();
        add(ui);
        
        final WIDTH = FlxG.width - 20;
        final BORDER = 5;
        ui.add(barBg = new FlxSprite()).makeGraphic(WIDTH, 50, FlxColor.BLACK);
        ui.add(barFg = new FlxSprite(BORDER, BORDER)).makeGraphic(barBg.frameWidth - BORDER * 2, barBg.frameHeight - BORDER * 2, FlxColor.GRAY);
        barFg.origin.x = 0;
        
        ui.add(text = new FlxBitmapText(barFg.x, "Unstarted"));
        final SCALE = 2;
        text.scale.scale(SCALE);
        text.updateHitbox();
        text.fieldWidth = Std.int(barFg.frameWidth / SCALE);
        text.autoSize = false;
        text.alignment = CENTER;
        text.y = barFg.y + (barFg.height - text.height) / 2;
        
        final btns = new FlxTypedSpriteGroup<FlxButton>();
        ui.add(btns);
        btns.add(startBtn = new FlxButton(0, 0, "Start 10s", ()->timer = FlxTimer.wait(10, onComplete)));
        btns.add(loopBtn = new FlxButton(startBtn.width, 0, "Start 10 Loops", ()->timer = FlxTimer.loop(10, onLoopComplete, 10)));
        btns.add(finishBtn = new FlxButton(loopBtn.x + loopBtn.width, 0, "Finish", ()->timer.completeEarly()));
        btns.y = barBg.height;
        
        ui.screenCenter();
        btns.screenCenter(X);
    }
    
    override function update(elapsed)
    {
        super.update(elapsed);
        if (timer != null && timer.finished == false)
        {
            barFg.setGraphicSize(barFg.frameWidth * (timer.elapsedTime / timer.time), barFg.frameHeight);
            final time = StringTools.rpad(Std.string(Std.int((timer.elapsedTime) * 10) / 10), ".0", 2);
            if (timer.loops > 1)
                text.text = '$time / ${timer.time} loops ${timer.elapsedLoops} / ${timer.loops}';
            else
                text.text = '$time / ${timer.time}';
        }
    }
    
    function onComplete()
    {
        text.text = "Completed";
        barFg.scale.x = 1.0;
    }
    
    function onLoopComplete(numLoops:Int)
    {
        FlxG.log.add('$numLoops loops');
    }
}

It doesn't work as expected, when completeEarly is called the timer starts ticking up from a negative number. onComplete is called immediately but also when the timer actually finishes, later.

Also maybe we should have both complete and completeLoop?

P.S.: It's easier for me to test your changes locally if you use a feature branch rather than making changes to your fork's dev branch. For more info, check the very hard-to-find Contribution Guide

Comment thread flixel/util/FlxTimer.hx Outdated
Comment thread flixel/util/FlxTimer.hx Outdated
Co-authored-by: George Kurelic <Gkurelic@gmail.com>
@Vulpicula
Copy link
Copy Markdown
Author

Thanks for letting me know! I sorta just threw it out there without properly testing it I think, as I was simultaneously attempting to get something else rolling.

I'll get this patched up and properly tested tonight.

Basically just a little sanity check in there to call the complete function. There might be a better way to do this, but it appears to work just fine.
@Vulpicula Vulpicula requested a review from Geokureli March 19, 2026 09:37
@Vulpicula
Copy link
Copy Markdown
Author

Used your little testing class, and appears everything is passing as intended now.

Only thing I'd mention is the name of the complete function now. I wonder if it might be a bit confusing, as there's both a timer.finished, and timer.complete, which can be read as the same thing.

Copy link
Copy Markdown
Member

@Geokureli Geokureli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes work as expected

Only thing I'd mention is the name of the complete function now. I wonder if it might be a bit confusing, as there's both a timer.finished, and timer.complete, which can be read as the same thing.

Screenshot 2026-04-12 at 10 41 22 AM

Since finished is a property and complete is a method, it's clear that complete is a verb, and finished is an adjective, but I always appreciate the concern for readability. Another option is skip, though that may imply the callback is NOT called

Also any thought's towards this, in my previous comment?

Also maybe we should have both complete and completeLoop?

Whatever we do here will eventually be mirrored in FlxTween, and likely other async tools (like maybe FlxSound)

@Geokureli Geokureli dismissed their stale review April 12, 2026 15:45

requested changes were made

@Vulpicula
Copy link
Copy Markdown
Author

Ah! My apologies, I didn't see the suggestion you made.

I can certainly look into it. I assume complete would just rapidly fire through every single remaining loop, and completeLoop would take the behavior of the new complete function?

As for the other er, mistakes regarding the contribution being fucky, I apologize for that. I appreciate the patience with this whole shebang, and will try and nail that next time. ^^'

Copy link
Copy Markdown

@rodney528 rodney528 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't this a thing? Genuinely happy I'm not the only one who thinks this. 😭

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants