Are you trying to design a game that tilting is your major control style? If your answer is YES, this is a right article for you. Recently I want to design a game using device acceleration to control my hero, however, it is more difficult than it seems to be.
PS: this article uses cocos2d to implement all tricks, readers better have some basic understanding of cocos2d.
Step 1: get acceleration value from device.
- In you CCLayer file, enable the acceleration detection.
- Add this method in you CCLayer file.
- Moreover, you may adjust the rate of receiving acceleration data from device by below code.
Step 2: map our acceleration data to object’s movement Intuitively,
We have three ways to translate those data, including mapping to acceleration, to speed, and to position.
Mapping to acceleration
object.acceleration = acceleration * MULTIPLIER
Here, we neither manipulate the position nor control the velocity directly, we use acceleration data to affect acceleration of an object. We translate device acceleration data to our object’s acceleration directly. Imagine that when you tilt our device to the left, our object gains an acceleration toward left, which gradually change the velocity leftward. Unfortunately, this mapping is very hard to for player to learn. Our human brains have no problem in estimating movement with a constant speed. Yet if an object’s speed is changing even changing gradually, it is hard for us to calculate the destination position in a short time. We are not math genius, who are able to calculate a polynomial distance formula in a very short time. As a result, though this method can provide the smoothest movement among three methods because this is how our world is operating, we may feel awkward controlling in this way. If you still can’t understand why, imagine a frictionless slope, can you quickly tell me how much time will a ball slide down from the top even if you know the length and angle of this slope?
Mapping to velocity
object.velocity = acceleration * MULTIPLIER
How much you tilt your device directly decides your object’s speed. For example, if you slightly tilt your device to the left and your object is going to have speed like 30 pixels per second, holding your device in a landscape view will greatly cause your speed change to like 3000 pixels per second. Compare to changing acceleration, changing speed is easier for us to understand. Human brain is familiar with calculating such linear formula. We calculate movement all the time when playing FPS games. We are comfortable with this consistent moving style. However, to achieve a smooth movement, we have to manipulate the acceleration instead of velocity. Suddenly setting velocity from a big value to a small value will cause a huge speed gap, which make objects move stiffly. We appreciate smooth movement. In our world, everything changing gradually pleases us. Therefore, instead of changing speed instantly, we set a target velocity and “gradually” set speed to the target velocity. See the below code.
We “slowly” change the velocity to our target velocity along with past time in the update circle. In this way, we achieve our smoothness goal and how smooth it will be depends on your acceleration. Note that the bigger your acceleration is, less smoothness your movement is. We need to adjust to a balance.
Mapping to position
object.position = acceleration * MULTIPLIER
Instead of manipulating speed, we map acceleration data to object’s position directly. This is perfectly easy, why not use this way? Players want simple and intuitive controlling way, let’s meet their needs. Unfortunately, it is not easy as what you think. Acceleration data from device is not stable as you may think. Even if you think you are holding your iPhone very steadily, the acceleration data changes all the time that usually varies around 0.1 if you hold really steadily. This is bad for our direct translating to position. You may have guessed that our object will “shake” like your device “is”. This is annoying. I have tried many methods to counteract the “shaking”, e.g. I used a wrap to pre-process the raw data from device. This wrap will compare the previous data with current data, only when their gap is bigger than a threshold (0.1) will we transfer this data to the upper methods for using. However, the result of applying a wrapper is that the object will move inconsistently. That is to say, the object will dash to next position suddenly and then stay steadily quite. This feeling is like you are playing a game which the only movement is teleporting. It is a paradox that if you lower your threshold, your object shakes, and if you raise your threshold, your object “teleports”. Therefore, if you only use some tilting levels, it is OK and preferable to use this simple method. However, if you want a precise control style, just forget this method.
I draw a graph to generalize above three methods’ difference. Mapping to acceleration is very hard to learn because our brain are not familiar with speed-changing movement. Yet this is the smoothest one because everything changes gradually. The second type – mapping to speed is easier to learn and is smooth as well if we still manipulate the acceleration instead of changing the speed suddenly. And the last one – position is very simple to understand and master, however, it is not stable. Only when we need several levels of tilting can we make use of this control style.
Aside from above tedious explanation, I have written a small xcode project to let you try all these control styles. Thousands lines of explanation is not as useful as some hands-on practices. If you are interested, please download here.
Press the top icon will iteratively change the control style among above three types. Sliding three icons in the bottom will respectively change the magnitude of mapping to position, speed, and acceleration. For example, under the velocity control style, increasing the velocity value by sliding the second bar will increase your maximum target speed, meanwhile changing acceleration slider bar will affect how fast your velocity is able to change. You may modify the code to test new ways of controlling, if you find a better solution, I’d appreciate if you share with us. Sharing is a virtue.