ebiten: Add VibrateGamepad and implement this on browsers

Updates #1452
This commit is contained in:
Hajime Hoshi 2021-10-25 01:39:01 +09:00
parent 0d9a165e8f
commit 2aa232878d
6 changed files with 89 additions and 6 deletions

View File

@ -33,6 +33,7 @@ const (
type Game struct { type Game struct {
touchIDs []ebiten.TouchID touchIDs []ebiten.TouchID
gamepadIDs []ebiten.GamepadID
} }
func (g *Game) Update() error { func (g *Game) Update() error {
@ -42,11 +43,33 @@ func (g *Game) Update() error {
ebiten.Vibrate(200 * time.Millisecond) ebiten.Vibrate(200 * time.Millisecond)
} }
g.gamepadIDs = g.gamepadIDs[:0]
g.gamepadIDs = ebiten.AppendGamepadIDs(g.gamepadIDs)
for _, id := range g.gamepadIDs {
for b := ebiten.GamepadButton0; b <= ebiten.GamepadButtonMax; b++ {
if !inpututil.IsGamepadButtonJustPressed(id, b) {
continue
}
// TODO: Test weak-magnitude.
op := &ebiten.VibrateGamepadOptions{
Duration: 200 * time.Millisecond,
StrongMagnitude: 1,
WeakMagnitude: 0,
}
ebiten.VibrateGamepad(id, op)
break
}
}
return nil return nil
} }
func (g *Game) Draw(screen *ebiten.Image) { func (g *Game) Draw(screen *ebiten.Image) {
ebitenutil.DebugPrint(screen, "Touch the screen to vibrate the screen.") msg := "Touch the screen to vibrate the screen."
if len(g.gamepadIDs) > 0 {
msg += "\nPress a gamepad button to vibrate the gamepad."
}
ebitenutil.DebugPrint(screen, msg)
} }
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {

View File

@ -14,6 +14,10 @@
package driver package driver
import (
"time"
)
type GamepadID int type GamepadID int
type TouchID int type TouchID int
@ -36,5 +40,6 @@ type Input interface {
StandardGamepadAxisValue(id GamepadID, button StandardGamepadAxis) float64 StandardGamepadAxisValue(id GamepadID, button StandardGamepadAxis) float64
StandardGamepadButtonValue(id GamepadID, button StandardGamepadButton) float64 StandardGamepadButtonValue(id GamepadID, button StandardGamepadButton) float64
TouchPosition(id TouchID) (x, y int) TouchPosition(id TouchID) (x, y int)
VibrateGamepad(id GamepadID, duration time.Duration, strongMagnitude float64, weakMagnitude float64)
Wheel() (xoff, yoff float64) Wheel() (xoff, yoff float64)
} }

View File

