Transform represents a 2D position for a node.
Component defines behavior that can update each frame.
Entity groups a set of components.
Node is a scene graph node with a transform and children.
AddChild appends a child node.
{
n.Children = append(n.Children, child)
}
AddEntity attaches an entity to the node.
{
n.Entities = append(n.Entities, e)
}
NewNode creates an empty node.
{
return &Node{}
}
Traverse walks the scene graph depth-first, invoking fn for each node.
{
if n == nil {
return
}
fn(n)
for _, c := range n.Children {
Traverse(c, fn)
}
}
Update traverses the graph and updates all components on every node.
{
Traverse(root, func(n *Node) {
for _, e := range n.Entities {
for _, c := range e.Components() {
c.Update(n, t)
}
}
})
}
Ticker mirrors the game loop ticker with delta time and FPS.
{ c.count++ }
{ return e.comps }
{
root := NewNode()
root.AddChild(NewNode())
root.AddChild(NewNode())
visited := 0
Traverse(root, func(*Node) { visited++ })
if visited != 3 {
t.Fatalf("expected 3 nodes visited, got %d", visited)
}
}
{
root := NewNode()
child := NewNode()
root.AddChild(child)
c1 := &testComponent{}
c2 := &testComponent{}
root.AddEntity(&testEntity{comps: []Component{c1}})
child.AddEntity(&testEntity{comps: []Component{c2}})
Update(root, Ticker{})
if c1.count != 1 {
t.Fatalf("expected root component updated once, got %d", c1.count)
}
if c2.count != 1 {
t.Fatalf("expected child component updated once, got %d", c2.count)
}
}
import "time"
import "testing"