Ruskul's Forum Posts

  • jup I brought this up before and wrote a suggestion to turn timers into true triggers.

    It's not only bad for perf it also leads to the weird case where -> on timer triggers with multiple instances picked. (this lead to c3 user actually adding for each to every trigger as they stopped trusting triggers altogether, leading to even worse performance xD)

    Was there a discussion at that time? How long ago was it? Is there a way to know if a trigger is fake? In c2 you could always check the behaviors code... because, you know... it was useful like that :p

  • Yeah it's kind of a pain: why can't conditions apply to all objects that it's valid for? For me, "Pick all" doesn't really act the same as "for each object" and it's difficult to tweak the code to make it act the same along with the benefit of lower CPU usage.

    It really depends on what you are doing with each object after it is picked and what other objects you are referencing. So you have an example in psuedo code you could share?

    Do you use the keyword "self" while writing expressions and events? If not, that would be an important reason things weren't working as you wanted.

  • I've noticed that the Moveto behavior maintains its speed when the target changes to the opposite direction... that it maintains its speed and "instantly" changes directions without regard to accelerations and deceleration seems like a bug. Even if you set rotation to > 0, the object weirdly hitches when the target switches to behind it.

    I've already got my own moveto behavior so my work around is obvious, but it just seems like it shouldn't act like that.

  • Looks like subpixels are not rendered correctly when scaled down? But I dunno, someone with more knowledge gotta weigh in on that.

    Originally I thought it was an issue with pixel stepping and the like, which was the first thing on the list of supsects, but you may be right. As I play with it more, it does indeed seem to be a rendering issue with sub pixels.

  • I mean, that's cool, but it is still a 3rd party plugin for what should probably be vanilla. At least its from a user with a grand reputation.

    And donkey doughnuts UIDtoAnything! Yeah, that's another thing construct always needed.... handling references without having to pick objects over and over.

  • If I have an object that needs to do something in 10 seconds...

    I can set a tween "" from x->y for 10 seconds.

    I can set a timer "" for 10 seconds.

    I can use a instance variable, set it to 10, and subtract dt every tick.

    (If I didn't need bulletTime / scaled dt, I could also just store the current timestamp and check that against the current time.

    For both tween and timer I can use the trigger onTimer "" and OnFinished "".

    For the event based method, I can simply check if variable <= 0;

    I wasn't too surprised that tweens perform worse than events. They have alot of extra fluff not needed for a simple linear 1:1 dt:value change.

    But timers!!!! They are the worst even though the tween is mimicking a timer and can do so much more.

    In a project with 20k objects tested with event based timers, tween based timers, and timer based timers... the event based timers were the only ones that could run at 60fps. The downside is that they had the overhead of needing to check if the timer variable was <= 0 every tick. The suprise is that the "trigger" for ontimer has exactly the same overhead, but the tween doesn't.

    With the timer test, if no timers are running, the "OnTimer" trigger alone causes 30% cpu usage. When activating all timers, the project runs at around 27 fps.

    With the Tween test, if no tweens are being run, the project sits at o-1% cpu usage. PERFECT... until you run the tweens and then you get around 27 fps. This indicates that tweens ARE slower than timers, but since timers have the overhead for the trigger, it evens out.

    Events use around 30% cpu for the conditional check to see if a timer is done, and an additional 15% to simply add dt to the timer. Total 45%.

    So basically, at scale, depending on needs and how often the timer is operational vs inactive, I would use either custom events or tweens.

    HOW can events outperform the timer behavior!!!! The timer should be king in performance for all timer related needs... but it isn't.

  • As often as not, I find my use of arrays and dictionary to be tied to objects. Dropping them in a container is great... but I always use families.

    Thus... object picking is required for every object pair... which can reduce performance and adds alot of boiler plate to families for no reason.

    Are others interested in being able to add lists, arrays, dictionaries, etc. directly to an object?

    Has this been suggested before? Are there cons to this? I know I have seen 3rd party behaviors that do this and wondered why it wasn't default in construct since the beginning?

  • Haha, Iʻve been trying to deal with that in my own project right now. Figuring out ways to git rid of foreach when you need to pick objects by uid associated with the current instance.

  • If you have an extreme performance requirement and the event system just isn't cutting it, there is also the scripting feature - I know writing JS isn't for everyone but at least the option is there for raw code to make things as fast as possible if necessary.

    Iʻve been running some comparisons and I noticed many times the events are already so well optimized that rewriting it in JS seemed to do nothing to speed it up. I actually managed to slow it down using JS in some cases - which is always nice. I know that many pretty sweet optimizations have been added to c3 over the years and it really shines through sometimes. Iʻve had several occasions where c3 is able to be beating both construct and construct 2 by quite a large margin doing the same exact thing.

    Iʻd be curious to know if anyone has tried creating an ECS like system in construct. I donʻt even know if JS can go low enough in memory allocations to enable that type of design, but that would be a neat project.

  • I would love to put things in containers, but they donʻt work with families, and I usually end up with everything in families, because I usually always end up with multiple types.

    Iʻve tried using instance variables on objects to hold dynamic function names and using those functions to differentiate behavior and that works, but I havenʻt fully investigated the other issues this might cause.

    One thing, I think... it would be nice if dictionaries and arrays could be able to be added as behaviors or instance variable types, rather than being their own object. I always wondered why that was. Basically have them more baked in. Any object that needs a bunch of data for each instance, always ends up needing to be in a container with them, or worse, as a family, needing to run a bunch of picks.

    As far as optimizations go, I generally try to cache data that is costly to compute, and filter conditions with by order of least common first. Usually I have isDirty flags on set and check. Alot of effects that needed updates every tick, I just set a tween on them. Iʻm assuming that is better, but even if it isnʻt, the tween is a pretty awesome tool for simplifying timers, delays, and other varibles that need to update every tick.

  • I structured a project like this:

    Characters hold a UID to a unique dictionary (one for abilities, another for effects). The dictionaries hold the UIDs for whatever abilities / effects are affecting that character. Basically, you will have a lot of picking objects from a UID reference.

    I actually create objects for the effects and abilities, even though they arenʻt rendered, add them to a family, and add custom actions on those families. In this way you can abstract away alot of the common behavior like adding and removing abilities from the player. Once you have the boiler plate done, adding a new effect/ability is as simple as creating a new sprite, dropping it in the correct families, and then overriding the base custom action with whatever you need the new ability to do when it ticks.

    Those abilities can simply be spawning bullets, explosions, particle effects or whatever you like. Just make sure you properly you have actions for removing an ability that ensures the ability also removes anything it adds to the game.

    Since vampire survivor largely operate on automatic abilities, you donʻt have to worry too much about hooking input through this system, but if you needed to do that, you would probably need a number of "input actions" that abilities would check when being iterated through. Either that, or they would add themselves to another list that on succesful completion of the input action, and you would simply call them via callback. I typically use an input object that can be changed by either player or ai, and then a movement handler reads that input and responds accordingly. Hooking a system like that into the player abilities will be easy because each aspect is already isolated and doing its own thing.

    If you have an extreme number of these objects linked like this, you will have performance issues. I make sure I only run foreach loops after filtering objects by other conditions. Also, iterating through arrays is faster than dictionaries, but the dictionary is faster to add and remove items arbitrarily, while the array handles pop/push more efficiently. I havenʻt tested queue, because I have had no need, but no optimization is needed until you have a problem anyway. In my case, I needed to be aware of this from the start because I knew I would have up to a 1000 lists to iterate through (each list having up to around 12 items)... basically, so long as you donʻt have to run picking events for 10k objects, you are fine.

    Also, most games wouldnʻt need to actually create those objects but simply refference data stored somewhere in one place. I just.... happened to have specific reasons why I needed to go overboard on it.

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • The gpu is used for rendering... event logic, scripts, etc... is handled by the cpu. Depending on your project, you could get really creative and shove some work towards the gpu, but you need to know how to both program and write shaders.

    Iʻm assuming your project is heavy on logic and light on graphics?

    Without knowing anything about the project, there isnʻt much I can suggest.

  • So yeah, don't use 'For each' unnecessarily.

    In the event where you are using foreach to pick associated objects by uid, do you know of more elegant solutions than the typical:

    Foreach Character

    Pick dictionary by UID (character.myDictionaryUID)

    Pick collider by UID (character.myColliderUID)

    etc...

    Foreach element in myArray

    pick Effect by uid (myArray.currentvalue)

    For each effect, pick refferences objects by uid

    In the past, I never had a need to think about the efficiency of all this foreach and picking stuff because it was only for dynamic characters (like npc and main player for example). Maybe you have 30 characters active in a scene. But now Iʻm trying to do a bullet hell and every bullet carries a dynamic list of effects (easily dozens) and those effects may further reference other objects, custom actions, etc.... So I find myself needing to do a foreach over a 1000 bullets (to pick ascociated objects) and then a foreach over an array of elements containing a reference to the list of effects that bullet is affected by. If the effect is a general effect, I can just do that without picking, but sometimes the effect also needs to pick other objects as well such as the object that fire the bullet.

    All this picking seems to be required in order to maintain a system where projectiles and characters can be decorated by numerous effects and have many links to one another or characters in the scene.

    Many times the effect list can be 0, so I can filter those out and not bother iterating and picking them. But other times, it can be every single bullet has a dozen effects that all need updated.

    For every object that needs to pick another object by uid, I have to run a foreach on using this architecture.

    This seemed to be the standard approach, but is there an updated way these days?

  • Ah, that is code snippet makes total sense. Thanks ASHLEY.

  • Hey, I'm curious if I have done something wrong, but when I change the height of a sprite smoothly over time, if the sprite is small (in screen space), the change to height appears as though it is happening at a low frame rate. The smaller the object, the lower the framerate.

    Given a different way, if an object is 32 pixels on screen, a tween from full height to 0 height, will appear to take place in obvious "discrete steps" at like 2fps. If the tween(linear) only lasts a second, you get a height change that more or less looks like full height, half height, done. The same object taking up 300 pixels on screen, will appear to have a more "steps" (basically 60 fps) to acomplish the same effect.

    Obviously a retro project will have pixel snapping and all that, but this issue affects any combo of those settings.

    Does anyone know what might be happening here to cause this? I can share a file, I just wasn't sure what the standard method of sharing was for c3.