Add a PreEvents tick/action type to CustomObjects, not just PostEvents as it is now. This can cause weird 1 frame visual issues or mismatches that are not always easy to solve or has to be worked around. Having the option to decide if events should run post or pre would be a helpful addition to CustomObjects.
Please can you give more details about your real-like use-case?
Like if you have multiple CustomObjects and want to guarantee something happens early to not cause it to be out of order and thus not get affected, like setting hide/show of a Sprite based on logic calculated elsewhere or whatever.
For example, a GameManager object and a Button object, the Button has an Icon who’s shown or hidden based on something calculated on tick in GameManager, if setting the value runs before the value calculation then there’ll be a frame where it’s not correctly applied – which can be quite noticeable.
Apply the same logic to pretty much any cross communication between CustomObjects. It would be really nice to separate out data driving logic from visual logic in Pre and Post to ensure if anything is using values from elsewhere to drive it’s visual state it won’t be out of sync.
What is the actual issue your facing? I mean what actually happens step by step for this case in particular.
For example, a GameManager object and a Button object, the Button has an Icon who’s shown or hidden based on something calculated on tick in GameManager, if setting the value runs before the value calculation then there’ll be a frame where it’s not correctly applied – which can be quite noticeable.
This is one of several. One extension who keeps it’s information contained to it’s extension, communicating with another CustomObjects who keeps it’s information contained within itself. I pass this information by writing to extension global variables and and having global functions within those extensions to read/write that information and/or set those values within doStepPostEvents inside a CustomObject within that extension.
Result leading to a completely separate CustomObject can access that information before it’s written, and cause 1 frame desyncs. Which is particularly noticeable when it comes to anything that is visually represented and updated from those values.
Unless I am completely missing something obvious here I am not sure how to really circumvent this without ensuring the Objects can write those values earlier in the chain and that I read from and manipulate them later on. I don’t think there’s any way to guarantee execution order otherwise, as object references are contained to their scenes(or other CustomObjects) and don’t have a global way of idk like casting or storing a reference to execute functions more event based, so I am at the mercy of a lot of logic on tick in many cases.
CustomObjects already have a field for other advanced lifetime functions, it would be nice to have it there as an option. Behaviours already run their logic on doStepPreEvents, it feels like it should be possible to expose?
I guess what I need to understand the issue might be:
- a scenario as a bullet list to give all the steps with screenshots of the events
- main events call this function which..
- main events call this other function which…
- the life-cycle happens and it…
- an explanation of what gets wrong and what you would like to actually get as a result.
Well the steps depend entirely on an arbitrary execution order that I have no control over, hence the feature request – but I’ll give it a try below:
Extension A:
Contains global variable “ButtonColor”
Has CustomObject named "GameManager"
Extension A Global functions:
SetColor(String color) of type Action sets ButtonColor
String GetColor() of type Expression returns ButtonColor
GameManager exists in MainScene
GameManager doStepPostEvents triggers ExtensionA::SetColor(newColorBasedOnConditions)
Extension B:
Contains CustomObject “MainMenu”
CustomObject MainMenu on doStepPostEvents runs ButtonSprite.Tint(ExtensionA::GetColor())
MainMenu CustomObject exists nested inside another CustomObject that exists in the MainScene
Result: these may be out of sync, and the button sprite color may be applied a frame later than it should.
In my real life scenario these are more nested and complex, but it boils down to the same thing. Cross-extension communication where I would like to be able to guarantee order of writing to and reading from variables.
I assume the nesting doesn’t really matter for the execution order, but it matters in being unable to call a tick function from the main scene graph – though this is already not very clean.
I suppose I may be able to makeshift my own doStepPreEvents inside CustomObjects by making a Behaviour for every single object and calling a custom Action from its doStepPreEvents.. but that’s not very feasible at all unless you design with it in mind from the beginning I think
- What does the
GameManagercustom object look like? - How and why does
GameManagerdecide of the button color?
What do you mean by what it looks like?
My actual GameManager extension has like 7 Custom Objects and 50+ actions/expressions/conditions etc., it doesn’t specifically drive the colour but it drives the game states, game hud, settings menu, and various game settings which propagate down to change things like visibility and other things depending on what other objects need. The example I gave was just to simplify what the logic flow is to make it digestable.
In your example, you said it was a custom object, not an extension so I’m confused. Which one is it?
I mean what really matters here is that when the Object who sets a value in doStepPostEvents runs before I read that value in another Objects doStepPostEvent, there is a 1 frame desync between them. Which would be fixed by being able to set that value in a doStepPreEvents to ensure I am always setting values before reading them.
In most other game engines I’d do something like this through event based logic, I can’t do that the same way in GDevelop because CustomObjects/scenes/etc have no context of anything that exists outside itself. So I would very much like another way to guarantee I can run the logic earlier.
I hear you, but I need real-life use-cases to make sure I understand the full length of the need and be able to take good design decisions.
Use cases can be simplified, but they need to be something you might do. “Extension A” doesn’t help me to understand.
I am not sure what you are asking me to elaborate on further, real world use cases include any information you may set within one extensions global variables, from within a CustomObjects doStepPostEvents, and read from another either within the same extension or not – inside a separate doStepPostEvents.
Anything from game states, to unlocked upgrades, to save data, game settings, economies, centralised default values, statistics, input methods, anything at all that you might want to setup with a more modular design. I drive my entire game this way, as it’s the most modular setup I’ve been able to achieve within GDevelop.
It saves me from a lot of hardcoding and lets me create a lot of reusable and state driven game components. Forcing all the games logic to exist within a single sheet is not suitably maintainable and will build up enormous technical debt.
My biggest issue so far from this is mostly visual, but I am triggering visibility of elements based on various data and that can be quite jarring when elements that should be hidden are visible for a frame because the data is set later in the execution than it’s read (within the same frame).
Like my entire games HUD being visible for a frame when it should not, or console input icons showing for a frame when they should not, etc.. as I mentioned earlier in the thread there are work arounds, they are just not very feasible and would add technical debt and hard to maintain junk to the project which isn’t very desirable.
Having the option to also override doStepPreEvents (assuming there are no big technical limitations to allow this) would go a long way, not just to enable my setup but also plenty of others. There could be many reasons you may want that control in GDevelop – when running more event driven logic isn’t really a much of possibility in this engine across extensions, objects or scenes since everything is mostly self-contained and unaware of anything that exists outside it’s context.
This is an issue you don’t face if you rely almost exclusively on the main scene graph and external events because you are confined within a single chain of execution – this is not the case when you spread logic across CustomObjects as afaik there is no way to guarantee execution order – which is completely understandable.
I wouldn’t expect them to be handled inside a custom object, at least for:
- game states
- unlocked upgrades
- save data
- economies
- statistics
If you meant something like a callback, conditions and expressions are what I would use to allow parent components to know what happens in their children and since it is driven by the parents there is no frame delay.
I’m probably wrong, but I get the feeling that you try to force everything to be a custom object. Behaviors are actually often a better choice. For instance, in the following template, the gameplay is organized into functions and behaviors.