mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-01-12 20:18:59 +01:00
ebiten: Add AppendInputChars, AppendGamepadIDs, and AppendTouchIDs
These functions reduce unnecessary allocations of arrays. Closes #1692
This commit is contained in:
parent
99a6b1b03e
commit
431cd33839
@ -83,6 +83,7 @@ type Input struct {
|
||||
mouseInitPosY int
|
||||
mouseDir Dir
|
||||
|
||||
touches []ebiten.TouchID
|
||||
touchState touchState
|
||||
touchID ebiten.TouchID
|
||||
touchInitPosX int
|
||||
@ -147,12 +148,13 @@ func (i *Input) Update() {
|
||||
case mouseStateSettled:
|
||||
i.mouseState = mouseStateNone
|
||||
}
|
||||
|
||||
i.touches = ebiten.AppendTouchIDs(i.touches[:0])
|
||||
switch i.touchState {
|
||||
case touchStateNone:
|
||||
ts := ebiten.TouchIDs()
|
||||
if len(ts) == 1 {
|
||||
i.touchID = ts[0]
|
||||
x, y := ebiten.TouchPosition(ts[0])
|
||||
if len(i.touches) == 1 {
|
||||
i.touchID = i.touches[0]
|
||||
x, y := ebiten.TouchPosition(i.touches[0])
|
||||
i.touchInitPosX = x
|
||||
i.touchInitPosY = y
|
||||
i.touchLastPosX = x
|
||||
@ -160,21 +162,20 @@ func (i *Input) Update() {
|
||||
i.touchState = touchStatePressing
|
||||
}
|
||||
case touchStatePressing:
|
||||
ts := ebiten.TouchIDs()
|
||||
if len(ts) >= 2 {
|
||||
if len(i.touches) >= 2 {
|
||||
break
|
||||
}
|
||||
if len(ts) == 1 {
|
||||
if ts[0] != i.touchID {
|
||||
if len(i.touches) == 1 {
|
||||
if i.touches[0] != i.touchID {
|
||||
i.touchState = touchStateInvalid
|
||||
} else {
|
||||
x, y := ebiten.TouchPosition(ts[0])
|
||||
x, y := ebiten.TouchPosition(i.touches[0])
|
||||
i.touchLastPosX = x
|
||||
i.touchLastPosY = y
|
||||
}
|
||||
break
|
||||
}
|
||||
if len(ts) == 0 {
|
||||
if len(i.touches) == 0 {
|
||||
dx := i.touchLastPosX - i.touchInitPosX
|
||||
dy := i.touchLastPosY - i.touchInitPosY
|
||||
d, ok := vecToDir(dx, dy)
|
||||
@ -188,7 +189,7 @@ func (i *Input) Update() {
|
||||
case touchStateSettled:
|
||||
i.touchState = touchStateNone
|
||||
case touchStateInvalid:
|
||||
if len(ebiten.TouchIDs()) == 0 {
|
||||
if len(i.touches) == 0 {
|
||||
i.touchState = touchStateNone
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
|
||||
// Input manages the input state including gamepads and keyboards.
|
||||
type Input struct {
|
||||
gamepadIDs []ebiten.GamepadID
|
||||
virtualGamepadButtonStates map[virtualGamepadButton]int
|
||||
gamepadConfig gamepadConfig
|
||||
}
|
||||
@ -28,7 +29,8 @@ type Input struct {
|
||||
// GamepadIDButtonPressed returns a gamepad ID where at least one button is pressed.
|
||||
// If no button is pressed, GamepadIDButtonPressed returns -1.
|
||||
func (i *Input) GamepadIDButtonPressed() ebiten.GamepadID {
|
||||
for _, id := range ebiten.GamepadIDs() {
|
||||
i.gamepadIDs = ebiten.AppendGamepadIDs(i.gamepadIDs[:0])
|
||||
for _, id := range i.gamepadIDs {
|
||||
for b := ebiten.GamepadButton(0); b <= ebiten.GamepadButtonMax; b++ {
|
||||
if ebiten.IsGamepadButtonPressed(id, b) {
|
||||
return id
|
||||
|
@ -176,6 +176,8 @@ type Game struct {
|
||||
pipeTileYs []int
|
||||
|
||||
gameoverCount int
|
||||
|
||||
gamepadIDs []ebiten.GamepadID
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
@ -204,7 +206,7 @@ func isAnyKeyJustPressed() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func jump() bool {
|
||||
func (g *Game) jump() bool {
|
||||
if isAnyKeyJustPressed() {
|
||||
return true
|
||||
}
|
||||
@ -214,7 +216,8 @@ func jump() bool {
|
||||
if len(inpututil.JustPressedTouchIDs()) > 0 {
|
||||
return true
|
||||
}
|
||||
for _, g := range ebiten.GamepadIDs() {
|
||||
g.gamepadIDs = ebiten.AppendGamepadIDs(g.gamepadIDs[:0])
|
||||
for _, g := range g.gamepadIDs {
|
||||
for i := 0; i < ebiten.GamepadButtonNum(g); i++ {
|
||||
if inpututil.IsGamepadButtonJustPressed(g, ebiten.GamepadButton(i)) {
|
||||
return true
|
||||
@ -231,13 +234,13 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
func (g *Game) Update() error {
|
||||
switch g.mode {
|
||||
case ModeTitle:
|
||||
if jump() {
|
||||
if g.jump() {
|
||||
g.mode = ModeGame
|
||||
}
|
||||
case ModeGame:
|
||||
g.x16 += 32
|
||||
g.cameraX += 2
|
||||
if jump() {
|
||||
if g.jump() {
|
||||
g.vy16 = -96
|
||||
jumpPlayer.Rewind()
|
||||
jumpPlayer.Play()
|
||||
@ -260,7 +263,7 @@ func (g *Game) Update() error {
|
||||
if g.gameoverCount > 0 {
|
||||
g.gameoverCount--
|
||||
}
|
||||
if g.gameoverCount == 0 && jump() {
|
||||
if g.gameoverCount == 0 && g.jump() {
|
||||
g.init()
|
||||
g.mode = ModeTitle
|
||||
}
|
||||
|
@ -60,7 +60,8 @@ func init() {
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
count int
|
||||
touches []ebiten.TouchID
|
||||
count int
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -74,7 +75,8 @@ func (g *Game) Update() error {
|
||||
}
|
||||
|
||||
// Paint the brush by touches
|
||||
for _, t := range ebiten.TouchIDs() {
|
||||
g.touches = ebiten.AppendTouchIDs(g.touches[:0])
|
||||
for _, t := range g.touches {
|
||||
x, y := ebiten.TouchPosition(t)
|
||||
g.paint(canvasImage, x, y)
|
||||
drawn = true
|
||||
@ -102,7 +104,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
||||
|
||||
mx, my := ebiten.CursorPosition()
|
||||
msg := fmt.Sprintf("(%d, %d)", mx, my)
|
||||
for _, t := range ebiten.TouchIDs() {
|
||||
for _, t := range g.touches {
|
||||
x, y := ebiten.TouchPosition(t)
|
||||
msg += fmt.Sprintf("\n(%d, %d) touch %d", x, y, t)
|
||||
}
|
||||
|
@ -115,9 +115,10 @@ const (
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
sprites Sprites
|
||||
op ebiten.DrawImageOptions
|
||||
inited bool
|
||||
touchIDs []ebiten.TouchID
|
||||
sprites Sprites
|
||||
op ebiten.DrawImageOptions
|
||||
inited bool
|
||||
}
|
||||
|
||||
func (g *Game) init() {
|
||||
@ -144,8 +145,8 @@ func (g *Game) init() {
|
||||
}
|
||||
}
|
||||
|
||||
func leftTouched() bool {
|
||||
for _, id := range ebiten.TouchIDs() {
|
||||
func (g *Game) leftTouched() bool {
|
||||
for _, id := range g.touchIDs {
|
||||
x, _ := ebiten.TouchPosition(id)
|
||||
if x < screenWidth/2 {
|
||||
return true
|
||||
@ -154,8 +155,8 @@ func leftTouched() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func rightTouched() bool {
|
||||
for _, id := range ebiten.TouchIDs() {
|
||||
func (g *Game) rightTouched() bool {
|
||||
for _, id := range g.touchIDs {
|
||||
x, _ := ebiten.TouchPosition(id)
|
||||
if x >= screenWidth/2 {
|
||||
return true
|
||||
@ -168,9 +169,10 @@ func (g *Game) Update() error {
|
||||
if !g.inited {
|
||||
g.init()
|
||||
}
|
||||
g.touchIDs = ebiten.AppendTouchIDs(g.touchIDs[:0])
|
||||
|
||||
// Decrease the number of the sprites.
|
||||
if ebiten.IsKeyPressed(ebiten.KeyArrowLeft) || leftTouched() {
|
||||
if ebiten.IsKeyPressed(ebiten.KeyArrowLeft) || g.leftTouched() {
|
||||
g.sprites.num -= 20
|
||||
if g.sprites.num < MinSprites {
|
||||
g.sprites.num = MinSprites
|
||||
@ -178,7 +180,7 @@ func (g *Game) Update() error {
|
||||
}
|
||||
|
||||
// Increase the number of the sprites.
|
||||
if ebiten.IsKeyPressed(ebiten.KeyArrowRight) || rightTouched() {
|
||||
if ebiten.IsKeyPressed(ebiten.KeyArrowRight) || g.rightTouched() {
|
||||
g.sprites.num += 20
|
||||
if MaxSprites < g.sprites.num {
|
||||
g.sprites.num = MaxSprites
|
||||
|
@ -74,10 +74,11 @@ type Game struct {
|
||||
x, y float64
|
||||
zoom float64
|
||||
|
||||
touches map[ebiten.TouchID]*touch
|
||||
pinch *pinch
|
||||
pan *pan
|
||||
taps []tap
|
||||
touchIDs []ebiten.TouchID
|
||||
touches map[ebiten.TouchID]*touch
|
||||
pinch *pinch
|
||||
pan *pan
|
||||
taps []tap
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -111,15 +112,17 @@ func (g *Game) Update() error {
|
||||
// What touches are new in this frame?
|
||||
for _, id := range inpututil.JustPressedTouchIDs() {
|
||||
x, y := ebiten.TouchPosition(id)
|
||||
g.touches[ebiten.TouchID(id)] = &touch{
|
||||
g.touches[id] = &touch{
|
||||
originX: x, originY: y,
|
||||
currX: x, currY: y,
|
||||
}
|
||||
}
|
||||
|
||||
g.touchIDs = ebiten.AppendTouchIDs(g.touchIDs[:0])
|
||||
|
||||
// Update the current position and durations of any touches that have
|
||||
// neither begun nor ended in this frame.
|
||||
for _, id := range ebiten.TouchIDs() {
|
||||
for _, id := range g.touchIDs {
|
||||
t := g.touches[id]
|
||||
t.duration = inpututil.TouchPressDuration(id)
|
||||
t.currX, t.currY = ebiten.TouchPosition(id)
|
||||
@ -133,7 +136,7 @@ func (g *Game) Update() error {
|
||||
// If the diff between their origins is different to the diff between
|
||||
// their currents and if these two are not already a pinch, then this is
|
||||
// a new pinch!
|
||||
id1, id2 := ebiten.TouchIDs()[0], ebiten.TouchIDs()[1]
|
||||
id1, id2 := g.touchIDs[0], g.touchIDs[1]
|
||||
t1, t2 := g.touches[id1], g.touches[id2]
|
||||
originDiff := distance(t1.originX, t1.originY, t2.originX, t2.originY)
|
||||
currDiff := distance(t1.currX, t1.currY, t2.currX, t2.currY)
|
||||
@ -149,7 +152,7 @@ func (g *Game) Update() error {
|
||||
}
|
||||
case 1:
|
||||
// Potentially this is a new pan.
|
||||
id := ebiten.TouchIDs()[0]
|
||||
id := g.touchIDs[0]
|
||||
t := g.touches[id]
|
||||
if !t.wasPinch && g.pan == nil && g.pinch == nil {
|
||||
diff := math.Abs(distance(t.originX, t.originY, t.currX, t.currY))
|
||||
|
@ -48,15 +48,17 @@ func repeatingKeyPressed(key ebiten.Key) bool {
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
runes []rune
|
||||
text string
|
||||
counter int
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
// Add a string from InputChars, that returns string input by users.
|
||||
// Note that InputChars result changes every frame, so you need to call this
|
||||
// Add a string by AppendInputChars, that appends runes input by users.
|
||||
// Note that AppendInputChars result changes every frame, so you need to call this
|
||||
// every frame.
|
||||
g.text += string(ebiten.InputChars())
|
||||
g.runes = ebiten.AppendInputChars(g.runes[:0])
|
||||
g.text += string(g.runes)
|
||||
|
||||
// Adjust the string to be at most 10 lines.
|
||||
ss := strings.Split(g.text, "\n")
|
||||
|
51
input.go
51
input.go
@ -18,21 +18,30 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
)
|
||||
|
||||
// InputChars return "printable" runes read from the keyboard at the time update is called.
|
||||
// AppendInputChars appends "printable" runes, read from the keyboard at the time update is called, to runes,
|
||||
// and returns the extended buffer.
|
||||
// Giving a slice that already has enough capacity works efficiently.
|
||||
//
|
||||
// InputChars represents the environment's locale-dependent translation of keyboard
|
||||
// AppendInputChars represents the environment's locale-dependent translation of keyboard
|
||||
// input to Unicode characters.
|
||||
//
|
||||
// IsKeyPressed is based on a mapping of device (US keyboard) codes to input device keys.
|
||||
// "Control" and modifier keys should be handled with IsKeyPressed.
|
||||
//
|
||||
// InputChars is concurrent-safe.
|
||||
// AppendInputChars is concurrent-safe.
|
||||
//
|
||||
// On Android (ebitenmobile), EbitenView must be focusable to enable to handle keyboard keys.
|
||||
//
|
||||
// Keyboards don't work on iOS yet (#1090).
|
||||
func AppendInputChars(runes []rune) []rune {
|
||||
return uiDriver().Input().AppendInputChars(runes)
|
||||
}
|
||||
|
||||
// InputChars return "printable" runes read from the keyboard at the time update is called.
|
||||
//
|
||||
// Deprecated: as of v2.2.0. Use AppendInputChars instead.
|
||||
func InputChars() []rune {
|
||||
return uiDriver().Input().AppendInputChars(nil)
|
||||
return AppendInputChars(nil)
|
||||
}
|
||||
|
||||
// IsKeyPressed returns a boolean indicating whether key is pressed.
|
||||
@ -134,13 +143,21 @@ func GamepadName(id GamepadID) string {
|
||||
return uiDriver().Input().GamepadName(id)
|
||||
}
|
||||
|
||||
// AppendGamepadIDs appends available gamepad IDs to gamepadIDs, and returns the extended buffer.
|
||||
// Giving a slice that already has enough capacity works efficiently.
|
||||
//
|
||||
// AppendGamepadIDs is concurrent-safe.
|
||||
//
|
||||
// AppendGamepadIDs doesn't append anything on iOS.
|
||||
func AppendGamepadIDs(gamepadIDs []GamepadID) []GamepadID {
|
||||
return uiDriver().Input().AppendGamepadIDs(gamepadIDs)
|
||||
}
|
||||
|
||||
// GamepadIDs returns a slice indicating available gamepad IDs.
|
||||
//
|
||||
// GamepadIDs is concurrent-safe.
|
||||
//
|
||||
// GamepadIDs always returns an empty slice on iOS.
|
||||
// Deprecated: as of v2.2.0. Use AppendGamepadIDs instead.
|
||||
func GamepadIDs() []GamepadID {
|
||||
return uiDriver().Input().AppendGamepadIDs(nil)
|
||||
return AppendGamepadIDs(nil)
|
||||
}
|
||||
|
||||
// GamepadAxisNum returns the number of axes of the gamepad (id).
|
||||
@ -188,17 +205,25 @@ func IsGamepadButtonPressed(id GamepadID, button GamepadButton) bool {
|
||||
// TouchID represents a touch's identifier.
|
||||
type TouchID = driver.TouchID
|
||||
|
||||
// TouchIDs returns the current touch states.
|
||||
// AppendTouchIDs appends the current touch states to touches, and returns the extended buffer.
|
||||
// Giving a slice that already has enough capacity works efficiently.
|
||||
//
|
||||
// If you want to know whether a touch started being pressed in the current frame,
|
||||
// use inpututil.JustPressedTouchIDs
|
||||
//
|
||||
// TouchIDs returns nil when there are no touches.
|
||||
// TouchIDs always returns nil on desktops.
|
||||
// AppendTouchIDs doesn't append anything when there are no touches.
|
||||
// AppendTouchIDs always does nothing on desktops.
|
||||
//
|
||||
// TouchIDs is concurrent-safe.
|
||||
// AppendTouchIDs is concurrent-safe.
|
||||
func AppendTouchIDs(touches []TouchID) []TouchID {
|
||||
return uiDriver().Input().AppendTouchIDs(touches)
|
||||
}
|
||||
|
||||
// TouchIDs returns the current touch states.
|
||||
//
|
||||
// Deperecated: as of v2.2.0. Use AppendTouchIDs instead.
|
||||
func TouchIDs() []TouchID {
|
||||
return uiDriver().Input().AppendTouchIDs(nil)
|
||||
return AppendTouchIDs(nil)
|
||||
}
|
||||
|
||||
// TouchPosition returns the position for the touch of the specified ID.
|
||||
|
@ -40,6 +40,9 @@ type inputState struct {
|
||||
touchDurations map[ebiten.TouchID]int
|
||||
prevTouchDurations map[ebiten.TouchID]int
|
||||
|
||||
gamepadIDsBuf []ebiten.GamepadID
|
||||
touchIDsBuf []ebiten.TouchID
|
||||
|
||||
m sync.RWMutex
|
||||
}
|
||||
|
||||
@ -117,7 +120,8 @@ func (i *inputState) update() {
|
||||
for id := range i.gamepadIDs {
|
||||
delete(i.gamepadIDs, id)
|
||||
}
|
||||
for _, id := range ebiten.GamepadIDs() {
|
||||
i.gamepadIDsBuf = ebiten.AppendGamepadIDs(i.gamepadIDsBuf[:0])
|
||||
for _, id := range i.gamepadIDsBuf {
|
||||
i.gamepadIDs[id] = struct{}{}
|
||||
if _, ok := i.gamepadButtonDurations[id]; !ok {
|
||||
i.gamepadButtonDurations[id] = make([]int, ebiten.GamepadButtonMax+1)
|
||||
@ -150,7 +154,8 @@ func (i *inputState) update() {
|
||||
for id := range i.touchIDs {
|
||||
delete(i.touchIDs, id)
|
||||
}
|
||||
for _, id := range ebiten.TouchIDs() {
|
||||
i.touchIDsBuf = ebiten.AppendTouchIDs(i.touchIDsBuf[:0])
|
||||
for _, id := range i.touchIDsBuf {
|
||||
i.touchIDs[id] = struct{}{}
|
||||
i.touchDurations[id]++
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user