ラベル as3 の投稿を表示しています。 すべての投稿を表示
ラベル as3 の投稿を表示しています。 すべての投稿を表示

2011年3月2日水曜日

Unity3DがFlash上で動くようになる?

Unity Technologies Blogによると、UnityからFlashへの書き出しを検討しているようです。
リリース時期やサポートされる3D機能等は明言していないですが、
開発は順調に進んでいるようです。

FlashPlayer11から搭載されるGPU描画可能な"3D API (Molehill)"を利用したものになるので、
FlashPlayer11がリリースされた後に正式発表でしょうか。
ちなみにFlashPlayer11は2011年前半にベータ版リリース予定です。

もしこれが実現すれば、Flash単体での3Dオーサリングより手軽に作れるようになるんでしょうか。
ゲームの3D部分はUnity、メニュー等の2D部分はFlashという作り方ができるとベストなんですが!


2011年2月3日木曜日

[as3] WIndows7タブレット上のFlashのタッチ感度を良くする

WIndows7タブレットでFlashを動かすとタッチの感度が悪いかったので調べてみました。

WIndows7タブレットでマウスダウンを受け取るFlashを動かすと
タッチ時にマウスダウンイベントが来ず、指を少しずらした時に来る仕様になっているようです。
このままではタッチ操作がワンテンポ遅れてしまい、追従性のよくない動きになってしまいます。

タッチパネルのドライバとFlashの相性の問題かと思って、
いろんなメーカーのタブレットを試しましたが、どれもは挙動は同じ。

そこでFlashCS5から新しく加わったマルチタッチイベントを試してみると
Flashにスクリプト一行追加するだけで直りました。
//Flash CS5が必要です。
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;

これでタッチ時にマウスイベントが来て、サクサク動くようになりました。
調べてないけど、もしかするとAndroidとかでも有効かもしれない。

ただ、これからはTouchEventを使う方がよさそうなので、勉強しないとね。
参考:FlashゲームPG講座 For AS3.0【入力コントロールについて】


オンキヨー Personal Mobile TWシリーズ TW317A5
新品最安価格:¥ 68,525 (14店出品)
売上ランク:53347位
レビュー平均:4.04.0点 (1人がレビュー投稿)
by amazon通販最速検索 at 2011/02/03

2011年1月6日木曜日

[Kinectハック] SD_KinectIOをFlashで受ける

[Kinectハック] SD_KinectIO とりあえず公開でKinectからFlashへスケルトン情報を送るプログラムを公開していますが、それをFlashで受けるためのサンプルとライブラリも併せて作ってみました。



先のエントリでは人物のスケルトンモデルを表示するだけのデモを動かしていましたが、それと以前のオブジェクト移動のデモを合体させたサンプルを作成しています。

SD_KinectIOからは

"ユーザーID","部位ID","状態","x座標","y座標","z座標" (Null)

(例)
1,1,add,100.223,600.032,1534,302
1,1,update,140.344,632.323,1523,324
1,1,remove,0,0,0

ユーザーID:1~10
部位ID:1~24
状態:add,update,remove


というフォーマットで信号が送られてきます。

今回はスケルトン情報からFlash上にスケルトンモデルを表示させたいのですが、各ユーザーの各パーツがバラバラに送信されてくるので、それをFlashの方でユーザーごとにまとめてやる必要があります。
IDとパーツとの対応づけや、それを各ユーザーに割り振る処理は中々面倒そうだったので、今回もライブラリとしてまとめました。Google Code上のライブラリを更新していて、com.sdtech.kinect以下がそれに該当します。

・kinectパッケージ
・kinect.usersパッケージ

ひとまず、各オブジェクトをコンストラクタでインスタンス化していきます。


public function Main():void{
//
//ポインタ生成
mp=new MultiPointer(-1 , false);
mp.simulate=true;
mp.registerDefaultCursor(HandCursor);
addChild(mp);
//
//ボーン描画用
kmu=new KinectMultiUser();
kmu.mouseEnabled=kmu.mouseChildren=false;
addChild(kmu);
//
//FieldOfView設定
fov.addEventListener(Event.ENTER_FRAME , getFOV);
//
//接続開始
connect_btn.addEventListener(MouseEvent.CLICK , connectStart);
//
}


スケルトンモデルとボーン描画用のクラスのKinectMultiUserをインスタンス化し、以前も使用したPointerパッケージを組み合わせて使うため、同じようにインスタンス化します。また、3DのFieldOfViewを動的に変更出来るようにスライダーに、接続先を動的に変更出来るようにボタンにイベントを貼付けています。


