4ian / GDevelop

🎮 Open-source, cross-platform 2D/3D/multiplayer game engine designed for everyone.
https://gdevelop.io
Other
10.42k stars 834 forks source link

OR operator not working although one condition is valid #1520

Closed PascalLadalle closed 4 years ago

PascalLadalle commented 4 years ago

Describe the bug

I'm having another logic issue... Here I want to delete the target icon if it is invisible or if another type of unit has been selected. When I use that opacity condition though, it won't delete Target anymore, even though the other condition is valid and I'm using an OR. There's only one instance of Target...

Is my logic flawed? 🤔 Why isn't the OR working as expected?

image

Sample project attached

Win10 x64 GD5b89

logicdeletetarget.zip

Bouh commented 4 years ago

Not sure about what i'am saying, The selection of instances seem empty at step 2, but the conditions at step 1 are correct, one of them is true, opacity is false and scene variable is true.

step1 is the conditions, step 2 the actions, and before each action if i'am right, the engine select the instances tested just before. This selection seem the problem, no?

Error for me is on blue line, in red rectangle. Because the list of instance to test is empty, then the next line isn't trigger. so the object isn't deleted. image

Note when you use "hide an object" the opacity isn't affected, these are two different value for the engine. Need to confirmation.

PascalLadalle commented 4 years ago

I'm not using hide/show, I'm changing the opacity or tweening it. Either way, I'm using an OR, so it shouldn't matter as long as the other condition is valid, right?

So, do you think it's a bug or not? I looked at your screenshot but it's too technical for me. 😅

4ian commented 4 years ago

The way OR works is a bit more complex than a simple logical disjunction:

How it works internally: GDevelop looks at the OR condition. It has two sub conditions, and will execute them:

The OR sub conditions have been executed. GDevelop now:

  1. Check if any sub condition was true? If not, the condition is false, and we go to the next event.
  2. If yes, then we "take" the list of objects and merge them together. If my example so far, we take the list of "Target", and merge it with nothing else, we still just have a single list of "Target", which is empty.

Then GDevelop finally execute actions:

  1. The first action is run.
  2. The second action is run. As it reference a "Target", GDevelop gives it the list of "Target" coming from conditions... which is empty!

So this seems to be working "by design".

Note that internally, this is translated to code by GDevelop.

Is it really logic to do so? It may be surprising. The reason is that as soon as you mention an object to GDevelop, it will remember it for the actions (and for the next conditions) (the exception are the sub conditions inside the "OR" - objects are not passed to each other, they are independent. The list of objects are "reset" to be the same as the list of objects that were in memory at the beginning of the OR).

The reason we keep this "Target" object list empty, even if the condition was false, is for this case:

Conditions:
* If any of these conditions is true:
  * If RedObject is in collision with FinishLine
  * If BlueObject is in collision with FinishLine

Actions:
* Set text to "Someone won the race, it's over!"
* Delete RedObject
* Delete BlueObject

Here, we want to show a text when a Red object OR a a Green object reaches the end of a race (in a racing game for example) and then we want to declare that the race is ended (first action) and delete this object (2nd and 3rd actions).

If we had the logic of ditching list of objects that have been filtered, when a RedObject would reach the end line, we would delete ALL the blue objects... also very surprising! (and vice versa if a blue object reaches the end first). So we're not doing this.

So we chose this logic: when you talk to GDevelop about an object, it will remember about it. If it's an OR, it will remember about objects NOT passing your condition... to be sure not to apply them any action in the future.

BUT the good thing is that you can tell to GDevelop "Hey you must use all objects!". Use "Pick All Instances" action: image

With this, you both are able to use the normal GDevelop behavior, or force it to consider all the objects so that you're sure that your OR is a "logical or".

If we chose the other solution (ditching list of objects that have been filtered), you would not be able to know in the actions if you're dealing with ALL objects or just with objects that are passing the condition... would be not great :)

Final note: Don't use "OR" ;) In most cases, using multiple events or a variable can make things clearer.

Note when you use "hide an object" the opacity isn't affected, these are two different value for the engine. Need to confirmation.

This is correct.

PascalLadalle commented 4 years ago

Thanks for the explanation, although I find your example quite puzzling:

The reason we keep this "Target" object list empty, even if the condition was false, is for this case:

Conditions:
* If any of these conditions is true:
  * If RedObject is in collision with FinishLine
  * If BlueObject is in collision with FinishLine

Actions:
* Set text to "Someone won the race, it's over!"
* Delete RedObject
* Delete BlueObject

This doesn't look right to me. If I specifically request some object deletion, I would expect the action to execute, regardless of which of the OR condition is valid. To follow your example, once the race is over, the other players don't need to keep racing so I would delete them all. To me, the correct/logical event to delete the winner only would be: If ColorObjectGroup is in collision with FinishLine, Delete ColorObjectGroup.

Thanks for the fix, I added a "pick all" and it works. But yeah, perhaps I should stop using that logical OR so much because it's not so logical to me. 😅

4ian commented 4 years ago

I do agree that in this example you would anyway want to remove everything - and use a group. In most cases, when you want to use an OR, you better be using:

  1. A group
  2. or multiple events (potentially using a function to avoid repeating the same action, or a variable)
  3. or a variable (or a function to avoid repeating the same conditions) to designate this situation.

If I specifically request some object deletion, I would expect the action to execute, regardless of which of the OR condition is valid. To follow your example, once the race is over, the other players don't need to keep racing so I would delete them all.

Sure, my example was just to highlight that if we do otherwise, we have a case where the behavior is changing a lot according to the condition:

This non "continuity" in the way objects are handled seems weird/error-prone. Remember that events in GDevelop are all about filtering objects.

Anyway, better avoid these. I think we would need a wiki page to explain this clearly because you're surely not the only one that had this kind of situation :)

Maybe you can remember something like this:

If you specify an object in conditions, even in an "OR" subcondition, GDevelop will remember the objects which are fulfilling the condition, and will only act on those. And those objects only.

PascalLadalle commented 4 years ago

Thanks for the reply and the rule of thumb, it's starting to make sense 😅 A wiki page on object selection would be useful, yes.

PascalLadalle commented 4 years ago

Turns out it makes a nice hack for wilful deselection 😬 image