-
Notifications
You must be signed in to change notification settings - Fork 9
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
Name Nodes #17
Comments
May I ask what your main goal is, re: visualising the tree? The tree printer was primarily added as a quick debugging tool, and I've used it in the past to unit test the structure of subtrees that are built dynamically. The reason why it is a text format is because its core use case is simply the If you wish to attach rich metadata, there are a few options. It is not intended for frequent runtime use, due to the mechanism used, but I have implemented If your goal is to be able to output a visual representation of any behavior tree that is as rich and informative as possible, it may be worth considering defining your tree using a data structure more amenable to that. For example, your own Regardless of how you go about it (there's more possibilities than what I've listed), if you want the Just in case it's useful, here's an example of an implementation from one of my personal projects. I'm not attempting to dissuade you from more sophisticated visualisation, just providing some context re: the degree of complexity and style that I find tenable w/o anything more than code: func (x *Service) start() bt.Ticker {
// stream state managed via bt
// subscribe is the core logic per stream, used in two spots (we wait for it to finish)
// note it always fails, triggering the teardown
subscribe := bt.New(
// memorize the sequence - so we keep running for to completion
bt.Memorize(bt.Sequence),
// guard invalid state (so we only run it once per stream)
bt.New(bt.Not(x.streamIsNil)),
bt.New(bt.Not(x.streamIsDone)),
bt.New(bt.Not(x.streamIsDisabled)),
bt.New(bt.Async(x.streamAccount)),
bt.New(bt.Selector), // fails
)
// manages the (re)connection lifecycle
lifecycle := bt.New(
bt.Selector,
// init and run stream
bt.New(
bt.Sequence,
// guard failures
bt.New(
bt.Selector,
bt.New(x.streamIsNil),
bt.New(bt.Not(x.streamIsDone)),
),
// connect if necessary
bt.New(
bt.Selector,
bt.New(bt.Not(x.streamIsNil)),
bt.New(x.setupStream),
),
// subscribes to the stream, runs to completion (see below above)
subscribe,
),
// teardown stream if necessary (and possible)
bt.New(
bt.Selector,
bt.New(x.streamIsNil),
// ensure we wait for subscribe to complete
bt.New(func([]bt.Node) (bt.Status, error) {
stat, err := subscribe.Tick()
if err != nil {
return 0, err
}
if stat == bt.Running {
// wait for subscribe to complete
return bt.Success, nil
}
// allow teardown to proceed
return bt.Failure, nil
}),
// note: this is the only thing that nils the stream
bt.New(x.teardownStream),
),
// debug failure - should never reach here
bt.New(func(children []bt.Node) (bt.Status, error) {
return bt.Failure, errors.New(`malformed bt`)
}),
)
// Shuts the active stream, if necessary.
//
// Returns success only if the following is all true:
//
// 1. disabled api
// 2. stream is nil (has been torn down)
// 3. shutdown isn't running
disable := bt.New(
bt.Memorize(bt.Sequence),
bt.New(x.streamIsDisabled),
bt.New(
bt.Memorize(bt.Selector),
bt.New(
bt.Sequence,
bt.New(x.streamIsNil),
bt.New(x.setStreamClosed(true)),
),
bt.New(
bt.Memorize(bt.Sequence),
x.shutdownStream(time.Minute*3), // also handles updating x.state
bt.New(bt.Selector), // always fails
),
),
)
root := bt.New(
bt.Selector,
disable,
bt.New(
bt.Sequence,
bt.New(x.setStreamClosed(false)),
lifecycle,
),
)
return bt.NewTicker(x.ctx, time.Millisecond*100, root)
} |
This was opened also relating it to #18 at the end. I knew about the ctx but as you mention (and checking the docs) looked like it should not be used for that, and also other libs, like the one you shared on another issue https://github.com/BehaviorTree/BehaviorTree.CPP also have names so I thought it would be a good idea to have those for the nodes, as IMO it makes sense. My examples are much smaller (and most likely it can be improved too haha I'm still building it):
It's a bot for a game I'm building hehe. I have to rely on
Having this names would allow to a more descriptive way to define the nodes and also the ones that are parametrized functions have a dedicated name instead of all of them have the same one. For example this is the docs I have of what I want to do (and also related to why I opened the DOT issue hehe): |
Gotcha. Regarding naming nodes, it doesn't seem unreasonable to want to name them, and it could be a purely optional feature. @xescugc what do you think of something like:
|
Is your feature request related to a problem? Please describe.
In any example I see of Behavior Trees, either graphic of code the Nodes always have names as it helps to describe what they are doing, and if the tree is a bit big, without names it's not that easy. I end up having to add comments just to know what each node is about on the construction of the tree.
Describe the solution you'd like
To not brake the API
bht.New()
andbht.NewNode()
I would add an extension to those 2 with abht.NewWithName()
andbht.NewNodeWithName
where thename string
would be the first parameter so then it would make it easier to read on the code.Now, the question is where is this
name string
stored? AsNode
is just afunc () (Tick, []Node)
so it cannot store anything. Reading the code I found thebht.Frame
which is basically used for printing (from the code):So basically adding there the
Name string
would be the best place as then you can also add it to the printing of the Nodes as then the output will be much more clear.Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
Additional context
Add any other context or screenshots about the feature request here.
The text was updated successfully, but these errors were encountered: