Ruskul's Recent Forum Activity

  • For the explanation, that is what I thought, but I can create scenarios where each A has a B pair, and for some reason several A will be moved to the same B, leaving several B oh so lonely.

    Its possible that somehow the order of b in the list isnʻt being preserved in the order they are added, Let me see if I can get a demonstration capx built.

  • Lest say you have two types of objects, A and B.

    Lets create a different number of each. Then, lets toss 'em in a layout, with a good number overlapping each other.

    and have the following event:

    On start of Layout

    A is Overlapping B

    --- Set A position to B

    Now, on one hand, I'd naively expect every A to be aligned to a B that it was overlapping, but I'm smart enough to know that won't nec be the case. It tends to work with predictably even pairings, but at other times it the pairing won't be accurate, and there will be a few A moved to a B that wasn't being overlapped by that A.

    This concept translates to any situation where you need A to respond to a specific data on B or reverse. such as:

    A is overlapping B

    --- A set instancevariable to B.somVar.

    //A will not nec have the value of the B that it was overlapping.

    Can someone tell me what exactly is happening behind the scenes that results in... the mixed results we see in this situation?

  • Ashley - Its easy to say the cost of the tradoff is worth it; because you aren't paying that price.

    I really need you to understand that dev-hell already exists in construct in a very real way as a result of trying to avoid hypothetical dev-hell in future construct. Without a road map, all I can do is sit here and hope. Instead of useful, and basic features, we know have a follow behavior and flowcharts. Both aren't nec, and could be made by users if we had a functional api.

    The current api, however well supported, is insufficient to create basic behaviors. Creating a custom platformer should totally be possible, but it isn't without making private calls to a number of systems.

    You could try it in events... but...they offer little abstraction potential. It only takes repeating a complex behavior twice and then making modifications before any sane person learns you should NEVER be repeating logic.

    This can be overcome with verbose boiler plate picking systems or custom action overrides that are repetitive and require performance draining for each loops. To avoid that repetition and create a generic version, this can be avoided by creating a modular component system from objects and uid refs, but at that point performance is dead because you are essentailly creating a game engine in a game engine to address the game engines shortfalls.

    Then comes js editor side. Super awesome, until you realize once again you have to recreate just about every wheel construct has already made, and it also has another api to learn with some of the api existing on one side but not the other ... iCollisionEngine being a fine example. And most importantly, and ignored, a js block has a huge overhead performance cost over standard events, meaning like functions and custom actions, they have to be rationed in performance critical areas... meaning its back to manual inline, copy/paste, clone object, dev hell.

    Can I can share an example, that demonstrates the high performance cost of abstraction for a basic bullet hell game?

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • In the addon sdk I can do unofficially supported things... like this:

    const wi = this.GetWorldInfo();
    wi.SetSourceCollisionPoly(someAnimationFrameRefference.GetCollisionPoly());
    wi.SetBboxChanged();

    Is it possible to bypass the official interfaces provided in the editor, either in modules or js blocks?

    I was trying to test out moving some behaviors into modules, for ease of cross behavior interaction and the ability to extend classes, and I was having trouble figuring out how to do basic, unsupported api calls.

  • github.com/Scirra/Construct-feature-requests/issues/173

    At the end of the day, scripting is suggested to be able to solve needs that the event system can't.

    But...

    There is limited api access for basically EVERYTHING.

    The devs know this, but choose to ignore it for other priorities, and that makes sense in their position. But if Scirra has to access private internals to get a behavior or plugin to work, its because the public API is far too limited. You can't recreate a huge swathe of vanilla behaviors, let alone create better versions of them with the current public api.

    This isn't good if you care about creating anything unique, or have higher standards - I'm looking at you pathfinding, platformer, and 8way.

    This makes Construct an engine that supports ONLY out of the box behaviors. Creating sophisticated behaviors in events is poor in performance if you keep them abstract or wish to scale, and using JS to recreate all the wheels construct won't expose is stupid when other engines do you the favor of allowing you access. Plus, to beat a dead horse, the event system is objectively one of the best things about construct, in terms of speed of design. Wading into scripting editor side essentially defeats the advantages of working with construct and, objectively, there are much better engines out there if you are coding.

    The issue as I see it is that Scirra wishes to keep things internal to allow them to be able to a.) refactor at will when needed, and b.) not break peoples projects in the process, which is a great goal and I understand. But the flipside is that while construct is very stable, there is so little exposed that the promised "stability" is nearly pointless as you have to use the undocumented api to accomplish anything.

    All and all, I understand I am in a minority here.

    I am at a cross roads. I can keep building up my brittle collection of behaviors built on so many undocumented api calls...

    Many undocumented features have remained very stable over the years, and I'm okay correcting the odd compatibility issue here and there - But what if they become inaccessible or obfuscated in the future - for no other reason than simply scirra wants it to be? Ashley has hinted at that possibility - though that would pointlessly break many 3rd party addons that have necessarily used internal features.

    This isn't an issue if you are making small, uncomplicated games, or are happy with the provided boxed solutions. I am not, and I am not.

    How many other people have simply ignored the official advice and built behaviors on undocumented API?

    I personally don't feel like I have a choice. Either I use the unofficial api, or I don't use construct for this project... again...

    And to be clear, my project isn't fancy. I just want a custom platformer that doesn't resolve collisions the same way construct does, is extendable and well written in "SOLID" fashion, and one that isn't pigeon holed into using the solid attribute, along with better oneway jump through handing, slope performance, and a different physics integration model that accurately deals with variable accelerations over time. This is all pretty basic needs stuff AND construct has everything built in to handle this... just not exposed. What is exposed through the custom behavior makes alot of hard-coded assumptions about what is needed instead of just letting the user decide.

    For example: PushOutSolid, which is an undocumented function that custom movement behavior uses, has a hard coded max distance for resolves, a fractional nudge algorithm that iterates a hard coded 4 times, and only works with solids, when in fact, along with other internal functions, you can do less work and achieve sub-pixel perfect collision resolutions without limiting it to solids only or hard-coding the details.

    Construct has trapped itself in a place where it is afraid to expose api because it needs to stay flexible, but insisting on remaining backwards compatible for decades means things can't advance.

    ---

    Perhaps a new class of api should be released. A publicly documented "experimental" api. This would allow construct to sanction the use of more internal features, but with the caveat that they can change in the future, with "fair" warning.

    Basically, you can use them, but they are subject to documented change.

    Thoughts anyone?

  • I should add, depending on the setup, you may need to wi.setwidth set height, change image point, etc...

    If you aren't familiar with any of that, you should probably dig around and make sure you know the basics.

  • How to swap collision polygons without interrupting an animation

    TLDR: I use unofficial "Getters" to the construct3 CollisionEngine, in order to directly set collision polygons and bypass the sprite plugin changeframe/animation behavior. This allows me to control and check collisions from a behavior, and reduces alot of the overhead to changing frames through an ace. Since I bypass the change frame entirely, it doesn't disrupt any currently playing animations. It only affects collision polys on the object.

    The problem : Compound collider objects require picking loops, containers(no families), hierarchies (with picking loops for animation), or similar solutions

    The issue isn't obvious until you try to scale, extend, or have performance issues, then it's painful.

    When it comes to managing complex/compound objects, do you ever get annoyed with picking, iterating hierarchies, or dealing with containers, just to be able to have multiple collision polygons for an object? Picking loops often require a "foreach" loop, which can be expensive at scale. Hierarchies do a lot of additional lifting but will still likely require a loop if you need to separate view and model. And containers don't work with families.

    Sometimes, all of this isn't a big deal for unique objects, or those in lower quantities. But the more you have, the more difficult scaling will be, and extending any solution through abstraction will also require a lot of repetition.

    You can avoid the above if you create an animation on the object and simply switch frames for different collider polygons, BUT that comes at the cost of not being able to run animations automatically, and will require additional systems for tracking the animation state. Swapping frames around can also cause any triggers set up to repeat.

    The solution : WorldInfo polygon swapping.

    There are a number of ways to approach this, but currently, the way I do it is as follows:

    You will need a distinct objectType in the editor to be able to create animations and create collision polygons for various frames. It has no other purpose than to serve as a place to edit your collision polygons.

    Then you will need the object you want to have the super ability to change colliders without changing animation frames or interrupting the animation playing.

    Last... you have to create a behavior or script an equivalent tool editor side to then automate the process of changing polys. I chose to use a behavior.

    The behavior

    The behavior is going to have an action with 3 parameters to pass in an objectType(restricted to sprites), an animation string name, and the number of frames in the animation to collect.

    Here is a sample bit of code that sets up the behavior: (obj, animName, frameCount)

    const pickedInstance = obj.GetFirstPicked();		
    frameCount = Math.min(frameCount, this._stateCount);		
    const animation = pickedInstance.GetSdkInstance()._objectClass.GetAnimationByName(animName);
    for(let i = 0; i < frameCount; i++) {
    	this._stateFrames[i] = animation.GetFrameAt( i );
    }

    I haven't done any error checks here, so you have to be sure there is at least one object instance you are referencing, and that the animation name exists on the object and there are enough frames in it.

    Basically, this just creates a reference in an array on the behavior to the animation frames that have the collision polygons you want to use

    Later, via actions, or in tick(), you can do something like this to use it:

    const wi = this.GetWorldInfo();
    const ce = this.GetRuntime().GetCollisionEngine();
    
    //you can iterate through all states with a for loop, or pick individual frames
    //Keep all related variables in equal length arrays and you can easily iterate
    //Use solids, build a candidate list, or test against whatever
    wi.SetSourceCollisionPoly(this._stateFrames[i].GetCollisionPoly());
    wi.SetBboxChanged();
    if (ce.TestOverlapSolid(this._inst)) {
    	this._state[i] = 1;
    }
    else this._state[i] = 0;

    All in all, you can use the index however you please, I have variables on each object type that are the keys : ie _stateUp = 3, You are also free to add as many states/frames as you wish.

    For me, I also loaded the behavior with PushOut functions for solids and arbitrary object types, a suite of vector math tools, raycast tools, and some advanced physics/velocity/integration ACES.

    Using aces editor side, Creating a goomba is as simple as defining initializing the behavior with a 2 frame state check.

    EveryTick:

    ---Goomba UpdateStates

    Goomba State(left) or Goomba State(right)

    ---Goomba InvertXVelocity

    EveryTick:

    ---Goomba HandlePhysics //Integrate velocity and pushout of collision if applicable

  • Okay! Sounds like this case is nicely wrapped up, and has been for a while. I will do as you suggest.

    You may well be right about gc in c# not being as well optimized - and that sounds like an excellent rabbit hole research project for next time I am distracted :D

    Thanks!

  • Thanks for the details. I suppose that all makes sense,

    As I understand, you are essentially saying the cost/benefit ratio also doesn't exist engine side, due to increased bugs/complexity without a "real" benefit to most games. I agree given your explanation.

    2 things I disagree with though:

    1. Making a pool via events isn't worth it. The cost of the event editor overhead eats a major portion of the performance gained, and its nigh impossible to create a generic one that doesn't spend more energy than it saves. This activity is much better to be done in script - but the cost of tying that into the editor can still outweigh the performance gained IF you use js blocks. If everything is in script it and you don't need to make recycle calls from events, perfect.

    For that reason, I would argue it isn't worth the time, because the cost/benefit ratio just isn't there.

    2. GC is most performant when collecting newly created items. I think the vast improvement in JS gc is in this realm, yes? But recycling is good because it helps major collection (though total allocations has an ongoing cost). If the bulk of gc allocations are items created every tick, the collection of those items is much, much faster. These items are part of a minor garbage collection and typically get collected in the idle time each frame, so have no impact on frame or stutter whatsoever. However, if performance is being impacted by minor gc, reducing it is as easy as not discarding obj refs every tick and not creating objs just to discard them every tick.

    Items that remain in memory for longer get collected by the major collector and those can indeed cause frame drops when it runs. Object pooling helps most in this arena.

  • Sorry for the lack of clarity.

    I am working on behaviors, so this is all runtime side. It would be in instance.js. Now that you ask that, I am curious, I should probably be setting up that reference to at a different point? I've read the manual, but I'm still pretty shaky when it comes to the architecture the general flow that happens when objects are created, when the code gets accessed, etc...

    For my purposes, it is to set up cross communication between behaviors and other behaviors, or other plugins.

    This way I can use behaviors to create modular behaviors, with a "handler" behavior that ties them all together. Then, all I have to do in the editor is attach whatever behavior modules I want, attach the handler, and it all gets interfaced through the handler in event ACEs.

  • IIRC maybe the C2 runtime did that, but the C3 runtime doesn't, so this hasn't been the case for years. JavaScript and modern GCs are so good that kind of pooling approach doesn't matter any more.

    Respectfully and in humor, lol.... What?!

    No way! For games that it matters for, it does matter alot. For the rest, it doesn't hurt any. A generic pool usually always helps performance for any objects being created/destroyed at runtime. Tweaking, or supplying specifics can improve a pool even further.

    Allocating and releasing memory takes cpu work, no question. Better gc doesn't really change that, just lessens the impact... but it doesn't eliminate the impact. Call me a skeptic - but industry standard is still to pool - and that is regardless of whether you are in c++, c#, js, or heaven forbid gsl. If you pool in unity or unreal, I can't see a reason why you wouldn't in js in construct, given c#/c++ has better performance at runtime.

    You can easily test this with an objectpool made out of construct events using inefficient arrays and pick by uid, and it will perform better than simply creating and destroying objects, despite the pool having a large overhead for looping objects. I still get 20% better performance in this case. If you perform the same equivalent loops to the non-pooling method, the performance increases. Move the pool to scripts and you will see bigger benefits. I didn't do it in script form because I still have to lumber through js and the api, but I'm sure you could whip something out to test in minutes.

    For a bullet hell game or any other where objects are frequently being destroyed and created, object pools are a absolute must for smooth performance.

    If I run equivalent loops for pooled/vs non pooled objects to eliminate event overhead for loops, I can get 5x the fps for pooled objects in perfect contexts. Engine side, you should be able to do even better by properly moving those objects to a space where nothing updates for them and they aren't "technically" on the layout anymore.

  • Hey all,

    So I've been having issues with some calls.

    For example, I see GetSdkInstance(); under behavior instance, in the manual, but when I call the function,

    this.GetSdkInstance();

    it doesn't work

    I have to do:

    this._inst.GetSdkInstance();

    I know _inst is supposed to be private, but I get an error when I do:

    this.GetInstance().GetSdkInstance();

    In both cases the error listed in the console is that there are no functions found.

    It must be said, I am a complete moron with js coming from c++ and c#, so this might be a simple noob mistake. is it supposed to be "self.whatever..." instead of this?

    Also, when making a call during the constructor, I get null for some of those. I expect that is because the order of initialization isn't guaranteed? But is there a place to call such things during creation that would be good for creating dependencies?

    Thanks a bunch!

Ruskul's avatar

Ruskul

Member since 23 Nov, 2013

Twitter
Ruskul has 2 followers

Trophy Case

  • 11-Year Club
  • Forum Contributor Made 100 posts in the forums
  • Forum Patron Made 500 posts in the forums
  • x6
    Coach One of your tutorials has over 1,000 readers
  • Educator One of your tutorials has over 10,000 readers
  • Regular Visitor Visited Construct.net 7 days in a row
  • RTFM Read the fabulous manual
  • Email Verified

Progress

18/44
How to earn trophies