ebiten: Remove the argument from Update

Fixes #1260
This commit is contained in:
Hajime Hoshi 2020-10-04 17:42:54 +09:00
parent 81f336ac46
commit 8f00c8fbf5
67 changed files with 95 additions and 116 deletions

2
doc.go
View File

@ -21,7 +21,7 @@
// //
// // Update proceeds the game state. // // Update proceeds the game state.
// // Update is called every tick (1/60 [s] by default). // // Update is called every tick (1/60 [s] by default).
// func (g *Game) Update(screen *ebiten.Image) error { // func (g *Game) Update() error {
// // Write your game's logical update. // // Write your game's logical update.
// return nil // return nil
// } // }

View File

@ -57,7 +57,7 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeigh
} }
// Update updates the current game state. // Update updates the current game state.
func (g *Game) Update(*ebiten.Image) error { func (g *Game) Update() error {
g.input.Update() g.input.Update()
if err := g.board.Update(g.input); err != nil { if err := g.board.Update(g.input); err != nil {
return err return err

View File

@ -38,7 +38,7 @@ var (
type Game struct{} type Game struct{}
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
return nil return nil
} }

View File

@ -104,7 +104,7 @@ func drawRect(screen *ebiten.Image, img *ebiten.Image, x, y, width, height float
type Game struct{} type Game struct{}
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
return nil return nil
} }

View File

@ -241,7 +241,7 @@ func NewGame() *Game {
} }
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
// Manipulate the player by the input. // Manipulate the player by the input.
if ebiten.IsKeyPressed(ebiten.KeySpace) { if ebiten.IsKeyPressed(ebiten.KeySpace) {
g.player.MoveForward() g.player.MoveForward()

View File

@ -40,7 +40,7 @@ type Game struct {
count int count int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.count++ g.count++
g.count %= ebiten.MaxTPS() * 10 g.count %= ebiten.MaxTPS() * 10
return nil return nil

View File

@ -45,7 +45,7 @@ type Game struct {
count int count int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.count++ g.count++
return nil return nil
} }

View File

@ -284,7 +284,7 @@ func NewGame() (*Game, error) {
}, nil }, nil
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
select { select {
case p := <-g.musicPlayerCh: case p := <-g.musicPlayerCh:
g.musicPlayer = p g.musicPlayer = p

View File

@ -51,7 +51,7 @@ type Game struct {
player *audio.Player player *audio.Player
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if g.player != nil { if g.player != nil {
return nil return nil
} }

View File

@ -94,7 +94,7 @@ func lerp(a, b, t float64) float64 {
return a*(1-t) + b*t return a*(1-t) + b*t
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.initAudio() g.initAudio()
g.count++ g.count++
r := float64(g.count) * ((1.0 / 60.0) * 2 * math.Pi) * 0.1 // full cycle every 10 seconds r := float64(g.count) * ((1.0 / 60.0) * 2 * math.Pi) * 0.1 // full cycle every 10 seconds

View File

@ -32,7 +32,7 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeigh
return ScreenWidth, ScreenHeight return ScreenWidth, ScreenHeight
} }
func (g *Game) Update(*ebiten.Image) error { func (g *Game) Update() error {
if g.sceneManager == nil { if g.sceneManager == nil {
g.sceneManager = &SceneManager{} g.sceneManager = &SceneManager{}
g.sceneManager.GoTo(&TitleScene{}) g.sceneManager.GoTo(&TitleScene{})

View File

@ -37,7 +37,7 @@ var (
type Game struct{} type Game struct{}
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
return nil return nil
} }

View File

@ -133,7 +133,7 @@ type Game struct {
camera Camera camera Camera
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if ebiten.IsKeyPressed(ebiten.KeyA) || ebiten.IsKeyPressed(ebiten.KeyLeft) { if ebiten.IsKeyPressed(ebiten.KeyA) || ebiten.IsKeyPressed(ebiten.KeyLeft) {
g.camera.Position[0] -= 1 g.camera.Position[0] -= 1
} }

View File

@ -90,7 +90,7 @@ func NewGame() *Game {
} }
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.space.Step(1.0 / float64(ebiten.MaxTPS())) g.space.Step(1.0 / float64(ebiten.MaxTPS()))
return nil return nil
} }

View File

@ -78,7 +78,7 @@ func (g *Game) loseAndRestoreContext(context js.Value) {
}() }()
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if inpututil.IsKeyJustPressed(ebiten.KeySpace) { if inpututil.IsKeyJustPressed(ebiten.KeySpace) {
doc := js.Global().Get("document") doc := js.Global().Get("document")
canvas := doc.Call("getElementsByTagName", "canvas").Index(0) canvas := doc.Call("getElementsByTagName", "canvas").Index(0)

View File

@ -125,7 +125,7 @@ func (g *Game) renderFire() {
} }
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.updateFirePixels() g.updateFirePixels()
return nil return nil
} }

View File

@ -266,7 +266,7 @@ func (g *Game) updateStroke(stroke *Stroke) {
stroke.SetDraggingObject(nil) stroke.SetDraggingObject(nil)
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) { if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
s := NewStroke(&MouseStrokeSource{}) s := NewStroke(&MouseStrokeSource{})
s.SetDraggingObject(g.spriteAt(s.Position())) s.SetDraggingObject(g.spriteAt(s.Position()))

View File

@ -39,7 +39,7 @@ var (
type Game struct { type Game struct {
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
return nil return nil
} }

View File

@ -203,7 +203,7 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
return screenWidth, screenHeight return screenWidth, screenHeight
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
switch g.mode { switch g.mode {
case ModeTitle: case ModeTitle:
if jump() { if jump() {

View File

@ -49,7 +49,7 @@ var (
type Game struct { type Game struct {
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
return nil return nil
} }

View File

@ -124,7 +124,7 @@ type Game struct {
kanjiTextColor color.RGBA kanjiTextColor color.RGBA
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
// Change the text color for each second. // Change the text color for each second.
if g.counter%ebiten.MaxTPS() == 0 { if g.counter%ebiten.MaxTPS() == 0 {
g.kanjiText = nil g.kanjiText = nil

View File

@ -79,7 +79,7 @@ type Game struct {
count int count int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.count++ g.count++
if ebiten.IsKeyPressed(ebiten.KeyQ) { if ebiten.IsKeyPressed(ebiten.KeyQ) {

View File

@ -39,7 +39,7 @@ type Game struct {
pressedButtons map[int][]string pressedButtons map[int][]string
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if g.gamepadIDs == nil { if g.gamepadIDs == nil {
g.gamepadIDs = map[int]struct{}{} g.gamepadIDs = map[int]struct{}{}
} }

View File

@ -49,7 +49,7 @@ type Game struct {
highDPIImage *ebiten.Image highDPIImage *ebiten.Image
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
// TODO: DeviceScaleFactor() might return different values for different monitors. // TODO: DeviceScaleFactor() might return different values for different monitors.
// Add a mode to adjust the screen size along with the current device scale (#705). // Add a mode to adjust the screen size along with the current device scale (#705).
// Now this example uses the device scale initialized at the beginning of this application. // Now this example uses the device scale initialized at the beginning of this application.

View File

@ -68,7 +68,7 @@ func NewGame() *Game {
} }
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
// Adjust HSV values along with the user's input. // Adjust HSV values along with the user's input.
if ebiten.IsKeyPressed(ebiten.KeyQ) { if ebiten.IsKeyPressed(ebiten.KeyQ) {
g.hue128-- g.hue128--

View File

@ -40,7 +40,7 @@ type Game struct {
count int count int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.count++ g.count++
return nil return nil
} }

View File

@ -78,7 +78,7 @@ type Game struct {
viewport viewport viewport viewport
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.viewport.Move() g.viewport.Move()
return nil return nil
} }

View File

@ -49,7 +49,7 @@ type Game struct {
pressed []ebiten.Key pressed []ebiten.Key
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.pressed = nil g.pressed = nil
for k := ebiten.Key(0); k <= ebiten.KeyMax; k++ { for k := ebiten.Key(0); k <= ebiten.KeyMax; k++ {
if ebiten.IsKeyPressed(k) { if ebiten.IsKeyPressed(k) {

View File

@ -160,7 +160,7 @@ type Game struct {
pixels []byte pixels []byte
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.world.Update() g.world.Update()
return nil return nil
} }

View File

@ -81,7 +81,7 @@ func init() {
type Game struct { type Game struct {
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
return nil return nil
} }

View File

@ -87,7 +87,7 @@ func (m *mascot) Layout(outsideWidth, outsideHeight int) (int, int) {
return width, height return width, height
} }
func (m *mascot) Update(screen *ebiten.Image) error { func (m *mascot) Update() error {
m.count++ m.count++
sw, sh := ebiten.ScreenSizeInFullscreen() sw, sh := ebiten.ScreenSizeInFullscreen()

View File

@ -96,7 +96,7 @@ func NewGame() *Game {
} }
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if g.spotLightVX == 0 { if g.spotLightVX == 0 {
g.spotLightVX = 1 g.spotLightVX = 1
} }

View File

@ -48,7 +48,7 @@ type Game struct {
counter int counter int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.counter++ g.counter++
if g.counter == 480 { if g.counter == 480 {
g.counter = 0 g.counter = 0

View File

@ -66,7 +66,7 @@ func (g *game) Layout(outsideWidth, outsideHeight int) (int, int) {
return screenWidth, screenHeight return screenWidth, screenHeight
} }
func (g *game) Update(screen *ebiten.Image) error { func (g *game) Update() error {
fullscreen := ebiten.IsFullscreen() fullscreen := ebiten.IsFullscreen()
if inpututil.IsKeyJustPressed(ebiten.KeyS) { if inpututil.IsKeyJustPressed(ebiten.KeyS) {

View File

@ -58,7 +58,7 @@ func init() {
type Game struct { type Game struct {
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
return nil return nil
} }

View File

@ -49,7 +49,7 @@ type Game struct {
noiseImage *image.RGBA noiseImage *image.RGBA
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
// Generate the noise with random RGB values. // Generate the noise with random RGB values.
const l = screenWidth * screenHeight const l = screenWidth * screenHeight
for i := 0; i < l; i++ { for i := 0; i < l; i++ {

View File

@ -63,7 +63,7 @@ type Game struct {
count int count int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
drawn := false drawn := false
// Paint the brush by mouse dragging // Paint the brush by mouse dragging

View File

@ -141,7 +141,7 @@ type Game struct {
sprites *list.List sprites *list.List
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if g.sprites == nil { if g.sprites == nil {
g.sprites = list.New() g.sprites = list.New()
} }

View File

@ -137,7 +137,7 @@ type Game struct {
currentNote rune currentNote rune
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
// Play notes for each half second. // Play notes for each half second.
if g.frames%30 == 0 && audioContext.IsReady() { if g.frames%30 == 0 && audioContext.IsReady() {
g.currentNote = playNote(g.scoreIndex) g.currentNote = playNote(g.scoreIndex)

View File

@ -37,7 +37,7 @@ var (
type Game struct{} type Game struct{}
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
return nil return nil
} }

View File

@ -207,7 +207,7 @@ var (
type Game struct { type Game struct {
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
// The piano data is still being initialized. // The piano data is still being initialized.
// Get the progress if available. // Get the progress if available.
if !pianoNoteSamplesInited { if !pianoNoteSamplesInited {

View File

@ -124,7 +124,7 @@ type Game struct {
gopher *char gopher *char
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if g.gopher == nil { if g.gopher == nil {
g.gopher = &char{x: 50 * unit, y: groundY * unit} g.gopher = &char{x: 50 * unit, y: groundY * unit}
} }

View File

@ -98,7 +98,7 @@ type Game struct {
prevNgon int prevNgon int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if inpututil.IsKeyJustPressed(ebiten.KeyLeft) { if inpututil.IsKeyJustPressed(ebiten.KeyLeft) {
g.ngon-- g.ngon--
if g.ngon < 1 { if g.ngon < 1 {

View File

@ -221,7 +221,7 @@ type Game struct {
objects []object objects []object
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if inpututil.IsKeyJustPressed(ebiten.KeyEscape) { if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
return errors.New("game ended by player") return errors.New("game ended by player")
} }

View File

@ -40,7 +40,7 @@ type Game struct {
count int count int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.count++ g.count++
return nil return nil
} }

View File

@ -45,7 +45,7 @@ func init() {
type Game struct { type Game struct {
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
w, h := offscreen.Size() w, h := offscreen.Size()
x := rand.Intn(w) x := rand.Intn(w)
y := rand.Intn(h) y := rand.Intn(h)

View File

@ -96,7 +96,7 @@ type Game struct {
time int time int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.time++ g.time++
if inpututil.IsKeyJustPressed(ebiten.KeyDown) { if inpututil.IsKeyJustPressed(ebiten.KeyDown) {
g.idx++ g.idx++

View File

@ -154,7 +154,7 @@ func rect(x, y, w, h float32, clr color.RGBA) ([]ebiten.Vertex, []uint16) {
}, []uint16{0, 1, 2, 1, 2, 3} }, []uint16{0, 1, 2, 1, 2, 3}
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.count++ g.count++
g.count %= 240 g.count %= 240
return nil return nil

View File

@ -97,7 +97,7 @@ type Game struct {
player *audio.Player player *audio.Player
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if g.player == nil { if g.player == nil {
// Pass the (infinite) stream to audio.NewPlayer. // Pass the (infinite) stream to audio.NewPlayer.
// After calling Play, the stream never ends as long as the player object lives. // After calling Play, the stream never ends as long as the player object lives.

View File

@ -102,7 +102,7 @@ func (g *Game) reset() {
g.moveDirection = dirNone g.moveDirection = dirNone
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if inpututil.IsKeyJustPressed(ebiten.KeyLeft) || inpututil.IsKeyJustPressed(ebiten.KeyA) { if inpututil.IsKeyJustPressed(ebiten.KeyLeft) || inpututil.IsKeyJustPressed(ebiten.KeyA) {
if g.moveDirection != dirRight { if g.moveDirection != dirRight {
g.moveDirection = dirLeft g.moveDirection = dirLeft

View File

@ -163,7 +163,7 @@ func rightTouched() bool {
return false return false
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if !g.inited { if !g.inited {
g.init() g.init()
} }

View File

@ -145,7 +145,7 @@ func (g *Game) init() {
var regularTermination = errors.New("regular termination") var regularTermination = errors.New("regular termination")
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if !g.inited { if !g.inited {
g.init() g.init()
} }

View File

@ -289,7 +289,7 @@ func init() {
type Game struct{} type Game struct{}
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
reset := false reset := false
if inpututil.IsKeyJustPressed(ebiten.KeyB) { if inpututil.IsKeyJustPressed(ebiten.KeyB) {

View File

@ -79,7 +79,7 @@ type Game struct {
kanjiTextColor color.RGBA kanjiTextColor color.RGBA
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
return nil return nil
} }

View File

@ -63,7 +63,7 @@ type Game struct {
layers [][]int layers [][]int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
return nil return nil
} }

View File

@ -51,7 +51,7 @@ type Game struct {
counter int counter int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
// Add a string from InputChars, that returns string input by users. // Add a string from InputChars, that returns string input by users.
// Note that InputChars result changes every frame, so you need to call this // Note that InputChars result changes every frame, so you need to call this
// every frame. // every frame.

View File

@ -490,7 +490,7 @@ func init() {
}) })
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.button1.Update() g.button1.Update()
g.button2.Update() g.button2.Update()
g.checkBox.Update() g.checkBox.Update()

View File

@ -175,7 +175,7 @@ type Game struct {
counter int counter int
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
g.counter++ g.counter++
return nil return nil
} }

View File

@ -74,7 +74,7 @@ func init() {
} }
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
if ebiten.IsKeyPressed(ebiten.KeyP) && !g.audioPlayer.IsPlaying() { if ebiten.IsKeyPressed(ebiten.KeyP) && !g.audioPlayer.IsPlaying() {
// As audioPlayer has one stream and remembers the playing position, // As audioPlayer has one stream and remembers the playing position,
// rewinding is needed before playing when reusing audioPlayer. // rewinding is needed before playing when reusing audioPlayer.

View File

@ -42,7 +42,7 @@ type Game struct {
y float64 y float64
} }
func (g *Game) Update(screen *ebiten.Image) error { func (g *Game) Update() error {
dx, dy := ebiten.Wheel() dx, dy := ebiten.Wheel()
g.x += dx g.x += dx
g.y += dy g.y += dy

View File

@ -97,7 +97,7 @@ func (g *game) Layout(outsideWidth, outsideHeight int) (int, int) {
return g.width, g.height return g.width, g.height
} }
func (g *game) Update(screen *ebiten.Image) error { func (g *game) Update() error {
var ( var (
screenWidth int screenWidth int
screenHeight int screenHeight int

View File

@ -84,7 +84,7 @@ func dumpInternalImages() error {
} }
type imageDumper struct { type imageDumper struct {
f func(screen *Image) error g Game
keyState map[Key]int keyState map[Key]int
@ -95,15 +95,21 @@ type imageDumper struct {
hasDumpInternalImagesKey bool hasDumpInternalImagesKey bool
dumpInternalImagesKey Key dumpInternalImagesKey Key
toDumpInternalImages bool toDumpInternalImages bool
err error
} }
func (i *imageDumper) update(screen *Image) error { func (i *imageDumper) update() error {
if i.err != nil {
return i.err
}
const ( const (
envScreenshotKey = "EBITEN_SCREENSHOT_KEY" envScreenshotKey = "EBITEN_SCREENSHOT_KEY"
envInternalImagesKey = "EBITEN_INTERNAL_IMAGES_KEY" envInternalImagesKey = "EBITEN_INTERNAL_IMAGES_KEY"
) )
if err := i.f(screen); err != nil { if err := i.g.Update(); err != nil {
return err return err
} }
@ -153,9 +159,7 @@ func (i *imageDumper) update(screen *Image) error {
i.keyState[key] = 0 i.keyState[key] = 0
} }
} }
return nil
// TODO: As the screen will be available only from Draw, move this to a drawing function.
return i.dump(screen)
} }
func (i *imageDumper) dump(screen *Image) error { func (i *imageDumper) dump(screen *Image) error {

View File

@ -17,11 +17,11 @@
package ebiten package ebiten
type imageDumper struct { type imageDumper struct {
f func(screen *Image) error g Game
} }
func (i *imageDumper) update(screen *Image) error { func (i *imageDumper) update() error {
return i.f(screen) return i.g.Update()
} }
func (i *imageDumper) dump(screen *Image) error { func (i *imageDumper) dump(screen *Image) error {

View File

@ -42,7 +42,7 @@ type game struct {
code int code int
} }
func (g *game) Update(*ebiten.Image) error { func (g *game) Update() error {
select { select {
case f := <-mainCh: case f := <-mainCh:
f() f()

View File

@ -30,7 +30,7 @@ type game struct {
code int code int
} }
func (g *game) Update(*ebiten.Image) error { func (g *game) Update() error {
g.code = g.m.Run() g.code = g.m.Run()
return regularTermination return regularTermination
} }

55
run.go
View File

@ -25,20 +25,14 @@ import (
type Game interface { type Game interface {
// Update updates a game by one tick. The given argument represents a screen image. // Update updates a game by one tick. The given argument represents a screen image.
// //
// Basically Update updates the game logic. Whether Update also draws the screen or not depends on the
// existence of Draw implementation.
//
// The Draw function's definition is:
//
// Draw(screen *Image)
//
// Update updates only the game logic and Draw draws the screen. // Update updates only the game logic and Draw draws the screen.
// In this case, the argument screen's updated content by Update is not adopted for the actual game screen, //
// and the screen's updated content by Draw is adopted instead.
// In the first frame, it is ensured that Update is called at least once before Draw. You can use Update // In the first frame, it is ensured that Update is called at least once before Draw. You can use Update
// to initialize the game state. After the first frame, Update might not be called or might be called once // to initialize the game state.
//
// After the first frame, Update might not be called or might be called once
// or more for one frame. The frequency is determined by the current TPS (tick-per-second). // or more for one frame. The frequency is determined by the current TPS (tick-per-second).
Update(screen *Image) error Update() error
// Draw draws the game screen by one frame. // Draw draws the game screen by one frame.
// //
@ -102,32 +96,20 @@ func IsScreenClearedEveryFrame() bool {
return atomic.LoadInt32(&isScreenClearedEveryFrame) != 0 return atomic.LoadInt32(&isScreenClearedEveryFrame) != 0
} }
type imageDumperGame struct { type imageDumperGameWithDraw struct {
game Game game Game
d *imageDumper d *imageDumper
err error
} }
func (i *imageDumperGame) Update(screen *Image) error { func (i *imageDumperGameWithDraw) Update() error {
if i.d == nil {
i.d = &imageDumper{f: i.game.Update}
}
return i.d.update(screen)
}
func (i *imageDumperGame) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
return i.game.Layout(outsideWidth, outsideHeight)
}
type imageDumperGameWithDraw struct {
imageDumperGame
err error
}
func (i *imageDumperGameWithDraw) Update(screen *Image) error {
if i.err != nil { if i.err != nil {
return i.err return i.err
} }
return i.imageDumperGame.Update(screen) if i.d == nil {
i.d = &imageDumper{g: i.game}
}
return i.d.update()
} }
func (i *imageDumperGameWithDraw) Draw(screen *Image) { func (i *imageDumperGameWithDraw) Draw(screen *Image) {
@ -136,14 +118,13 @@ func (i *imageDumperGameWithDraw) Draw(screen *Image) {
} }
i.game.Draw(screen) i.game.Draw(screen)
// Call dump explicitly. IsDrawingSkipped always returns true when Draw is defined.
if i.d == nil {
i.d = &imageDumper{f: i.game.Update}
}
i.err = i.d.dump(screen) i.err = i.d.dump(screen)
} }
func (i *imageDumperGameWithDraw) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
return i.game.Layout(outsideWidth, outsideHeight)
}
// RunGame starts the main loop and runs the game. // RunGame starts the main loop and runs the game.
// game's Update function is called every tick to update the game logic. // game's Update function is called every tick to update the game logic.
// game's Draw function is, if it exists, called every frame to draw the screen. // game's Draw function is, if it exists, called every frame to draw the screen.
@ -188,7 +169,7 @@ func (i *imageDumperGameWithDraw) Draw(screen *Image) {
func RunGame(game Game) error { func RunGame(game Game) error {
fixWindowPosition(WindowSize()) fixWindowPosition(WindowSize())
return runGame(&imageDumperGameWithDraw{ return runGame(&imageDumperGameWithDraw{
imageDumperGame: imageDumperGame{game: game}, game: game,
}, 0) }, 0)
} }
@ -211,7 +192,7 @@ func runGame(game Game, scale float64) error {
func RunGameWithoutMainLoop(game Game) { func RunGameWithoutMainLoop(game Game) {
fixWindowPosition(WindowSize()) fixWindowPosition(WindowSize())
game = &imageDumperGameWithDraw{ game = &imageDumperGameWithDraw{
imageDumperGame: imageDumperGame{game: game}, game: game,
} }
theUIContext.set(game, 0) theUIContext.set(game, 0)
uiDriver().RunWithoutMainLoop(theUIContext) uiDriver().RunWithoutMainLoop(theUIContext)

View File

@ -194,13 +194,7 @@ func (c *uiContext) update() error {
if err := hooks.RunBeforeUpdateHooks(); err != nil { if err := hooks.RunBeforeUpdateHooks(); err != nil {
return err return err
} }
if err := c.game.Update(); err != nil {
// Multiple successive Clear call should be integrated into one graphics command, then
// calling Clear on every Update should not affect the performance.
if IsScreenClearedEveryFrame() {
c.offscreen.Clear()
}
if err := c.game.Update(c.offscreen); err != nil {
return err return err
} }
uiDriver().ResetForFrame() uiDriver().ResetForFrame()