アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

Flashコンテンツのスマホアプリ(iOS/Android)への移植手法に関して

あけましておめでとうございます、鴨田です。

今年一本目のアシアルブログの投稿になります。
今年もどうぞよろしくお願いいたします。

さて、昨年末に弊社で開発を行った案件として、
FlashコンテンツのiOS/Androidアプリ移植というのがありました。

Flashの移植では、いろいろと手法はあると思いますが、
今回は純粋にネイティブアプリに移植しました。

開発手法の選定や開発中の試行錯誤について、お話ししたいと思います。



手法の決定に関して



まず、元のFLAファイルが一つだけではなく、
複数のFLAファイルに分かれていたこと、
元のFLAファイルが存在しないコンテンツが存在していた、
ActionScriptがそもそも2.0だった、などのことから、
Abobe AIR for iOS/Androidを使うことはありませんでした。

いろいろな情報を集めた限りでは、
AIRで出来るのであれば、AIRを使うのがいいのかなと思います。

その次に考えたことは、CreateJSを使うことです。
弊社でも実績があるため、結構有力な方法として考えていました。

CreateJS

試しにいくつかのコンテンツでCreateJSを使用して、
HTML5に書き出してみました。

結果として、うまくいくコンテンツもあれば、
オブジェクト数が多すぎて、アプリ内のWebViewではもちろんのこと、
Androidの標準ブラウザにおいても、
処理が重すぎてまともに動作しないものもありました。
(PCのブラウザではサクサク動くのに・・・)

ということで、最終的にはネイティブアプリで作成することとしました。



ネイティブアプリで使う素材を準備する



まず、元のFLASHのメニュー部分などは、画角が合わないため、
スマートフォン端末用にレイアウトの組み直しと、
一部デザインの修正を行いました。

単純にムービーを再生するだけのコンテンツに関しては、
「Swivel」という、SWFを動画変換できるフリーソフトを使用して、
H264書き出しを行いました。
ActionScriptまで読み取って変換してくれるいいソフトです。

Swivel

あとは、タップ時などにアニメーションを行うというのが、
元になったコンテンツで主に使用されるアクションだったので、
Flashから各オブジェクトを連番PNGの形で書き出して、
ものによってはスプライト化、あるいは、ムービー化しました。



ネイティブアプリで実装する



前述したように、基本的にはオブジェクトがアニメーションするというのが、
アプリのコンテンツに共通した内容であったため、
連番PNGあるいはスプライト画像を使用して、
パラパラアニメーションを行うというのが主な実装内容でした。

これだけを聞くとすぐに実装できそうです。
事実、iOSでは特に問題なく、実装が完了したのですが、
Androidに関しては、OSバージョン、機種依存の問題が多々あり、
思うように実装が進みませんでした。

そのほとんどはAndroidのバグなので、
実装方法が悪いというわけでもなく、
どうにかこうにかやり過ごしましたが、
いろいろと煮え湯を飲まされました。

特に悩まされたこととして、
VideoViewとSurfaceViewの重なり順がおかしくなる、
というのがあるのですが、結局解決しなかったため、
重ならないようにレイアウト変更を行うことで避けたりしました。




FlashiOS/Androidへの移植関連で検索しても、最近の記事が見あたらないので、
もしかしたら、最近はあまり移植が行われていない可能性もありますが、
そのような案件があれば、参考にしてもらえたらと思います。。

まとめとしては、
ネイティブで開発する場合はクロスプラットフォームという意味では難がありますが、
いろいろと柔軟に対応できるのはとても魅力だと思います。

AIRで問題ないコンテンツであれば、もちろんAIRが第一選択になります。
クロスプラットフォームという意味でも問題ありませんし、
最近のAIRであれば、ネイティブ機能を使うことも問題ないようです。

今はまだ実用的とは言い難いですが、CreateJSなどを使用して、
HTML5化するというのも、今後は十分視野に入ると思いますし、
そうなって欲しいと願っています。

【Flex】FlexからJavascriptを実行してみる

こんにちは、橋本です。

今日は、FlexからJavascript関数へアクセスする方法についてお話したいと思います。

FlexからJavascriptへアクセスするためには、ExternalInterface APIを使います。

使い方は非常に簡単です。call()メソッドを使ってラッパーのJavascriptを呼び出すだけです。
Javascriptの関数に引数を渡したり、Javascript側から戻り値を受け取ることも可能です。

簡単なコードを書いて、実際に使ってみましょう。

Flexコード


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="955" minHeight="600">
	<mx:Script>
		<![CDATA[
			import flash.external.*;
			
			import mx.controls.Alert;
			
			public function setWrapperTitle(title:String):void
			{
				var ret:String;
				
				if (ExternalInterface.available)
				{
					ret = ExternalInterface.call("setTitle",title);
				}
				else
				{
					ret = "Fault";
				}
				
				Alert.show(ret);
			}
	
			protected function execBtn_clickHandler(event:MouseEvent):void
			{
				this.setWrapperTitle(this.titleInput.text);
			}
		]]>
	</mx:Script>
	<mx:Panel id="hoge"
			  width="280"
			  height="150"
			  x="{this.width / 2 - hoge.width / 2}"
			  y="{this.height / 2 - hoge.height / 2}"
			  title="タイトル変更"
			  >
		<mx:Form>
			<mx:FormItem label="タイトル:">
				<mx:TextInput id="titleInput"/>
			</mx:FormItem>
		</mx:Form>
		<mx:ControlBar width="100">
			<mx:Spacer width="100%"/>
			<mx:Button id="execBtn"
					   label="変更"
					   click="execBtn_clickHandler(event)"
					   />
		</mx:ControlBar>
	</mx:Panel>
	