@ -23,6 +23,7 @@ package glfw
import ( import (
"math" "math"
"sync" "sync"
"time"
"unicode" "unicode"
"github.com/hajimehoshi/ebiten/v2/internal/driver" "github.com/hajimehoshi/ebiten/v2/internal/driver"
@ -409,6 +410,10 @@ func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button drive
return gamepaddb.IsButtonPressed(g.guid, button, gamepadState{&g}) return gamepaddb.IsButtonPressed(g.guid, button, gamepadState{&g})
} }
func (i *Input) VibrateGamepad(id driver.GamepadID, duration time.Duration, strongMagnitude float64, weakMagnitude float64) {
// TODO: Implement this (#1452)
}
func init() { func init() {
// Confirm that all the hat state values are the same. // Confirm that all the hat state values are the same.
if gamepaddb.HatUp != glfw.HatUp { if gamepaddb.HatUp != glfw.HatUp {

View File

@ -17,11 +17,14 @@ package js
import ( import (
"encoding/hex" "encoding/hex"
"syscall/js" "syscall/js"
"time"
"unicode" "unicode"
"github.com/hajimehoshi/ebiten/v2/internal/driver" "github.com/hajimehoshi/ebiten/v2/internal/driver"
) )
var object = js.Global().Get("Object")
var ( var (
stringKeydown = js.ValueOf("keydown") stringKeydown = js.ValueOf("keydown")
stringKeypress = js.ValueOf("keypress") stringKeypress = js.ValueOf("keypress")
@ -60,6 +63,8 @@ type pos struct {
} }
type gamepad struct { type gamepad struct {
value js.Value
name string name string
mapping string mapping string
axisNum int axisNum int
@ -310,7 +315,9 @@ func (i *Input) updateGamepads() {
} }
id := driver.GamepadID(gp.Get("index").Int()) id := driver.GamepadID(gp.Get("index").Int())
g := gamepad{} g := gamepad{
value: gp,
}
g.name = gp.Get("id").String() g.name = gp.Get("id").String()
g.mapping = gp.Get("mapping").String() g.mapping = gp.Get("mapping").String()
@ -506,3 +513,37 @@ func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button drive
} }
return g.standardButtonPressed[button] return g.standardButtonPressed[button]
} }
func (i *Input) VibrateGamepad(id driver.GamepadID, duration time.Duration, strongMagnitude float64, weakMagnitude float64) {
g, ok := i.gamepads[id]
if !ok {
return
}
// vibrationActuator is avaialble on Chrome.
if va := g.value.Get("vibrationActuator"); va.Truthy() {
if !va.Get("playEffect").Truthy() {
return
}
prop := object.New()
prop.Set("startDelay", 0)
prop.Set("duration", float64(duration/time.Millisecond))
prop.Set("strongMagnitude", strongMagnitude)
prop.Set("weakMagnitude", weakMagnitude)
va.Call("playEffect", "dual-rumble", prop)
return
}
// hapticActuators is available on Firefox.
if ha := g.value.Get("hapticActuators"); ha.Truthy() {
// TODO: Is this order correct?
if ha.Length() > 0 {
ha.Index(0).Call("pulse", strongMagnitude, float64(duration/time.Millisecond))
}
if ha.Length() > 1 {
ha.Index(1).Call("pulse", weakMagnitude, float64(duration/time.Millisecond))
}
return
}
}

View File

@ -191,6 +191,10 @@ func (i *Input) IsMouseButtonPressed(key driver.MouseButton) bool {
return false return false
} }
func (i *Input) VibrateGamepad(id driver.GamepadID, duration time.Duration, strongMagnitude float64, weakMagnitude float64) {
// TODO: Implement this (#1452)
}
func (i *Input) update(keys map[driver.Key]struct{}, runes []rune, touches []Touch) { func (i *Input) update(keys map[driver.Key]struct{}, runes []rune, touches []Touch) {
i.ui.m.Lock() i.ui.m.Lock()
defer i.ui.m.Unlock() defer i.ui.m.Unlock()

View File

@ -28,8 +28,8 @@ func Vibrate(duration time.Duration) {
uiDriver().Vibrate(duration) uiDriver().Vibrate(duration)
} }
// GamepadVibrateOptions represents the options to vibrate a gamepad. // VibrateGamepadOptions represents the options to vibrate a gamepad.
type GamepadVibrateOptions struct { type VibrateGamepadOptions struct {
// Duration is the time duration of the effect. // Duration is the time duration of the effect.
Duration time.Duration Duration time.Duration
@ -42,4 +42,9 @@ type GamepadVibrateOptions struct {
WeakMagnitude float64 WeakMagnitude float64
} }
// TODO: Add a function VibrateGamepad. // VibrateGamepad vibrates the specified gamepad with the specified options.
//
// VibrateGamepad is concurrent-safe.
func VibrateGamepad(gamepadID GamepadID, options *VibrateGamepadOptions) {
uiDriver().Input().VibrateGamepad(gamepadID, options.Duration, options.StrongMagnitude, options.WeakMagnitude)
}