Shaker: a class for shake detection

Here's a minimal class I whipped together to make it easy to detect with the player has shaken their Playdate (thanks @dave for helping me understand the values coming off the sensor!).

shaker.lua.zip (820 Bytes)

I'll plop it on GitHub when the SDK is publicly available.

Usage is something like this:

-- Initialize:

local shaker = Shaker.new(function()
   print("THE PLAYDATE IS SHOOK!!")
end, {sensitivity = Shaker.kSensitivityMedium, threshold = 0.5, samples = 40})

shaker:setEnabled(true)

-- Called each frame:

shaker:update()

Options:

sensitivity is essentially what magnitude is considered accelerated. There are a few built-in defaults: Shaker.kSensitivityLow, Shaker.kSensitivityMedium, and Shaker.kSensitivityHigh. However, you can simply specify your own value too.

threshold is the percentage of samples within within the current window that need to be accelerated for the current window of samples to be considered a shake. This value is 0.0 – 1.0.

samples is the number of samples to collect before testing begins. This is a rolling window, meaning each update a new sample is added and the oldest sample is removed. The samples are reset when a shake is detected.

Let me know if you find any bugs! (There aren't any—promise! :wink: )

9 Likes

Thanks for sharing this code Dustin. I started poking around to get some ideas for shake detection in Pulp/PulpScript and I can't get the example to work. Is it expected to work in the Simulator?

A few potential bugs I noticed while trying to figure out what was going on:

  • In Shaker:reset(), self.samples_window is nil. Should that be self.sample_size?
  • playdate.startAccelerometer() doesn't appear in Shaker.lua or the example (calling it didn't do anything either though).
  • In Shaker:test(), average and self.shake_sample_total are always 0, which is possibly related to:
  • In Shaker:sample(), while wildly scrubbing the Accelerometer widget in the Simulator, accel maxes out around 96 (while medium sensitivity squared is 196)

Maybe those last two aren't bugs but evidence that the results of the simulated and actual accelerometer aren't comparable for the purposes of sensitivity?

Here's an updated version that fixes the first issue (changes self.samples_window to self.sample_size) and adds self.index which is used to insert new accelerating values into self.shake_samples without mutating the table every frame.

shaker.zip (1.2 KB)

1 Like

Thanks! It seemed to be working well on device however I wasn't able to get it working in simulator. I had meant to ask what I should expect from the Simulator's accelerometer control. I'll check out your changes soon!

Maybe you could use playdate.isSimulator to scale down sensitivity when run in the Simulator? Or maybe that’s just on the person providing that value when creating a new Shaker...

Yeah, good question. It feels weird that simulated acceleration isn’t like the device. It would be handy if it just worked in simulator though. I’ll try adding some multiple for simulator and see if I can get it at all close.

Thanks for making this! I would never be able to figure out the math for this :sweat_smile:
Seems like on sim the Z is always 1, which means with the gravitation value it’s always 9, causing the accel to always be 96 no matter where I put the accelerometer - so maybe for sim the value for accel should take only x,y and ignore z?

In the simulator z is always sqrt(x^2+y^2), making the magnitude of the gravity vector = 1. You used to be able to get g > 1 by dragging the arrow outside the circle, but that was "fixed" at some point recently. I think what I'll do is let it go outside while you're dragging, and then have it snap back to the circle when you let go.

1 Like

Oh that actually sounds really intuitive!
Maybe also show the xyz values in there as editable text fields? - same way I can see and set the crank degrees

Missing from your example above is a call to playdate.startAccelerometer(). Took me a bit to figure that out. :sweat_smile:

I could also imagine putting it in setEnabled(), maybe like this:

	if not playdate.accelerometerIsRunning() then
		playdate.startAccelerometer()
	end
2 Likes

could you help me out with the accelerometer code to move a player accross the screen in all dire
directions?Thanks

BTW this Shaker class works great in Simulator now too if you just wildly shake the accelerometer control around. Thanks (most likely fixed a while ago I just hadn't tried it)!

probably this fix from 1.10:

  • Simulator: Mac/Linux/Windows: Accelerometer is no longer constrained to unit circle, in order to simulate shake events
1 Like

Just a quick bug report on using this in Simulator...

  • with mouse I can drag slowly outside the circle and when i am, like, the diameter away from the edge of the circle the shake will trigger
  • it is impossible to trigger shake when using a controller (where the arrow barely goes outside the circle, accel is 96 at rest and ranges 100 to 160 with movement of the analog stick)
  • pointing analog stick directly up/down/left/right gives accel of 96, which shaker does not deal take into consideration
  • simulator accelerometer defaults to pointing down, so we have to ignore that

my naïve solution for Simulator that addresses these issues:

  • ignore z
  • hard code 95 value for sensitivity
  • ignore scenario of default accelerometer value (x==0 && y == G)
-- existing code
local accelerating = (accel > (self.sensitivity * self.sensitivity)) and 1 or 0
-- my change
if pd.isSimulator then
    accel = x * x + y * y
    accelerating = (accel > 95 and (x ~= 0 or y ~= STANDARD_GRAVITY)) and 1 or 0
end

(not tested much)

I might also increase sample window for Simulator by a factor of 2 or 3 so shaking is more deliberate.

thanks all for the thought behind these workarounds!