private function connectStart(e:MouseEvent):void{
//
kc=new KinectConnector();
kc.addEventListener(Event.CONNECT , connectComplete);
kc.addEventListener(KinectEvent.RECEIVE , receiveKinectData);
kc.connect(ip.text , int(port.text));
//
}


接続ボタンが押されたら、SD_KinectIOに接続に行きます。受け取るデータは単なるプレーンテキストなのでXMLSocketで受け取っても問題ないのですが、今後特殊な仕様が追加される事を考えて、ここではKinectConnectorを使用しています。イベントリスナも専用の物を使用していますが、結局DataEvent.DATAと同じ処理になっているので、実はDataEvent.DATAを使用しても問題なかったりします。


private function receiveKinectData(e:KinectEvent):void{
//
//受け取ったデータをパースし、ボーンを描画
kmu.parseData(e.data);
//
for(var i:int=0 ; i<kmu.users ; i++){
//
//ユーザーを取得
var ku:KinectUser=kmu.getUserById(i);
if(!ku)continue;
//
//両手を取得
for(var n:int=0 ; n<2 ; n++){
//
//一意のIDを作成
var pointer_id:int=int(String(i+1)+(n+1));
//
var parts:KinectUserParts;
if(n==0){
parts=ku.getPartsById(KinectUserParts.R_HAND);
}else{
parts=ku.getPartsById(KinectUserParts.L_HAND);
}
//
if(!parts){
mp.lost(0,0,pointer_id);
continue;
}
//
//グローバル座標に変換
var p:Point=ku.local3DToGlobal(new Vector3D(parts.x , parts.y , parts.z));
//
//ポインタ認識
mp.detect(p.x,p.y , pointer_id);
//ポインタを動かす
mp.move(p.x,p.y,pointer_id);
if(parts.z>1500){
mp.down(p.x,p.y,pointer_id);
}else{
mp.up(p.x,p.y,pointer_id);
}
//
}
//
}
//
//
}


データを受け取ったらボーンを描画しますが、KinectMultiUserにはサーバーから受け取ったデータを渡すと自動的にボーンを描画してくれるparseDataというメソッドが実装されているので、ボーン描画部分はその一行で済んでいます。
内部的には、受け取ったデータをパースしてユーザーIDを取得し、まだ存在しなかったらユーザー追加、存在したらデータ更新、という何の変哲も無い処理になっています。

肝心のボーン描画部分は一行で済んでしまっていますが(笑)、これでFlash上にスケルトンモデルを描画する事が出来ました。

さて、ここから以前のようにオブジェクトを動かせるようにしていきます。


for(var i:int=0 ; i<kmu.users ; i++){
//
//ユーザーを取得
var ku:KinectUser=kmu.getUserById(i);
if(!ku)continue;
//
//両手を取得
for(var n:int=0 ; n<2 ; n++){
//
//一意のIDを作成
var pointer_id:int=int(String(i+1)+(n+1));
//
var parts:KinectUserParts;
if(n==0){
parts=ku.getPartsById(KinectUserParts.R_HAND);
}else{
parts=ku.getPartsById(KinectUserParts.L_HAND);
}
//
if(!parts){
mp.lost(0,0,pointer_id);
continue;
}
//
//グローバル座標に変換
var p:Point=ku.local3DToGlobal(new Vector3D(parts.x , parts.y , parts.z));
//
//ポインタ認識
mp.detect(p.x,p.y , pointer_id);
//ポインタを動かす
mp.move(p.x,p.y,pointer_id);
if(parts.z<1500){
mp.down(p.x,p.y,pointer_id);
}else{
mp.up(p.x,p.y,pointer_id);
}
//
}
//
}


まず、KinectMultiUserのusersプロパティで現在認識されている最大のユーザー数を取得し、各KinectUserインスタンスへの参照を取得します。各ユーザーの両手を認識したいので、さらにfor文で両手分処理を繰り返します。繰り返し処理の中は以前のエントリとほぼ同じですが、x,y座標は各ユーザーの両手の座標を使用したいので、各パーツ(KinectUserParts)の座標を使用します。また、今回はx,yに加えてz座標も加味する必要があるので、座標変換の時にlocalToGlobalでなくlocal3DToGlobaを使用しています。

これで、スケルトンモデル+オブジェクト操作で、スケルトンがオブジェクトを操作しているようなデモができました。
オブジェクトの操作について、現在は奥行きでDOWN/UPを判断していますが、手のひらの開閉が取れればもっと自然で良いんですけどね。C++は専門外なので、解析するにしても時間がかかりそうです…

