mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
ebiten: Add VibrationOptions to specify intensity (#1891)
Updates #1452
This commit is contained in:
parent
b638b72f0b
commit
39ef252c2e
@ -34,13 +34,19 @@ const (
|
||||
type Game struct {
|
||||
touchIDs []ebiten.TouchID
|
||||
gamepadIDs []ebiten.GamepadID
|
||||
touchCounter int
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
g.touchIDs = g.touchIDs[:0]
|
||||
g.touchIDs = inpututil.AppendJustPressedTouchIDs(g.touchIDs)
|
||||
if len(g.touchIDs) > 0 {
|
||||
ebiten.Vibrate(200 * time.Millisecond)
|
||||
g.touchCounter++
|
||||
op := &ebiten.VibrateOptions{
|
||||
Duration: 200 * time.Millisecond,
|
||||
Intensity: 0.5*float64(g.touchCounter%2) + 0.5,
|
||||
}
|
||||
ebiten.Vibrate(op)
|
||||
}
|
||||
|
||||
g.gamepadIDs = g.gamepadIDs[:0]
|
||||
|
@ -63,7 +63,7 @@ type UI interface {
|
||||
SetScreenTransparent(transparent bool)
|
||||
SetInitFocused(focused bool)
|
||||
|
||||
Vibrate(duration time.Duration)
|
||||
Vibrate(duration time.Duration, intensity float64)
|
||||
|
||||
Input() Input
|
||||
Window() Window
|
||||
|
@ -1673,6 +1673,6 @@ func (u *UserInterface) setOrigPos(x, y int) {
|
||||
u.origPosY = y
|
||||
}
|
||||
|
||||
func (u *UserInterface) Vibrate(duration time.Duration) {
|
||||
func (u *UserInterface) Vibrate(duration time.Duration, intensity float64) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
@ -648,7 +648,9 @@ func (u *UserInterface) SetInitFocused(focused bool) {
|
||||
u.initFocused = focused
|
||||
}
|
||||
|
||||
func (u *UserInterface) Vibrate(duration time.Duration) {
|
||||
func (u *UserInterface) Vibrate(duration time.Duration, intensity float64) {
|
||||
// intensity is ignored.
|
||||
|
||||
if js.Global().Get("navigator").Get("vibrate").Truthy() {
|
||||
js.Global().Get("navigator").Call("vibrate", float64(duration/time.Millisecond))
|
||||
}
|
||||
|
@ -21,30 +21,41 @@ import (
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
// Basically same as:
|
||||
//
|
||||
// Vibrator v = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
|
||||
// if (Build.VERSION.SDK_INT >= 26) {
|
||||
// v.vibrate(VibrationEffect.createOneShot(milliseconds, intensity * 255))
|
||||
// } else {
|
||||
// v.vibrate(millisecond)
|
||||
//
|
||||
// TODO: As of API Level 26, the new API should be Used instead:
|
||||
//
|
||||
// Vibrator v = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
|
||||
// v.vibrate(VibrationEffect.createOneShot(millisecond, VibrationEffect.DEFAULT_AMPLITUDE))
|
||||
// }
|
||||
//
|
||||
// Note that this requires a manifest setting:
|
||||
//
|
||||
// <uses-permission android:name="android.permission.VIBRATE"/>
|
||||
//
|
||||
static void vibrateOneShot(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx, int64_t milliseconds) {
|
||||
static void vibrateOneShot(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx, int64_t milliseconds, double intensity) {
|
||||
JavaVM* vm = (JavaVM*)java_vm;
|
||||
JNIEnv* env = (JNIEnv*)jni_env;
|
||||
jobject context = (jobject)ctx;
|
||||
|
||||
static int apiLevel = 0;
|
||||
if (!apiLevel) {
|
||||
const jclass android_os_Build_VERSION = (*env)->FindClass(env, "android/os/Build$VERSION");
|
||||
|
||||
apiLevel = (*env)->GetStaticIntField(
|
||||
env, android_os_Build_VERSION,
|
||||
(*env)->GetStaticFieldID(env, android_os_Build_VERSION, "SDK_INT", "I"));
|
||||
|
||||
(*env)->DeleteLocalRef(env, android_os_Build_VERSION);
|
||||
}
|
||||
|
||||
const jclass android_content_Context = (*env)->FindClass(env, "android/content/Context");
|
||||
const jclass android_os_Vibrator = (*env)->FindClass(env, "android/os/Vibrator");
|
||||
|
||||
@ -59,10 +70,29 @@ static void vibrateOneShot(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx,
|
||||
(*env)->GetMethodID(env, android_content_Context, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"),
|
||||
android_context_Context_VIBRATOR_SERVICE);
|
||||
|
||||
if (apiLevel >= 26) {
|
||||
const jclass android_os_VibrationEffect = (*env)->FindClass(env, "android/os/VibrationEffect");
|
||||
|
||||
const jobject vibrationEffect =
|
||||
(*env)->CallStaticObjectMethod(
|
||||
env, android_os_VibrationEffect,
|
||||
(*env)->GetStaticMethodID(env, android_os_VibrationEffect, "createOneShot", "(JI)Landroid/os/VibrationEffect;"),
|
||||
milliseconds, (int)(intensity * 255));
|
||||
|
||||
(*env)->CallVoidMethod(
|
||||
env, vibrator,
|
||||
(*env)->GetMethodID(env, android_os_Vibrator, "vibrate", "(Landroid/os/VibrationEffect;)V"),
|
||||
vibrationEffect);
|
||||
|
||||
(*env)->DeleteLocalRef(env, android_os_VibrationEffect);
|
||||
|
||||
(*env)->DeleteLocalRef(env, vibrationEffect);
|
||||
} else {
|
||||
(*env)->CallVoidMethod(
|
||||
env, vibrator,
|
||||
(*env)->GetMethodID(env, android_os_Vibrator, "vibrate", "(J)V"),
|
||||
milliseconds);
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, android_content_Context);
|
||||
(*env)->DeleteLocalRef(env, android_os_Vibrator);
|
||||
@ -74,10 +104,10 @@ static void vibrateOneShot(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx,
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func (u *UserInterface) Vibrate(duration time.Duration) {
|
||||
func (u *UserInterface) Vibrate(duration time.Duration, intensity float64) {
|
||||
_ = app.RunOnJVM(func(vm, env, ctx uintptr) error {
|
||||
// TODO: This might be crash when this is called from init(). How can we detect this?
|
||||
C.vibrateOneShot(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx), C.int64_t(duration/time.Millisecond))
|
||||
C.vibrateOneShot(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx), C.int64_t(duration/time.Millisecond), C.double(intensity))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ package mobile
|
||||
// return nil;
|
||||
// }
|
||||
//
|
||||
// static void vibrate(double duration) {
|
||||
// static void vibrate(double duration, double intensity) {
|
||||
// if (@available(iOS 13.0, *)) {
|
||||
// static BOOL initializeHapticEngineCalled = NO;
|
||||
// static CHHapticEngine* engine = nil;
|
||||
@ -64,7 +64,7 @@ package mobile
|
||||
// (id<NSCopying>)(CHHapticPatternKeyEventParameters):@[
|
||||
// @{
|
||||
// (id<NSCopying>)(CHHapticPatternKeyParameterID): CHHapticEventParameterIDHapticIntensity,
|
||||
// (id<NSCopying>)(CHHapticPatternKeyParameterValue): @1.0,
|
||||
// (id<NSCopying>)(CHHapticPatternKeyParameterValue): [NSNumber numberWithDouble:intensity],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
@ -103,9 +103,9 @@ import (
|
||||
|
||||
var vibrationM sync.Mutex
|
||||
|
||||
func (u *UserInterface) Vibrate(duration time.Duration) {
|
||||
func (u *UserInterface) Vibrate(duration time.Duration, intensity float64) {
|
||||
vibrationM.Lock()
|
||||
defer vibrationM.Unlock()
|
||||
|
||||
C.vibrate(C.double(float64(duration) / float64(time.Second)))
|
||||
C.vibrate(C.double(float64(duration)/float64(time.Second)), C.double(intensity))
|
||||
}
|
||||
|
26
vibrate.go
26
vibrate.go
@ -18,20 +18,38 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Vibrate vibrates the device.
|
||||
// VibrateOptions represents the options for device vibration.
|
||||
type VibrateOptions struct {
|
||||
// Duration is the time duration of the effect.
|
||||
Duration time.Duration
|
||||
|
||||
// Intensity is the strength of the device vibration.
|
||||
// The value is in between 0 and 1.
|
||||
Intensity float64
|
||||
}
|
||||
|
||||
// Vibrate vibrates the device with the specified options.
|
||||
//
|
||||
// Vibrate works on mobiles and browsers.
|
||||
//
|
||||
// On browsers, Intensity in the options is ignored.
|
||||
//
|
||||
// On Android, this line is required in the manifest setting to use the vibration:
|
||||
//
|
||||
// <uses-permission android:name="android.permission.VIBRATE"/>
|
||||
//
|
||||
// On Android, Intensity in the options is recognized only when the API Level is 26 or newer.
|
||||
// Otherwise, Intensity is ignored.
|
||||
//
|
||||
// On iOS, Vibrate works only when iOS version is 13.0 or newer.
|
||||
// Otherwise, Vibrate does nothing.
|
||||
//
|
||||
// Vibrate is concurrent-safe.
|
||||
func Vibrate(duration time.Duration) {
|
||||
uiDriver().Vibrate(duration)
|
||||
func Vibrate(options *VibrateOptions) {
|
||||
uiDriver().Vibrate(options.Duration, options.Intensity)
|
||||
}
|
||||
|
||||
// VibrateGamepadOptions represents the options to vibrate a gamepad.
|
||||
// VibrateGamepadOptions represents the options for gamepad vibration.
|
||||
type VibrateGamepadOptions struct {
|
||||
// Duration is the time duration of the effect.
|
||||
Duration time.Duration
|
||||
|
Loading…
Reference in New Issue
Block a user