From b8a5ea7bd6030fb41fc41946768a33ef1e3c57e0 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 23 Oct 2021 18:27:27 +0900 Subject: [PATCH] ebiten: Add Vibrate and VibrateOptions, and implement this on browsers Updates #1452 --- examples/vibrate/main.go | 65 ++++++++++++++++++++++++++++++++++ internal/driver/ui.go | 3 ++ internal/uidriver/glfw/ui.go | 4 +++ internal/uidriver/js/ui_js.go | 6 ++++ internal/uidriver/mobile/ui.go | 4 +++ vibrate.go | 43 ++++++++++++++++++++++ 6 files changed, 125 insertions(+) create mode 100644 examples/vibrate/main.go create mode 100644 vibrate.go diff --git a/examples/vibrate/main.go b/examples/vibrate/main.go new file mode 100644 index 000000000..1cd749461 --- /dev/null +++ b/examples/vibrate/main.go @@ -0,0 +1,65 @@ +// Copyright 2021 The Ebiten Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build example +// +build example + +package main + +import ( + "log" + "time" + + "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/ebitenutil" + "github.com/hajimehoshi/ebiten/v2/inpututil" +) + +const ( + screenWidth = 640 + screenHeight = 480 +) + +type Game struct { + touchIDs []ebiten.TouchID +} + +func (g *Game) Update() error { + g.touchIDs = g.touchIDs[:0] + g.touchIDs = inpututil.AppendJustPressedTouchIDs(g.touchIDs) + if len(g.touchIDs) > 0 { + op := &ebiten.VibrateOptions{ + Duration: 200 * time.Millisecond, + StrongMagnitude: 1, + } + ebiten.Vibrate(op) + } + + return nil +} + +func (g *Game) Draw(screen *ebiten.Image) { + ebitenutil.DebugPrint(screen, "Touch the screen to vibrate the screen.") +} + +func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { + return screenWidth, screenHeight +} + +func main() { + ebiten.SetWindowTitle("Vibrate (Ebiten Demo)") + if err := ebiten.RunGame(&Game{}); err != nil { + log.Fatal(err) + } +} diff --git a/internal/driver/ui.go b/internal/driver/ui.go index 03f90e633..a8ebf6ac0 100644 --- a/internal/driver/ui.go +++ b/internal/driver/ui.go @@ -17,6 +17,7 @@ package driver import ( "errors" "image" + "time" ) type UIContext interface { @@ -62,6 +63,8 @@ type UI interface { SetScreenTransparent(transparent bool) SetInitFocused(focused bool) + Vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) + Input() Input Window() Window Graphics() Graphics diff --git a/internal/uidriver/glfw/ui.go b/internal/uidriver/glfw/ui.go index 55b222e04..823f25275 100644 --- a/internal/uidriver/glfw/ui.go +++ b/internal/uidriver/glfw/ui.go @@ -1685,3 +1685,7 @@ func (u *UserInterface) setOrigPos(x, y int) { u.origPosX = x u.origPosY = y } + +func (u *UserInterface) Vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { + // Do nothing. +} diff --git a/internal/uidriver/js/ui_js.go b/internal/uidriver/js/ui_js.go index 332bcd75c..196888c58 100644 --- a/internal/uidriver/js/ui_js.go +++ b/internal/uidriver/js/ui_js.go @@ -648,6 +648,12 @@ func (u *UserInterface) SetInitFocused(focused bool) { u.initFocused = focused } +func (u *UserInterface) Vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { + if js.Global().Get("navigator").Get("vibrate").Truthy() { + js.Global().Get("navigator").Call("vibrate", float64(duration/time.Millisecond)) + } +} + func (u *UserInterface) Input() driver.Input { return &u.input } diff --git a/internal/uidriver/mobile/ui.go b/internal/uidriver/mobile/ui.go index 3e8ca62a0..44ce8d368 100644 --- a/internal/uidriver/mobile/ui.go +++ b/internal/uidriver/mobile/ui.go @@ -492,3 +492,7 @@ func (u *UserInterface) ScheduleFrame() { u.renderRequester.RequestRenderIfNeeded() } } + +func (u *UserInterface) Vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { + // TODO: Implement this (#1452) +} diff --git a/vibrate.go b/vibrate.go new file mode 100644 index 000000000..277012e49 --- /dev/null +++ b/vibrate.go @@ -0,0 +1,43 @@ +// Copyright 2021 The Ebiten Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ebiten + +import ( + "time" +) + +// VibrateOptions represents the options to vibrate a device. +type VibrateOptions struct { + // Duration is the time duration of the effect. + Duration time.Duration + + // StrongMagnitude is the rumble intensity of a low-frequency rumble motor. + // The value is in between 0 and 1. + StrongMagnitude float64 + + // StrongMagnitude is the rumble intensity of a high-frequency rumble motor. + // The value is in between 0 and 1. + WeakMagnitude float64 +} + +// Vibrate vibrates the device. +// +// Vibrate works on mobiles and browsers. +// On browsers, StrongManitude and WeakMagnitude might be ignored. +// +// Vibrate is concurrent-safe. +func Vibrate(options *VibrateOptions) { + uiDriver().Vibrate(options.Duration, options.StrongMagnitude, options.WeakMagnitude) +}