</mx:Application>


ラッパーにScriptタグを追加して、Flexで呼び出す関数を設定します。



<script language="JavaScript" type="text/javascript">
	function setTitle(title)
	{
		window.document.title = title;
		
		return "success";
	}
</script>


実行結果がこちらです。







また、オブジェクトや配列をそのまま渡すことも可能です。
先程のソースを少し修正します。



<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="955" minHeight="600">
	<mx:Script>
		<![CDATA[
			import flash.external.*;
			
			import mx.controls.Alert;
			
			public function setWrapperTitle(obj:Object):void
			{
				var ret:String;
				
				if (ExternalInterface.available)
				{
					ret = ExternalInterface.call("setTitle",obj);
				}
				else
				{
					ret = "Fault";
				}
				
				Alert.show(ret);
			}
	
			protected function execBtn_clickHandler(event:MouseEvent):void
			{
				var obj:Object = 
				{
					title1: this.titleInput1.text,
					title2: this.titleInput2.text
				};
				
				this.setWrapperTitle(obj);
			}
		]]>
	</mx:Script>
	<mx:Panel id="hoge"
			  width="300"
			  height="180"
			  x="{this.width / 2 - hoge.width / 2}"
			  y="{this.height / 2 - hoge.height / 2}"
			  title="タイトル変更"
			  >
		<mx:Form>
			<mx:FormItem label="タイトル1:">
				<mx:TextInput id="titleInput1"/>
			</mx:FormItem>
			<mx:FormItem label="タイトル2:">
				<mx:TextInput id="titleInput2"/>
			</mx:FormItem>
		</mx:Form>
		<mx:ControlBar width="100">
			<mx:Spacer width="100%"/>
			<mx:Button id="execBtn"
					   label="変更"
					   click="execBtn_clickHandler(event)"
					   />
		</mx:ControlBar>
	</mx:Panel>
	
</mx:Application>


javascriptの方も、オブジェクトを受け取るように変更


<script language="JavaScript" type="text/javascript">
	function setTitle(obj)
	{
		window.document.title = obj.title1 + obj.title2;
		
		return "success";
	}
</script>


実行結果







また、無名関数をFlex内で直接記述して実行することも可能です。

さきほどのコードを、無名関数を使うように変更します。


	public function setWrapperTitle(obj:Object):void
	{
		var ret:String;
				
		if (ExternalInterface.available)
		{
			ret = ExternalInterface.call(
				"function(obj)" +
				"{" +
					"window.document.title = obj.title1 + obj.title2;" +
					"return 'success';" +
				"}"
			, obj);
		}
		else
		{
			ret = "Fault";
		}
		
		Alert.show(ret);
	}
	


実行結果は先程の例と同様になります。

無名関数を使うことで、適用の幅が広がると思います。
非常に簡単ですので、試してみてください。

【Flex】Flexのコーディング規約のお話

こんにちは、橋本です。

今日はFlexのコーディング規約についてお話しようと思います。

「え、Flexにコーディング規約なんてあったの!?」

とお思いの方も多いかと思いますが、実は公式のコーディング規約が存在します。

Flex SDK coding conventions and best practices

日本語訳はこちら


今日はこの中で個人的に気になったところを拾って見ていきたいと思います。


略語


原則は、略語を使用しないということになっていますが、一部標準化されている略語があります。

acc: accessibility(アクセシビリティ)。使用例: ButtonAccImpl
auto: automatic(自動)。使用例: autoLayout
eval: evaluate(評価)。使用例: EvalBindingResponder
impl: implementation(実装)。使用例: ButtonAccImpl
info: information(情報)。使用例: GridRowInfo
num: number(数値)。使用例: numChildren
min: minimum(最小)。使用例: minWidth
max: maximum(最大)。使用例: maxHeight
nav: navigation(ナビゲーション)。使用例: NavBar
regexp: regular expression(正規表現)。使用例: RegExpValidator
util: utility(ユーティリティ)。使用例: StringUtil


個人的には、obj(object)、arr(array)、str(string)なんかも標準に入れても良い気がするのですが。

プロパティ名(変数およびgetter/setter)


小文字で綴りを開始し、以後の連語をキャメルケース方式で記述します。例: i、width、numChildren。

ループのインデックスにはi、上限値にはnをそれぞれ使用します。 内部ループのインデックスにはj、上限値にはmをそれぞれ使用します。

for (var i:int = 0; i < n; i++)
{
    for (var j:int = 0; j < m; j++)
    {
        ...
    }
}

for-inループの変数には、p(プロパティの頭文字)を使用します。

for (var p:String in o)
{
    ...
}



for文に関しては、特に異論はないのですが、for-in文の規約には個人的に納得出来ないというか、微妙な気がします。

