Events, Tweens, Timers. Timers have worse performance than tweens?! Events are best... WHAT?

3 favourites
From the Asset Store
Very simple code without excess options (15 events for server and 11 events for client)
  • It's kinda funny that on almost every topic I read Ashley say "dont worry about performance. difference is not really noticable. 99.9% of projects doesnt need this" and so on. And then guess what? Peformance was literally the main problem i had with C3 through all those years. And i make pretty simple games! Some things in C3 cause absurdly bad performance and you will never read about that in docs, and the only way to figure out is to extensive testing and comparing different approaches. Without WebGL debugger and literal months of trial and error i would've never made my games playable on mobile or low end devices.

    In most cases i agree with Ashley, but...

    Ashley "dont worry about performance" Gullen

  • In a sense you do have to worry about performance at least a little bit because there's always gonna be this one guy with his forgotten relic of a computer expecting to play the game. Which is fair enough considering we're talking about 2D games here. They should run on any toaster you throw them at.

    Regardless I do think the engine does perform really well in most cases. Things that do cause bad performance that I'm aware of are:

    - any kind of loops every tick especially if they manipulate instances.

    - The physics plugin

    - Shaders/effects also tend to be unusually(?) expensive, especially on mobile.

    Am I missing something?

    EDIT:

    I wanted to add. Construct being tightly tied to vsync can also cause performance issues, theoretically at least. Lets just assume my game performs 50.000 collision detections per second. That is... as long as it's a 60hz screen. Newer mobiles for example often have 120hz screens, now it's 100.000 collision detections per second. Or a fancy gaming monitor with 240hz... 200.000 collision detections per second. On top of that, don't forget that this also means that collision detections are inherently framerate dependent, just to add a little extra annoyance.

    I'd really like to see these type of calculations untied from the monitor framerate. At least as an optional feature. I'd like to be able to run the game logic at a fixed rate, then have the visuals on top interpolate accordingly. This will stop collision checks from ballooning out of control for no actual reason, and also would guarantee framerate independence for collision checks. And yes, this will slow down the game if the fps dip too low. That is a tradeoff I'm willing to take, considering this approach is good enough for a multi-billion dollar company youtu.be/dDxMv33QlFs

    There's a reason this is done this way. I've run into many many inconsistencies because of this. So many times have I made something that works nicely, then I remembered I have a high fps screen and swap to 60hz. Boom, everything's broken. No amount of deltatime is gonna save me here because how am I supposed to deltatime the rate of raycasts being performed if it's tied to vsync. So I could do something like "every 0.0167 seconds -> do raycast" to have it run at "60 fps". Does this work? Honestly I don't even know, probably not. What about the platform behavior? That is also tied to vsync, but I don't have the ability to execute that only "every 0.167" seconds. How can I tie this together without massive spaghetti? I probably can't.

    But I also don't expect this to change, because changing that is probably a massive task. What I do know is that the whole interpolate on top thing works because I sort of do exactly that in my current project. Technically speaking, it runs at ~13 fps. I get position updates to my sprites that I then simply tween to their new position. Visually it runs at a normal framerate, just everything in the background happens at 13 fps. And it will run at 13 fps in any case.

  • In this case I would point to the relevant blog post being Optimisation: don't waste your time. These days, Construct can achieve outstanding performance even on old devices.

    Sometimes we optimise parts of the engine we know were previously a bottleneck and write blogs about it. That does not contradict at all the point that it's important to first know it's a meaningful thing to optimise.

  • Yeah i agree we shouldn't waste time optimizing stuff that don't matter, I just had performance issues on a specific heavy task in my game but I managed to solve it by making my own Addons.

    Anyway i went ahead and released a new Addon Pack that fix all the issues i've been mentionning for months and that i've been using extensively using in my project for about a year, it basically implements all the things i've been advocating for. I couldn't imagine making any project without those now :

    ADVANCED SIGNALS & CUSTOM EXPRESSIONS

    GRAB IT HERE

    A powerful ADDON PACK containing 3 new behaviors for Construct 3

    It contains :

    • ADVANCED SIGNALS Behavior (Per-Instance Functions on steroid)
    • CUSTOM EXPRESSIONS Behavior
    • SIMPLE TRIGGER Behavior
    • (all those behaviors also support polymorphism, making the Family feature way more powerful)
    • Example/Documentation .c3p project

    Those are the 3 addons I used in all my systems to create a highly modular and maintainable Roguelike. Thanks to this pack : you can create scalable systems easily, decouple your logic to avoid spaghetti code. It also makes the Family feature way more powerful thanks to the polymorphism support.

    Above all, it allows you to "CREATE YOUR OWN BEHAVIORS" only using the eventsheet.

    (In fact it's even more powerful than Behavior on some aspects, thanks to the polymorphism feature allowing each member of a Family to act differently)

    There is so much use-case and advantages of being able to create Custom Signals, Triggers and Expressions (supporting polymorphism and multiple parameters)

    it's hard to explain all use-cases and advantages, take a look at the addon pack page for more info !

    ADVANCED SIGNALS & CUSTOM EXPRESSIONS

    (currently running a sale/bundle to grab all my packs with a discount)

    Regarding the performance issue I faced at some point calling a bunch of Advanced Signals, a good thing with this improved solution is that Custom Expressions and Custom Signals are 2 different behaviors, this way you just add the functionality you need on the relevant object and the "workload" is split, on top of being better UX-wise. (Calling an expression will only check the expressions triggers of the same behavior, same for signals, they are separated). There are also a few optimization tricks we can do that i explain in the last part of this post.

    In most situations performance doesn't matter at all, I agree, we should only worry about them when we need to optimize very heavy stuff

    In my project I wanted to optimize further because it happenned very often that many many entities were hit at the same times calling a bunch of signals (on hit received, on critical hit received, on death, on damage dealt, on critical damage dealt etc...), and I had many many different signals handled by a single behavior with many Triggers blocks so it was like :

    (a bunch of entities + their damage dealer)

    * (a lot of signal that are triggered at the same time)

    * (a lot of existing signal handled by the same behavior)

    * (a lot of listeners blocks for each Signal

    = the exponential overhead i was talking about, and fixed

    I think it's pretty rare to have that and i reckon Trigger Overhead wasn't the main bottleneck (it's just that I wanted to make sure that scenario was as optimized as possible, even if it would just save a few CPU% on those especially heavy frames), I mainly solved those heavy frames thanks to some other addons i'll probably release soon that weren't related to Trigger overhead I had.

    My goal was being able to hit 100 entities at the same frame yet being able to launch a bunch of signals doing a bunch of extra checks and logic on many eventsheets for all of them without any noticeable perf drop and I managed to do it.

    (Those behaviors are all as optimized as they can be, nothing is happening on tick - as opposed to Timers Behaviors - and they don't require to init anything fancy etc)

    Here are a few tricks on how to enhance the performance if someone also has specific events in their game with very very intensive use of the Advanced Signal behavior on a single Object and needs to save every CPU% they can :

    • Create several Advanced Signal on your object : "HitSignals", "MiscSignals" each handling just a subset of all your signals

    • Use the SimpleTrigger variant for the most commonly used "Signals" or requiring the biggest number of eventblocks.

    As ever with optimization, and i join Ashley on this : only do it after you actually runned into perf issue

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • I'm looking over the behaviors code, I can understand why one might want a fake trigger for order of events stuff. (Right, true triggers can fire at any time? Or is the order in the event sheet still protected?)

    That's my assumption too.

  • Looping back to the original point of the post, I'm still confused why "OnTween" finished seemingly causes no reduction in fps, while "onTimer" does. Seems like timers are.... outdated? Tweens are nice and fast for all they do.

  • Looping back to the original point of the post, I'm still confused why "OnTween" finished seemingly causes no reduction in fps, while "onTimer" does. Seems like timers are.... outdated? Tweens are nice and fast for all they do.

    It's because Fake Triggers which is used by the "On Timer" in the Timer Behavior actually check if they're true everytick as opposed to True Triggers So if you have a bunch of objects checking a bunch of On Timers it can be heavy.

    True Trigger on the other hand don't do anything every tick, they're just triggered when they're called (with a little overhead)

    Both approach have their own trade-offs as often in programming. Even if I admit I did tricks to avoid many "On Timer" Fake Triggers in my project

    (Ruskul, I think the comment of tunderrunz was about official behaviors not the Advanced Signals pack I made)

  • It's because Fake Triggers which is used by the "On Timer" in the Timer Behavior actually check if they're true everytick as opposed to True Triggers So if you have a bunch of objects checking a bunch of On Timers it can be heavy.

    True Trigger on the other hand don't do anything every tick, they're just triggered when they're called (with a little overhead)

    Both approach have their own trade-offs as often in programming. Even if I admit I did tricks to avoid many "On Timer" Fake Triggers in my project

    (Ruskul, I think the comment of tunderrunz was about official behaviors not the Advanced Signals pack I made)

    Oh no, I understand why one runs slower, I think I meant why did Scirra choose to use a fake trigger at all on the timer, but then not on the tween.

    Imo, if there really is a need for a fake trigger (or perhaps they wont change it in order to not break projects) then why not add an option for a real one. Its a wash as far as I am concerned because I already copied the behavior, stripped out the fluff, and added a single "untagged" timer and reduced it to a simple true trigger alarm and a second timer for polling. If you need multiple simple timers you just add the behavior again and name it what you need.

    Simple Alarm. A behavior that solves 1 problem, and solves it in as performant a way as I can manage. Let me know if anyone wants to try it out.

  • I wrote a new timer behavior that uses real triggers https://www.construct.net/en/make-games/addons/1236/trigger-timer it outperforms the build in timer behavior in all cases I have tested and also only has one instance picked in the on timer trigger. (I also added some additional features)

  • It's kinda funny that on almost every topic I read Ashley say "dont worry about performance. difference is not really noticable. 99.9% of projects doesnt need this" and so on. And then guess what? Peformance was literally the main problem i had with C3 through all those years. And i make pretty simple games! Some things in C3 cause absurdly bad performance and you will never read about that in docs, and the only way to figure out is to extensive testing and comparing different approaches. Without WebGL debugger and literal months of trial and error i would've never made my games playable on mobile or low end devices.

    In most cases i agree with Ashley, but...

    Ashley "dont worry about performance" Gullen

    Yeah, I struggle with his responses: "Usually this won't matter" -links article about preoptimization. The only reason I noticed it was a problem was because it was a problem, whether that's usual or not. I too moved many a project prototype from contruct to unity because of performance.

    In unity, I would just make the game and it would run well enough. Construct I always felt like a nes developer in the 90s squeezing everything I could out of the system.

  • I wrote a new timer behavior that uses real triggers https://www.construct.net/en/make-games/addons/1236/trigger-timer it outperforms the build in timer behavior in all cases I have tested and also only has one instance picked in the on timer trigger. (I also added some additional features)

    Sweet, I'll have to check it out. I'll probably stick with what I have at this point, but I may use yours in the future.

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)