Actionscript, Web, Interactive and Design

FlashPlayer10.1の新機能、マルチタッチを管理する。

admin : 2010. 4. 18. 23:08 — ActionScript

FlashPlayer10.1には、マルチタッチに対応したコンテンツに対応するために、新しいAPIが用意されています。

基本的には、Multitouch.inputModeを定義し、flash.events.TouchEventやflash.events.TransformGestureEventなどで値を受け取ることになります。

TransformGestureEventについては、すでにAdobe AIRデベロッパーセンターに掲載されている
「マルチタッチ機能を活用した AIR 2.0 アプリケーション Touch Viewer の紹介 | デベロッパーセンター」
が非常にわかりやすいです。

今回はTouchEventで効率的にタッチポイントを管理する方法について書きたいと思います。

TouchEventのタイプは

TOUCH_BEGIN
TOUCH_END
TOUCH_MOVE
TOUCH_OUT
TOUCH_OVER
TOUCH_ROLL_OUT
TOUCH_ROLL_OVER
TOUCH_TAP

以上の8つで、TouchEventではタッチ関連のプロパティが取得できます。タッチを管理していく上でメインになってくるのは touchPointID, localX, localYです。touchPointIDには、それぞれのタッチポイントにユニークなIDが割り振られており、localX, localYは、文字通りタッチポイントの座標です。

今回は、TOUCH_BEGIN, TOUCH_END, TOUCH_MOVEの3つにリスナを登録しておき、touchPointIDを添字としたPoint型のVectorにlocalX,localYを格納していく、という方法です。
実際には以下のようなコードになります。

public function MultiTouchSprite()
{
     Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
 
     _startPoint   = new Vector.<Point>(10);
     _currentPoint = new Vector.<Point>(10);
     _previewPoint = new Vector.<Point>(10);
 
     for (var i:int = 0; i < 10; i++)
     {
          _startPoint[i]   = new Point();
          _currentPoint[i] = new Point();
          _previewPoint[i] = new Point();
     }
 
     addEventListener(TouchEvent.TOUCH_BEGIN, _touchBeginHandler);
     addEventListener(TouchEvent.TOUCH_MOVE, _touchMoveHandler);
     addEventListener(TouchEvent.TOUCH_END,    _touchEndHandler);
}
 
private function _touchBeginHandler(e:TouchEvent):void
{
     _startPoint[e.touchPointID].x = e.localX;
     _startPoint[e.touchPointID].y = e.localY;
}

今回はstartPoint, currentPoint, previewPointとい3つのVectorを用意しました。これでcurrentPoint[touchPointID].x, currentPoint[touchPointID].yとかすると、座標が取れます。

あと、僕の環境だと、touchPointIDが2から始まるんですけど、これってなんなんですかね。
ほかの環境でもそうでしょうか。

現在のタッチ個数を得るために、touchPointというint型を用意しておき、TOUCH_BEGINで++, TOUCH_ENDで–しています。

private function _touchBeginHandler(e:TouchEvent):void
{
     _touchPoints++;
}
 
private function _touchEndHandler(e:TouchEvent):void
{
     _touchPoints--;
}

また、今回はタップ、ダブルタップを使えるようにしました。
TouchEvent.TOUCH_TAPを使うと、TOUCH_BEGIN, TOUCH_END, TOUCH_MOVE, TOUCH_TAPと4つのイベントすべてが発生してしまうので、それを回避するためです。
その部分のコードはこんな感じになります。

private function _touchBeginHandler(e:TouchEvent):void
{
     _touchDownTime = getTimer();
}
 
private function _touchEndHandler(e:TouchEvent):void
{
     _touchPoints--;
 
     if (_touchPoints == 0) _touching = false;
 
     if (getTimer() - _touchDownTime < TIME_DIFF) {
          var dist:Number = Math.sqrt(Math.pow(_currentPoint[e.touchPointID].x - _startPoint[e.touchPointID].x, 2) + Math.pow(_currentPoint[e.touchPointID].y - _startPoint[e.touchPointID].y, 2));
          if (Math.abs(dist) < POS_DIFF) _touchTap(e);
     }
}
 
public function _touchTap(e:TouchEvent):void
{
     _tapCnt++;
     if (!_timer.running) {
          _timer.addEventListener(TimerEvent.TIMER_COMPLETE, _timerHandler);
          _timer.start();    
     }
}
 
private function _timerHandler(e:TimerEvent):void
{
     switch(_tapCnt) {
          case 1 : atSingleTap.call(); break;
          case 2 : atDoubleTap.call(); break;
          case 3 : atTripleTap.call(); break;
          default:break;
     }
     _tapCnt = 0;
}
  1. TOUCH_BEGINが発生してからTOUCH_ENDが発生するまでの時間がしきい値以下
  2. TOUCH_BEGINの座標とTOUCH_ENDの座標がしきい値以下

2つの条件を満たした時にTimer.start()させます。タイマー作動中にもう一度2つの条件を満たした場合はtapCountを増やし、timerイベントがディスパッチされたタイミングでtapCountを判定し、シングルタップ、ダブルタップを判断します。この処理を利用すれば、3回や4回など、それ以上の回数も取れます。
ネックはラグが発生することですかねー。

また、イベントのハンドリングはProgressionのCommandやAS2と同じように関数を与えておき、適切な場所でそいつを実行してやることにしました。

MultiTouchSprite.atTouchBegin = function():void
{
     trace(currentPoint[touchObj.touchPointID]);
};

最初はExTouchEventというのを作ってディスパッチしていたんですけど、Flash Pratform Campで、Mike Chambersがディスパッチはパフォーマンス低下するよ!って言ってたので変更しました。
また当初Array型を使ってPointを管理していたのをVector型に変更し、パフォーマンス向上を図っています。

MultiTouchSpriteというクラスとしてまとめておいたので、使ってもらえるとうれしいです。
http://alterna.in/demo/MultiTouchSprite/MultiTouchSprite.zip

iPhoneアプリ「wonderP5」、iPadアプリ「wonderP5HD」をつくりました。

admin : 2010. 4. 14. 10:30 — iPhone

コード画面でコードをかき、ボタンを押すとレンダリングしてくれます。
なぜかiPad版もあります。iPad版は左にコード、右にレンダリング結果が表示されます。

経緯

@ll_koba_ll Processing jsやったらiPhone(iPad)で書いて実行とかできるのか
http://twitter.com/ll_koba_ll/status/11632081826

という@ll_koba_llさんのtwitterでの発言を見て、「あ、それほしい」となって、ここらへんの記事を読んだら意外と簡単そうだったので作ってみました。

まだまだほしいものがあったり(リファレンス的なものとか、twitpicへの投稿機能とか)しますが、通勤中にコードをかけるというのは素晴らしいです。

裏話

UITextViewのテキストを取り出して\nを削除し、UIWebViewでそのコードを実行してあげてるだけです。(すべての\nを削除しているために問題が発生しているみたいですが・・・)
あと作っているうちにiPhoneのオンライン版を発見したりとか本家がすごいのリリースしたりとかでびっくりしました。
でも、wonderP5だとhtmlとJSファイルをアプリ内にバンドルしているので、オフラインでも使えるよ!っていうのがイイトコだと思います。
ライセンス的にプロジェクトファイルの公開が可能かどうかがわからないので、問題がないことがわかれば公開します。
また、ベータ版として配信ということもできるかなーと思います。
完成度が上がれば、リリースもあるかもしれません。

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
(c) 2010 blog.alterna.in | powered by WordPress with Barecity