Skip to content
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

Open
piller187 opened this issue Aug 9, 2016 · 14 comments · May be fixed by #12
Open

Multiple instances with same task name used in BT #8

piller187 opened this issue Aug 9, 2016 · 14 comments · May be fixed by #12

Comments

@piller187
Copy link

piller187 commented Aug 9, 2016

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.

@piller187 piller187 changed the title Multiple instances with same node name used in BT Multiple instances with same task name used in BT Aug 9, 2016
@jsykes
Copy link

jsykes commented Dec 4, 2016

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?

@piller187
Copy link
Author

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.

@tanema
Copy link
Owner

tanema commented Dec 6, 2016

I see if I can look into this in the near future and I will let you know what I find.

@tanema
Copy link
Owner

tanema commented Dec 6, 2016

Can one of you please give me a short simple example of what is wrong and what you expect should be right?

@jsykes
Copy link

jsykes commented Dec 7, 2016

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);

@piller187
Copy link
Author

piller187 commented Dec 7, 2016 via email

@tanema
Copy link
Owner

tanema commented Dec 9, 2016

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.

@piller187
Copy link
Author

piller187 commented Dec 9, 2016 via email

@tanema
Copy link
Owner

tanema commented Dec 12, 2016

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.

@jsykes
Copy link

jsykes commented Dec 12, 2016

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.

@s-kania
Copy link

s-kania commented Jun 18, 2023

Years have passed, but nothing has changed :(

@tanema
Copy link
Owner

tanema commented Jun 19, 2023

You're welcome to open a PR and I will review it.

@s-kania s-kania linked a pull request Jun 23, 2023 that will close this issue
@s-kania
Copy link

s-kania commented Jun 23, 2023

@tanema I created a draft ;)

@timjen3 timjen3 mentioned this issue Sep 6, 2024
2 tasks
@timjen3
Copy link

timjen3 commented Sep 6, 2024

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants