libgdx / gdx-ai

Artificial Intelligence framework for games based on libGDX or not. Features: Steering Behaviors, Formation Motion, Pathfinding, Behavior Trees and Finite State Machines
Apache License 2.0
1.18k stars 241 forks source link

Guarded task start() method running before guard. #89

Open lukz opened 7 years ago

lukz commented 7 years ago

Is it intended to run start() method of guarded task before guard?

In my case I'm using guards to check if task should run and I'm setting some values that guarded task may use.

For example: (isPlayerVisible? range:512 outVar:"targetPlayer") interpose ent1Var:"targetGuardEnt" ent2Var:"targetPlayer"

Guard is checking if any player is visible and output visible player reference to blackboard. Interpose task is using this reference in its start() method to set up Interpose task. But because interpose start() method is run before guard I've got null ptr exception.

davebaol commented 7 years ago

Yeah I see your point. Not sure but considering checkGuard occurrences it looks like you can replace code like this

        child.setControl(this);
        child.start();
        if (child.checkGuard(this))
            child.run();
        else
            child.fail();

with something along the line of

        child.setControl(this);
                boolean ok = child.checkGuard(this);
        child.start();
        if (ok)
            child.run();
        else
            child.fail();

I'm really busy these days, sorry. Can you try it and let me know?

lukz commented 7 years ago

I can't see how this change would fix the problem.

davebaol commented 7 years ago

Well, maybe I'm missing something. As said above, I've not tested this change myself. Just looked quickly into the code. Assuming you have a tree as simple as

parent
  (guard) task

wouldn't this change make guard run before task.start() ?

mgsx-dev commented 7 years ago

I'm just wondering if start method shouldn't be called at all in this context.

Wiki says :

a guard is a condition that must be met before executing the respective task

start() called when the task is entered, just before run() is invoked.

But "task execution" is not clearly defined. Is start method included in "task execution" ?

DynamicGuardSelector evaluates guard before starting children but Selector (and others) doesn't. Consider following example :

selector
  (hungry?) eat

Should we really start eating even if we're not hungry ?

lukz commented 7 years ago

@davebaol sorry I wrote my first question imprecisely

@mgsx-dev is right, the problem is that task start() method is called even when guard fail

davebaol commented 7 years ago

Sounds reasonable. It looks like this code

        child.setControl(this);
        child.start();
        if (child.checkGuard(this))
            child.run();
        else
            child.fail();

should become

        child.setControl(this);
        if (child.checkGuard(this)) {
            child.start();
            child.run();
        }
        else
            childFail(null); // actually child has not failed

This kind of code should work for Decorator and BehaviorTree. For Parallel and the other branches some other changes are likely needed.

Ali-RS commented 1 year ago

@davebaol any plan to fix this?

IMHO task.start() should be called only if the guard succeeds as mentioned by others.