4

我正在尝试在 go 中实现一个行为树,并且我正在努力解决它的组合功能。基本上,我需要Tick()在下面实现来调用由它嵌入的位置定义的方法。

这里是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
}

这是Behavior嵌入的结构:

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()
}

让这个例子有意义的更多文件:

type ILeaf interface {
  IBehavior
}

type Leaf struct {
  Behavior
}

和这个:

type Test struct {
  Leaf

  Status Status
}

func NewTest() *Test {
    return &Test{}
}

func (n Test) Update() Status {
    fmt.Println("Testing!")
    return SUCCESS
}

这是它的用法示例:

tree := ai.NewBehaviorTree()
test := ai.NewTest()
tree.Root = test

tree.Tick()

我期待树通过打印这个来正常滴答作响:

ticking!
Tree tick!

但相反,我得到:

ticking!
This update is being called

谁能帮我解决这个问题?

编辑:添加了一些额外的文件来说明问题。另外,我不明白反对票。我有一个诚实的问题。我只应该问对我有意义的问题吗?

4

2 回答 2

2

您的问题Tick()是未在您的 BehaviorTree 结构中定义。结果,当您调用 时tree.Tick(),没有定义直接方法,因此它调用Tick()了嵌入Behavior结构的提升方法。该Behavior结构不知道 aBehaviorTree是什么! 在 Go 的伪继承嵌入风格中,“子”类型没有“父”的概念,也没有任何对它们的引用或访问。嵌入式方法被调用时使用嵌入式类型作为它们的接收者,而不是嵌入结构。

如果您想要您的预期行为,您需要Tick()在您的类型上定义一个方法BehaviorTree,并让该方法调用它自己的Update()方法(然后根据需要调用 subTick()Update()方法)。例如:

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
}
于 2017-12-11T21:36:15.533 回答
0

正如沃尔克所说

Go 绝对没有继承的概念(嵌入不是继承),你根本不能在 Go 中做父/子的事情。重新设计

据我所知,您想要的是一个使用接口多次执行相同任务的功能。

func Tick(n IBehavior) Status {
  fmt.Println("ticking!")
  if n.Status != RUNNING { n.Initialize() }
  status := n.Update()
  if n.Status != RUNNING { n.Terminate(status) }
  return status
}

当然 Initialize 必须在界面中。

于 2017-12-11T21:25:20.213 回答