ソースをダウンロード

2010年12月21日火曜日

SDLibrary公開しました

Google Codeにて、ブログ編集メンバーで作ったライブラリを公開中です。

SDLibrary
http://code.google.com/p/sd-tech-blog-as3-library/

asdocも書き出していて、リポジトリ上のファイルがそのまま閲覧出来ます。
http://sd-tech-blog-as3-library.googlecode.com/svn/trunk/doc/index.html

今回は2つパッケージを公開していて、

■「osc」パッケージ

oscを用いてCCVやReactivisionとの通信を受け持つライブラリです。
以前のエントリ「自作マルチタッチシステムを作ってみた」でもこのパッケージを使用しています。

■「pointer」パッケージ

Flash上でマルチユーザーマルチタッチを実装するライブラリです。
このライブラリも、「自作マルチタッチシステムを作ってみた」「Kinectハック」で使用しています。

今後も、公開出来そうな物ができたら更新していこうと思います。

[Kinectハック]OpenNI+Flashでマルチユーザー・マルチタッチ Flashで実装編



[Kinectハック]OpenNI+Flashでマルチユーザー・マルチタッチ OpenNI解析編 の続き。


fukusinさんがopenNIのサンプルを解析/改造してくれたおかげで、Kinectの信号をXMLSocketを利用してFlashでも受け取れるようになりました。現時点では各ユーザーの両手のみの検出になっていますが、信号的には頭、首、肩…と、ボーンを表示するのに必要な頂点は全て取れているようです。

さて、今回は「Flashで実装編」として、Kinectから送られてきた信号を解析してFlashに組み込んでいきます。今回のデモでは、各ユーザーの両手が識別できるためマルチタッチのような操作が可能になりますが、正確には「マルチ」ですが「タッチ」ではないですね。空中操作になりますから。「マルチポインタ」と言った所でしょうか。重箱の隅をつつくみたいですが、これ、重要なんです。



この場合、UI的にマルチタッチと全く同じ作法にするのは問題があるのです。タッチ操作であれば画面上のオブジェクトに触れる前にどこに触れるか分かりますが、空中操作、しかもKinectのように画面から離れて操作するものの場合は、実際に手を出してみないとどこにカーソルが表示されるか分かりにくいですよね。

普通タッチパネルでは触った=マウスダウンと同じ操作になり、ロールオーバーとダウン操作を共存させる事が出来ないのですが、前述の理由からKinectの場合はそれが必要になってきます。本家Microsoftは長押しの様な動作で決定(ダウン)操作としていますが、幸いにしてKinectは各ポイントのz値も取れるので、今回は各ポイントのz値がある閾値を下回ったら(手が前に突き出されたら)ダウン状態、閾値を越えたら(手が引っ込んだら)アップ状態として扱う事にします。

今回のデモでは、自前の汎用マルチポインタライブラリを使用しています。ポインタが「認識」「ダウン」「移動」「アップ」「消失」した状態をそれぞれ持つ事が出来、さらにポインタの下にある各DisplayObjectがイベントを発行するように設計したため、MouseEventと同じ様に使う事が出来ます。また、Kinectのような特殊なシステムでない、普通のマルチタッチにも対応できるようになっています。以前のエントリにある「自作マルチタッチシステムを作ってみた」でも、このクラスを使用してマルチタッチを実装しました。

まず、コンストラクタでマルチタッチの用意をし、XMLSocketコネクトのための準備をします。

//==========================
//コンストラクタ
//==========================
public function Main():void{
//
mp=new MultiPointer(-1 , false);
mp.simulate=true;
mp.registerDefaultCursor(HandCursor);
addChild(mp);
//
connect_btn.addEventListener(MouseEvent.CLICK , connectStart);
//
}


マルチタッチに用いるクラスは「MultiPointer」クラスです。汎用クラスとして色々出来るように作ってあるのですが、ここでは詳しい説明は割愛します。
詳細はGoogle Codeにアップしたドキュメントをご覧下さい。

//==========================
//接続開始
//==========================
private function connectStart(e:MouseEvent):void{
//
socket=new XMLSocket();
socket.addEventListener(Event.CONNECT , connectComplete);
socket.addEventListener(DataEvent.DATA , receiveData);
socket.connect(ip.text , int(port.text));
//
}
//
//
//==========================
//接続完了
//==========================
private function connectComplete(e:Event):void{
//接続のためダミーデータを送信(サーバー仕様による)
socket.send("test");
}