pってわかりにくいですよね?

for-in文の中でさらにfor-in文を使うときにはどうするんでしょうか?pをプロパティの頭文字と言うのであれば、qだとおかしいですよね?だとすると、p2?

微妙ですね。。。


ストレージ変数名



getter/setterのfooのストレージ変数には、_fooという名前を付けます。



これも、好き嫌いがあると思います。個人的には、内部プロパティについては、全て_hogehogeといった感じで、アンダーバーからスタートする変数名に統一するのが、意外と分かりやすくていいんじゃないかな、と。

イベントハンドラ


イベントハンドラには、イベントの種類を示す語句に「Handler」を結合した名前を付けます。例: mouseDownHandler()。

仮にハンドラが、サブコンポーネント(this}}以外のものなど)によってディスパッチされるイベント用のものである場合は、ハンドラ名の前にサブコンポーネント名を付け、これらをアンダースコアで結合します。例: textInput_focusInHandler()。


イベントハンドラについては、onを接頭詞として付ける派(onMouseDown、など)の方もいらっしゃるかと思いますが、FlashBuilder4から追加された、イベントハンドラを自動で作成してくれる機能では、上記の規約に従ってメソッドが作成されるので、こちらに移行した方がいろいろと楽かもしれません。

引数名


各setterの引数には、valueを使用します。

public function set label(value:String):void

各イベントハンドラの引数には、(e、evt、eventObjではなく)eventを使用します。

protected function mouseDownHandler(event:Event):void


個人的には、setterの引数には、setする引数名を使いたくなるんですが。。



private var _hoge:String;
			
public function set hoge(hoge:String):void
{
   _hoge = hoge;
}


どっちがわかりやすいんでしょうか。

型宣言


すべての定数、変数、関数引数、関数の戻り値に対して、型宣言を記述します。
Arrayデータ型を宣言する場合は、/* of ElementType */の体裁のコメントをArray直後に記述し、配列要素の型を示すようにします。 将来バージョンの言語では、型付けされた配列が含まれる見込みです。


これは、めんどくさいんですが、慣れるとコードが読みやすくていいかもしれません。
こんな感じです。




var arr:Array /* of String */ = [];



また、この規約はFlash10以降使えるようになった、Vectorクラスの記述に似せたものなのかもしれません。
Vectorクラスは配列みたいなものなのですが、中に格納するデータの型を指定する必要があります。




private var vector:Vector.<String>;



リテラル


String:
文字列の区切りとしては、たとえその文字列にクオーテーションマークが文字として含まれている場合でも、アポストロフィ(1重引用符)ではなくクオーテーションマーク(2重引用符)を使用します。

"What's up, \"Big Boy\"?";

Array:
new Array()ではなく、配列リテラルを使用する。

var arr:Array = [];

Object:
new Object()ではなく、Objectリテラルを使用する。

var obj:Object= {};



ArrayとObjectは基本かと思いますが、Stringが気持ち悪いですね。わざわざエスケープするくらいなら、シングルクォート使う方がわかりやすいと思うんですけどね。。

ifステートメント


if/elseステートメントの分岐後条件に単一のステートメントのみが含まれる場合は、これらをブロックにすることを避けます。
1.
if (flag)
    doThing1();

2.  
if (flag)
    doThing1();
else
    doThing2():



1番はまぁいいのですが、2番はブロックにしたいですよね。なんとなく気持ち悪い。。。

forステートメント


たとえステートメントが1つしかない場合でも、{{for}}ループの命令部分はブロックで記述します。
for (var i:int = 0; i < 3; i++)
{
   doSomething(i);
}


なんで、ifと逆なんだ…。

switchステートメント


各case句の内容、およびdefault句の内容はブロックで記述します。breakステートメントおよびreturnステートメントは、ブロックの後ではなくブロック内に記述します。 returnがある場合は、returnをbreakの後に配置しないようにします。 default句はcase句同様に扱うようにし、breakやreturnを記述してswitchの最後まで処理が達するのを防ぐようにします。

switch (n)
{
    case 0:
    {
        foo();
        break;
    }

    case 1:
    {
        bar();
        return;
    }

    case 2:
    {
        baz();
        return;
    }

    default:
    {
        blech();
        break;
    }
}


これは慣れると、非常に見やすいです。

PHPを書いてるときにも、switch文の書き方に違和感を感じていたので、この書き方は目から鱗でした。
ちなみに、PHPでもこの書き方、できます。

ローカル変数


ローカル変数は、その変数が初めて使用される時点、または使用される直前に宣言するようにします。 すべての宣言を関数の最初の部分に記述することは避けます。

正しい記述例
private function f(i:int, j:int):int
{
    var a:int = g(i - 1) + g(i + 1);
    var b:int = g(a - 1) + g(a + 1);
    var c:int  = g(b - 1) + g(b + 1);

    return (a * b * c) / (a + b + c);
}

誤った記述例
private function f(i:int, j:int):int
{
    var a:int;
    var b:int;
    var c:int;

    a = g(i - 1) + g(i + 1);
    b = g(a - 1) + g(a + 1);
    c = g(b - 1) + g(b + 1);

    return (a * b * c) / (a + b + c);
}


