"If else" event (We have a solution)

Hello

First topic

With @Pelitaiteilija we have talked a lot and we have maybe a solution for implement a new event type.

We present “If else” (mockup)
mockup_if_else_event

I’ve edited the exported generated code from a game for add this directly in the engine.
And it’s working.

Here the files of the basic game

Here the game playable with the code edited with “else” like on first screen.

This is the basic exported code:

And with the “if else” added

6 Likes

It is going to be a useful addition, however what I dislike about it is that it is going against the practice we have in GD which is conditions on the left and actions on the right.

Personally I like it better the way it have been implemented in Construct.
We could have either an else event or else condition that is being trigger only if the previous event returned false, otherwise it would be skipped.
else

I find this solution more elegant than having a whole new block type dedicated for this with condition on the top and actions on bottom.

1 Like

Giving the user the possibility to put the block “Else” is a problem for the code generation during the export.

It’s more simple to add a new event “if else”, because if we add only “Else” event then the engine need to analyse which event is above this “Else”… this is a big headache in perspective i guess.

But with the unique “if else” event we can just to copy/paste the code for standard event and add “else” in generated code.

Maybe my mockup is not good, i can change it like this
image

But the most important is think with the engine, how the engine can generate this.

I see on construct if you have a eventsheet with only “Else do XXX”
When you wish start game you can’t and the engine said “Hey you can’t use Else without If”
And GDevelop don’t make altert like this because the engine need to do the job.

3 Likes

Code generation certainly need to adapt which is the reason it is never been implemented I guess because it does not justify the amount of work required to implement it since a work around do exist.

But the second mockup of the “if-else” block is way more friendly, I like that :+1:

1 Like

Hi
Can I use this If Then Else thing programaticly today?
Or it will be available in the next version?

Impossible, this is just a mockup.

Mockups can indeed be discussed. The main issues is about object picking. How should that work?

If I do:
Conditions: Position X of Object1 is <100
Then Actions: Set Object1 to be red
Else Actions: Set Object1 to be green

What should happen?
It’s tricky because let’s consider that there are some “Object1” that are verifying the condition. In this case, they should be made red. But what about the other (that have position X greater or equal to 100)? Should they be set to green?

  1. If yes, then it’s “weird” because we have the Then actions AND the Else Actions that are executed. Something that is never seen in traditional programming language if/then/else.

  2. If no, then it’s not “intuitive” because the user would expect to have some “Object1” to be turned green while they are not. They will only be turned green if the conditions is false. In other words, if ALL the “Object1” have their position greater or equal to 100.

If we decide to implement 1), how should we do with multiple conditions on unrelated objects?

Conditions:
Position X of Object1 is <100
Position X of Object2 is <100
Then Actions:
Set Object1 to be red
Set Object2 to be blue
Else Actions:
Set Object1 to be green
Set Object2 to be blue

What should be red, green and blue? :slight_smile:
It’s an open question, feel free to think about it and suggest answers - but make sure to cover all the possible cases and explain why.

In terms of programming, events are more akin to “filtering”/“iterating” on objects lists, which translate not very well in terms of “else”.
The answer might not be a single “else” but something like “Conditions, Actions Then, Actions for other objects”.

But this requires very very careful planning to get something intuitive and right. Otherwise we’re stuck with a bad implementation.

Not sure what you mean, we can do “if A do B else C” in language programming, it’s same here.

For me all instances of Object1 under 100 will be red, and the other instance not under 100 will be green.

All instances of Object1 under 100 will be red, the other instance of Object1 are green.
All instances of Object2 under 100 will be blue, the other instance of Object2 are blue.

I’ve modify the generated code for implement this two examples, you can take a look here.

With else we need always thinking with instances. Then we need use “for each” loop in GD.

This example is easy to handle, perhaps it would be necessary to have a more difficult example by using the example of a platform to have a case closer to reality.

Not sure what you mean, we can do “if A do B else C” in language programming, it’s same here.

In JavaScript, if you do:

