MacBook Pro Core i5

  • 2010 年 4月 23 日
  • kosuke

発売日の夜に注文したMacBook Pro Core i5 2.4GHz/15″がやっと到着。
CTOのせいなのか到着まで9日間って遅いよ!今使っているEarly 2008のCore 2 Duo 2.5GHz/15″からどのくらい変わるのか楽しみ。

無線LAN経由の移行アシスト実行したら、予想時間10時間って出たんで一旦キャンセル。これ寝る前に実行して朝終わるだろうか。早く使いたいけど仕事もあるんで移行作業は週末かな…。今のモデルはYさんに降ろす。また酷使されるだろうけどお疲れさまでした。

ApplicationDomain

  • 2010 年 4月 18 日
  • kosuke

最近のFlashはサイトは1つのプロジェクトを分業して複数人で開発することが多くなってきた。大規模なサイトを構築・運営するには一人の開発者が全てまかなえるわけもなく当然な話でもある。

そうなると問題になりそうなことがクラス名の衝突。実際、AS2のフルフラッシュサイトでは問題になったことも度々あった。
クラスベースで開発することが多いAS3では、親と子側のSWFで開発者が違うと同名のクラスがあって思うように動かないなんてことがますます増えそうだ。

そこで同名クラスの問題を回避するApplicationDomainの使い方を記録しておく。
ApplicationDomainの指定で同名クラスであっても親と子のクラスを分離できる。

2つのSWFがありどちらもドキュメントクラスがIndexだとします。
ただし、このIndexは別の開発者が作った別のクラス。そこで、

1) Index1.swf = Aさんが作ったswfで、Aさんが作ったIndexドキュメントクラスを持つ。
2) Index2.swf = Bさんが作ったswfで、Bさんが作ったIndexドキュメントクラスを持つ。
3) Index1.swfは、子としてIndex2.swfを読み込む。

とします。

で、Aさんが作ったindex1.swfのIndexクラスは、

package{
	import flash.display.*;
	public class Index extends Sprite{
		public function Index(){
			trace( "Aさん" );
		}
	}
}

「Aさん」と出力する。

かたや、Bさんが作ったindex2.swfのIndexクラスは、

package{
	import flash.display.*;
	public class Index extends Sprite{
		public function Index(){
			trace( "Bさん" );
		}
	}
}

「Bさん」と出力する。この二つもちろん単体では問題なく動きます。

しかし、Aさんの作ったIndexでBさんのindex2.swfを読み込むと

package{
	import flash.display.*;
	public class Index extends Sprite{
		public function Index(){
			trace( "Aさん" );
			var loader:Loader	= new Loader();
			loader.load( new URLRequest( "Index2.swf" ) );
		}
	}
}

期待に反して「Aさん」が出力され続ける。

読み込まれたBさんのIndexは、AさんのIndexクラスと同名の為、親側のAさんのIndexクラスと区別がつかず、AさんのIndexクラスを実行し続けてしまいます。なんにも取り決めをせず、別々に作ったら起きそうなエラーでしょ?
こんな時の為にApplicationDomainがあります。

AさんのIndexで、LoaderContextでアプリケーションドメインを分離して読み込むと、

package{
	import flash.display.*;
	public class Index extends Sprite{
		public function Index(){
			trace( "Aさん" );
			var context:LoaderContext	= new LoaderContext( false, new ApplicationDomain( null ) );
			var loader:Loader	= new Loader();
			loader.load( new URLRequest( "Index2.swf" ), context );
		}
	}
}

今度は正しく「Aさん」「Bさん」と出力されました。

ApplicationDomainはクラスを分離しているだけで、Index2.swfからIndex1.swfのプロパティやメソッドにアクセス出来なくなるわけではありません。こちらのアクセスはまた別の話。参照すれば親のメソッドを実行できます。

AさんのIndexでindex2.swfを読み込み表示する。

package{
	import flash.display.*;
	public class Index extends Sprite{
		public function Index(){
			trace( "Aさん" );
			var context:LoaderContext	= new LoaderContext( false, new ApplicationDomain( null ) );
			var loader:Loader	= new Loader();
			loader.load( new URLRequest( "Index2.swf" ), context );
			loader.contentLoaderInfo.addEventListener( Event.COMPLETE, 
				function onComplete(e:Event):void{
					addChild( loader );
				}
			);
		}
 
		public function onTest():void{
			trace( "Aさんのテスト" );
		}
	}
}

BさんのIndexで、AさんのIndexのメソッドを実行する。

package{
	import flash.display.*;
	public class Index extends Sprite{
		public function Index(){
			trace( "Bさん" );
			addEventListener( Event.ADDED_TO_STAGE,
				function( e:Event ):void{
					var parentIndex:Object = parent.parent as Object;
					if( parentIndex ) parentIndex.onTest();
				}
			);
		}
	}
}

