diff --git a/pkg/internal/entities/player.go b/pkg/internal/entities/player.go index 26b7788..ea100e4 100644 --- a/pkg/internal/entities/player.go +++ b/pkg/internal/entities/player.go @@ -56,4 +56,10 @@ func (p *Player) Draw(pen *sdl.Renderer) { W: int32(p.Size.X), H: int32(p.Size.Y), }) + + for _, child := range p.Children { + if drawableChild, ok := child.(land.DrawableObject); ok { + drawableChild.Draw(pen) + } + } } diff --git a/pkg/internal/land/prof.go b/pkg/internal/land/prof.go new file mode 100644 index 0000000..8177b59 --- /dev/null +++ b/pkg/internal/land/prof.go @@ -0,0 +1,39 @@ +package land + +import ( + "log" + "sync/atomic" + "time" +) + +type PerformanceAnalyzer struct { + tickCount int64 + drawCount int64 +} + +func (p *PerformanceAnalyzer) Tick() { + atomic.AddInt64(&p.tickCount, 1) +} + +func (p *PerformanceAnalyzer) Draw() { + atomic.AddInt64(&p.drawCount, 1) +} + +func (p *PerformanceAnalyzer) KeepResetting(duration time.Duration) { + ticker := time.NewTicker(duration) + defer ticker.Stop() + for { + <-ticker.C + log.Printf("TPS: %d FPS: %d\n", atomic.LoadInt64(&p.tickCount), atomic.LoadInt64(&p.drawCount)) + atomic.StoreInt64(&p.tickCount, 0) + atomic.StoreInt64(&p.drawCount, 0) + } +} + +func (p *PerformanceAnalyzer) GetTPS() int64 { + return atomic.LoadInt64(&p.tickCount) +} + +func (p *PerformanceAnalyzer) GetFPS() int64 { + return atomic.LoadInt64(&p.drawCount) +} diff --git a/pkg/internal/land/root.go b/pkg/internal/land/root.go index 8ff3ce2..4f4a854 100644 --- a/pkg/internal/land/root.go +++ b/pkg/internal/land/root.go @@ -2,16 +2,56 @@ package land import ( "github.com/veandco/go-sdl2/sdl" + "time" ) type RootObject struct { BaseObject + + Analyzer *PerformanceAnalyzer +} + +func NewRootObject() *RootObject { + in := &RootObject{ + Analyzer: &PerformanceAnalyzer{}, + } + + go in.Analyzer.KeepResetting(1 * time.Second) + + return in +} + +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) Update() { + p.BaseObject.Update() + + 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 for _, child := range p.Children { if drawableChild, ok := child.(DrawableObject); ok { drawableChild.Draw(pen) } } + + p.Analyzer.Draw() } diff --git a/pkg/main.go b/pkg/main.go index 261211b..68af000 100644 --- a/pkg/main.go +++ b/pkg/main.go @@ -5,14 +5,14 @@ import ( "git.solsynth.dev/highland/codingland/pkg/internal/land" "log" "runtime" + "time" "github.com/veandco/go-sdl2/sdl" ) const ( - windowWidth = 640 + windowWidth = 720 windowHeight = 480 - playerSize = 50 ) func init() { @@ -37,12 +37,15 @@ func main() { } defer renderer.Destroy() - root := &land.RootObject{} + root := land.NewRootObject() root.AddChild(&entities.Player{ - Position: land.Vector2D{X: windowWidth / 2, Y: windowHeight / 2}, - Size: land.Vector2D{X: playerSize, Y: playerSize}, + Position: land.Vector2D{X: windowWidth/2 - 25, Y: windowHeight/2 - 25}, + Size: land.Vector2D{X: 50, Y: 50}, }) + // 10ms delay use be 100tps average + go root.RunEventLoop(10 * time.Millisecond) + running := true for running { for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { @@ -52,11 +55,6 @@ func main() { } } - root.Update() - - renderer.SetDrawColor(0, 0, 0, 255) - renderer.Clear() - root.Draw(renderer) renderer.Present()