AS3はブロック内のみが有効範囲のローカル変数に対応しておらず、変数名の重複でコンパイルエラーが出るときが多々あるので、個人的には、最初にまとめて宣言しちゃいたいです。

まぁ、変数名にもっと気を使ってコード書けって話になるのかもしれませんが。

記述書式


コードは1行あたり半角文字80字で折り返します。 これにより以下のメリットを享受できます。

デベロッパーが小さな画面を使用している場合でも、長い行を読む際に水平にスクロールする必要がありません。
比較ユーティリティを使用する際、ファイルの2つのバージョンを並べて表示できます。
プロジェクタを使用してグループにプレゼンする際、スクロールではなくフォントサイズを大きくすることで対応できます。
途切れや無駄な改行なく、ソースコードを印刷できます。


一行あたり80文字は少なくないですか。
下手したら、メソッドの宣言だけで80文字こえちゃいますよ?
メリットは確かにあるのかもしれませんが、普段コードを書く分には80文字だと少し物足りないですよね。


インデント



半角スペース4文字のインデントを使用します。



PHPを書くときは、半角2文字派だったんですが、慣れると4文字の方が見やすいです。

その他にもいろいろとあるのですが、個人的に気になったのはこの辺でしょうか。
コーディングスタイルは人それぞれだと思いますので、そんなに気にすることもないのかもしれませんが、
時間があれば一度目を通してみると、いろいろと発見があって面白いかもしれません。

Flash内で作成した複数画像を同時にアップロードする

こんにちは、中川です。

つい最近、「Flashで作成した画像(jpg)をサーバ側にアップロードする」ということが必要になることがありました。
普通に画像1個であれば簡単なのですが、今回は複数同時にアップしたいという状況でした。

連続してのアップロードや、zip圧縮、画像を結合してなど様々な方法を教えていただいたりしたのですが、サーバ側の処理をいかに通常処理、かつ楽するかの部分でいろいろ探したところ、
「HTTPPostBinary」というas3のライブラリで実現することができそうですので、ご紹介したいと思います。
こちらを利用するとAS側のプログラムも特に面倒ということもなさそうです。

それでは、早速試してみましょう。

HTTPPostBinary class connects your flash program to general webservice」から「HTTPPostBinary.as」をダウンロードしてFlexプロジェクト内に配置します。

で、実際に使いかたも、上記ブログ記事のとおり、



var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest("http://www.flickr.com/tools/uploader_go.gne");
var httpdata:HTTPPostBinary = new HTTPPostBinary();
httpdata.addBinary("photo", jpegDat, "image/jpeg", "snap.jpg");
request.contentType = httpdata.contentType;
request.method = httpdata.method;
request.data = httpdata.encodeData();
loader.load(request);


このように簡単に利用できます。

以下、ボタンを押したら2種類のサイズの画面イメージをサーバにPOSTするサンプルです。
今回のサンプルの構成は以下のようになっています。



UploadFlex.mxml


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	<mx:Script>
		<![CDATA[

			import mx.graphics.codec.JPEGEncoder;
			import ym.net.HTTPPostBinary;
			
			public function upload():void { 
				
				//1個目の画像
				var bmd:BitmapData = new BitmapData(100, 200, false, 0xFFFFFF);
				bmd.draw(this);
				var encoder1:JPEGEncoder = new JPEGEncoder(100);
				var bytes1:ByteArray = encoder1.encode(bmd);
				
				//2個目の画像
				var bmd2:BitmapData = new BitmapData(50, 50, false, 0xFFFFFF);
				bmd2.draw(this);
				var encoder2:JPEGEncoder = new JPEGEncoder(100);
				var bytes2:ByteArray = encoder2.encode(bmd2);
				
				var loader:URLLoader = new URLLoader();
				var request:URLRequest = new URLRequest("/sample/post.php");
				var httpdata:HTTPPostBinary = new HTTPPostBinary();
				
				//画像を添付
				httpdata.addBinary("img1", bytes1, "image/jpeg", "img1.jpg");
				httpdata.addBinary("img2", bytes2, "image/jpeg", "img2.jpg");
				
				//テキストデータも同時に送信してみる
				httpdata.addString("hoge", "test string");				
				
				request.contentType = httpdata.contentType;
				request.method = httpdata.method;
				request.data = httpdata.encodeData();
				
				//送信
				loader.load(request);
			
			}
			
		]]>
	</mx:Script>
	<mx:Button click="upload()" label="upload" />
</mx:Application>


手元のFlexBuilderでの作成が手軽だったので、Flexプロジェクトとして作成していますが、
通常のASプロジェクトでもHTTPPostBinary自体の動作には影響なく動くでしょう。

そして、受け取る側のphpコードはおなじみの$_POST, $_FILESで大丈夫です。

post.php


<?php

/*
■UploadFlex.swfから以下のようなデータがPOSTされてくる

$_POST = Array
(
    [hoge] => test string
)

$_FILES = Array
(
    [img1] => Array
        (
            [name] => img1.jpg
            [type] => image/jpeg
            [tmp_name] => /tmp/phpD7lTa9
            [error] => 0
            [size] => 4873
        )

    [img2] => Array
        (
            [name] => img2.jpg
            [type] => image/jpeg
            [tmp_name] => /tmp/php7V23q5
            [error] => 0
            [size] => 2733
        )

)

*/