let a = 0;
let b = 0;
if (condition) {
  a = 1 ;
} else {
  b = 1
}

Then at the end, either a or b is equal to 1.

In GDevelop, if I do:

Conditions: Position X of Object1 is <100
Then Actions: 
  Set Object1 to be red, 
  Do =1 to scene variable A
Else Actions: 
  Set Object1 to be green 
  Do =1 to scene variable B

Let’s consider that there are some “Object1” that are verifying the condition. In this case, they should be made red. But what about the other (that have position X greater or equal to 100)?

  1. First solution, as you explained: “With else we need always thinking with instances”. So we run the “Then actions”, and some objects are set to red. Then we run the “Else actions”, and some objects are set to green.

Sounds good BUT now we have the scene variable A and the scene variable B that are set to 1. This is not a else! :wink:

  1. Second solution, we can say “If the conditions are true, run the “Then actions” as usual. If they are false, then run the “Else actions””. In this case, at the we either scene variable A or scene variable B that is set to 1 - not both :+1:

BUT this is almost useless, because your “Else actions” will only run if not a single Object1 has a position < 100.

Conclusion: seems that, as you said “With else we need always thinking with instances”. So let’s go for solution 1… but as explained strictly speaking this is not a “else”. We should name it otherwise. Something like:

Conditions: Position X of Object1 is <100
Then Actions: 
  Set Object1 to be red, 
  Do =1 to scene variable A 
Actions for the other objects: 
  Set Object1 to be green 
  Do =1 to scene variable B

Then we need use “for each” loop in GD.

You’re right that in your example, we need the for each. I would like to avoid having the user to do this.

So can we find a solution that:

  • Avoid having the user to use for each
  • Can turn a bunch of “Object1” red and green according to their position?

In other words:
Problem: Should “else” be exclusive (run only some actions) or always run both actions list?


Ok, now there is another problematic use case where I would like your view:

In a traditional event, if I do:

Conditions: 
  Scene variable C is =1
  Position X of Object1 is <100
Then Actions: 
  Set Object1 to be red
  Do =1 to scene variable A 

It’s straighforward:

  • If scene variable C is equal to 1, then we look at which object1 position are under 100. Finally, we run the actions to set them red. And we set the scene variable A to 1. Easy! :slight_smile:
  • If scene variable C is equal to 0, then we stop everything and go to the next event. This is very useful to avoid running useless conditions. Also we don’t run the actions, so scene variable A stays to 0.

Sounds good? So now let’s use this with or “Else” event instead:

Conditions: 
  Scene variable C is =1
  Position X of Object1 is <100
Then Actions: 
  Set Object1 to be red, 
  Do =1 to scene variable A 
Actions for the other objects: 
  Set Object1 to be green 
  Do =1 to scene variable B
  • If scene variable C is equal to 1, then we look at which object1 position are under 100. We then run the “Then Actions”, we set these object1 to red and variable A to 1. We then run the “Actions for the other objects”: the object1 that have not been picked previously are now set to be green and variable B is set to 1.

(So both variable A and variable B are set to 1. A bit weird but why not, we decided it’s ok).

  • Now if Scene variable C is equal to 0. What should we do??
    • We can run the “Else actions”. But this means that ALL object1 will be set to green, as not a single one has been filtered by the second condition because the second condition was NOT run. I guess we agree that having all the Object1 set to green is weird…
    • Or we can say “in this case, run all the conditions” :slight_smile: Even if some conditions are false… But this means that if Scene variable C is equal to 0, then all actions will STILL be run, so variable A and variable B will be set to 1.

