How to detect phone tilt?

Hi everyone,
Newcomer here :slight_smile: I am working on a charades-inspired game app where the user tilts their phone down if they guess a word correctly or up if they would like to pass (similar to ‘Heads Up!’ if you’ve played that before). The user’s phone is in landscape orientation as the game is played. My current logic uses a math formula to calculate the phone’s angle using its accelerometer z-value. Then, I have an if statement where the next card is pulled if the phone is tilted past a certain angle. The issue with this is that once the phone is tilted past this angle, multiple cards flow through at once and sometimes the game will run out of cards. I’ve tried setting the update interval to a couple of seconds with the thought that the user will have tilted the phone back up in that time period to avoid another card passing the if statement logic while the phone is still down (i.e. hasn’t gotten back to its reference point). This still didn’t work.
I really appreciate any ideas that anyone has on another possible solution to get this working as it should. I looked into expo’s device motion as an option but it does the same thing as the sensor logic is currently doing. Thank you for reading.


You might also want to look at the Gyroscope support if you haven’t already, but the sensors are not really the problem.

In terms of preventing all the cards from “flowing through at once” it sounds like you could do with a state machine :slight_smile: (a.k.a. finite state machines, finite automata, etc. Or statecharts which are related.)

I think you want something that keeps track of the state of the game. In the middle of the game, presumably there are states that the game should move through. If you were playing it manually (as a board game with no phones involved) you would not allow one player to suddenly take a bunch of cards. The rules say to take one card and then let the next player have their turn (or whatever).

Also you probably want to abstract the low level changes from the sensor to a higher level “downward tilt”, “upward tilt”. (Based on your description you are doing something like this already, I think.)

So the game logic would just need to stay in the same state unless the right conditions are met.
So you could have a state machine that says:

  • state == “user’s turn to guess a word”, event == “downward tilt”, transition to state “correct guess”
  • state == “user’s turn to guess a word”, event == “upward tilt”, transition to state “pass”

In state “pass” you would not have “upward tilt” as a valid event, so just ignore it.

I’m not sure if I’ve explained it clearly enough, but maybe have a look at some talks by and his XState library.

See also:

First off, thank you for responding :slight_smile:. I think my logic is currently using a form of state machine based on your description. Basically, my logic looks at the phone angle as a ‘value’, say x, and calls the next card if the value either meets the condition to be ‘correct’ or meets the condition to ‘pass’, for example, if x > 90, mark as ‘correct’ and get next card. Else if x < 0, mark as ‘pass’ and get next card (these are just random numbers to illustrate my logic).
What I am struggling with is how to make it such that only one card can flow through at a time while the phone is either up or down i.e. if the user keeps their phone at an angle greater than 90 for more than one second, it should stay on that same card until the phone is brought back up. Currently if the user’s phone stays down, it technically still meets the criteria where x > 90 and thus multiple cards flow through. The solution here I think is to find a way to determine if the user’s phone has returned to its original state first and only then should the card change. I’m just not sure how to implement this.

Basically the problem is you have a bunch of “tilt up” events happening at once, but you don’t change to a different state. The state you’re in at the time says “if there’s a tilt event, deal a card”. So, while you keep getting tilt events you will keep dealing cards.

If instead you have a “Guessing” state where you accept a “tilt up” event and just move to another state, e.g. “Passing” you won’t have this problem. Because in the “Passing” state you could e.g. deal a card as a side effect of moving to that state and the “tilt up” event can be completely ignored.

i.e. one “tilt up” event in the “Guessing” state moves your machine to the “Passing” state. “tilt up” events in the “Passing” state are ignored, so only one card is dealt.

Then you need some other event (e.g. “phone is level”) to move to a third state, or maybe back to “Guessing”.

I hope that points you in the right direction :slight_smile: