Skip to content

Commit

Permalink
ebiten: Add VibrateGamepad and implement this on browsers
Browse files Browse the repository at this point in the history
  • Loading branch information
hajimehoshi committed Oct 24, 2021
1 parent 0d9a165 commit 2aa2328
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 6 deletions.
27 changes: 25 additions & 2 deletions examples/vibrate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ const (
)

type Game struct {
touchIDs []ebiten.TouchID
touchIDs []ebiten.TouchID
gamepadIDs []ebiten.GamepadID
}

func (g *Game) Update() error {
Expand All @@ -42,11 +43,33 @@ func (g *Game) Update() error {
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
}

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) {
Expand Down
5 changes: 5 additions & 0 deletions internal/driver/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

package driver

import (
"time"
)

type GamepadID int

type TouchID int
Expand All @@ -36,5 +40,6 @@ type Input interface {
StandardGamepadAxisValue(id GamepadID, button StandardGamepadAxis) float64
StandardGamepadButtonValue(id GamepadID, button StandardGamepadButton) float64
TouchPosition(id TouchID) (x, y int)
VibrateGamepad(id GamepadID, duration time.Duration, strongMagnitude float64, weakMagnitude float64)
Wheel() (xoff, yoff float64)
}
5 changes: 5 additions & 0 deletions internal/uidriver/glfw/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package glfw
import (
"math"
"sync"
"time"
"unicode"

"github.com/hajimehoshi/ebiten/v2/internal/driver"
Expand Down Expand Up @@ -409,6 +410,10 @@ func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button drive
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() {
// Confirm that all the hat state values are the same.
if gamepaddb.HatUp != glfw.HatUp {
Expand Down
43 changes: 42 additions & 1 deletion internal/uidriver/js/input_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ package js
import (
"encoding/hex"
"syscall/js"
"time"
"unicode"

"github.com/hajimehoshi/ebiten/v2/internal/driver"
)

var object = js.Global().Get("Object")

var (
stringKeydown = js.ValueOf("keydown")
stringKeypress = js.ValueOf("keypress")
Expand Down Expand Up @@ -60,6 +63,8 @@ type pos struct {
}

type gamepad struct {
value js.Value

name string
mapping string
axisNum int
Expand Down Expand Up @@ -310,7 +315,9 @@ func (i *Input) updateGamepads() {
}

id := driver.GamepadID(gp.Get("index").Int())
g := gamepad{}
g := gamepad{
value: gp,
}
g.name = gp.Get("id").String()
g.mapping = gp.Get("mapping").String()

Expand Down Expand Up @@ -506,3 +513,37 @@ func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button drive
}
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
}
}
4 changes: 4 additions & 0 deletions internal/uidriver/mobile/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ func (i *Input) IsMouseButtonPressed(key driver.MouseButton) bool {
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) {
i.ui.m.Lock()
defer i.ui.m.Unlock()
Expand Down
11 changes: 8 additions & 3 deletions vibrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ func Vibrate(duration time.Duration) {
uiDriver().Vibrate(duration)
}

// GamepadVibrateOptions represents the options to vibrate a gamepad.
type GamepadVibrateOptions struct {
// VibrateGamepadOptions represents the options to vibrate a gamepad.
type VibrateGamepadOptions struct {
// Duration is the time duration of the effect.
Duration time.Duration

Expand All @@ -42,4 +42,9 @@ type GamepadVibrateOptions struct {
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)
}

0 comments on commit 2aa2328

Please sign in to comment.