error_log(print_r($_POST, true), 3, '/tmp/hoge.txt');
error_log(print_r($_FILES, true), 3, '/tmp/hoge.txt');

//uploadディレクトリにPOSTされたファイルを保存
foreach ($_FILES as $key => $file) {
    if ($file['error'] == UPLOAD_ERR_OK) {
        $tmp_name = $file["tmp_name"];
        $name = $file["name"];
        move_uploaded_file($tmp_name, "./upload/".$name);
    }
}


実際にアップロードされた画像ファイルが以下の2個となります。
  
※ボタンだけを配置したFlashのキャプチャをしているため、見た目はアレですが、、、ちゃんと、指定した2種類のサイズで切り抜いて作成されています。


まだ、ちゃんとした検証はしてないですが、最新のFlash10のバージョンでは、手元のIE6, IE7, IE8, Firefox3.5では複数画像もPOSTデータも正常にサーバ側で受け取ることができました。

Box2DFlashAS3を使ってゲームっぽいものを作ってみる

こんばんは。松田です。
今回は以前ちょっとだけいじってみたActionScript用2D物理エンジンBox2DFlashAS3を使って簡単なゲームを作ってみたいと思います。

前回のエントリーはこちら

今回は前回いじったものをちょっとずつ直しながら、ゲームっぽく仕上げてみたいと思います。

ゲームセンターにあるなつかしのコインゲームをつくってみます。
コインを入れると上からコインがカタカタと落ちて来て、下のほうにある枠に入ります。
横一列に並ぶといっぱいコインがもらえ、同じマスに2つコインが入ると全部ボッシューとなります。
高校時代に近くのゲーセンに行くと、最初にこのゲームをやって所持コインを増やしてから他のゲームに回ってました。なついです。
参考URLでも出せれば説明しやすいのですが、正式名称がわからないのでググれませんでした。あれってなんてゲームなんですかねー。


さて、今回作るものは以下のような感じです。


1.コインの初期方向を決める左右に揺れて動く棒
2.パチンコのピンのような障害物となるちっちゃいbox
3.最終的にコインが収まる枠(枠の中にコインが2枚たまると床部分が一瞬消えるようにする)



2は単純にboxをたくさん配置するだけなので特に説明不要です。
3も単純ですが、枠の床部分を消すために、 world.DestoryBody(b2Body) を使用して床のboxを削除する必要があります。(この削除方法がわかるまで苦労しました・・・)

1のようなオブジェクトを作るには、自動的に動くモーター機能のついた、回転ジョイント(Revolute Joint)を使う必要があります。
回転ジョイントのおおまかな使い方は以下の通りです。


・動くboxを作成
・動きの支点となるちっちゃいboxを作成
・ジョイントの設定をするb2RevoluteJointDefを作成し、モーターの速度、ジョイントに使用する上記二つのオブジェクトを指定する
・world.CreateJoint(def)でジョイントを設置


他のコインが2枚重なった判定やその他のもろもろの処理はものすっごく汚い判定になってしまったので説明は省きます。
ソースコードはここ

別画面で開く
「投入」ボタンを押すとコインを落とします。
下に9つの枠がありますが、コインが隣同士に並ぶと払い戻し金が増えます。
2枚並ぶと4枚払い戻し、3枚並ぶと8枚、4枚並ぶと16枚・・・。
ただし、同じ枠に2枚コインが入ってしまうと全て没収されます。
そろそろ危ないな・・・と思ったタイミングで「払戻」ボタンを押しましょう。

いろいろと不具合が残りまくりですがそろそろ眠気がピークに達してきたので続きはそのうち・・・。

Box2Dはマニュアルがほとんど見当たらないので、目的の処理を行う方法を探すまでがなかなか大変ですね。

GoogleMapsAPI for FlashとJavscript版のGoogleMapsAPIを比べてみた

こんちわ。松田です。
つい最近GoogleMapsAPIを触る機会があったので、今まで使ったことのなかったFlash版のGoogleMapsAPIをいじってみました。
Flash版のFlex SDK、FlexBuilder、Flash CS3の場合のチュートリアルがそれぞれ公開されていますが、今回は最近良く使っているFlexBuilder上で実装しました。

以下、FlexBuilder使用時のGoogleMap表示までの大体の道筋を記述しておきます。

1. GoogleMapsAPI Keyの取得
GoogleMapsAPIを使用するために必要なAPI Keyを取得します。
http://code.google.com/intl/en/apis/maps/signup.html
すでにJavascript版のGoogleMapsAPIでキーを取得済みの場合はそれをそのまま使用できます。

2. GoogleMapsAPI for Flash SDKのダウンロード
ここのページの右中央部分、「How do start?」の2番、「Download the Google Maps API for Flash SDK」のリンクからSDKをダウンロードします。
このファイルを解凍し、適当な場所においておきます。

