internal/ui: refactoring: allow slices in InputState

This commit is contained in:
Hajime Hoshi 2023-01-22 00:04:30 +09:00
parent d53803615a
commit b79f0394cc
11 changed files with 61 additions and 67 deletions

View File

@ -147,8 +147,8 @@ func (g *gameForUI) Layout(outsideWidth, outsideHeight float64) (float64, float6
return float64(sw), float64(sh) return float64(sw), float64(sh)
} }
func (g *gameForUI) UpdateInputState(inputState ui.InputState) { func (g *gameForUI) UpdateInputState(fn func(*ui.InputState)) {
theInputState.set(inputState) fn(&theInputState.state)
} }
func (g *gameForUI) Update() error { func (g *gameForUI) Update() error {

View File

@ -405,7 +405,7 @@ func (i *inputState) set(inputState ui.InputState) {
func (i *inputState) appendInputChars(runes []rune) []rune { func (i *inputState) appendInputChars(runes []rune) []rune {
i.m.Lock() i.m.Lock()
defer i.m.Unlock() 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 { func (i *inputState) isKeyPressed(key Key) bool {
@ -453,9 +453,6 @@ func (i *inputState) appendTouchIDs(touches []TouchID) []TouchID {
defer i.m.Unlock() defer i.m.Unlock()
for _, t := range i.state.Touches { for _, t := range i.state.Touches {
if !t.Valid {
continue
}
touches = append(touches, t.ID) touches = append(touches, t.ID)
} }
return touches return touches
@ -466,9 +463,6 @@ func (i *inputState) touchPosition(id TouchID) (int, int) {
defer i.m.Unlock() defer i.m.Unlock()
for _, t := range i.state.Touches { for _, t := range i.state.Touches {
if !t.Valid {
continue
}
if id != t.ID { if id != t.ID {
continue continue
} }

View File

@ -36,7 +36,7 @@ type Game interface {
NewOffscreenImage(width, height int) *Image NewOffscreenImage(width, height int) *Image
NewScreenImage(width, height int) *Image NewScreenImage(width, height int) *Image
Layout(outsideWidth, outsideHeight float64) (screenWidth, screenHeight float64) Layout(outsideWidth, outsideHeight float64) (screenWidth, screenHeight float64)
UpdateInputState(InputState) UpdateInputState(fn func(*InputState))
Update() error Update() error
DrawOffscreen() error DrawOffscreen() error
DrawFinalScreen(scale, offsetX, offsetY float64) DrawFinalScreen(scale, offsetX, offsetY float64)
@ -128,9 +128,9 @@ func (c *context) updateFrameImpl(graphicsDriver graphicsdriver.Graphics, update
// Update the game. // Update the game.
for i := 0; i < updateCount; i++ { 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). // Read the input state and use it for one tick to give a consistent result for one tick (#2496, #2501).
var inputState InputState c.game.UpdateInputState(func(inputState *InputState) {
ui.readInputState(&inputState) ui.readInputState(inputState)
c.game.UpdateInputState(inputState) })
if err := hooks.RunBeforeUpdateHooks(); err != nil { if err := hooks.RunBeforeUpdateHooks(); err != nil {
return err return err

View File

@ -32,10 +32,9 @@ const (
type TouchID int type TouchID int
type Touch struct { type Touch struct {
Valid bool ID TouchID
ID TouchID X int
X int Y int
Y int
} }
type InputState struct { type InputState struct {
@ -45,16 +44,28 @@ type InputState struct {
CursorY int CursorY int
WheelX float64 WheelX float64
WheelY float64 WheelY float64
Touches [16]Touch Touches []Touch
Runes [16]rune Runes []rune
RunesCount int
WindowBeingClosed bool 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.WheelX = 0
i.WheelY = 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 i.WindowBeingClosed = false
} }
@ -62,10 +73,5 @@ func (i *InputState) appendRune(r rune) {
if !unicode.IsPrint(r) { if !unicode.IsPrint(r) {
return return
} }
if i.RunesCount >= len(i.Runes) { i.Runes = append(i.Runes, r)
return
}
i.Runes[i.RunesCount] = r
i.RunesCount++
} }

View File

@ -123,20 +123,17 @@ func (u *userInterfaceImpl) recoverCursorPosition() {
} }
func (u *userInterfaceImpl) updateTouchesFromEvent(e js.Value) { func (u *userInterfaceImpl) updateTouchesFromEvent(e js.Value) {
for i := range u.inputState.Touches { u.inputState.Touches = u.inputState.Touches[:0]
u.inputState.Touches[i].Valid = false
}
touches := e.Get("targetTouches") touches := e.Get("targetTouches")
for i := 0; i < touches.Length(); i++ { for i := 0; i < touches.Length(); i++ {
t := touches.Call("item", i) t := touches.Call("item", i)
x, y := u.context.clientPositionToLogicalPosition(t.Get("clientX").Float(), t.Get("clientY").Float(), u.DeviceScaleFactor()) x, y := u.context.clientPositionToLogicalPosition(t.Get("clientX").Float(), t.Get("clientY").Float(), u.DeviceScaleFactor())
u.inputState.Touches[i] = Touch{ u.inputState.Touches = append(u.inputState.Touches, Touch{
Valid: true, ID: TouchID(t.Get("identifier").Int()),
ID: TouchID(t.Get("identifier").Int()), X: int(x),
X: int(x), Y: int(y),
Y: int(y), })
}
} }
} }

View File

@ -35,20 +35,16 @@ func (u *userInterfaceImpl) updateInputState(keys map[Key]struct{}, runes []rune
u.inputState.KeyPressed[k] = ok u.inputState.KeyPressed[k] = ok
} }
copy(u.inputState.Runes[:], runes) u.inputState.Runes = append(u.inputState.Runes, runes...)
u.inputState.RunesCount = len(runes)
for i := range u.inputState.Touches { u.inputState.Touches = u.inputState.Touches[:0]
u.inputState.Touches[i].Valid = false for _, t := range touches {
}
for i, t := range touches {
x, y := u.context.clientPositionToLogicalPosition(t.X, t.Y, u.DeviceScaleFactor()) x, y := u.context.clientPositionToLogicalPosition(t.X, t.Y, u.DeviceScaleFactor())
u.inputState.Touches[i] = Touch{ u.inputState.Touches = append(u.inputState.Touches, Touch{
Valid: true, ID: t.ID,
ID: t.ID, X: int(x),
X: int(x), Y: int(y),
Y: int(y), })
}
} }
} }

View File

@ -38,17 +38,17 @@ func (u *userInterfaceImpl) updateInputState() {
C.ebitengine_GetTouches(&u.nativeTouches[0]) C.ebitengine_GetTouches(&u.nativeTouches[0])
} }
for i := range u.inputState.Touches { u.m.Lock()
u.inputState.Touches[i].Valid = false defer u.m.Unlock()
}
for i, t := range u.nativeTouches { u.inputState.Touches = u.inputState.Touches[:0]
for _, t := range u.nativeTouches {
x, y := u.context.clientPositionToLogicalPosition(float64(t.x), float64(t.y), deviceScaleFactor) x, y := u.context.clientPositionToLogicalPosition(float64(t.x), float64(t.y), deviceScaleFactor)
u.inputState.Touches[i] = Touch{ u.inputState.Touches = append(u.inputState.Touches, Touch{
Valid: true, ID: TouchID(t.id),
ID: TouchID(t.id), X: int(x),
X: int(x), Y: int(y),
Y: int(y), })
}
} }
} }

View File

@ -1341,8 +1341,7 @@ func monitorFromWindow(window *glfw.Window) *glfw.Monitor {
func (u *userInterfaceImpl) readInputState(inputState *InputState) { func (u *userInterfaceImpl) readInputState(inputState *InputState) {
u.m.Lock() u.m.Lock()
defer u.m.Unlock() defer u.m.Unlock()
*inputState = u.inputState u.inputState.copyAndReset(inputState)
u.inputState.reset()
} }
func (u *userInterfaceImpl) Window() Window { func (u *userInterfaceImpl) Window() Window {

View File

@ -676,8 +676,7 @@ func (u *userInterfaceImpl) updateScreenSize() {
} }
func (u *userInterfaceImpl) readInputState(inputState *InputState) { func (u *userInterfaceImpl) readInputState(inputState *InputState) {
*inputState = u.inputState u.inputState.copyAndReset(inputState)
u.inputState.reset()
u.keyboardLayoutMap = js.Value{} u.keyboardLayoutMap = js.Value{}
} }

View File

@ -421,8 +421,7 @@ func (u *userInterfaceImpl) DeviceScaleFactor() float64 {
func (u *userInterfaceImpl) readInputState(inputState *InputState) { func (u *userInterfaceImpl) readInputState(inputState *InputState) {
u.m.Lock() u.m.Lock()
defer u.m.Unlock() defer u.m.Unlock()
*inputState = u.inputState u.inputState.copyAndReset(inputState)
u.inputState.reset()
} }
func (u *userInterfaceImpl) Window() Window { func (u *userInterfaceImpl) Window() Window {

View File

@ -23,6 +23,7 @@ import "C"
import ( import (
stdcontext "context" stdcontext "context"
"runtime" "runtime"
"sync"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
@ -69,6 +70,8 @@ type userInterfaceImpl struct {
mainThread *thread.OSThread mainThread *thread.OSThread
renderThread *thread.OSThread renderThread *thread.OSThread
m sync.Mutex
} }
func (u *userInterfaceImpl) Run(game Game, options *RunOptions) error { func (u *userInterfaceImpl) Run(game Game, options *RunOptions) error {
@ -149,8 +152,9 @@ func (*userInterfaceImpl) ScreenSizeInFullscreen() (int, int) {
} }
func (u *userInterfaceImpl) readInputState(inputState *InputState) { func (u *userInterfaceImpl) readInputState(inputState *InputState) {
*inputState = u.inputState u.m.Lock()
u.inputState.reset() defer u.m.Unlock()
u.inputState.copyAndReset(inputState)
} }
func (*userInterfaceImpl) CursorMode() CursorMode { func (*userInterfaceImpl) CursorMode() CursorMode {