It’s a bit like before: seems like the “else event” we’re discussing about is either not adapted to objects or not adapted to variables :’( What do you think?

In other words:

Problem: Should else run all the conditions, or stop at the first condition that is false?

Yeah I’m also not sure what is weird about this. Else should be executed if the previous condition was false, does not matter why, if it was false just execute Else. This is how usually If-Else work.

There is also If-ElseIf-Else where ElseIf also require a condition to be tested like

If a < 100 : Do this
ElseIf a > 100 : Do this
Else : Do this

In which case ElseIf executed if the previous condition was false, why? not important, if it was false the program test if a > 100 and Else going to be executed if the previous was false, why? not important again, if the previous was false, Else is executed.

What is weird is that I am explaining this to someone way more experienced in programming than I am :zipper_mouth_face:

Wondering where is the twist here :sweat_smile:

Please read fully this answer: "If else" event (We have a solution) :slight_smile:

If you do what you said “Else should be executed if the previous condition was false”, then doing:

Conditions : position X of Object1 < 100
Actions: set Object1 to red
Else actions: Set Object1 to green

is not doing what everyone is thinking. because “Else actions” will be run only if the condition is false. And the condition is false only when all object1 X position are superior to 100.

So Object1 will never be green.
(You might argue that “it’s how else works”… but @Bouh described the exact opposite solution, so you can see that you two don’t agree on this simple case :))

So there is the twist.
Can’t you make it so to test and execute then similar to For each loop?
It would be expensive but this is what I would personally expect to happen.

1st Instance < 100 : green
Else : red
2nd Instance < 100 : green
Else : red

Or we could just use a For each if this is the result we want.

For each Object
If Instance < 100: green
Else : red

Otherwise it would be false only when all object1 X position are superior to 100 as you mentioned.

Or we could just use a Fore each if this is the result we want.

I can already see tons of users telling that “else is not working, this is a dumbass game engine” :grimacing:

Otherwise it would be false only when all object1 X position are superior to 100 as you mentioned.

Yeah that’s one problem. I can’t see myself adding a “else” event that requires to know that you must use For each Object otherwise you’re probably messing things up. Such an easy way to make mistakes. :grimacing:


An additional note, for people that are familiar with JS or programming.

GDevelop events are NOT if/then. That’s why we can’t just say “just add else plz lol”.
GDevelop events are filtering of objects, bailing out at the first “filter” returning 0 object:

let actionsObjects = AllObjectsOfTheScene.filter(condition1).filter(condition2).filter(condition3);
if (actionsObjects is not empty) {
  action1(actionsObjects); 
  action2(actionsObjects); 
  action3(actionsObjects); 
  ...
}

So a “else” can’t be used as is.
But again, give a careful read to "If else" event (We have a solution) and try to answer both problems.

I’m ok to add something to the events, but it’s probably not a “simple else” that we’re searching for.

I understand the problem.
If this is added as I thought it would cause confusion for users.
They would set actions/conditions that will not necessarily be executed.

I would say that the second case would be more logical.
Stop the “then” if one of conditions is false, and execute “else”.
But I think it is not explicit enough.

It requires thinking again and seeing the approach in other software.

So we don’t want to use For each or similar approach here but the current approach can not support the implementation to work and behave as it usual would, we could only mimic the behaviour but that would be not optimal solution and we don’t want to call it “Else”.

Sounds like to me the best approach is to adapt the code generation then to return the list of object did not meet the condition and execute the Else action on them but unfortunately I don’t know enough about how GD works internally and how much effort we are talking about. So all I can say is dig as deep as you need and “just add else plz lol” or don’t worry about it. There are more important things to do and we don’t really need Else imo.

But if you ever decide to dig deep just to add this, please consider the way Construct does it. It is feels a natural straight forward approach imo. :+1:

1 Like

I’m a programmer, and I went to help my son with his GDevelop project with an issue that calls for an else clause. I looked around was having trouble finding the else feature, which I felt was pretty bizarre. That led me to finding this thread.

I have some experience with object-picking event systems. I’m actually considering writing one as an extension of Godot, so this stuff interests me.

I personally find that the solution I’m proposing is pretty clear, regardless of whether all users find it fully intuitive in all cases. There isn’t a solution that makes perfect sense to all users instantly.

To stick with examples in this thread, for the case of

Event1: Conditions:
Object1 x < 100
Actions:
Object1 set to green
Event2: Conditions:
Else
Actions:
Object1 set to blue

