I'm currently using go to implement a Game server due to the awesome concurrency primitives. That has all been a breeze to implement and works very reliably. I come mostly from a Java background though and I am having trouble forgetting Java's type hierarchy. I need to have a collection of game objects which all share a similar data structure like position, velocity, etc., but they may all have different behavior within their update methods, or special fields to allow different functionality. Initially I had a struct containing all of the shared data, and each custom type would embed that struct. The trouble is using data structures for organization. I use a quadtree to keep clients notified about nearby object's state. This way I can pass the tree a pointer to the embedded struct of each game object and everything works.
The problem with this is I can't access the containing type once I query the quadtree. So for example,
type GameObject struct {
Position Point
Velocity Point
ID int32
}
type Client struct {
GameObject
conn net.Conn
// other fields
}
Now, when If I want to update nearby players about an object's state, I query the quadtree, but there is now way to determine if the GameObject is actually a Client, and there is no way to access it's connection to send packets.
From Java, I'm used to creating a base class and subclassing it for Client, etc. Then I can use instanceof
to determine which ones need special treatment and cast them accordingly to access custom functionality. I think I could do something like the following:
type GameObject interface {
Position() Point
Velocity() Point
ID() int32
}
type Client struct {
pos Point
vel Point
id int32
conn net.Conn
// other fields
}
func (c *Client) Position() Point {
return c.pos
}
func (c *Client) Velocity() Point {
return c.vel
}
func (c *Client) ID() int32 {
return c.id
}
With this method I can use a type assertion to isolate the clients, but this will lead to a lot of duplicate code for implementing other game objects. I assume there is a more idiomatic way to do something like this in go, and I appreciate any help I can get. If this is the go way, maybe someone can help me understand the reasoning behind this design.