gocomposition

Allow using composite as function argument in struct


Let's say I'm making something like a game engine.

I need an GameObject struct which defines some event handlers:

type GameObject struct {
    transform        Transform
    animatedMesh     AnimatedMesh
    updateHandler    func(self GameObjectGetter)
    onCreateHandler  func(self GameObjectGetter)
    onDestroyHandler func(self GameObjectGetter)
}


func (g GameObject)getGameObject() GameObject {
    return g
 }

 type GameObjectGetter interface {
    getGameObject() GameObject
 }

Then, when I'm initializing some concrete GameObject, I want to define a handler as a custom function:

g.updateHandler = func(self FishGameObject) {  // Error here
    self.tailMotionSpeed = self.boid.acceleration.Normalize().Len()
}

Note here that tailMotionSpeed and boid aren't members of GameObject. They're members of struct FishGameObject which has some custom properties and anonymous GameObject:

type FishGameObject struct {
    leftFinPosition  float32
    rightFinPosition float32
    tailMotionSpeed  float32
    boid             Boid
    GameObject
}

I'm getting an error self.tailMotionSpeed undefined (type GameObjectGetter has no field or method tailMotionSpeed) if I specify argument as GameObjectGetter, and also I'm getting an error cannot use handler (variable of type func(self FishGameObject)) as func(self GameObjectGetter) value in struct literal if I specify argument as FishGameObject. What do I do?


Solution

  • What you are trying to do is not possible in Go in the way you are trying to do. However, you can do this:

    Define GameObject as an interface:

    type GameObject interface {
       GetTransform() *Transform
       GetAnimatedMesh() *AnimatedMesh
       SetUpdateHandler(func(GameObject))
       UpdateHandler() func(GameObject)
       ...
    }
    

    The you can define a BaseGameObject:

    type BaseGameObject struct {
        transform        Transform
        animatedMesh     AnimatedMesh
        updateHandler    func(GameObject)
        onCreateHandler  func(GameObject)
        onDestroyHandler func(GameObject) 
    }
    

    Define all the methods so BaseGameObject is a GameObject.

    Then, define FishGameObject as you did, but

    fish.SetUpdateHandler(func(self GameObject) {  
        fish:=self.(*FishGameObject)
         ...
       })
    

    You also should use pointer receivers for all the methods.