In the above scenario, then the conditions attempt to pick instances of Object1 whose x property is less than 100. If instances are picked (filtered), then those instances are set to green. NO INSTANCES ARE SET TO BLUE. The Else condition in the next event doesn’t attempt to pick some kind of inverse of the previous event. The second event is simply skipped altogether, since this is how Else works, and would create more gaps in functionality if you tried to do some strange else picking algorithm. If you wanted to set the instances of Object1 to blue, then the condition in the second event should be Object1 x >= 100.

In the above code, if no Object1 instances are picked in the first event (i.e. no instances have an x property less than 100), then all instances of Object1 should be set to blue.

If we look at 4ian’s other scenario:

Event1 Conditions:
Object1 x < 100
Object2 x < 100
Actions:
Object1 set to green
Object2 set to blue
Event2 Conditions:
Else
Actions:
Object1 set to red
Object2 set to blue

For the above code, here these are the proposed outcomes for the following scenarios:

Scenario 1: There are picked instances of both Object1 and Object2 that match the conditions of Event1.
Outcome: All picked instances of Object1 set to green and all picked instances of Object2 set to blue. No non-picked instances set to anything.

Scenario2: only 1 condition of Event1 is “true”, meaning that instances were only picked for Object1 or Object2, not both.
Outcome: ALL instances of Object1 set to red, and ALL instances of Object2 set to blue. Event2 only had Else as a condition, which doesn’t pick anything by itself. It simply means that this event should be considered only if the above event of the same scope did not satisfy all of its conditions. If the user wanted to pick instances of Object1 or Object2, they should have conditions which reference those objects.

Scenario 3: no instances of Object1 or Object2 picked in Event1.
Outcome: obviously all instances of Object1 set to red and all instances of Object2 set to blue.

Users can freely add more conditions to an event that possesses an Else condition. This effectively turns the event into an “else if” kind of event. Those additional conditions can serve to pick instances as desired.

The solutions I’m suggesting above should prevent all gaps related to the absence of an else feature, and should remain the most consistent with GDevelop’s paradigms, as well as standard programming paradigms.

The problem is not the else logic itself, it is it’s implementation I think. How do you know what objects were selected for the last object? Etc. Maybe I completely missunderstood too. But you said you are a programmer and this interrests you, right? Why don’t you give a try implementing it, as 4ian said, he has nothing against implementing a working solution. Make something working and do a PR! Oh and don’t make Else a condition, that’s messed up. Make a separate event for it.

Anyways I don’t think that is really needed. You can just invert the condition in the next event. Sure it would be more convenient but it really is just something for convenience and not nessecary.

Here is the solution I came up with (independent of this discussion - so if it overlaps, mia culpa):

Before entering hitting the If-Else area, set the doElse variable to 0

If the IF portion of the logic is executed, set the doElse variable to 1

The Else logic will only execute if the doElse variable is still 0 (meaning the IF section failed the test)

You can expand this to a sudo-case statement as follows:

doElse = 0
If variable = red
do red stuff
doElse = 1
If variable = green and doElse = 0
do green stuff
doElse = 1
if variable = blue and doElse = 0
do blue stuff
doElse = 1

This follows the standard logic for a case/switch statements.

Hope this is repeating something above (it is late and I’m tired) and maybe provides a simplified way to handle IF-Else logic.

2 Likes

I’ve been thinking about it for a while, and I think that such a feature really would be important for GDevelop, and we should reconsider adding it.

About the object picking problem, what I would do is make the else behave like you would invert all conditions: basically, yes, execute the else event for all objects for which the condition is false. This for me the most logical and consistent with the rest of the event sheet way of doing it. For the case one would not want it to behave that way, I’d suggest a “Get logical result of” condition, that simply returns the logical result of its subconditions, like an inverted not condition. That way, we can make object conditions be handled like free conditions.

I already do stuff like this today. For example when I want to check that the mouse hovers over no objects, I can’t simply invert the condition cursor on object since that would execute for every object not under the cursor, and not only when there are no objects under a cursor. So I use the not condition instead of inverting to get the logical result, not the “object lists” result.