3. FlexBuilderで新規プロジェクトを作成
FlexBuilderを立ち上げ、「ファイル」→「新規」→「Flexプロジェクト」を選択。
「ライブラリパス」の設定タブが現れる画面まで「次へ」をクリック。
そのタブ内の「SWCの追加」ボタンをクリックし、先ほどダウンロードしたSDK内のswcファイルを指定します。
map_flex_1_9.swcとmap_1_9.swcの二つがありますが(2009年4月13日現在)、flex用のmap_flex_1_9.swcを選択します。

↑こんな状態になります。
これで「終了」をクリックしてプロジェクトを作成。

4. ActionScriptコードの記述
生成されたmxmlファイルに、
http://code.google.com/p/gmaps-samples-flash/source/browse/trunk/samplecode/MarkerDrag.mxml
この辺のサンプルコードをコピペ。
mapオブジェクトの生成直後に、


map.key = '取得したAPI Key';

を入力。これで実行すれば完了です。あとはリファレンスページを眺めながら欲しい機能を追加していきます。



上記のサンプルだと特に面白くなかったので、こっちの記事で作った機能をFlash版で実装してみました。
ソースコードは、Flash内で右クリックして「ソースの表示」をすれば見ることができます。



Javascript版と比べてどうなの?
あれ・・・なんかFlash版のほうが速い?となんとなく感じたので、Javascript版とFlash版の速度を比較してみました。

マーカーを表示させる数を100個、200個、300個・・・と増やしていき、何秒かかるか計測しています。すべてIE7で計測してます。念のため毎回ブラウザを終了させてやってます。
ちなみに計測開始はそれぞれの最初のメソッドが呼び出された箇所で、ページ表示時からの時間ではないので、そのあたりで多少の差はあるかもしれません。

個数:表示までにかかった時間(ミリ秒)
マーカー数JavascriptFlash
100個21251109
200個38281531
300個59072187
400個82192781
500個101413391
1000個228907453
Flash版がすんごい速いですね。
単純計算で描画の速度は3倍近くになってます。あっとうてきじゃないか。


Javascript版とFlash版で使用できる機能に差があるのかどうかはいまいち不明なのですが、ストリートビューは使用できないようです。
ですがこちらのmotuLogさんの記事によるとJavascript版との連携によりFlash内に表示させることは可能なようです。すげー。
http://plug.heteml.jp/motulog/


開発中の感想としては、これまではGoogleMapAPIを使用すると必ずJavascript開発がくっついてきてたわけですが、その周辺の問題を特に気にしなくて良くなったので、ブラウザの違いによる(IEによる)ストレス・心労負担が軽減されること間違い無しです。
また、FlexBuilder等の入力補完機能が使えたりデバッグが楽になるのもありがたいです。

これで機能も一通りそろっているのであれば、これからGoogleMapsAPIを使った開発はFlash版でもアリかもしれません。
今後地図アプリを作る予定のある方、Javascriptアレルギーのある方はぜひ使ってみてはいかがでしょうか。


参考:Flex BuilderでGoogle Maps API for Flash [ちょこっと]

Box2DFlashAS3を使ってFlash上で物理演算を行う

こんちは。松田です。
今日はそのうち試してみようと思いながらずっと放置してたBox2DFlashAS3を、今更ですがいじってみました。Box2Dはもともとc++用の物理演算ライブラリですが、それをFlash用にActionScriptで作られたのがBox2DFlashAS3です。

今回は以下の記事を参考にして勉強していきました。
http://gihyo.jp/dev/feature/01/box2d/

上記の記事のコードを最新版2.0.2のBox2Dを使用して試そうとすると、CreateStaticBody/CreateDynamicBodyの部分でエラーが出てしまうため、今回は記事と同じ2.0.0を使用してます。
過去バージョンも含めてBox2DFlashは以下からダウンロードできます。
http://sourceforge.net/project/showfiles.php?group_id=210232&package_id=252417

自分はFlexBuilder3を使って作成してるのですが、以下はその場合の初期設定方法です。


・上記URLからBox2DFlashAS3をダウンロードし解凍。
・FlexBuilderメニューの「ファイル」→「新規」→「ActionScriptプロジェクト」
・適当なプロジェクト名を指定してプロジェクトを作成。
・Flexナビゲータ内の生成したプロジェクト以下のsrcディレクトリ以下に解凍したファイルを全部つっこむ
・その中のMain.asを右クリックして「デフォルトのアプリケーションに設定」
・Ctrl+F11で実行

これでFlexBuilderから下のBox2Dのサンプルが実行できます。
(んでも自分の環境で生成するとピクリとも動きませんでした。。。なぜ・・・。)

本来のカッコイイサンプルはこちら


そして今回は勉強しながらドミノ倒しっぽいものを作ってみました。
ほんとはもっといろいろ仕込んでピタゴラスイッチ的なものを作りたかったんですが、まだまだ勉強が追いつかなかったので今回はこの辺で終了ということで・・・。

ソースコードここをクリック

このライブラリを使う用途がゲーム意外に思いつかないので、次の機会があればもうちょっとゲームっぽいモノを作ってみたいと思います。

FlexでWebカメラを使ってスナップショット撮影し、サーバーを経由せずにローカルに保存させてみた

こんばんは。まだまだ正月ボケが抜けてない松田です。

