I am supposed to implement a gesture-based menu in which you scroll through a horizontal list of items by panning or flinging through them. This kind of menus is very common in smart phone games. Example case would be Cut the Rope where you select box (Cardboard box, Fabric box) or Angry Birds where you select the set of levels (Poached Eggs, Mighty Hoax).
What I am thinking is that I’ll have to do some complex physics calculations and give velocities and accelerations to menu items based on the gestures. Any better solutions? I am using libgdx btw.
I don’t think you’d need to go through all that to implement a simple menu! It’s all about defining offsets for various items (I’ll just assume you want Cut the Rope-style menus, with only one entry in sight at a given moment (excluding transitions)) and then tweening between those offsets whenever a flick is detected!
You seem to have the gesture system all wired up, so right now, we just need to figure out how to display the menu. For simplicity’s sake, we’ll just assume that we don’t want the menu to wrap around.
We’ll start by envisioning what this menu will look like, in our heads. It would be just like a filmstrip which passes through the phone and can be seen through the screen.
We’ll just assume that the screen width is
wand, consequently, all menu entries are exactly that width (think Cut the Rope again!).Now, when “Start”, is to be displayed, we should just render the flimstrip on the screen starting with the first element, “Start”, while the rest would, theoretically, lie to the right of the screen. This will be considered the basic case, rendering the menu with the offset = 0.
Yes, yes, this offset will be the key to our little slidey-slidey menu! Now, it’s pretty obvious that when about is selected, we’ll just have to offset the “filmstrip” to the left by one “frame”, and here offset = – 1 * frameWidth. Our example case illustrated by my brilliant ASCII art has the third menu item selected, and since the frames are indexed starting from 0, we’ll just subtract two times the frameWidth and get the desired offset. We’ll just render the menu starting at offset = -2 * frameWidth.
(Obviously you can just compute frameWidth in advance, by using the API to fetch the screen width, and then just drawing the menu element text/ graphic centered).
So this is pretty simple:
the user sweeps to the left, we need to get to the menu closer to offset 0, we reduce the index of the selected entity by one and the menu then jumps to the right position
the user sweeps to the right, we increase the index (obviously as long as it doesn’t go over the number of menu elements – 1)
But what about smooth tweens?
Libgdx thankfully has interpolations all set for nice little tweens. We just need to take care of a few things so we don’t shoot ourselves in the leg. I’ll list them here.
One quick note:
The Cut the Rope level selector works a tad differently than what I’m saying here. It doesn’t just react to flicks (pre-defined gestures), rather it’s more sensitive. You can probably achieve a similar effect by playing with offsets and tracking the position of the finger on the screen. (If the user dragged a menu entry too much to the left/right, transition to the previous/next automatically) Friendly advice: just set up a simple, working menu, and leave details like this towards the end, since they can end up taking a lot of time! 😛
Alright, back on track!
What we have now is a way to quickly switch between offsets. We just need to tween. There are some additional members that come into play, but I think they’re pretty self-explanatory. While we’re transitioning between two elements, we remember the “old” offset, and the one we’re heading towards, as well as remembering the time we have left from the transition, and we use these four variables to compute the offset (using a libgdx interpolation, exp10 in this case) at the current moment, resulting in a smooth animation.
Let’s see, I’ve created a quick’n’dirty mock-up. I’ve commented the code as best as I could, so I hope the following snippet speaks for itself! 😀
}
And I believe a simple text-based menu entry that can draw itself would suffice! (do mind the dirty hard-coded text-wrap width!)
}
Oh, and Action is just a thingy that has an execute method and, well, represents an action.
}
Feel free to ask any related question in the comments, and I’ll try to clarify what’s needed.
Hope this helps!