mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-02-02 22:14:29 +01:00
examples/blocks: Bug fix: multiple gamepad detection
This commit is contained in:
parent
8ed02efd28
commit
d6e109555d
@ -47,6 +47,9 @@ type axis struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type gamepadConfig struct {
|
type gamepadConfig struct {
|
||||||
|
gamepadID int
|
||||||
|
gamepadIDInitialized bool
|
||||||
|
|
||||||
current virtualGamepadButton
|
current virtualGamepadButton
|
||||||
buttons map[virtualGamepadButton]ebiten.GamepadButton
|
buttons map[virtualGamepadButton]ebiten.GamepadButton
|
||||||
axes map[virtualGamepadButton]axis
|
axes map[virtualGamepadButton]axis
|
||||||
@ -56,7 +59,20 @@ type gamepadConfig struct {
|
|||||||
defaultAxesValues map[int]float64
|
defaultAxesValues map[int]float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *gamepadConfig) SetGamepadID(id int) {
|
||||||
|
c.gamepadID = id
|
||||||
|
c.gamepadIDInitialized = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *gamepadConfig) IsInitialized() bool {
|
||||||
|
return c.gamepadIDInitialized
|
||||||
|
}
|
||||||
|
|
||||||
func (c *gamepadConfig) initializeIfNeeded() {
|
func (c *gamepadConfig) initializeIfNeeded() {
|
||||||
|
if !c.gamepadIDInitialized {
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
|
|
||||||
if c.buttons == nil {
|
if c.buttons == nil {
|
||||||
c.buttons = map[virtualGamepadButton]ebiten.GamepadButton{}
|
c.buttons = map[virtualGamepadButton]ebiten.GamepadButton{}
|
||||||
}
|
}
|
||||||
@ -77,15 +93,17 @@ func (c *gamepadConfig) initializeIfNeeded() {
|
|||||||
// For example, on PS4 controllers, L2/R2's axes valuse can be -1.0.
|
// For example, on PS4 controllers, L2/R2's axes valuse can be -1.0.
|
||||||
if c.defaultAxesValues == nil {
|
if c.defaultAxesValues == nil {
|
||||||
c.defaultAxesValues = map[int]float64{}
|
c.defaultAxesValues = map[int]float64{}
|
||||||
const gamepadID = 0
|
na := ebiten.GamepadAxisNum(c.gamepadID)
|
||||||
na := ebiten.GamepadAxisNum(gamepadID)
|
|
||||||
for a := 0; a < na; a++ {
|
for a := 0; a < na; a++ {
|
||||||
c.defaultAxesValues[a] = ebiten.GamepadAxis(gamepadID, a)
|
c.defaultAxesValues[a] = ebiten.GamepadAxis(c.gamepadID, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *gamepadConfig) Reset() {
|
func (c *gamepadConfig) Reset() {
|
||||||
|
c.gamepadID = 0
|
||||||
|
c.gamepadIDInitialized = false
|
||||||
|
|
||||||
c.buttons = nil
|
c.buttons = nil
|
||||||
c.axes = nil
|
c.axes = nil
|
||||||
c.assignedButtons = nil
|
c.assignedButtons = nil
|
||||||
@ -94,37 +112,45 @@ func (c *gamepadConfig) Reset() {
|
|||||||
|
|
||||||
// Scan scans the current input state and assigns the given virtual gamepad button b
|
// Scan scans the current input state and assigns the given virtual gamepad button b
|
||||||
// to the current (pysical) pressed buttons of the gamepad.
|
// to the current (pysical) pressed buttons of the gamepad.
|
||||||
func (c *gamepadConfig) Scan(gamepadID int, b virtualGamepadButton) bool {
|
func (c *gamepadConfig) Scan(b virtualGamepadButton) bool {
|
||||||
|
if !c.gamepadIDInitialized {
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
|
|
||||||
c.initializeIfNeeded()
|
c.initializeIfNeeded()
|
||||||
|
|
||||||
delete(c.buttons, b)
|
delete(c.buttons, b)
|
||||||
delete(c.axes, b)
|
delete(c.axes, b)
|
||||||
|
|
||||||
ebn := ebiten.GamepadButton(ebiten.GamepadButtonNum(gamepadID))
|
ebn := ebiten.GamepadButton(ebiten.GamepadButtonNum(c.gamepadID))
|
||||||
for eb := ebiten.GamepadButton(0); eb < ebn; eb++ {
|
for eb := ebiten.GamepadButton(0); eb < ebn; eb++ {
|
||||||
if _, ok := c.assignedButtons[eb]; ok {
|
if _, ok := c.assignedButtons[eb]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if inpututil.IsGamepadButtonJustPressed(gamepadID, eb) {
|
if inpututil.IsGamepadButtonJustPressed(c.gamepadID, eb) {
|
||||||
c.buttons[b] = eb
|
c.buttons[b] = eb
|
||||||
c.assignedButtons[eb] = struct{}{}
|
c.assignedButtons[eb] = struct{}{}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
na := ebiten.GamepadAxisNum(gamepadID)
|
na := ebiten.GamepadAxisNum(c.gamepadID)
|
||||||
for a := 0; a < na; a++ {
|
for a := 0; a < na; a++ {
|
||||||
v := ebiten.GamepadAxis(gamepadID, a)
|
v := ebiten.GamepadAxis(c.gamepadID, a)
|
||||||
|
const delta = 0.25
|
||||||
|
|
||||||
// Check |v| < 1.0 because there is a bug that a button returns
|
// Check |v| < 1.0 because there is a bug that a button returns
|
||||||
// an axis value wrongly and the value may be over 1 on some platforms.
|
// an axis value wrongly and the value may be over 1 on some platforms.
|
||||||
if axisThreshold <= v && v <= 1.0 && v != c.defaultAxesValues[a] {
|
if axisThreshold <= v && v <= 1.0 &&
|
||||||
|
(v < c.defaultAxesValues[a]-delta || c.defaultAxesValues[a]+delta < v) {
|
||||||
if _, ok := c.assignedAxes[axis{a, true}]; !ok {
|
if _, ok := c.assignedAxes[axis{a, true}]; !ok {
|
||||||
c.axes[b] = axis{a, true}
|
c.axes[b] = axis{a, true}
|
||||||
c.assignedAxes[axis{a, true}] = struct{}{}
|
c.assignedAxes[axis{a, true}] = struct{}{}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if -1.0 <= v && v <= -axisThreshold && v != c.defaultAxesValues[a] {
|
if -1.0 <= v && v <= -axisThreshold &&
|
||||||
|
(v < c.defaultAxesValues[a]-delta || c.defaultAxesValues[a]+delta < v) {
|
||||||
if _, ok := c.assignedAxes[axis{a, false}]; !ok {
|
if _, ok := c.assignedAxes[axis{a, false}]; !ok {
|
||||||
c.axes[b] = axis{a, false}
|
c.axes[b] = axis{a, false}
|
||||||
c.assignedAxes[axis{a, false}] = struct{}{}
|
c.assignedAxes[axis{a, false}] = struct{}{}
|
||||||
@ -139,16 +165,20 @@ func (c *gamepadConfig) Scan(gamepadID int, b virtualGamepadButton) bool {
|
|||||||
// IsButtonPressed returns a boolean value indicating whether
|
// IsButtonPressed returns a boolean value indicating whether
|
||||||
// the given virtual button b is pressed.
|
// the given virtual button b is pressed.
|
||||||
func (c *gamepadConfig) IsButtonPressed(b virtualGamepadButton) bool {
|
func (c *gamepadConfig) IsButtonPressed(b virtualGamepadButton) bool {
|
||||||
|
if !c.gamepadIDInitialized {
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
|
|
||||||
c.initializeIfNeeded()
|
c.initializeIfNeeded()
|
||||||
|
|
||||||
bb, ok := c.buttons[b]
|
bb, ok := c.buttons[b]
|
||||||
if ok {
|
if ok {
|
||||||
return ebiten.IsGamepadButtonPressed(0, bb)
|
return ebiten.IsGamepadButtonPressed(c.gamepadID, bb)
|
||||||
}
|
}
|
||||||
|
|
||||||
a, ok := c.axes[b]
|
a, ok := c.axes[b]
|
||||||
if ok {
|
if ok {
|
||||||
v := ebiten.GamepadAxis(0, a.id)
|
v := ebiten.GamepadAxis(c.gamepadID, a.id)
|
||||||
if a.positive {
|
if a.positive {
|
||||||
return axisThreshold <= v && v <= 1.0
|
return axisThreshold <= v && v <= 1.0
|
||||||
} else {
|
} else {
|
||||||
@ -160,6 +190,10 @@ func (c *gamepadConfig) IsButtonPressed(b virtualGamepadButton) bool {
|
|||||||
|
|
||||||
// Name returns the pysical button's name for the given virtual button.
|
// Name returns the pysical button's name for the given virtual button.
|
||||||
func (c *gamepadConfig) ButtonName(b virtualGamepadButton) string {
|
func (c *gamepadConfig) ButtonName(b virtualGamepadButton) string {
|
||||||
|
if !c.gamepadIDInitialized {
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
|
|
||||||
c.initializeIfNeeded()
|
c.initializeIfNeeded()
|
||||||
|
|
||||||
bb, ok := c.buttons[b]
|
bb, ok := c.buttons[b]
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GamepadScene struct {
|
type GamepadScene struct {
|
||||||
|
gamepadID int
|
||||||
currentIndex int
|
currentIndex int
|
||||||
countAfterSetting int
|
countAfterSetting int
|
||||||
buttonStates []string
|
buttonStates []string
|
||||||
@ -32,6 +33,7 @@ type GamepadScene struct {
|
|||||||
func (s *GamepadScene) Update(state *GameState) error {
|
func (s *GamepadScene) Update(state *GameState) error {
|
||||||
if s.currentIndex == 0 {
|
if s.currentIndex == 0 {
|
||||||
state.Input.gamepadConfig.Reset()
|
state.Input.gamepadConfig.Reset()
|
||||||
|
state.Input.gamepadConfig.SetGamepadID(s.gamepadID)
|
||||||
}
|
}
|
||||||
if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
|
if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
|
||||||
state.Input.gamepadConfig.Reset()
|
state.Input.gamepadConfig.Reset()
|
||||||
@ -62,8 +64,7 @@ func (s *GamepadScene) Update(state *GameState) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b := virtualGamepadButtons[s.currentIndex]
|
b := virtualGamepadButtons[s.currentIndex]
|
||||||
const gamepadID = 0
|
if state.Input.gamepadConfig.Scan(b) {
|
||||||
if state.Input.gamepadConfig.Scan(gamepadID, b) {
|
|
||||||
s.currentIndex++
|
s.currentIndex++
|
||||||
if s.currentIndex == len(virtualGamepadButtons) {
|
if s.currentIndex == len(virtualGamepadButtons) {
|
||||||
s.countAfterSetting = ebiten.MaxTPS()
|
s.countAfterSetting = ebiten.MaxTPS()
|
||||||
|
@ -25,16 +25,17 @@ type Input struct {
|
|||||||
gamepadConfig gamepadConfig
|
gamepadConfig gamepadConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAnyGamepadButtonPressed returns a boolean value indicating
|
// GamepadIDButtonPressed returns a gamepad ID where at least one button is pressed.
|
||||||
// whether any gamepad button is pressed.
|
// If no button is pressed, GamepadIDButtonPressed returns -1.
|
||||||
func (i *Input) IsAnyGamepadButtonPressed() bool {
|
func (i *Input) GamepadIDButtonPressed() int {
|
||||||
const gamepadID = 0
|
for _, id := range ebiten.GamepadIDs() {
|
||||||
for b := ebiten.GamepadButton(0); b <= ebiten.GamepadButtonMax; b++ {
|
for b := ebiten.GamepadButton(0); b <= ebiten.GamepadButtonMax; b++ {
|
||||||
if ebiten.IsGamepadButtonPressed(gamepadID, b) {
|
if ebiten.IsGamepadButtonPressed(id, b) {
|
||||||
return true
|
return id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
}
|
||||||
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Input) stateForVirtualGamepadButton(b virtualGamepadButton) int {
|
func (i *Input) stateForVirtualGamepadButton(b virtualGamepadButton) int {
|
||||||
@ -45,6 +46,10 @@ func (i *Input) stateForVirtualGamepadButton(b virtualGamepadButton) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Input) Update() {
|
func (i *Input) Update() {
|
||||||
|
if !i.gamepadConfig.IsInitialized() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if i.virtualGamepadButtonStates == nil {
|
if i.virtualGamepadButtonStates == nil {
|
||||||
i.virtualGamepadButtonStates = map[virtualGamepadButton]int{}
|
i.virtualGamepadButtonStates = map[virtualGamepadButton]int{}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,10 @@ type TitleScene struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func anyGamepadAbstractButtonPressed(i *Input) bool {
|
func anyGamepadAbstractButtonPressed(i *Input) bool {
|
||||||
|
if !i.gamepadConfig.IsInitialized() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for _, b := range virtualGamepadButtons {
|
for _, b := range virtualGamepadButtons {
|
||||||
if i.gamepadConfig.IsButtonPressed(b) {
|
if i.gamepadConfig.IsButtonPressed(b) {
|
||||||
return true
|
return true
|
||||||
@ -54,6 +58,7 @@ func (s *TitleScene) Update(state *GameState) error {
|
|||||||
state.SceneManager.GoTo(NewGameScene())
|
state.SceneManager.GoTo(NewGameScene())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if anyGamepadAbstractButtonPressed(state.Input) {
|
if anyGamepadAbstractButtonPressed(state.Input) {
|
||||||
state.SceneManager.GoTo(NewGameScene())
|
state.SceneManager.GoTo(NewGameScene())
|
||||||
return nil
|
return nil
|
||||||
@ -61,8 +66,10 @@ func (s *TitleScene) Update(state *GameState) error {
|
|||||||
|
|
||||||
// If 'abstract' gamepad buttons are not set and any gamepad buttons are pressed,
|
// If 'abstract' gamepad buttons are not set and any gamepad buttons are pressed,
|
||||||
// go to the gamepad configuration scene.
|
// go to the gamepad configuration scene.
|
||||||
if state.Input.IsAnyGamepadButtonPressed() {
|
if id := state.Input.GamepadIDButtonPressed(); id >= 0 {
|
||||||
state.SceneManager.GoTo(&GamepadScene{})
|
g := &GamepadScene{}
|
||||||
|
g.gamepadID = id
|
||||||
|
state.SceneManager.GoTo(g)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
Loading…
Reference in New Issue
Block a user