逆に名前問題は解決していて子から親のクラスを使いたいってこともあると思います。
複数人での開発プロジェクトでは、セキュリティや受け渡しをしっかり話あっておかないと、合体させた時に思わぬトラブルに陥りそうですね。
Flashのセキュリティ関連は、バージョンが上がる度にややこしくなっているので、よくよく調べておこう。

参考:
ApplicationDomain クラスの使用
LoaderInfo
Flash Player セキュリティ

定数の構成

  • 2010 年 4月 16 日
  • kosuke

CS4から加えられたこの機能を今頃になって知る。実用的な機能なので記録しておこう。

ActionScript パブリッシュ設定

定数の構成を使うと、コンパイル時の条件指定が可能になる。
つまり定数の真偽値に応じてソースをSWFに含めるかどうか指定できるわけだ。
開発環境と本番環境とで異なる値を使う時や、デバック中はtrace出力したいけど公開するファイルには含みたくないなどの場合に使える。

ソース内に記述する変数で分岐させるのと違って、書き出したSWFにソース自体が含まれないので逆コンパイルの心配もないだろう。

定数の構成の設定パネルは、パブリッシュ設定 → ActionScript30.の詳細設定 → 定数の構成で表示する。

AS3のFlashファイルを作った場合、最初からCONFIG::FLASH_AUTHORINGという定数が宣言されている。これを使って例えば開発環境と本番環境で異なるURLが必要な場合、

package{
 
	import flash.display.Sprite;
 
	public class Teisu extends Sprite{
 
		public function Teisu(){
			super();
 
			var url:String = "http://nipx.jp/";
 
			CONFIG::FLASH_AUTHORING
			{
				url = "http://test.nipx.jp/";
			}
 
			trace( url );
		}
 
	}
 
}

のように記述すると、定数の真偽値によってURLを変更できる。
CONFIG::FLASH_AUTHORINGがtrueの場合、{ } 内のソースがコンパイルされて、urlはhttp://test.nipx.jp/になる。

多角形のパスの向き

  • 2010 年 4月 9 日
  • kosuke

多角形を構成する座標がある時、その多角形を左回りに描いているか右回りに描いているかの判定方法を記録。やらんとしていることは3Dの陰面消去と同様ですが、たとえば数字の「8」のアウトラインデータには、外側輪郭のパスが一つと、内側の抜きのパスが2あって、パスデータが輪郭のものか抜きのものか判断したかった。イラレでいうところの複合パスを作った時のパスの方向の部分です。

この判断方法ですが検索して、すごくわかりやすいページを見つけましたので紹介させていただきます。

参考
閉図形の座標の配列が右回りか左回りか調べる方法 – 教えて!goo
多角形の面積,重心(図心),断面N次モーメントの公式と,向き (頂点列の回転方向) の判別方法

わー、こういう公式があるんですね。試してみて期待通りの結果が得られました。

//右回りの座標
var _pts1:Vector.<Point>	= Vector.<Point>( [
	new Point( -50, -50 ),
	new Point(  50, -50 ),
	new Point(  50,  50 ),
	new Point( -50,  50 )
] );
 
//左周りの座標
_pts2:Vector.<Point>	= Vector.<Point>( [
	new Point( -50, -50 ),
	new Point( -50,  50 ),
	new Point(  50,  50 ),
	new Point(  50, -50 )
] );
 
//符号付面積を返す
function getArea( pts:Vector.<Point> ):Number{
	var S:Number	= 0;
	for( var i:uint=0; i<pts.length; i++ ){
		var a:Point = pts[i];
		var b:Point = ( i<pts.length-1 ) ? pts[ i+1 ] : pts[0];
		S += a.x * b.y - a.y * b.x;
	}
	return S / 2;
}
 
//右回りの座標より取得
getArea( _pts1 );
 
//左回りの座標より取得
getArea( _pts2 );

プロットして確認したファイル:多角形のパスの向き

This movie requires Flash Player 10.0.0

この公式、こちら作品でパスデータから塗りに抜きを作るのに使いました。
OutlineClock

pixelDissolveとDisplacementMapFilterのエフェクト

  • 2010 年 4月 8 日
  • kosuke

2BLOGの投稿は結構久しぶりになってしまいました。pixelDissolveを使ったエフェクト。
Flashやってて今更って話ですけど、はじめてwonderflを使った…。便利ですね。

フォーワードロック

  • 2010 年 3月 17 日
  • kosuke

モバイルコンテンツでは、どうも慣例的にこういうことをするようだ。

■参照
SWFファイルの再配布を防止するには
http://www.plusmb.jp/2009/03/27/3008.html