ちょうど一年ぐらい前に、「Flex2でWebカメラを使ってスナップショット撮影してみた」という記事をあげました。これは、Webカメラで撮影した画像をローカルに保存するというモノだったのですが、撮影した画像をローカルにダウンロードさせるには、一度サーバーにアップロードしてサーバースクリプトでダウンロードさせるしかない、という非常に使いづらいものでした。
あれから1年が過ぎ、サーバーを経由せずに保存する方法が出来ているようなので作ってみました。

以前のFlashPlayerでは、ローカルへのファイルの保存が許可されていなかったため、それ以上どうしようも無かったのですが、FlashPlayer10からはFlashからのローカルへのファイルの保存ができるようになったようです。
というわけで、今回は以前のスクリプトを改造して、スナップショット撮影から画像の保存までをFlashアプリ単体でやってみました。

まずはFlexBuilder側でFlashPlayer10に対応したアプリをつくるための設定が必要になるのですが、これは以下のサイトで詳しく解説されていましたのでこちらを参考にしました。
Flex Builder 3をFlash Player 10に対応させる at AS3S.ORG

そして完成品が↓です。ソースコードは画面内を右クリックして「ソースの表示」を選択して下さい。


Webカメラが接続されているPCでしか動作しません。
動くっちゃ動きますが真っ黒い画像がダウンロードされるだけです。

以前のスクリプトから修正したポイントは、保存ボタンが押されたときに呼び出されるclickSave()メソッドのみです。
以下のスクリプトでファイルをローカルに保存しています。


var ff:FileReference = new FileReference();
ff.addEventListener(Event.OPEN, function(e:Event):void {} );
ff.addEventListener(ProgressEvent.PROGRESS, function(e:ProgressEvent):void {} );
ff.addEventListener(Event.COMPLETE, function(e:Event):void {} );
ff.addEventListener(Event.CANCEL, function(e:Event):void {} );
ff.addEventListener(Event.SELECT, function(e:Event):void {} );
ff.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void {} );
var date:Date = new Date();
// pngはByteArrayデータ
ff.save(png, "snapshot" + date.getTime() + ".png");



Flashからローカルへのファイルの保存はいろんな場所で使えそうですね!

Away3Dを使ってFlex上で3Dを表示させてみる

前回に引き続きFlexの勉強中の松田です。

Flashで3Dを表示しなければならない機会があったので、Flash用の3D描画ライブラリを探して試してみました。
有名どころにPaperVision3Dというライブラリがあるのですが、今回はこれから派生したAway3Dを使ってみました。
ここのデモページでどんなことが出来るのか見ることができます。すごいです。



3Dを扱うこと自体が初めてなので、とりあえずは付属のサンプルを表示させるところからやってみたいと思います。

ダウンロードページから最新版のソースコードをダウンロードします。
解凍すると「lessons」というディレクトリがあってその中にサンプルがいくつか入っているので、その中から「Lesson_Basic_02_Primitives.swf」を表示させてみたいと思います。

同梱のflaファイルはAdobe Flash CS3等のアプリケーションが無いと開けませんが、サンプルのソースコードだけはこのページで見ることができるのでこっちから取得しましょう。

まずは通常のFlexプロジェクトの作成と同様に<mx:Application>タグまで生成します。
その後、<mx:Script>タグを追加してこのソースコードを貼り付けることになるのですが、このソースコードFlex用に作られたものではないので、これだけでは動作しません。
サンプルコード上では、CubeやSphereを乗せたView3DオブジェクトをaddChild()しているだけですが、Flex上で動作させるには、View3DをUIComponentにaddChild()した後、そのUIComponentをaddChild()することになります。
UIComponentを経由してaddChildさせる感じです。

あとはそのスクリプトを<mx:Application>のcreationCompleteで呼び出します。
これで実行。


やった。無事表示できました。
ソースコードは表示画面を右クリックして「ソースの表示」を選択してください。
物体上で右クリックするとAway3Dのメニューが開いちゃうので、背景で右クリックしてください。



これでFlex上で動作できるようになったので、あとはサンプルを見ながらいじりまくってみます。
Away3Dソースコードを覗いてみるとわかりますが、このライブラリはほっとんどコメントがありません。
Googleとカンと根性を頼りに試しまくるとなんとなく効果がわかってくるのでがんばりましょう。


そして今回触ってみてわかった成果が下の通りです。
覚えたことを思いつくまま羅列していきます。

物体の表示、移動
表示させる物体は全てObject3Dクラスを継承している
Object3Dクラスを移動させるにはmoveFoward(), moveBackward(), moveUp(), moveDown(), moveRight(), moveLeft(), moveTo()あたりを使う
物体を回転させるには、rotationX, rotationY, rotationZの値を増減させる

カメラ
カメラもObject3Dを継承したCamera3Dオブジェクトなので、Object3Dと同じメソッドで移動させることができる
カメラは移動しただけじゃ向いてる方向は変わらないので、どこかを向かせたいときはlookAt()メソッドを使う
moveTo()やlookAt()で指定する引数はNumber3Dオブジェクト(x,y,zの値だけを持つオブジェクト)
Object3Dの座標もこのNumber3D型のpositionという変数で持っている
なので、カメラを特定の方向に向けたければ view.camera.lookAt(new Number3D(100, 200, 300)); 
cubeの方を向かせたければ view.camera.lookAt(cube.position);

