ui: Add IsRunnableInBackground / SetRunnableInBackground (#272)

This commit is contained in:
Hajime Hoshi 2017-08-02 23:37:50 +09:00
parent bb5036b3e1
commit f0d47312c4
6 changed files with 105 additions and 25 deletions

View File

@ -58,7 +58,7 @@ type Input struct {
} }
func (i *Input) update() { func (i *Input) update() {
for _, key := range []ebiten.Key{ebiten.KeyP, ebiten.KeyS, ebiten.KeyX, ebiten.KeyZ} { for _, key := range []ebiten.Key{ebiten.KeyP, ebiten.KeyS, ebiten.KeyX, ebiten.KeyZ, ebiten.KeyB} {
if !ebiten.IsKeyPressed(key) { if !ebiten.IsKeyPressed(key) {
i.keyStates[key] = 0 i.keyStates[key] = 0
} else { } else {
@ -170,6 +170,10 @@ func (p *Player) update() error {
p.updatePlayPause() p.updatePlayPause()
p.updateSE() p.updateSE()
p.updateVolume() p.updateVolume()
if p.input.isKeyTriggered(ebiten.KeyB) {
b := ebiten.IsRunnableInBackground()
ebiten.SetRunnableInBackground(!b)
}
if err := p.audioContext.Update(); err != nil { if err := p.audioContext.Update(); err != nil {
return err return err
} }
@ -262,6 +266,7 @@ func (p *Player) draw(screen *ebiten.Image) {
Press S to toggle Play/Pause Press S to toggle Play/Pause
Press P to play SE Press P to play SE
Press Z or X to change volume of the music Press Z or X to change volume of the music
Press B to switch the run-in-background state
%s`, ebiten.CurrentFPS(), currentTimeStr) %s`, ebiten.CurrentFPS(), currentTimeStr)
ebitenutil.DebugPrint(screen, msg) ebitenutil.DebugPrint(screen, msg)
} }

View File

@ -21,6 +21,7 @@ import (
"image/color" "image/color"
_ "image/jpeg" _ "image/jpeg"
"log" "log"
"math"
"github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/ebitenutil" "github.com/hajimehoshi/ebiten/ebitenutil"
@ -41,7 +42,9 @@ var (
ebiten.KeyRight: 0, ebiten.KeyRight: 0,
ebiten.KeyS: 0, ebiten.KeyS: 0,
ebiten.KeyF: 0, ebiten.KeyF: 0,
ebiten.KeyB: 0,
} }
count = 0
) )
func update(screen *ebiten.Image) error { func update(screen *ebiten.Image) error {
@ -56,6 +59,7 @@ func update(screen *ebiten.Image) error {
d := int(32 / screenScale) d := int(32 / screenScale)
screenWidth, screenHeight := screen.Size() screenWidth, screenHeight := screen.Size()
fullscreen := ebiten.IsFullscreen() fullscreen := ebiten.IsFullscreen()
runnableInBackground := ebiten.IsRunnableInBackground()
if keyStates[ebiten.KeyUp] == 1 { if keyStates[ebiten.KeyUp] == 1 {
screenHeight += d screenHeight += d
@ -88,9 +92,15 @@ func update(screen *ebiten.Image) error {
if keyStates[ebiten.KeyF] == 1 { if keyStates[ebiten.KeyF] == 1 {
fullscreen = !fullscreen fullscreen = !fullscreen
} }
if keyStates[ebiten.KeyB] == 1 {
runnableInBackground = !runnableInBackground
}
ebiten.SetScreenSize(screenWidth, screenHeight) ebiten.SetScreenSize(screenWidth, screenHeight)
ebiten.SetScreenScale(screenScale) ebiten.SetScreenScale(screenScale)
ebiten.SetFullscreen(fullscreen) ebiten.SetFullscreen(fullscreen)
ebiten.SetRunnableInBackground(runnableInBackground)
count++
if ebiten.IsRunningSlowly() { if ebiten.IsRunningSlowly() {
return nil return nil
@ -101,12 +111,16 @@ func update(screen *ebiten.Image) error {
w2, h2 := screen.Size() w2, h2 := screen.Size()
op := &ebiten.DrawImageOptions{} op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(-w+w2)/2, float64(-h+h2)/2) op.GeoM.Translate(float64(-w+w2)/2, float64(-h+h2)/2)
dx := math.Cos(2*math.Pi*float64(count)/360) * 10
dy := math.Sin(2*math.Pi*float64(count)/360) * 10
op.GeoM.Translate(dx, dy)
screen.DrawImage(gophersImage, op) screen.DrawImage(gophersImage, op)
x, y := ebiten.CursorPosition() x, y := ebiten.CursorPosition()
msg := fmt.Sprintf(`Press arrow keys to change the window size msg := fmt.Sprintf(`Press arrow keys to change the window size
Press S key to change the window scale Press S key to change the window scale
Press F key to change the fullscreen state Press F key to change the fullscreen state
Press B key to change the run-in-background state
Cursor: (%d, %d) Cursor: (%d, %d)
FPS: %0.2f`, x, y, ebiten.CurrentFPS()) FPS: %0.2f`, x, y, ebiten.CurrentFPS())
ebitenutil.DebugPrint(screen, msg) ebitenutil.DebugPrint(screen, msg)

View File

@ -45,6 +45,7 @@ type userInterface struct {
origPosX int origPosX int
origPosY int origPosY int
initFullscreen bool initFullscreen bool
runnableInBackground bool
m sync.Mutex m sync.Mutex
} }
@ -133,6 +134,19 @@ func (u *userInterface) setInitFullscreen(initFullscreen bool) {
u.m.Unlock() u.m.Unlock()
} }
func (u *userInterface) isRunnableInBackground() bool {
u.m.Lock()
v := u.runnableInBackground
u.m.Unlock()
return v
}
func (u *userInterface) setRunnableInBackground(runnableInBackground bool) {
u.m.Lock()
u.runnableInBackground = runnableInBackground
u.m.Unlock()
}
func (u *userInterface) runOnMainThread(f func() error) error { func (u *userInterface) runOnMainThread(f func() error) error {
if u.funcs == nil { if u.funcs == nil {
// already closed // already closed
@ -213,6 +227,14 @@ func SetFullscreen(fullscreen bool) {
}) })
} }
func SetRunnableInBackground(runnableInBackground bool) {
currentUI.setRunnableInBackground(runnableInBackground)
}
func IsRunnableInBackground() bool {
return currentUI.isRunnableInBackground()
}
func ScreenOffset() (float64, float64) { func ScreenOffset() (float64, float64) {
u := currentUI u := currentUI
if !u.isRunning() { if !u.isRunning() {
@ -372,7 +394,7 @@ func (u *userInterface) update(g GraphicsContext) error {
_ = u.runOnMainThread(func() error { _ = u.runOnMainThread(func() error {
u.pollEvents() u.pollEvents()
for u.window.GetAttrib(glfw.Focused) == 0 { for !u.isRunnableInBackground() && u.window.GetAttrib(glfw.Focused) == 0 {
// Wait for an arbitrary period to avoid busy loop. // Wait for an arbitrary period to avoid busy loop.
time.Sleep(time.Second / 60) time.Sleep(time.Second / 60)
u.pollEvents() u.pollEvents()

View File

@ -31,6 +31,7 @@ type userInterface struct {
height int height int
scale float64 scale float64
fullscreen bool fullscreen bool
runnableInBackground bool
deviceScale float64 deviceScale float64
sizeChanged bool sizeChanged bool
@ -67,6 +68,14 @@ func IsFullscreen() bool {
return currentUI.fullscreen return currentUI.fullscreen
} }
func SetRunnableInBackground(runnableInBackground bool) {
currentUI.runnableInBackground = runnableInBackground
}
func IsRunnableInBackground() bool {
return currentUI.runnableInBackground
}
func ScreenOffset() (float64, float64) { func ScreenOffset() (float64, float64) {
return 0, 0 return 0, 0
} }
@ -104,7 +113,7 @@ func (u *userInterface) actualScreenScale() float64 {
} }
func (u *userInterface) update(g GraphicsContext) error { func (u *userInterface) update(g GraphicsContext) error {
if !u.windowFocus { if !u.runnableInBackground && !u.windowFocus {
return nil return nil
} }
if opengl.GetContext().IsContextLost() { if opengl.GetContext().IsContextLost() {

View File

@ -118,12 +118,20 @@ func SetCursorVisibility(visibility bool) {
// Do nothing // Do nothing
} }
func SetFullscreen(fullscreen bool) bool { func SetFullscreen(fullscreen bool) {
// Do nothing
}
func IsFullscreen() bool {
// Do nothing // Do nothing
return false return false
} }
func IsFullscreen() bool { func SetRunnableInBackground(runnableInBackground bool) {
// Do nothing
}
func IsRunnableInBackground() bool {
// Do nothing // Do nothing
return false return false
} }

22
run.go
View File

@ -178,3 +178,25 @@ func IsFullscreen() bool {
func SetFullscreen(fullscreen bool) { func SetFullscreen(fullscreen bool) {
ui.SetFullscreen(fullscreen) ui.SetFullscreen(fullscreen)
} }
// IsRunnableInBackground returns a boolean value indicating whether the game runs even in background.
//
// This function is concurrent-safe.
func IsRunnableInBackground() bool {
return ui.IsRunnableInBackground()
}
// SetRunnableInBackground sets the state if the game runs even in background.
//
// If the given value is true, the game runs in background e.g. when losing focus.
// The initial state is false.
//
// Known issue: On browsers, even if the state is on, the game doesn't run in background tabs.
// This is because browsers throttles background tabs not to often update.
//
// SetRunnableInBackground doesn't work on mobiles so far.
//
// This function is concurrent-safe.
func SetRunnableInBackground(runnableInBackground bool) {
ui.SetRunnableInBackground(runnableInBackground)
}