From 0c1c6ea6c348dee1e16086fd0291aaf8c4254f30 Mon Sep 17 00:00:00 2001 From: Trevor Slocum Date: Mon, 30 Aug 2021 21:26:49 -0700 Subject: [PATCH] Draw screen only when required --- .gitignore | 1 + game/assets/checker_black.png | Bin 11818 -> 10554 bytes game/board.go | 258 ++++++++++++++++++++++++---------- game/game.go | 76 +++++++--- go.mod | 3 +- go.sum | 6 +- main.go | 20 ++- 7 files changed, 265 insertions(+), 99 deletions(-) diff --git a/.gitignore b/.gitignore index aef148e..a9c4922 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea *.sh *.wasm +boxcars dist diff --git a/game/assets/checker_black.png b/game/assets/checker_black.png index 63c7bdf77634cca95ca75ff438c8e456505cc5f4..66d750610d4e87a2df6785ba90c9a65d771de2aa 100644 GIT binary patch delta 7166 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 aM@n_|bq6-~LZknkJ7}uvA!;8#jr<<~kMBbO delta 8621 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 diff --git a/game/board.go b/game/board.go index 9d24199..eff2d20 100644 --- a/game/board.go +++ b/game/board.go @@ -51,6 +51,8 @@ type board struct { moveQueue chan *stateUpdate + drawFrame chan bool + debug int // Print and draw debug information } @@ -69,6 +71,7 @@ func NewBoard() *board { spaceRects: make([][4]int, 26), V: make([]int, 42), moveQueue: make(chan *stateUpdate, 10), + drawFrame: make(chan bool, 10), } for i := range b.Sprites.sprites { @@ -88,6 +91,8 @@ func NewBoard() *board { b.spaces[space] = append(b.spaces[space], s) } + go b.handleDraw() + go b.handlePieceMoves() b.op = &ebiten.DrawImageOptions{} @@ -97,6 +102,31 @@ func NewBoard() *board { return b } +func (b *board) handleDraw() { + drawFreq := time.Second / 144 // TODO + lastDraw := time.Now() + for v := range b.drawFrame { + if !v { + return + } + since := time.Since(lastDraw) + if since < drawFreq { + t := time.NewTimer(drawFreq - since) + DELAYDRAW: + for { + select { + case <-b.drawFrame: + continue DELAYDRAW + case <-t.C: + break DELAYDRAW + } + } + } + ebiten.ScheduleFrame() + lastDraw = time.Now() + } +} + func (b *board) newSprite(white bool) *Sprite { s := &Sprite{} s.colorWhite = white @@ -106,6 +136,18 @@ func (b *board) newSprite(white bool) *Sprite { func (b *board) updateBackgroundImage() { tableColor := color.RGBA{0, 102, 51, 255} + frameColor := color.RGBA{65, 40, 14, 255} + borderColor := color.RGBA{0, 0, 0, 255} + faceColor := color.RGBA{120, 63, 25, 255} + triangleA := color.RGBA{225.0, 188, 125, 255} + triangleB := color.RGBA{120.0, 17.0, 0, 255} + + borderSize := b.horizontalBorderSize + if borderSize > b.barWidth/2 { + borderSize = b.barWidth / 2 + } + frameW := b.w - ((b.horizontalBorderSize - borderSize) * 2) + innerW := b.w - (b.horizontalBorderSize * 2) // Outer board width (including frame) // Table box := image.NewRGBA(image.Rect(0, 0, b.w, b.h)) @@ -113,39 +155,33 @@ func (b *board) updateBackgroundImage() { img.Fill(tableColor) b.backgroundImage = ebiten.NewImageFromImage(img) - // Border - borderColor := color.RGBA{65, 40, 14, 255} - borderSize := b.horizontalBorderSize - if borderSize > b.barWidth/2 { - borderSize = b.barWidth / 2 - } - box = image.NewRGBA(image.Rect(0, 0, b.w-((b.horizontalBorderSize-borderSize)*2), b.h)) + // Frame + box = image.NewRGBA(image.Rect(0, 0, frameW, b.h)) img = ebiten.NewImageFromImage(box) - img.Fill(borderColor) + img.Fill(frameColor) b.op.GeoM.Reset() b.op.GeoM.Translate(float64(b.horizontalBorderSize-borderSize), 0) b.backgroundImage.DrawImage(img, b.op) // Face - box = image.NewRGBA(image.Rect(0, 0, b.w-(b.horizontalBorderSize*2), b.h-(b.verticalBorderSize*2))) + box = image.NewRGBA(image.Rect(0, 0, innerW, b.h-(b.verticalBorderSize*2))) img = ebiten.NewImageFromImage(box) - img.Fill(color.RGBA{120, 63, 25, 255}) + img.Fill(faceColor) b.op.GeoM.Reset() b.op.GeoM.Translate(float64(b.horizontalBorderSize), float64(b.verticalBorderSize)) b.backgroundImage.DrawImage(img, b.op) - baseImg := image.NewRGBA(image.Rect(0, 0, b.w-(b.horizontalBorderSize*2), b.h-(b.verticalBorderSize*2))) - gc := draw2dimg.NewGraphicContext(baseImg) - // Bar box = image.NewRGBA(image.Rect(0, 0, b.barWidth, b.h)) img = ebiten.NewImageFromImage(box) - img.Fill(borderColor) + img.Fill(frameColor) b.op.GeoM.Reset() b.op.GeoM.Translate(float64((b.w/2)-(b.barWidth/2)), 0) b.backgroundImage.DrawImage(img, b.op) // Draw triangles + baseImg := image.NewRGBA(image.Rect(0, 0, b.w-(b.horizontalBorderSize*2), b.h-(b.verticalBorderSize*2))) + gc := draw2dimg.NewGraphicContext(baseImg) for i := 0; i < 2; i++ { triangleTip := float64((b.h - (b.verticalBorderSize * 2)) / 2) if i == 0 { @@ -160,9 +196,9 @@ func (b *board) updateBackgroundImage() { } if colorA { - gc.SetFillColor(color.RGBA{219.0, 185, 113, 255}) + gc.SetFillColor(triangleA) } else { - gc.SetFillColor(color.RGBA{120.0, 17.0, 0, 255}) + gc.SetFillColor(triangleB) } tx := b.spaceWidth * j @@ -177,12 +213,56 @@ func (b *board) updateBackgroundImage() { gc.Fill() } } - img = ebiten.NewImageFromImage(baseImg) - b.op.GeoM.Reset() b.op.GeoM.Translate(float64(b.horizontalBorderSize), float64(b.verticalBorderSize)) b.backgroundImage.DrawImage(img, b.op) + + // Border + borderImage := image.NewRGBA(image.Rect(0, 0, b.w, b.h)) + gc = draw2dimg.NewGraphicContext(borderImage) + gc.SetStrokeColor(borderColor) + // - Outside left + gc.SetLineWidth(2) + gc.MoveTo(float64(1), float64(0)) + gc.LineTo(float64(1), float64(b.h)) + // - Center + gc.SetLineWidth(2) + gc.MoveTo(float64(frameW/2), float64(0)) + gc.LineTo(float64(frameW/2), float64(b.h)) + // - Outside right + gc.MoveTo(float64(frameW), float64(0)) + gc.LineTo(float64(frameW), float64(b.h)) + gc.Close() + gc.Stroke() + // - Inside left + gc.SetLineWidth(1) + edge := float64((((innerW) - b.barWidth) / 2) + borderSize) + gc.MoveTo(float64(borderSize), float64(b.verticalBorderSize)) + gc.LineTo(edge, float64(b.verticalBorderSize)) + gc.LineTo(edge, float64(b.h-b.verticalBorderSize)) + gc.LineTo(float64(borderSize), float64(b.h-b.verticalBorderSize)) + gc.LineTo(float64(borderSize), float64(b.verticalBorderSize)) + gc.Close() + gc.Stroke() + // - Inside right + edgeStart := float64((innerW / 2) + (b.barWidth / 2) + borderSize) + edgeEnd := float64(innerW + borderSize) + gc.MoveTo(float64(edgeStart), float64(b.verticalBorderSize)) + gc.LineTo(edgeEnd, float64(b.verticalBorderSize)) + gc.LineTo(edgeEnd, float64(b.h-b.verticalBorderSize)) + gc.LineTo(float64(edgeStart), float64(b.h-b.verticalBorderSize)) + gc.LineTo(float64(edgeStart), float64(b.verticalBorderSize)) + gc.Close() + gc.Stroke() + img = ebiten.NewImageFromImage(borderImage) + b.op.GeoM.Reset() + b.op.GeoM.Translate(float64(b.horizontalBorderSize-borderSize), 0) + b.backgroundImage.DrawImage(img, b.op) +} + +func (b *board) ScheduleFrame() { + b.drawFrame <- true } func (b *board) draw(screen *ebiten.Image) { @@ -280,7 +360,7 @@ func (b *board) setRect(x, y, w, h int) { b.horizontalBorderSize = 0 - b.triangleOffset = float64(b.h-(b.verticalBorderSize*2)) / 33 + b.triangleOffset = float64(b.h-(b.verticalBorderSize*2)) / 15 for { b.verticalBorderSize = 7 // TODO configurable @@ -304,7 +384,6 @@ func (b *board) setRect(x, y, w, h int) { if extraSpace >= largeBarWidth { b.barWidth = largeBarWidth } - // TODO barwidth in calcs is wrong b.horizontalBorderSize = ((b.w - (b.spaceWidth * 12)) - b.barWidth) / 2 if b.horizontalBorderSize < 0 { @@ -312,6 +391,7 @@ func (b *board) setRect(x, y, w, h int) { } loadAssets(b.spaceWidth) + for i := 0; i < b.Sprites.num; i++ { s := b.Sprites.sprites[i] s.w, s.h = imgCheckerWhite.Size() @@ -524,37 +604,77 @@ func (b *board) ProcessState() { func (b *board) _movePiece(sprite *Sprite, from int, to int, speed int) { moveSize := 1 - moveDelay := time.Duration(2/speed) * time.Millisecond + moveDelay := time.Duration(1/speed) * time.Millisecond - stackTo := len(b.spaces[to]) - if stackTo == 1 && sprite.colorWhite != b.spaces[to][0].colorWhite { - stackTo = 0 // Hit - } - x, y, _, _ := b.stackSpaceRect(to, stackTo) - x, y = b.offsetPosition(x, y) + space := from + for { + if space == to { + break + } else if to > space { + space++ + } else { + space-- + } - if sprite.x != x { - // Center - cy := (b.h / 2) - (b.spaceWidth / 2) - for { - if sprite.y == cy { - break - } - if sprite.y < cy { - sprite.y += moveSize - if sprite.y > cy { - sprite.y = cy + // Go to bar or home immediately + if from == 0 || from == 25 || to == 0 || to == 25 { + space = to + } + + stack := len(b.spaces[space]) + if stack == 1 && sprite.colorWhite != b.spaces[space][0].colorWhite { + stack = 0 // Hit + } + + x, y, _, _ := b.stackSpaceRect(space, stack) + x, y = b.offsetPosition(x, y) + + cy := y + if cy > sprite.y == b.bottomRow(space) { + cy = sprite.y + } + + if sprite.x != x { + // Center + for { + if sprite.y == cy { + break } - } else if sprite.y > cy { - sprite.y -= moveSize if sprite.y < cy { - sprite.y = cy + sprite.y += moveSize + if sprite.y > cy { + sprite.y = cy + } + } else if sprite.y > cy { + sprite.y -= moveSize + if sprite.y < cy { + sprite.y = cy + } } + b.ScheduleFrame() + time.Sleep(moveDelay) + } + for { + if sprite.x == x { + break + } + if sprite.x < x { + sprite.x += moveSize + if sprite.x > x { + sprite.x = x + } + } else if sprite.x > x { + sprite.x -= moveSize + if sprite.x < x { + sprite.x = x + } + } + b.ScheduleFrame() + time.Sleep(moveDelay / 2) } - time.Sleep(moveDelay) } for { - if sprite.x == x { + if sprite.x == x && sprite.y == y { break } if sprite.x < x { @@ -568,36 +688,20 @@ func (b *board) _movePiece(sprite *Sprite, from int, to int, speed int) { sprite.x = x } } - time.Sleep(moveDelay / 2) - } - } - for { - if sprite.x == x && sprite.y == y { - break - } - if sprite.x < x { - sprite.x += moveSize - if sprite.x > x { - sprite.x = x - } - } else if sprite.x > x { - sprite.x -= moveSize - if sprite.x < x { - sprite.x = x - } - } - if sprite.y < y { - sprite.y += moveSize - if sprite.y > y { - sprite.y = y - } - } else if sprite.y > y { - sprite.y -= moveSize if sprite.y < y { - sprite.y = y + sprite.y += moveSize + if sprite.y > y { + sprite.y = y + } + } else if sprite.y > y { + sprite.y -= moveSize + if sprite.y < y { + sprite.y = y + } } + b.ScheduleFrame() + time.Sleep(moveDelay) } - time.Sleep(moveDelay) } // TODO do not add bear off pieces @@ -609,6 +713,10 @@ func (b *board) _movePiece(sprite *Sprite, from int, to int, speed int) { } } b.moving = nil + + b.ScheduleFrame() + + time.Sleep(time.Second) } func (b *board) handlePieceMoves() { @@ -638,8 +746,11 @@ func (b *board) handlePieceMoves() { b._movePiece(sprite, from, to, 1) if moveAfter != nil { toBar := 0 - if b.V[fibs.StateDirection] == 1 { - toBar = 25 + if b.V[fibs.StateTurn] == b.V[fibs.StatePlayerColor] { + toBar = 25 // TODO how is this determined? + } + if b.V[fibs.StateDirection] == -1 { + toBar = 25 - toBar } b._movePiece(moveAfter, to, toBar, 2) } @@ -658,9 +769,8 @@ func (b *board) update() { // TODO allow grabbing multiple pieces by grabbing further down the stack if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) { - x, y := ebiten.CursorPosition() - if b.dragging == nil { + x, y := ebiten.CursorPosition() s := b.spriteAt(x, y) if s != nil { b.dragging = s diff --git a/game/game.go b/game/game.go index 192b45e..d89efd9 100644 --- a/game/game.go +++ b/game/game.go @@ -8,10 +8,12 @@ import ( "image/color" _ "image/png" "log" + "os" "strings" "time" "code.rocketnine.space/tslocum/fibs" + "code.rocketnine.space/tslocum/kibodo" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/ebitenutil" "github.com/hajimehoshi/ebiten/v2/examples/resources/fonts" @@ -162,6 +164,9 @@ type Game struct { inputBuffer string Debug int + + keyboard *kibodo.Keyboard + shownKeyboard bool } func NewGame() *Game { @@ -176,8 +181,12 @@ func NewGame() *Game { Board: NewBoard(), runeBuffer: make([]rune, 24), - } + keyboard: kibodo.NewKeyboard(), + } + g.keyboard.SetKeys(kibodo.KeysQWERTY) + + // TODO go func() { t := time.NewTicker(time.Second / 4) for range t.C { @@ -270,10 +279,30 @@ func (g *Game) Update() error { // Called by ebiten only when input occurs return err } + if ebiten.IsWindowBeingClosed() { + g.Exit() + return nil + } + + err = g.keyboard.Update() + if err != nil { + return fmt.Errorf("failed to update virtual keyboard: %s", err) + } + if !g.loggedIn { f := func() { var clearBuffer bool defer func() { + if strings.ContainsRune(g.inputBuffer, '\n') { + g.inputBuffer = strings.Split(g.inputBuffer, "\n")[0] + clearBuffer = true + } + if !g.usernameConfirmed { + g.Username = g.inputBuffer + } else { + g.Password = g.inputBuffer + } + if clearBuffer { g.inputBuffer = "" @@ -285,6 +314,23 @@ func (g *Game) Update() error { // Called by ebiten only when input occurs } }() + if !g.shownKeyboard { + ch := make(chan *kibodo.Input, 10) + go func() { + for input := range ch { + if input.Rune > 0 { + g.inputBuffer += string(input.Rune) + continue + } + if input.Key == ebiten.KeyEnter { + g.inputBuffer += "\n" + } + } + }() + g.keyboard.Show(ch) + g.shownKeyboard = true + } + if inpututil.IsKeyJustPressed(ebiten.KeyBackspace) && len(g.inputBuffer) > 0 { g.inputBuffer = g.inputBuffer[:len(g.inputBuffer)-1] } @@ -296,17 +342,6 @@ func (g *Game) Update() error { // Called by ebiten only when input occurs g.runeBuffer = ebiten.AppendInputChars(g.runeBuffer[:0]) if len(g.runeBuffer) > 0 { g.inputBuffer += string(g.runeBuffer) - - if strings.ContainsRune(g.inputBuffer, '\n') { - g.inputBuffer = strings.Split(g.inputBuffer, "\n")[0] - clearBuffer = true - } - if !g.usernameConfirmed { - g.Username = g.inputBuffer - } else { - g.Password = g.inputBuffer - } - log.Println("INPUT BUFFER IS:" + g.inputBuffer) } } @@ -350,6 +385,8 @@ func (g *Game) Draw(screen *ebiten.Image) { // Log in screen if !g.loggedIn { + g.keyboard.Draw(screen) + const welcomeText = `Please enter your FIBS username and password. If you do not have a FIBS account yet, visit http://www.fibs.com/help.html#register` @@ -372,19 +409,18 @@ http://www.fibs.com/help.html#register` g.Board.draw(screen) - if g.Debug == 1 { + if g.Debug > 0 { debugBox := image.NewRGBA(image.Rect(10, 20, 200, 200)) debugImg := ebiten.NewImageFromImage(debugBox) g.drawBuffer.Reset() - g.drawBuffer.Write([]byte(fmt.Sprintf("FPS %0.0f\nTPS %0.0f", ebiten.CurrentFPS(), ebiten.CurrentTPS()))) + g.drawBuffer.Write([]byte(fmt.Sprintf("FPS %0.0f %c\nTPS %0.0f", ebiten.CurrentFPS(), spinner[g.spinnerIndex], ebiten.CurrentTPS()))) - /* TODO enable when vsync is able to be turned off g.spinnerIndex++ if g.spinnerIndex == 4 { g.spinnerIndex = 0 - }*/ + } scaleFactor := ebiten.DeviceScaleFactor() if scaleFactor != 1.0 { @@ -415,9 +451,17 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { g.screenW, g.screenH = outsideWidth, outsideHeight g.Board.setRect(0, 0, g.screenW, g.screenH) + + displayArea := 200 + g.keyboard.SetRect(0, displayArea, g.screenW, g.screenH-displayArea) return outsideWidth, outsideHeight } func (g *Game) resetImageOptions() { g.op.GeoM.Reset() } + +func (g *Game) Exit() { + g.Board.drawFrame <- false + os.Exit(0) +} diff --git a/go.mod b/go.mod index 03d050b..6168c40 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,8 @@ go 1.17 require ( code.rocketnine.space/tslocum/fibs v0.0.0-00010101000000-000000000000 - github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.12.0.20210825183521-91a72880271d + code.rocketnine.space/tslocum/kibodo v0.0.0-20210830194839-05789279ce56 + github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.12.0.20210828073710-0e5dca9453a5 github.com/llgcode/draw2d v0.0.0-20210313082411-577c1ead272a github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d diff --git a/go.sum b/go.sum index 193b1ea..0780a39 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +code.rocketnine.space/tslocum/kibodo v0.0.0-20210830194839-05789279ce56 h1:+KVT4Zw9CEQkxdNP81wuTvX3EHRPpPUQFwn6UVLoMFY= +code.rocketnine.space/tslocum/kibodo v0.0.0-20210830194839-05789279ce56/go.mod h1:nWGK8LvmYgMZQcwGMYOOuZ19VsVYL5E1hREEJ2gV46M= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/go-gl/gl v0.0.0-20180407155706-68e253793080/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= github.com/go-gl/glfw v0.0.0-20180426074136-46a8d530c326 h1:QqWaXlVeUGwSH7hO8giZP2Y06Qjl1LWR+FWC22YQsU8= @@ -8,8 +10,8 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/hajimehoshi/bitmapfont/v2 v2.1.3 h1:JefUkL0M4nrdVwVq7MMZxSTh6mSxOylm+C4Anoucbb0= github.com/hajimehoshi/bitmapfont/v2 v2.1.3/go.mod h1:2BnYrkTQGThpr/CY6LorYtt/zEPNzvE/ND69CRTaHMs= -github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.12.0.20210825183521-91a72880271d h1:EMEmUvZhS8hZ4eq1732CWs7aKcSWXhVvcxllfhVZc9Y= -github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.12.0.20210825183521-91a72880271d/go.mod h1:B4Cje+Kb1ZjztrKFPaiMWOGXO3Vp8u+zIBdxkZqkyD4= +github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.12.0.20210828073710-0e5dca9453a5 h1:fUSKz2wvklV02UTmBXXDlNKc6molRGUu5O8b80AvEa4= +github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.12.0.20210828073710-0e5dca9453a5/go.mod h1:B4Cje+Kb1ZjztrKFPaiMWOGXO3Vp8u+zIBdxkZqkyD4= github.com/hajimehoshi/file2byteslice v0.0.0-20200812174855-0e5e8a80490e/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE= github.com/hajimehoshi/go-mp3 v0.3.2/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= diff --git a/main.go b/main.go index 5c24258..c10ea2a 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,8 @@ import ( "flag" "log" "os" + "os/signal" + "syscall" "time" "code.rocketnine.space/tslocum/boxcars/game" @@ -20,14 +22,10 @@ func main() { ebiten.SetWindowTitle("Boxcars") ebiten.SetWindowSize(screenWidth, screenHeight) ebiten.SetWindowResizable(true) + ebiten.SetFPSMode(ebiten.FPSModeVsyncOffMinimum) ebiten.SetMaxTPS(60) // TODO allow users to set custom value ebiten.SetRunnableOnUnfocused(true) // Note - this currently does nothing in ebiten - - // TODO set up system to call scheduleframe automatically - //ebiten.SetFPSMode(ebiten.FPSModeVsyncOffMinimum) - // TODO breaks justpressedkey - - //ebiten.SetWindowClosingHandled(true) TODO implement + ebiten.SetWindowClosingHandled(true) fullscreenWidth, fullscreenHeight := ebiten.ScreenSizeInFullscreen() if fullscreenWidth <= screenWidth || fullscreenHeight <= screenHeight { @@ -68,6 +66,16 @@ func main() { } }() + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, + syscall.SIGINT, + syscall.SIGTERM) + go func() { + <-sigc + + g.Exit() + }() + if err := ebiten.RunGame(g); err != nil { log.Fatal(err) }