物体の色
new Cube({material:"grey#black",・・・ ここで指定するmaterialで物体の色や特性を決める
単純に色だけ指定する場合は、"面の色#線の色"
光源を反映する物体にする場合は、new ShadingColorMaterial(何かの色)

光源
光源はLight3Dオブジェクトを配置
光源によって色が変わるオブジェクトは、 material に new ShadingColorMaterial(0xFF0000) とか指定

ちょっとはまった細かいところ
カメラをY軸上から(0,0,0)を向かせるとうまく表示されない (0,0,1)あたりにして回避
灰色は"gray"じゃなく"grey"で定義されてる

分からないこと
ある物体を見ながら回りこむ動きって出来るの?
moveRight(target.position);の直後にlookAt(target.position);するとそれっぽくなるけど違うような・・・
地道に座標計算するしかないのか


役に立つかどうかは分かりませんが、このあたりを勉強したときに出来たサンプルを置いておきます。
何かの役に立てば幸いです。
ソースコードは上と同じで、右クリックして「ソースを表示」してください。

Flex3でカレンダーの指定日に色を付ける方法

こんにちは、中川です。最近は社内用のAirアプリを作ったりしています。
Flex3では、いろいろと便利なコントロールが容易されていますが、
標準のものでは、なかなかかゆいところに手が届かないものも出てくると思います。
その中の一つに「DateChooser」というものがあります。
日付選択用のカレンダーコントロールを簡単に設置できるのですが、
曜日に色をつけたり、指定した日に色をつけたりする方法がデフォルトの設定では、
なさそうでしたので、ちょっとカスタマイズしてみました。


これが、普通のDateChooserです。今日の日付に色を付ける機能は備わっています。

(※画像です)

今回は、土曜日、日曜日、指定日に色を付けるようにカスタマイズしてみます。
実際に動作させてみるとこんな感じになります。


以下のように使用することができます。

■Main.mxml


<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:as="*" 
	backgroundColor="#ffffff"
	creationComplete="initApp()">
	<mx:Script>
		<![CDATA[
		import mx.controls.Alert;
			
		private function initApp():void {
			// YYYY-MM-DD 形式の値の配列
			var daysArray:Array = [
				'2008-01-01','2008-02-11', '2008-03-20', 
				'2008-04-29', '2008-05-03','2008-05-04',
				'2008-05-05','2008-05-06','2008-07-21',
				'2008-09-15','2008-09-23','2008-10-13',
				'2008-11-03','2008-11-24','2008-12-32',
				];
			dateChooser1.setHilightDays(daysArray);
			dateChooser1.highlightColor = 0xff8800;
			dateChooser1.highlight();
		}
		
		private function upadteDateChooser():void {
			dateChooser1.highlight();
		}
		]]>
	</mx:Script>
	<as:ExDateChooser id="dateChooser1" 
		updateComplete="upadteDateChooser()" 
		todayColor="#BCF533"/>
</mx:Application>


上記サンプルでは、直接スクリプト内に日付の配列を書いていますが、
実際は、XMLや、DBから持って来ることになると思います。
DBからのデータを扱い安いように「YYYY-MM-DD」形式を渡すようにしています。

カスタマイズした、ExDateChooser.mxmlは以下のようになっています。

■ExDateChooser.mxml
>>JS



use namespace mx_internal;

import mx.core.UITextField;

private var hilightDaysObj:Object = { };
private var _hilightDays:Array = ;
private var _highlightColor:int = 0xff0000;
private var _saturdayColor:int = 0x0000ff;
private var _sundayColor:int = 0xff0000;

public function setHilightDays(days:Array):void {
this._hilightDays = days;
for (var i:int = 0; i < days.length; i++) {
this.hilightDaysObj[days[i]] = true;
}
}

public function set highlightColor(value:int):void {
_highlightColor = value;
}

public function set saturdayColor(value:int):void {
_saturdayColor = value;
}

public function set sundayColor(value:int):void {
_sundayColor = value;
}

public function removeHilight():void {
this._hilightDays =
;
this.hilightDaysObj = ;
this.highlight();
}

public function highlight():void {
var y:String = String(this.displayedYear);
var _m:int = this.displayedMonth + 1;
var m:String = (_m < 10)? String("0" + _m): String(_m);
var calBody:Array = this.dateGrid.dayBlocksArray;
var dd:Array =
;
for (var i:int = 0; i < calBody.length; i++) {
if (calBody[i] is Array) {
var line:Array = calBody[i];
for (var j:int = 1; j < line.length; j++) {
var txt:UITextField = line[j];
var _txt:String = (int(txt.text) < 10)? "0" + txt.text: txt.text;
var _date:String = y + "-" + m + "-" + _txt;
var key:String = _date;
//trace(i + ":" + j + ":" + key);
if (this.hilightDaysObj[key]) {
txt.setColor(this._highlightColor);
} else if (i == 0) {
txt.setColor(this._sundayColor);
} else if (i == 6) {
txt.setColor(this._saturdayColor);
} else {
txt.setColor(0x000000);
}
}
}
}
}
]]>