jarinosuke blog

about software engineering, mostly about iOS

iOS上でジョイスティックを手軽に実装できるSneakingInputクラス

ゲームをiOS上で作る上でのインターフェース

何か面白いアイディアがあったとして、iOS上でゲームを作るときには、それを楽しんでもらうインターフェースをどうするかを良く考えなければいけないと思います。

加速度センサーを使ってシェイクモーションを取り入れるか。
タッチ操作にするか、そうするならフリック、ピンチはどうするか。
iPadにゲーム画面を表示しiPhoneをコントローラとしてBT通信を行うか。

様々な方法が思い浮かびあがり、これを決めるのにはとても時間がかかります。
しかし、ここを疎かにしてしまうと全てが台無しになってしまうのでたっぷり考えるべきだと思います。
なので、これらを実装する際にはなるべく時間をかけずに、できれば今あるものを使って作りたいですよね。

あえて現実にあるジョイスティックを実装する

ここでは、インターフェースを実現するための一つの方法としてジョイスティックを紹介します。
とはいっても、すでに公開されているクラスを使って実装するだけです。

ジョイスティックの利点は、現実で既にハードウェアとして認識されているので一目でどのようなインターフェースなのかが分かるところだと思います。
逆に欠点は、iPhoneの画面は縦480横320という狭い空間しか無いうえに、その一部をコントローラが陣取ってしまう所だと思います。

実装方法

f:id:jarinosuke0808:20101204190529p:image:right
簡単に紹介します。
僕の作った右のようなRollingStoneというスティックを使ってただ石ころを転がすだけサンプルアプリも参考にしてみてください。

git clone https://jarinosuke@github.com/jarinosuke/RollingStone.git
本家から持ってくる

githubにSneakyInputというリポジトリが立っているので、そこから持ってきましょう。

git clone https://github.com/sneakyness/SneakyInput.git

まぁこれ自体がサンプルプロジェクトなので、これをビルドすれば動くんですけどね…。

必要なファイルを自分のプロジェクトに加える

Classesの中の、赤で囲んだ合計10個のファイルを自分のプロジェクトに加えます。
今回はジョイスティックだけしか実装しないのでButton系のクラスは必要ないのですが気にせず加えます。
f:id:jarinosuke0808:20101204190530p:image

コードを書く

Layerに付け加えるまでと、スティックから算出された移動量をどのようにオブジェクトの移動に反映させるかの二つのコードを簡単に示します。

まずはaddChildするまで。

     float stickRadius = 40;
     SneakyJoystick* joystick = [SneakyJoystick joystickWithRect:CGRectMake(0, 0, stickRadius, stickRadius)];
     joystick.autoCenter = YES;
     joystick.hasDeadzone = YES;
     joystick.deadRadius = 10;
    
     CGSize screenSize = [[CCDirector sharedDirector] winSize];
    
     SneakyJoystickSkinnedBase* skinStick = [SneakyJoystickSkinnedBase skinnedJoystick];
     skinStick.position = CGPointMake(screenSize.width / 2, stickRadius );
     skinStick.backgroundSprite = [CCSprite spriteWithFile:@"joystick-sheet.png"];
          //be able to change color
          //skinStick.backgroundSprite.color = ccYELLOW;
     skinStick.thumbSprite = [CCSprite spriteWithFile:@"joystick-stick.png"];
     skinStick.thumbSprite.scale = 1.5f;
     skinStick.joystick = joystick;
     [self addChild:skinStick];

移動量を反映させるコードはupdateメソッドなど定期的に呼び出される関数内で実行させます。

     // Moving the stone with the thumbstick.
     GameScene* game = [GameScene sharedGameScene];
     Stone* stone = [game defaultStone];
    
     CGPoint velocity = ccpMult(joystick.velocity, 150);
     if (velocity.x != 0 && velocity.y != 0)
     {
          stone.position = CGPointMake(stone.position.x + velocity.x * delta, stone.position.y + velocity.y * delta);
     }

こんな感じでジョイスティックを導入することが出来ます。
上記のコードで

joystick.velocity

がどれ位の量なのか気になるかと思いますが、かなり小さな量なので適当な値をかけてあげる必要があります。

終わりに

まだSneakyInputのソースは詳しく読んでいないのですが、こういうクラスを公開してくれている方がいると非常に助かります。

今回これを見つけたのはcocos2d本として有名なLearn iPhone and iPad Cocos2D Game Development
がきっかけなのですが、そこにも書いてあった言葉が印象的でした。

一般的に言えることだけど、何かプログラムを書こうとしたときに、その目的に沿うプログラムが予めどこかに無いか探す癖をつけた方が良い。もしあれば、それを使うことで時間の短縮になるし、無い場合はたくさんの時間をかけてそれを作ることで価値を生み出せる。