ebiten: Add StandardGamepadButtonValue

Closes #1721
This commit is contained in:
Hajime Hoshi 2021-09-12 20:13:23 +09:00
parent 7422a3353a
commit ea12ede127
7 changed files with 116 additions and 101 deletions

View File

@ -98,99 +98,44 @@ func (g *Game) Update() error {
return nil return nil
} }
func standardMap(id ebiten.GamepadID) string { var standardButtonToString = map[ebiten.StandardGamepadButton]string{
m := ` [FBL] [FBR] ebiten.StandardGamepadButtonRightBottom: "RB",
[FTL] [FTR] ebiten.StandardGamepadButtonRightRight: "RR",
ebiten.StandardGamepadButtonRightLeft: "RL",
ebiten.StandardGamepadButtonRightTop: "RT",
ebiten.StandardGamepadButtonFrontTopLeft: "FTL",
ebiten.StandardGamepadButtonFrontTopRight: "FTR",
ebiten.StandardGamepadButtonFrontBottomLeft: "FBL",
ebiten.StandardGamepadButtonFrontBottomRight: "FBR",
ebiten.StandardGamepadButtonCenterLeft: "CL",
ebiten.StandardGamepadButtonCenterRight: "CR",
ebiten.StandardGamepadButtonLeftStick: "LS",
ebiten.StandardGamepadButtonRightStick: "RS",
ebiten.StandardGamepadButtonLeftBottom: "LB",
ebiten.StandardGamepadButtonLeftRight: "LR",
ebiten.StandardGamepadButtonLeftLeft: "LL",
ebiten.StandardGamepadButtonLeftTop: "LT",
ebiten.StandardGamepadButtonCenterCenter: "CC",
}
[LT] [CC] [RT] func standardMap(id ebiten.GamepadID) string {
[LL][LR] [CL][CR] [RL][RR] m := ` [FBL ] [FBR ]
[LB] [RB] [FTL ] [FTR ]
(LS) (RS)
[LT ] [CC ] [RT ]
[LL ][LR ] [CL ][CR ] [RL ][RR ]
[LB ] [RB ]
[LS ] [RS ]
` `
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonRightBottom) {
m = strings.Replace(m, "[RB]", "[**]", 1) for b, str := range standardButtonToString {
} else { placeholder := "[" + str + strings.Repeat(" ", 4-len(str)) + "]"
m = strings.Replace(m, "[RB]", "[ ]", 1) v := ebiten.StandardGamepadButtonValue(id, b)
} if ebiten.IsStandardGamepadButtonPressed(id, b) {
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonRightRight) { m = strings.Replace(m, placeholder, fmt.Sprintf("[%0.2f]", v), 1)
m = strings.Replace(m, "[RR]", "[**]", 1) } else {
} else { m = strings.Replace(m, placeholder, fmt.Sprintf(" %0.2f ", v), 1)
m = strings.Replace(m, "[RR]", "[ ]", 1) }
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonRightLeft) {
m = strings.Replace(m, "[RL]", "[**]", 1)
} else {
m = strings.Replace(m, "[RL]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonRightTop) {
m = strings.Replace(m, "[RT]", "[**]", 1)
} else {
m = strings.Replace(m, "[RT]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonFrontTopLeft) {
m = strings.Replace(m, "[FTL]", "[**]", 1)
} else {
m = strings.Replace(m, "[FTL]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonFrontTopRight) {
m = strings.Replace(m, "[FTR]", "[**]", 1)
} else {
m = strings.Replace(m, "[FTR]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonFrontBottomLeft) {
m = strings.Replace(m, "[FBL]", "[**]", 1)
} else {
m = strings.Replace(m, "[FBL]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonFrontBottomRight) {
m = strings.Replace(m, "[FBR]", "[**]", 1)
} else {
m = strings.Replace(m, "[FBR]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonCenterLeft) {
m = strings.Replace(m, "[CL]", "[**]", 1)
} else {
m = strings.Replace(m, "[CL]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonCenterRight) {
m = strings.Replace(m, "[CR]", "[**]", 1)
} else {
m = strings.Replace(m, "[CR]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftStick) {
m = strings.Replace(m, "(LS)", "[**]", 1)
} else {
m = strings.Replace(m, "(LS)", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonRightStick) {
m = strings.Replace(m, "(RS)", "[**]", 1)
} else {
m = strings.Replace(m, "(RS)", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftBottom) {
m = strings.Replace(m, "[LB]", "[**]", 1)
} else {
m = strings.Replace(m, "[LB]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftRight) {
m = strings.Replace(m, "[LR]", "[**]", 1)
} else {
m = strings.Replace(m, "[LR]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftLeft) {
m = strings.Replace(m, "[LL]", "[**]", 1)
} else {
m = strings.Replace(m, "[LL]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftTop) {
m = strings.Replace(m, "[LT]", "[**]", 1)
} else {
m = strings.Replace(m, "[LT]", "[ ]", 1)
}
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonCenterCenter) {
m = strings.Replace(m, "[CC]", "[**]", 1)
} else {
m = strings.Replace(m, "[CC]", "[ ]", 1)
} }
m += fmt.Sprintf(" Left Stick: X: %+0.2f, Y: %+0.2f\n Right Stick: X: %+0.2f, Y: %+0.2f", m += fmt.Sprintf(" Left Stick: X: %+0.2f, Y: %+0.2f\n Right Stick: X: %+0.2f, Y: %+0.2f",
@ -222,7 +167,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
str += fmt.Sprintf(" Buttons: %s\n", strings.Join(g.pressedButtons[id], ", ")) str += fmt.Sprintf(" Buttons: %s\n", strings.Join(g.pressedButtons[id], ", "))
if ebiten.IsStandardGamepadLayoutAvailable(id) { if ebiten.IsStandardGamepadLayoutAvailable(id) {
str += "\n" str += "\n"
str += standardMap(id) str += standardMap(id) + "\n"
str += "\n" str += "\n"
} }
str += "\n" str += "\n"

View File

@ -219,6 +219,15 @@ func StandardGamepadAxisValue(id GamepadID, axis StandardGamepadAxis) float64 {
return uiDriver().Input().StandardGamepadAxisValue(id, axis) return uiDriver().Input().StandardGamepadAxisValue(id, axis)
} }
// StandardGamepadButtonValue returns a float value [0.0 - 1.0] of the given gamepad (id)'s standard button (button).
//
// StandardGamepadButtonValue returns 0 when the gamepad doesn't have a standard gamepad layout mapping.
//
// StandardGamepadButtonValue is concurrent safe.
func StandardGamepadButtonValue(id GamepadID, button StandardGamepadButton) float64 {
return uiDriver().Input().StandardGamepadButtonValue(id, button)
}
// IsStandardGamepadButtonPressed reports whether the given gamepad (id)'s standard gamepad button (button) is pressed. // IsStandardGamepadButtonPressed reports whether the given gamepad (id)'s standard gamepad button (button) is pressed.
// //
// IsStandardGamepadButtonPressed returns false when the gamepad doesn't have a standard gamepad layout mapping. // IsStandardGamepadButtonPressed returns false when the gamepad doesn't have a standard gamepad layout mapping.

View File

@ -34,6 +34,7 @@ type Input interface {
IsStandardGamepadButtonPressed(id GamepadID, button StandardGamepadButton) bool IsStandardGamepadButtonPressed(id GamepadID, button StandardGamepadButton) bool
IsStandardGamepadLayoutAvailable(id GamepadID) bool IsStandardGamepadLayoutAvailable(id GamepadID) bool
StandardGamepadAxisValue(id GamepadID, button StandardGamepadAxis) float64 StandardGamepadAxisValue(id GamepadID, button StandardGamepadAxis) float64
StandardGamepadButtonValue(id GamepadID, button StandardGamepadButton) float64
TouchPosition(id TouchID) (x, y int) TouchPosition(id TouchID) (x, y int)
Wheel() (xoff, yoff float64) Wheel() (xoff, yoff float64)
} }

View File

@ -394,6 +394,40 @@ func AxisValue(id string, axis driver.StandardGamepadAxis, state GamepadState) f
return 0 return 0
} }
func ButtonValue(id string, button driver.StandardGamepadButton, state GamepadState) float64 {
mappingsM.RLock()
defer mappingsM.RUnlock()
mappings, ok := gamepadButtonMappings[id]
if !ok {
return 0
}
switch m := mappings[button]; m.Type {
case mappingTypeAxis:
v := state.Axis(m.Index)*float64(m.AxisScale) + float64(m.AxisOffset)
if v > 1 {
return 1
} else if v < -1 {
return -1
}
// Adjust [-1, 1] to [0, 1]
return (v + 1) / 2
case mappingTypeButton:
if state.Button(m.Index) {
return 1
}
return 0
case mappingTypeHat:
if state.Hat(m.Index)&m.HatState != 0 {
return 1
}
return 0
}
return 0
}
func IsButtonPressed(id string, button driver.StandardGamepadButton, state GamepadState) bool { func IsButtonPressed(id string, button driver.StandardGamepadButton, state GamepadState) bool {
mappingsM.RLock() mappingsM.RLock()
defer mappingsM.RUnlock() defer mappingsM.RUnlock()

View File

@ -388,6 +388,17 @@ func (i *Input) StandardGamepadAxisValue(id driver.GamepadID, axis driver.Standa
return gamepaddb.AxisValue(g.guid, axis, gamepadState{&g}) return gamepaddb.AxisValue(g.guid, axis, gamepadState{&g})
} }
func (i *Input) StandardGamepadButtonValue(id driver.GamepadID, button driver.StandardGamepadButton) float64 {
i.ui.m.Lock()
defer i.ui.m.Unlock()
if len(i.gamepads) <= int(id) {
return 0
}
g := i.gamepads[int(id)]
return gamepaddb.ButtonValue(g.guid, button, gamepadState{&g})
}
func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button driver.StandardGamepadButton) bool { func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button driver.StandardGamepadButton) bool {
i.ui.m.Lock() i.ui.m.Lock()
defer i.ui.m.Unlock() defer i.ui.m.Unlock()

View File

@ -66,8 +66,10 @@ type gamepad struct {
axes [16]float64 axes [16]float64
buttonNum int buttonNum int
buttonPressed [256]bool buttonPressed [256]bool
buttonValues [256]float64
standardButtonPressed [driver.StandardGamepadButtonMax + 1]bool standardButtonPressed [driver.StandardGamepadButtonMax + 1]bool
standardButtonValues [driver.StandardGamepadButtonMax + 1]float64
standardAxisValues [driver.StandardGamepadAxisMax + 1]float64 standardAxisValues [driver.StandardGamepadAxisMax + 1]float64
} }
@ -315,27 +317,24 @@ func (i *Input) updateGamepads() {
axes := gp.Get("axes") axes := gp.Get("axes")
axesNum := axes.Length() axesNum := axes.Length()
g.axisNum = axesNum g.axisNum = axesNum
for a := 0; a < len(g.axes); a++ { for a := 0; a < axesNum; a++ {
if axesNum <= a {
break
}
g.axes[a] = axes.Index(a).Float() g.axes[a] = axes.Index(a).Float()
} }
buttons := gp.Get("buttons") buttons := gp.Get("buttons")
buttonsNum := buttons.Length() buttonsNum := buttons.Length()
g.buttonNum = buttonsNum g.buttonNum = buttonsNum
for b := 0; b < len(g.buttonPressed); b++ { for b := 0; b < buttonsNum; b++ {
if buttonsNum <= b { btn := buttons.Index(b)
break g.buttonPressed[b] = btn.Get("pressed").Bool()
} g.buttonValues[b] = btn.Get("value").Float()
g.buttonPressed[b] = buttons.Index(b).Get("pressed").Bool()
} }
if g.mapping == "standard" { if g.mapping == "standard" {
// When the gamepad's mapping is "standard", the button and axis IDs are already mapped as the standard layout. // When the gamepad's mapping is "standard", the button and axis IDs are already mapped as the standard layout.
// See https://www.w3.org/TR/gamepad/#remapping. // See https://www.w3.org/TR/gamepad/#remapping.
copy(g.standardButtonPressed[:], g.buttonPressed[:]) copy(g.standardButtonPressed[:], g.buttonPressed[:])
copy(g.standardButtonValues[:], g.buttonValues[:])
copy(g.standardAxisValues[:], g.axes[:]) copy(g.standardAxisValues[:], g.axes[:])
} }
@ -486,6 +485,17 @@ func (i *Input) StandardGamepadAxisValue(id driver.GamepadID, axis driver.Standa
return g.standardAxisValues[axis] return g.standardAxisValues[axis]
} }
func (i *Input) StandardGamepadButtonValue(id driver.GamepadID, button driver.StandardGamepadButton) float64 {
g, ok := i.gamepads[id]
if !ok {
return 0
}
if !g.hasStandardLayoutMapping() {
return 0
}
return g.standardButtonValues[button]
}
func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button driver.StandardGamepadButton) bool { func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button driver.StandardGamepadButton) bool {
g, ok := i.gamepads[id] g, ok := i.gamepads[id]
if !ok { if !ok {

View File

@ -142,6 +142,11 @@ func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button drive
return false return false
} }
func (i *Input) StandardGamepadButtonValue(id driver.GamepadID, button driver.StandardGamepadButton) float64 {
// TODO: Implement this (#1557)
return 0
}
func (i *Input) StandardGamepadAxisValue(id driver.GamepadID, axis driver.StandardGamepadAxis) float64 { func (i *Input) StandardGamepadAxisValue(id driver.GamepadID, axis driver.StandardGamepadAxis) float64 {
// TODO: Implement this (#1557) // TODO: Implement this (#1557)
return 0 return 0