SWFに限った話ではないのだが、コンテンツの再配布を防止する為に自身の端末にダウンロードしたファイルを他の端末に転送できなくするメタデータを付与しておくらしい。

確かに有料コンテンツや企業サイトでよくみるようなインセンティブコンテンツの場合、その対価としてのコンテンツ配布であるのだからユーザーに転送されることは問題だろう。無料コンテンツの場合もサイトへの集客を考えればやはり転送されることは望ましくないかもしれない。

その気になれば簡単に解除できそうだし、ユーザーにとって純粋にバックアップや自身の別の端末に転送したいといった場合に不便さもあり、こういった対策がどれほど効果をもたらすものかわからないが打てる手は打っておくってところなんだろう。

CastPreloaderのイベント処理

  • 2010 年 3月 10 日
  • kosuke

Progression 4.0.1 Public Bate 1.3 を使っていて気づいたこと。CastPreloaderではProgressionインスタンスが生成されていないので、CastPreloader内でCastSpriteなど、Progressionの表示オブジェクトをAddChildコマンドで加えても、CastSpriteのatCastAddedなどイベント処理の実行がされないようだ。

たとえば以下のように、CastPreloaderのatCastLoadStart処理中にCastSpriteを加え,そのcastAddedイベント中にTraceコマンドで出力を試みても「 sample onCastAdded 」のtraceは出力されない。

override protected function atCastLoadStart():void{
	var sample:CastSprite	= new CastSprite();
	sample.onCastAdded = function():void{
		addCommand(
			new Trace( "sample onCastAdded" )
		)
	}
 
	addCommand(
		new AddChild( this.foreground, sample )
	);
}

castAddedイベントが正しく処理されるようにするには、PreloaderでもProgressionのインスタンスを生成しておくと期待通りになる。

override protected function atCastLoadStart():void{
	Progression.initialize( new WebConfig() );
	var manager:Progression	= new Progression( "preloader", this.stage );
 
	var sample:CastSprite	= new CastSprite();
	sample.onCastAdded = function():void{
		addCommand(
			new Trace( "sample onCastAdded" )
		)
	}
 
	addCommand(
		new AddChild( this.foreground, sample )
	);
}

ここでは、atCastLoadStart内でProgressionクラスの初期化とインスタンスを作っているけど、コンストラクタで作った方が自然かな。

ちなみに、PreloaderにProgressionクラスを加えると10K以上ファイルサイズが増えます。不要ならProgressionインスタンスをPreloaderで使う必要はないでしょう。
Preloaderの性質を考えるとそのファイルサイズは小さいほどよいと思いますので、CastPreloaderがデフォルトでProgressionインスタンスを生成しないのは僕は望ましいと思います。おそらくそのあたりがこの仕様の理由なんじゃないかと思ってみたり、みなかったり。

Basic認証を越える方法

  • 2010 年 2月 27 日
  • kosuke

前回エントリーの際に、Basic認証越えを試した時のメモ。

Basic認証を越える方法は、FLASH-JP.COM – フォーラム にスレッドが有名だと思います。

検索するとこれをAS3に置き換えた方法が沢山あったのですが、試してみて気づいたところがあります。それは送信メソッドがPOSTじゃないと認証されなかったことです。

例えば、以下だとリクエストヘッダで認証できませんでした。Base64エンコーダーはFlex SDKにインストールされているものを使っています。

var encoder:Base64Encoder	= new Base64Encoder();
encoder.encodeUTFBytes( "ユーザー名" : "パスワード" );
 
var header:URLRequestHeader	= new URLRequestHeader("Authorization", "Basic " + encoder.toString() );
var req:URLRequest = new URLRequest( "リクエストURL" );
req.requestHeaders.push( header );
 
navigateToURL( req );

こう書き直したら認証されるようになりました。

var encoder:Base64Encoder	= new Base64Encoder();
encoder.encodeUTFBytes( "ユーザー名" : "パスワード" );
 
var header:URLRequestHeader	= new URLRequestHeader("Authorization", "Basic " + encoder.toString() );
var req:URLRequest = new URLRequest( "リクエストURL" );
req.requestHeaders.push( header );
req.method= URLRequestMethod.POST;
req.data	= {};
navigateToURL( req );

変わっていることは、送信メソッドにPOSTを指定したことと、dataに空オブジェクトを加えたこと。リファレンスによれば、methodを指定してもdataが無いと自動的にGETで処理されるとあり、でダミーの値を入れておく必要があるようだ。ちなみにdataにオブジェクトを入れて、methodをGETにした場合も認証されませんでした。

FileReference

  • 2010 年 2月 25 日
  • kosuke

