I'm trying to implement a behavior tree in go, and I'm struggling with its composition features. Basically, I need Tick()
implemented below to call the method defined by wherever it was embedded.
Here is behavior.go
:
type IBehavior interface {
Tick() Status
Update() Status
}
type Behavior struct {
Status Status
}
func (n *Behavior) Tick() Status {
fmt.Println("ticking!")
if n.Status != RUNNING { n.Initialize() }
status := n.Update()
if n.Status != RUNNING { n.Terminate(status) }
return status
}
func (n *Behavior) Update() Status {
fmt.Println("This update is being called")
return n.Status
}
And here is the Behavior
struct being embedded:
type IBehaviorTree interface {
IBehavior
}
type BehaviorTree struct {
Behavior
Root IBehavior
}
func (n *BehaviorTree) Update() Status {
fmt.Printf("Tree tick! %#v\n", n.Root)
return n.Root.Tick()
}
A few more files to make this example make sense:
type ILeaf interface {
IBehavior
}
type Leaf struct {
Behavior
}
And this one:
type Test struct {
Leaf
Status Status
}
func NewTest() *Test {
return &Test{}
}
func (n Test) Update() Status {
fmt.Println("Testing!")
return SUCCESS
}
And here is an example of its usage:
tree := ai.NewBehaviorTree()
test := ai.NewTest()
tree.Root = test
tree.Tick()
I was expecting the tree to tick normally by printing this:
ticking!
Tree tick!
But instead I'm getting:
ticking!
This update is being called
Could anyone help me with this issue?
Edit: Added a few extra files to illuminate the issue. Also, I don't understand the downvotes. I have an honest go question. Am I only supposed to ask questions that make sense to me already?
Your issue here is that Tick()
is not defined on your BehaviorTree structure. As a result, when you call tree.Tick()
, there's no direct method defined, so it calls the promoted Tick()
method of the embedded Behavior
struct. That Behavior
struct has no idea what a BehaviorTree
is! In Go’s embedding style of pseudo-inheritance, “child” types have no concept of their "parents", nor any reference or access to them. Embedded methods are called with the embedded type as their receiver, not the embedding struct.
If you want your expected behavior, you need to define a Tick()
method on your BehaviorTree
type, and have that method to call its own Update()
method (and then call sub Tick()
or Update()
methods if you wish). For example:
type BehaviorTree struct {
Behavior
Root IBehavior
}
func (n *BehaviorTree) Tick() Status {
n.Update() // TODO: do you want this status or the Root.Tick() status?
return n.Root.Tick()
}
func (n *BehaviorTree) Update() Status {
fmt.Printf("Tree tick! %#v\n", n.Root)
return nil
}