package land import ( "github.com/veandco/go-sdl2/sdl" "time" ) type RootObject struct { Children []Object Overlays []Object Analyzer *PerformanceAnalyzer } func NewRootObject() *RootObject { in := &RootObject{ Analyzer: &PerformanceAnalyzer{}, } go in.Analyzer.RunResetter(1 * time.Second) return in } func (p *RootObject) AddChild(child Object) { p.Children = append(p.Children, child) } func (p *RootObject) AddOverlay(overlay Object) { p.Overlays = append(p.Overlays, overlay) } func (p *RootObject) RunEventLoop(tickDuration time.Duration) { for { startTime := time.Now() p.Update() elapsed := time.Since(startTime) hangDuration := tickDuration - elapsed if hangDuration > 0 { time.Sleep(hangDuration) } } } func (p *RootObject) ForEachChildren(cb func(child Object)) { var caller func(current Object) caller = func(current Object) { cb(current) for _, child := range current.GetChildren() { caller(child) } } for _, child := range p.Children { caller(child) } for _, child := range p.Overlays { caller(child) } } func (p *RootObject) HandleUserEvent(event sdl.Event) { switch event := event.(type) { case *sdl.MouseButtonEvent: x, y := float64(event.X), float64(event.Y) vec := Vector2D{x, y} p.ForEachChildren(func(child Object) { if interChild, ok := child.(InteractableObject); ok { if IsOverlapWithPoint(child.(PositionedObject), vec) { if event.Type == sdl.MOUSEBUTTONDOWN { interChild.OnEvent(UserEventMouseDown, vec) } else if event.Type == sdl.MOUSEBUTTONUP { interChild.OnEvent(UserEventMouseUp, vec) } } } }) case *sdl.MouseMotionEvent: x, y := float64(event.X), float64(event.Y) vec := Vector2D{x, y} p.ForEachChildren(func(child Object) { if interChild, ok := child.(InteractableObject); ok { isOverlap := IsOverlapWithPoint(child.(PositionedObject), vec) interChild.OnEvent(UserEventMouseMove, vec, isOverlap) } }) } } func (p *RootObject) Update() { p.ForEachChildren(func(child Object) { child.Update() }) // Check collision p.ForEachChildren(func(child Object) { p.ForEachChildren(func(other Object) { if child == other { return } collidableChild, ok := child.(CollidableObject) if !ok { return } collidableOther, ok := other.(CollidableObject) if !ok { return } if checkCollisionBetweenObject(collidableChild, collidableOther) { collidableChild.OnCollide(collidableOther) collidableOther.OnCollide(collidableChild) } }) }) p.Analyzer.Tick() } func (p *RootObject) Draw(pen *sdl.Renderer) { // Render background and clear previous state pen.SetDrawColor(77, 77, 77, 255) pen.Clear() // Render each child p.ForEachChildren(func(child Object) { if drawableChild, ok := child.(DrawableObject); ok { drawableChild.Draw(pen) } }) p.Analyzer.Draw() }