ステージ上にあるボタンを押したら接続を開始し、接続が完了したらサーバーにデータを送信します。これは今回作成したサーバー側の仕様で、一旦双方向に通信しないと接続が確立出来ないようになっているためです。

//==========================
//データ受信
//==========================
private function receiveData(e:DataEvent):void{
//
//データ解析
var data:Array=e.data.split(",");
var id:int=data[0];
var parts:int=int(data[1]);
var x:Number=Number(data[2]);
var y:Number=Number(data[3]);
var z:Number=Number(data[4]);
//
//一意のIDを作成
var pointer_id:int=int(parts.toString()+id.toString());
//
//ポインタ認識
mp.detect(x,y,pointer_id);
//ポインタを動かす
mp.move(x,y,pointer_id);
if(z<1500){
mp.down(x,y,pointer_id);
}else{
mp.up(x,y,pointer_id);
}
//
}


データを受信したら、受信したデータを解析してMultiPointerクラスに渡します。 今回、データは「,」区切りの文字列として送信されてくるので、splitで分割し、それぞれの変数に入れていきます。 サーバーから送られてくるデータの中身は

ユーザーID , パーツ名(左手9/右手15) , x座標 , y座標 , z座標

というフォーマットになっています。
このデータを受け、ポインタ生成部分は以下のようになっています。

//一意のIDを作成
var pointer_id:int=int(parts.toString()+id.toString());
//
//ポインタ認識
mp.detect(x,y,pointer_id);
//ポインタを動かす
mp.move(x,y,pointer_id);
if(z<1500){
mp.down(x,y,pointer_id);
}else{
mp.up(x,y,pointer_id);
}


MultiPointer内に以下のメソッドがあり、それぞれ

・ポインタ認識 - detect()
・ポインタ移動 - move()
・ポインタ押下 - down()
・ポインタ押上 - up()

そしてここでは出てきていないですが、

・ポインタ消失 - lost()

となっています。

各関数にはx , y , idの引数を渡す必要があり、ここではマルチユーザーに対応するためパーツのIDとユーザーIDを一旦String形式で結合し、intに変換する事で一意のIDを生成しています。

押下/押上の判定については、z値を使用しています。暫定的に閾値を1500と設定し、手の前後操作でdown/upをそれぞれ実行するようにしています。
肝心のマルチタッチを受けてオブジェクトを操作する部分ですが、これは良く使う操作ですので、基本クラスとして用意しました。 ステージ上のオブジェクトの基本クラスに「PointerHandlingObject」というクラスを設定しています。このクラスは、マルチポイントによる操作と言えば王道な移動、拡縮、回転をサポートしています。

これで、Kinectと接続してFlash上のオブジェクトを操作する簡単なデモが出来ました。
Flashのソース: KinectFlash_sdtech.zip

今回使用した「MultiPointer」クラスは「自作マルチタッチシステムを作ってみた」でも使用しているのですが、その解説はまた今度ということで。

2010年12月16日木曜日

タイムラインにMCを置いてgotoAndStopでフレームを移動するときの注意

タイムライン上に画像等を配置して、フレームを動かす事によってMCの内容を切り替えるという手法、まだまだよく使います。しかし、フレームに配置されている要素がMCだった場合、少し注意が必要です。

例えばA.asというクラスを持ったMCを1〜3フレームに配置します。
各フレームにはキーフレームを切ってあり、MCの座標は各フレームで違い、各MCには60フレーム程のアニメーションが設定されているとします。

public function A():void{
addEventListener(Event.ADDED_TO_STAGE , init);
addEventListener(Event.REMOVED_FROM_STAGE , init);
trace("construct");
}

private function init(e:Event):void{
if(e.type==Event.ADDED_TO_STAGE){
trace("added");
gotoAndPlay(2);
}else{
trace("removed");
gotoAndStop(1);
}
}


のようにコードを書きます。
すると、下記のような挙動になります。
(マウスクリックで次のフレームに進みます)



各フレームに別のインスタンスを生成したつもりなのに、あたかも一つのインスタンスの座標が変わったかのようにアニメーション状態を引き継いでしまいます。
これを回避するには、各MCに名前を付けると良いようです。
下記は、各MCに名前を付けたものです。
(マウスクリックで次のフレームに進みます)



タイムラインにMCを並べてレイアウト等を管理する時は、少しこの点に注意して作成した方が良いかもしれません。