Search code examples
gogoroutinegame-loop

Game Loop simulation in Golang


I want to create game loop in go(lang), so i tried this:

package main

import (
    "fmt"
    // "runtime"
    "sync"
    "time"
)

var v = 0
var wg sync.WaitGroup
var sec = 5

func main() {
    wg.Add(1)
    gameLoop()
    wg.Wait()
}

func gameLoop() {
    time.AfterFunc(16*time.Millisecond, gameLoop)
    v++
    fmt.Println(v)
    if v == sec*60 {
        // fmt.Println("Goroutines: ", runtime.NumGoroutine())
        panic("err")
        wg.Done()
    }
}

This program running at 62.5Hz (16*time.Millisecond), var sec is used for calling wg.Done() after 5 second and caused var v printed 300 times.

calling panic("err") making the result like this:

panic: err

goroutine 314 [running]:
panic(0x493c60, 0xc420094370)
    /usr/local/go/src/runtime/panic.go:500 +0x1a1
main.gameLoop()
    /home/billyzaelani/Desktop/main.go:26 +0x11f
created by time.goFunc
    /usr/local/go/src/time/sleep.go:154 +0x44
exit status 2

Well what is the meaning of goroutine 314 [running] ? did i use 314 goroutine for 5 second game loop? how if this run for hours?

But, if the program use runtime package and print runtime.NumGoroutine which is return number of goroutine, the result is Goroutines: 2

So, back again what is the meaning of goroutine 314 [running]? while runtime package say different things.

Last one, if anyone can show me the better way to create game loop in golang, i really appreciate that, thankyou


Solution

  • AfterFunc executes the registered function in a goroutine. https://golang.org/pkg/time/#AfterFunc

    While there are only 2 go routines running at a time, there have been 314 (maybe?? Not sure how goroutine ids work) goroutines throughout the program.


    i don't consider it a "better" way, but a different way, and my preferred, could be to model the game loop as a for loop.

    func gameLoop()  {
        tick := time.Tick(16 * time.Millisecond)
    
        for {
            select {
            case <-tick:
    
            }
        }
    }
    

    In addition to concisely registering a case for an interval, selecting over a channel allows you to easily model a timeout, by adding another case for <-time.After, or for cancellation, by adding another case for a <-done channel.