diff --git a/gameforui.go b/gameforui.go index 76cff965a..15d8aaaf3 100644 --- a/gameforui.go +++ b/gameforui.go @@ -147,8 +147,8 @@ func (g *gameForUI) Layout(outsideWidth, outsideHeight float64) (float64, float6 return float64(sw), float64(sh) } -func (g *gameForUI) UpdateInputState(inputState ui.InputState) { - theInputState.set(inputState) +func (g *gameForUI) UpdateInputState(fn func(*ui.InputState)) { + fn(&theInputState.state) } func (g *gameForUI) Update() error { diff --git a/input.go b/input.go index 3119c4d09..3183679cb 100644 --- a/input.go +++ b/input.go @@ -405,7 +405,7 @@ func (i *inputState) set(inputState ui.InputState) { func (i *inputState) appendInputChars(runes []rune) []rune { i.m.Lock() defer i.m.Unlock() - return append(runes, i.state.Runes[:i.state.RunesCount]...) + return append(runes, i.state.Runes...) } func (i *inputState) isKeyPressed(key Key) bool { @@ -453,9 +453,6 @@ func (i *inputState) appendTouchIDs(touches []TouchID) []TouchID { defer i.m.Unlock() for _, t := range i.state.Touches { - if !t.Valid { - continue - } touches = append(touches, t.ID) } return touches @@ -466,9 +463,6 @@ func (i *inputState) touchPosition(id TouchID) (int, int) { defer i.m.Unlock() for _, t := range i.state.Touches { - if !t.Valid { - continue - } if id != t.ID { continue } diff --git a/internal/ui/context.go b/internal/ui/context.go index 54e1f40bc..773935d43 100644 --- a/internal/ui/context.go +++ b/internal/ui/context.go @@ -36,7 +36,7 @@ type Game interface { NewOffscreenImage(width, height int) *Image NewScreenImage(width, height int) *Image Layout(outsideWidth, outsideHeight float64) (screenWidth, screenHeight float64) - UpdateInputState(InputState) + UpdateInputState(fn func(*InputState)) Update() error DrawOffscreen() error DrawFinalScreen(scale, offsetX, offsetY float64) @@ -128,9 +128,9 @@ func (c *context) updateFrameImpl(graphicsDriver graphicsdriver.Graphics, update // Update the game. for i := 0; i < updateCount; i++ { // Read the input state and use it for one tick to give a consistent result for one tick (#2496, #2501). - var inputState InputState - ui.readInputState(&inputState) - c.game.UpdateInputState(inputState) + c.game.UpdateInputState(func(inputState *InputState) { + ui.readInputState(inputState) + }) if err := hooks.RunBeforeUpdateHooks(); err != nil { return err diff --git a/internal/ui/input.go b/internal/ui/input.go index a7a439323..ef76cd65f 100644 --- a/internal/ui/input.go +++ b/internal/ui/input.go @@ -32,10 +32,9 @@ const ( type TouchID int type Touch struct { - Valid bool - ID TouchID - X int - Y int + ID TouchID + X int + Y int } type InputState struct { @@ -45,16 +44,28 @@ type InputState struct { CursorY int WheelX float64 WheelY float64 - Touches [16]Touch - Runes [16]rune - RunesCount int + Touches []Touch + Runes []rune WindowBeingClosed bool } -func (i *InputState) reset() { +func (i *InputState) copyAndReset(dst *InputState) { + dst.KeyPressed = i.KeyPressed + dst.MouseButtonPressed = i.MouseButtonPressed + dst.CursorX = i.CursorX + dst.CursorY = i.CursorY + dst.WheelX = i.WheelX + dst.WheelY = i.WheelY + dst.Touches = append(dst.Touches[:0], i.Touches...) + dst.Runes = append(dst.Runes[:0], i.Runes...) + dst.WindowBeingClosed = i.WindowBeingClosed + + // Reset the members that are updated by deltas, rather than absolute values. i.WheelX = 0 i.WheelY = 0 - i.RunesCount = 0 + i.Runes = i.Runes[:0] + + // Reset the member that is never reset until it is explicitly done. i.WindowBeingClosed = false } @@ -62,10 +73,5 @@ func (i *InputState) appendRune(r rune) { if !unicode.IsPrint(r) { return } - if i.RunesCount >= len(i.Runes) { - return - } - - i.Runes[i.RunesCount] = r - i.RunesCount++ + i.Runes = append(i.Runes, r) } diff --git a/internal/ui/input_js.go b/internal/ui/input_js.go index 223e7b589..eee27a246 100644 --- a/internal/ui/input_js.go +++ b/internal/ui/input_js.go @@ -123,20 +123,17 @@ func (u *userInterfaceImpl) recoverCursorPosition() { } func (u *userInterfaceImpl) updateTouchesFromEvent(e js.Value) { - for i := range u.inputState.Touches { - u.inputState.Touches[i].Valid = false - } + u.inputState.Touches = u.inputState.Touches[:0] touches := e.Get("targetTouches") for i := 0; i < touches.Length(); i++ { t := touches.Call("item", i) x, y := u.context.clientPositionToLogicalPosition(t.Get("clientX").Float(), t.Get("clientY").Float(), u.DeviceScaleFactor()) - u.inputState.Touches[i] = Touch{ - Valid: true, - ID: TouchID(t.Get("identifier").Int()), - X: int(x), - Y: int(y), - } + u.inputState.Touches = append(u.inputState.Touches, Touch{ + ID: TouchID(t.Get("identifier").Int()), + X: int(x), + Y: int(y), + }) } } diff --git a/internal/ui/input_mobile.go b/internal/ui/input_mobile.go index e3126547f..6a92d4dd0 100644 --- a/internal/ui/input_mobile.go +++ b/internal/ui/input_mobile.go @@ -35,20 +35,16 @@ func (u *userInterfaceImpl) updateInputState(keys map[Key]struct{}, runes []rune u.inputState.KeyPressed[k] = ok } - copy(u.inputState.Runes[:], runes) - u.inputState.RunesCount = len(runes) + u.inputState.Runes = append(u.inputState.Runes, runes...) - for i := range u.inputState.Touches { - u.inputState.Touches[i].Valid = false - } - for i, t := range touches { + u.inputState.Touches = u.inputState.Touches[:0] + for _, t := range touches { x, y := u.context.clientPositionToLogicalPosition(t.X, t.Y, u.DeviceScaleFactor()) - u.inputState.Touches[i] = Touch{ - Valid: true, - ID: t.ID, - X: int(x), - Y: int(y), - } + u.inputState.Touches = append(u.inputState.Touches, Touch{ + ID: t.ID, + X: int(x), + Y: int(y), + }) } } diff --git a/internal/ui/input_nintendosdk.go b/internal/ui/input_nintendosdk.go index 7c1824740..9e29e5967 100644 --- a/internal/ui/input_nintendosdk.go +++ b/internal/ui/input_nintendosdk.go @@ -38,17 +38,17 @@ func (u *userInterfaceImpl) updateInputState() { C.ebitengine_GetTouches(&u.nativeTouches[0]) } - for i := range u.inputState.Touches { - u.inputState.Touches[i].Valid = false - } - for i, t := range u.nativeTouches { + u.m.Lock() + defer u.m.Unlock() + + u.inputState.Touches = u.inputState.Touches[:0] + for _, t := range u.nativeTouches { x, y := u.context.clientPositionToLogicalPosition(float64(t.x), float64(t.y), deviceScaleFactor) - u.inputState.Touches[i] = Touch{ - Valid: true, - ID: TouchID(t.id), - X: int(x), - Y: int(y), - } + u.inputState.Touches = append(u.inputState.Touches, Touch{ + ID: TouchID(t.id), + X: int(x), + Y: int(y), + }) } } diff --git a/internal/ui/ui_glfw.go b/internal/ui/ui_glfw.go index 6c949b3b4..0d4e6fc7c 100644 --- a/internal/ui/ui_glfw.go +++ b/internal/ui/ui_glfw.go @@ -1341,8 +1341,7 @@ func monitorFromWindow(window *glfw.Window) *glfw.Monitor { func (u *userInterfaceImpl) readInputState(inputState *InputState) { u.m.Lock() defer u.m.Unlock() - *inputState = u.inputState - u.inputState.reset() + u.inputState.copyAndReset(inputState) } func (u *userInterfaceImpl) Window() Window { diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index 3291151df..76a635321 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -676,8 +676,7 @@ func (u *userInterfaceImpl) updateScreenSize() { } func (u *userInterfaceImpl) readInputState(inputState *InputState) { - *inputState = u.inputState - u.inputState.reset() + u.inputState.copyAndReset(inputState) u.keyboardLayoutMap = js.Value{} } diff --git a/internal/ui/ui_mobile.go b/internal/ui/ui_mobile.go index 848f123d1..998c1cfa0 100644 --- a/internal/ui/ui_mobile.go +++ b/internal/ui/ui_mobile.go @@ -421,8 +421,7 @@ func (u *userInterfaceImpl) DeviceScaleFactor() float64 { func (u *userInterfaceImpl) readInputState(inputState *InputState) { u.m.Lock() defer u.m.Unlock() - *inputState = u.inputState - u.inputState.reset() + u.inputState.copyAndReset(inputState) } func (u *userInterfaceImpl) Window() Window { diff --git a/internal/ui/ui_nintendosdk.go b/internal/ui/ui_nintendosdk.go index 8528f6f06..0555ff94f 100644 --- a/internal/ui/ui_nintendosdk.go +++ b/internal/ui/ui_nintendosdk.go @@ -23,6 +23,7 @@ import "C" import ( stdcontext "context" "runtime" + "sync" "golang.org/x/sync/errgroup" @@ -69,6 +70,8 @@ type userInterfaceImpl struct { mainThread *thread.OSThread renderThread *thread.OSThread + + m sync.Mutex } func (u *userInterfaceImpl) Run(game Game, options *RunOptions) error { @@ -149,8 +152,9 @@ func (*userInterfaceImpl) ScreenSizeInFullscreen() (int, int) { } func (u *userInterfaceImpl) readInputState(inputState *InputState) { - *inputState = u.inputState - u.inputState.reset() + u.m.Lock() + defer u.m.Unlock() + u.inputState.copyAndReset(inputState) } func (*userInterfaceImpl) CursorMode() CursorMode {