jpgやpng、mp3などをダウンロードさせたい時、navigateToURLで直接URLを指定するとブラウザのウインドウに表示さる。ブラウザのウインドウに表示せずダウンロードさせるにはFileReferenceが有効だ。

参考:FileReference – ActionScript 3.0 言語およびコンポーネントリファレンス

例:画像ファイルをダウンロードする

This movie requires Flash Player 10.0.0

private function _onMouseDown(e:MouseEvent):void{
	var req:URLRequest	= new URLRequest( "http://blog.nipx.jp/wp-content/uploads/2009/09/ceocle.jpg" );
	var file:FileReference	= new FileReference();
	file.download( req );
}

先日、これを使ってつまづいたところをメモしておく。よく読めばリファレンスに記載があったのだが…。

・認証がある場合、ブラウザからでないとダウンロードできない。
認証がある場合、Flashでパブリッシュした後の画面やスタンドアローンプレイヤーではダウンロードが失敗する。ブラウザで表示している場合、認証の入力画面が表示され認証可能。
仕事の場合、開発用のサーバーには大抵Basic認証がかかっていますがいちいちブラウザで確認するのは手間なので、パブリッシュの画面からダウンロードできないか試してみたのだけどダメっぽい。Basic認証を抜けるにはリクエストヘッダを送る方法が知られているけど、FileReferenceでは追加したリクエストヘッダ自体が無視されるようだ。


リファレンス download()メソッドより引用

サーバーでユーザー認証が必要な場合、ブラウザ内で実行される、つまり、ブラウザプラグインまたは ActiveX コントロールを使用する SWF ファイルでのみ、認証用のユーザー名とパスワードをユーザーが入力できるダイアログボックスを表示できます。〜

〜 URLRequest オブジェクトの requestHeaders プロパティは無視されるため、カスタム HTTP リクエストヘッダはアップロードまたはダウンロードでサポートされません。


FileReferenceを使う場合、ダウンロード状況を表示する演出なんか入れることありそうなんで、開発上ちょっと面倒だなぁと思う。ところでこのFileReference、Player 10以上ではFlashで生成したデータを保存させることが出来る。AirならFileで出来ると知っていたがFlash PlayerでもFileReferenceで保存できるようになっていたんですね。saveのdata引数にはByteArrayが渡せるのでどんなファイル形式でも保存出来るようだ。

例:テキストファイルに保存する

private function _onMouseDown(e:MouseEvent):void{
	var file:FileReference	= new FileReference();
	file.save( "FileReferenceでテキストデータを保存。", "sample.txt" );
}

executeのextra引数

  • 2010 年 2月 23 日
  • kosuke

Progressionでコマンドを実行するexecuteメソッドには、extraという引数があります。
シーン遷移でコマンドを実行する場合、extraを使うケースはほとんどないと思いますので、あまり馴染みのない引数ですが、コマンドを単体で利用する場合、extraを使うと便利なこともあります。

コマンドリストを実行する際extraを渡すと、コマンドリストに登録された全てのコマンドは実行時に渡されたextraをリレーします。つまり、登録されたコマンドはすべて実行時にextraを利用できます。

たとえば、一連のアニメーションを登録したコマンドリストを実行し、最後の挙動だけ異なるようにしたい場合など、extraを渡して挙動を変更することが可能です。

例:同じコマンドリストを実行し、最後のコマンドでextraで渡した異なる色値に変更する。

This movie requires Flash Player 10.0.0

btn0.label	= "RED";
btn1.label	= "GREEN";
btn2.label	= "BLUE";
 
 
_comm	= new SerialList( null, 
	new Prop( ball, { x:450, y:130 } ),
	new Prop( ball.transform, { colorTransform:new ColorTransform() } ),
	[
		new DoTweener( ball, { x:200, transition:"easeOutSine", time:3 } ),
		new DoTweener( ball, { y:350, transition:"easeOutBounce", time:3 } )
	],
	new Func( function():void{
		var trans:ColorTransform = new ColorTransform();
		trans.color	= this.extra;
		ball.transform.colorTransform = trans;
	})
);
_comm.interruptType = CommandInterruptType.RESTORE;
 
 
 
btn0.addEventListener( MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void{
	if( _comm.state == ExecutorObjectState.EXECUTING ) _comm.interrupt( true );
	_comm.execute( 0xFF0000 );
});
 
btn1.addEventListener( MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void{
	if( _comm.state == ExecutorObjectState.EXECUTING ) _comm.interrupt( true );
	_comm.execute( 0x00FF00 );
});
 
btn2.addEventListener( MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void{
	if( _comm.state == ExecutorObjectState.EXECUTING ) _comm.interrupt( true );
	_comm.execute( 0x0000FF );
});
@