-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple instances with same task name used in BT #8
Comments
I'm running into the same issue right now. My workaround is going to have behaviors be an object that returns itself and then insert the returned leaf into each entities root tree. I'm also requiring the BehaviourTree for each new instance of an actor/entity. I'm suspecting this is the right way to go so there is a fresh instance of a tree for each actor. Did you have to do the same? |
Yeah, that's what I ended up doing. In my system the filename of the lua file to run is the same name as the node/task whatever you want to call it. Inside that file is a function named GetTask() which returns a new BehaviourTree.Task object which represents that task. I load the file first, then call GetTask() which depending on the node/task name used will return the right object for me to insert into the tree. |
I see if I can look into this in the near future and I will let you know what I find. |
Can one of you please give me a short simple example of what is wrong and what you expect should be right? |
Threw this together real quick. I hope it helps explain. There are 2 different trees updating from a reference named task. When one dog finished the other didn't. Both don't seem to log out at all times. At first glance of the library, I thought I could define some tasks with names and reference those names in various different objects running their own behavior trees. My fallback was to have each behavior tree task in a file and instantiate it as a new object for each new actor that wanted to run their own. It's a useful library either way and plan to use it. Also, this was done with CoronaSDK (which should explain the "enterFrame" event being used as the game loop. local leaf = BehaviourTree.Task:new({
name = 'dance',
run = function(task, dog)
if (dog.finished) then return end;
if(dog.count >= dog.howLong) then
dog.finish();
task:success();
return;
end
dog.count = dog.count + 1;
task:running();
end
});
local btree = BehaviourTree:new({
tree = BehaviourTree.Sequence:new({
nodes = {
'dance'
}
})
});
local btree2 = BehaviourTree:new({
tree = BehaviourTree.Sequence:new({
nodes = {
'dance'
}
})
});
local Dog = {};
function Dog.new(params)
local self = {};
self.name = params.name;
self.count = 0;
self.howLong = params.howLong;
self.finished = false;
print(self.name .. ' started dancing');
function self.finish()
self.finish = true;
print(self.name .. ' finished dancing');
end
return self;
end
btree:setObject(Dog.new({ name = "Ralf", howLong = 10}));
btree2:setObject(Dog.new({ name = "Fido", howLong = 50}));
Runtime:addEventListener("enterFrame", function(event)
btree:run();
btree2:run();
end); |
I think the main idea is that if 2 objects share a task instance, via its name, when one of the objects returns a success on its task the other gets the success as well instead of the task return value being unique to the object or at least just unique to that objects iteration of the task in that frame.
If you had a task that would check if the player was in range of the ai and you had 2 ai instances that shared this check distance task and one of the ai was in distance the task would return success, but it would return success for both ai's even if the other was not even close to the player.
…Sent from my iPhone
On Dec 6, 2016, at 6:29 PM, John Sykes ***@***.***> wrote:
Threw this together real quick. I hope it helps explain. There are 2 different trees updating from a reference named task. When one dog finished the other didn't. Both don't seem to log out at all times. At first glance of the library, I thought I could define some tasks with names and reference those names in various different objects running their own behavior trees. My fallback was to have each behavior tree task in a file and instantiate it as a new object for each new actor that wanted to run their own. It's a useful library either way and plan to use it. Also, this was done with CoronaSDK (which should explain the "enterFrame" event being used as the game loop.
local leaf = BehaviourTree.Task:new({
name = 'dance',
run = function(task, dog)
if (dog.finished) then return end;
if(dog.count >= dog.howLong) then
dog.finish();
task:success();
return;
end
dog.count = dog.count + 1;
task:running();
end
});
local btree = BehaviourTree:new({
tree = BehaviourTree.Sequence:new({
nodes = {
'dance'
}
})
});
local btree2 = BehaviourTree:new({
tree = BehaviourTree.Sequence:new({
nodes = {
'dance'
}
})
});
local Dog = {};
function Dog.new(params)
local self = {};
self.name = params.name;
self.count = 0;
self.howLong = params.howLong;
self.finished = false;
print(self.name .. ' started dancing');
function self.finish()
self.finish = true;
print(self.name .. ' finished dancing');
end
return self;
end
btree:setObject(Dog.new({ name = "Ralf", howLong = 10}));
btree2:setObject(Dog.new({ name = "Fido", howLong = 50}));
Runtime:addEventListener("enterFrame", function(event)
btree:run();
btree2:run();
end);
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
Okay so this is a bug but the fix isn't easy because it required cloning a task when they are retrieved from the registry. This isn't trivial in lua especially since I am using middleclass. I have not yet figured out how to fix it. I will keep you updated. |
Is cloning really the way to go about it? I mean that's basically what we are doing now and it seems it would take up more memory than needed. I wouldn't think the return result should affect anything but that task call. Shouldn't these basically be functions that pass in the actor and process the result? Why is the result part of the task itself?
…Sent from my iPhone
On Dec 9, 2016, at 9:06 AM, Tim Anema ***@***.***> wrote:
Okay so this is a bug but the fix isn't easy because it required cloning a task when they are retrieved from the registry. This isn't trivial in lua especially since I am using middleclass. I have not yet figured out how to fix it. I will keep you updated.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
An instance of a tree node is the item that returns success, fail, or running and that get propagated up the tree. When you create and register a task, it is one instance of a node. That means even if it is in two different contexts/trees they are both still the same instance. So when you call any of the status functions, it is called on the same instance in all contexts. Either I have to clone each node that is registered or change the way registration is done. |
Would metatables help? I'm thinking from the perspective of JavaScript prototypes where the same function is reused for every object instance thus saving memory. The performance tradeoff means no private variables though but this tree may not need them. Since the tasks get the obj passed into it, those functions can be reused because the object context is different for each run. But then for the task returning a fail is where it probably gets more complicated with registration. Maybe task success/fail can take the obj parameter and infer the tree it belongs to? But then it sounds like some hidden __metadata may need to be tacked onto the object which may not be desired due to edge cases of cloning or other uncommon object manipulation. I'm also using the JavaScript version of this and am aiming for the registration name approach to try and save memory by reusing the task. I'll find out if it was a bug from the original fork soon enough. |
Years have passed, but nothing has changed :( |
You're welcome to open a PR and I will review it. |
@tanema I created a draft ;) |
@tanema proposed an alternative solution in PR #16. From some limited testing it is working well for me and is compatible with the existing API - at least the surface area I've interacted with. I am struggling to get busted working on windows and decided to just check in before I spend any more time on the PR. |
Am I correct in thinking that if I use the name feature of a Task and then use that string name in a BT, if I have 2+ BT's that reference that string name of the Task it's sharing that task instance vs making it's own? I'm seeing issues where I have 2 agents/actors that have action tasks by string name in their own BT instance where it moves around but it seems like when 1 stops it's task (fail/success) it's screwing up the other one. because I'm guessing they are sharing that task instead of getting their own instance. Does that sound right?
If so that seems like a bug. Why would you want to do that ever? Referring to a task by name is great but it seems like it should really create a new instance of said task in said tree.
I say this because when there is only 1 agent/actor in the scene everything works fine.
The ideal reason this should create a new instance of the task is because I've created a loader from a visual bt editor and I have the users define their tasks in a separate file and give it the name property, but building bt tree itself per agent/actor is done in code where the name is used for all tasks since it's easy doing that for a loader. It's either that or there is a generic way to "clone" a task based on it's name and I could add that table in place of the string name when building the tree.
The text was updated successfully, but these errors were encountered: