2009年5月29日
例えばイテレータみたいなのを定義するときに
public interface Iterator 
{
    public function next():Object;
}
ってすると、これを実装したクラスを作るときに、 next() が必要なことは明示できるけど 使うときに中身がなんなのかはっきりしなくて、何となく気に入らないので
public interface Iterator 
{
    public function get next():Function;
}
ってやって、実装したクラスは
public class SpriteIterator implements Iterator 
{
    public function get next():Function
    {
        return getNext;
    }
    
    private function getNext():Sprite
    {
        return spriteInstance;
    }
}
ってやればいいんじゃないかと、つぶやいたら
隣から「邪道」「余計にめんどくさい」と一蹴されてしまった。

そもそも、こんなことしてもコード補完は効かないから、 型に * 指定するのと変わらなくなってしまった。

っていうダメダメな話。


CS4 の fl パッケージの場所
C:\Program Files\Adobe\Adobe Flash CS4\Common\Configuration\ActionScript 3.0\projects\Flash\src

mx パッケージ
C:\Program Files\Adobe\Adobe Flash CS4\Common\First Run\Classes\

AS3 リファレンス
file:///C:/Program%20Files/Common%20Files/Adobe/Help/ja_JP/AS3LCR/Flash_10.0/index.html

2009年5月14日
var x:int = 9;
var y:int = 3;
trace(x + y); // 12
trace(x - y); //  6
trace(x * y); // 27
trace(x / y); //  3
trace(x % y); //  0
trace(x & y); //  1
trace(x | y); // 11
trace(x ^ y); // 10
2009年2月20日
FlashDevelop から入力ダイアログを表示して、計算式を入力するとその結果が現在のキャレット位置に挿入されるプラグインです。

対応しているバージョンは FlashDevelop3 RC1 以降となります。
下位のバージョンでも動作するかもしれないですが、動作確認を取っておりません。

FDCalculator.zip ダウンロード

上記リンクからダウンロード、解凍後、中に入っている FDCalculator.dll を
以下のフォルダにコピーします。

C:\Program Files\FlashDevelop\Plugins

FlashDevelop を再起動すると、Insert メニュー内に以下の項目が追加されます。
  • FDCalculator

FDCalculator (Ctrl + Shift + 4)
使用方法はダイアログ内に計算式を入力して Enter キーを押すか、OKボタンを押すだけです。
以下にいくつか入力例を挙げておきます。
exp は入力した計算式、
res はその結果です。

四則演算
exp : (5+6-7)*4/2
res : 8

ビット演算
exp : 1 << 16
res : 65536

AS3 に実装されている Math クラスのメソッドやプロパティを使用することも出来ます。
使用する際に Math は必要ありません。
exp : cos(0.5) + sin(0.5)
res : 1.35700810049458
exp : sqrt(pow(4, 2) + pow(6, 2))
res : 7.21110255092798
exp : floor(PI*100)/100
res : 3.14

16進数の入力も可能です。
exp : 0x7F7F7F & 0xFF
res : 127


特殊関数
独自に実装された関数もいくつか用意しています。

hex(value:uint):String
数値を16進数の文字に変換します。
exp : hex(10079487)
res : 0x99CCFF

deg(value:Number):Number
ラジアン値を角度(180度)に変換します。
exp : deg(PI*0.5)
res : 90

rad(value:Number):Number
角度(180度)をラジアン値に変換します。
exp : rad(60)
res : 1.0471975511966

color(ARGB:uint, s:Number, exp:String):uint
色をARGBに分解してそれぞれの値を計算した結果を返します。
exp に入る文字は次のいずれかになります。(+ - / * % & |)
exp : hex(color(0xFFFFFF, 0.5, "*"))
res : 0x7F7F7F
color2(ARGB1:uint, ARGB2:uint, exp:String):uint
2 つの色情報をもとに演算を行った結果を返します。
exp に入る文字は次のいずれかになります。(+ - / * % & |)
exp : hex(color2(0xFF9933, 0x404040, "|"))
res : 0xFFD973


2009年2月19日
追記 (2009.05.08)
RC2 になって一部ディレクトリ構造が変わってしまい、使えなくなっていたので修正しました。
RC2、RC1 どちらでも使えます。
一応前のバージョンのものも残しておきます。
TemporaryProject_0.1.2.zip ダウンロード

--------------------------------------------------------------

FlashDevelop + FlexSDK は非常に便利で、書き出しも早いので重宝しているのですが、 簡単なテスト用のスクリプトを書いて実行する場合でも、毎回プロジェクトを作成しなくてはならないのが煩わしいと思ってました。
なのでプロジェクトをほとんど気にせずに、簡単にテスト環境を用意するプラグインを作ってみました。

wonderfl のエディタとして利用している場合にも便利なんじゃないかと思います。


対応しているバージョンは FlashDevelop3 RC1 以降となります。

最新のバージョン
TemporaryProject_0.1.2.zip ダウンロード

過去のバージョン
TemporaryProject_0.1.1.zip ダウンロード

上記リンクからダウンロード、解凍後、中に入っている TemporaryProject.dll を
以下のフォルダにコピーします。

C:\Program Files\FlashDevelop\Plugins

FlashDevelop を再起動すると、Project メニュー内に以下の項目が追加されます。
  • Temporary Project
  • Previous Project
  • Next Project

Temporary Project (Ctrl + Shift + 3)
新たにプロジェクトを作成します。
このプロジェクトは FlashDevelop を終了すると削除されます。
削除されないようにするには Program Settings (F10) 内の
TemporaryProject > ClearTemporaryProjects を false にします。

ここで作成されるプロジェクトは、
{FlashDevelop}\Data\TemporaryProject\template
上記テンプレートから生成されるようになっています。
このテンプレートを変更することで、自由にカスタマイズできます。
MXML ベースのプロジェクトにも変更できます。

{FlashDevelop}\Data\TemporaryProject\tmp
作成した一時プロジェクトは、この中に作成されています。

Previous Project (Ctrl + Shift + ,)
Next Project (Ctrl + Shift + .)
このプラグインを使用していると簡単に新規プロジェクトを作成して試し書きができますが、
メインで使用していたプロジェクトが閉じてしまいます。
そのため、このプラグインではプロジェクトの履歴を最大20件まで記録しています。
「Previous Project」「Next Project」を使用して過去に開いていたプロジェクトへ、簡単に行き来することができます。


2009年2月 2日
FlashDevelop 3 用のプラグインを作りました。
このプラグインは、FlashDevelop の編集中のドキュメントに対して JavaScript を実行して編集することができるようになります。
コマンド用のスクリプトは .jsfd ファイルとしてプラグインディレクトリ内に保存されますので、自由に追加・編集・削除が可能です。
これを使うことで、簡単なプラグインであれば、C# を使うことなく作成、編集することができるようになります。


現在はまだ制作の途中段階ですので、今後仕様が変わる可能性はあります。


ダウンロード
fdcommands_0_1_2.zip

追記
fdcommands_0_1_3.zip
prompt() と alert() が使えなかったので、実装しました。

内容
  • FDCommands.dll
  • commandList.txt

導入方法
FlashDevelop の起動ディレクトリ内に Plugins というディレクトリがあるので、そこに FDCommands.dllをコピーしてください。
例(XP の場合):
C:\Program Files\FlashDevelop\Plugins
FlashDevelop を再起動すれば「メニュー > View」に FDCommands と追加されています。選択すると上記のパネルが表示されます。
初回起動時に、FlashDevelop の Application Files に指定されているディレクトリの Data\FDCommands ディレクトリの中に Commands というディレクトリが作成されます。(以下 Commands はこれを指します。)この中にコマンドファイルが作成されます。


使い方

コマンドリスト名
パネル上部のコンボボックスです。
Commands 内に存在するディレクトリの中から1つ選択することが出来ます。
初期状態では、ディレクトリは "default" のみです。

メニューボタン
Run
パネル下部のテキストボックスに表示されているコマンドを実行します。コマンドが選択されていない状態でも、エディタ部分にコードが書き込まれていた場合は、それを実行します。
Refresh
Commands ディレクトリを再読み込みします。
Edit
選択中のコマンドを FlashDevelop で開きます。
Add
新しくコマンドファイルを作成します。作成すると FlashDevelop に表示され、編集することができます。
Delete
選択中のコマンドを削除します。実行すると jsfd ファイルも削除されます。
Add Directory
コマンドファイルを入れておくディレクトリを新しく作成します。

コマンド一覧
選択中のリスト内のファイルが一覧表示されます。
リスト内のアイテムは、クリックすると選択状態となり、ダブルクリックで選択中のコマンドが実行されます。

コマンド簡易エディタ
リストからコマンドを選択すると、コマンドのソースが表示されます。
メニューの Run ボタンは、このソースを実行します。
このエディタは、編集が可能ですが、編集した内容を保存することは出来ません。
保存する場合は、新しくコマンドファイルを作成するか、既存のコマンドを編集して保存しなければなりません。



コマンドの作成
zipファイル内に同梱されているテキストファイル内に、使用できるオブジェクトと関数を書いておきましたので、こちらを参考にしてください。
内部で JScriptCodeProvider を使用しているので、基本的な JavaScript は普通に使えるかと思います。(実際には JScript なんですが。)
また改めてドキュメントを作成する予定ですが、今はまだ仕様もはっきり決まっていないため、作っていません。



今後実装したいと思っている機能について
  • キーボードショートカットの実装
  • AS3のクラスの参照
  • JSFDソースのコードヒント


クラスの参照については、対象のクラス内で定義された import や implements を参照して、クラス内で定義されているプロパティを簡単に取得できるようにしたいのですが、 swc の場合など、どうすればいいのか正直分からなくて困ってます。
ProjectManager や Outline などのプラグインを参照して、そこから取得できればと思っているのですが、他のプラグインの参照の仕方が分からなかったり。

あと、このプラグインのソースも誰か助言くれる人とかいるのなら、GoogleCode か Spark(いいのかな?)で公開したいとも思ってますが、まだ未定です。
手探りで作ってるので、バグもたぶんあります。
もし使用される方がいらっしゃれば、バグが見つかったときはコメントなりTwitter なりで報告していただけると助かります。


また、これを使ってみんなが便利なコマンドを作ってくれたらなあ。なんて浅はかな願望もあったり、なかったり、らじばんだり。



ちょっと立て込んでいるので遅くなるかもしれないですが、またアップデートしたらご報告します。

そもそもこんなプラグインに需要があるかのかどうか。


2009年1月27日
FlashDevelop のプラグインの作り方をメモ。其の二。

■試しに一からこさえてみる。

# 準備
FD3 ディレクトリ内に CustomPlugin という空のディレクトリを作っておく。

# プロジェクトを作成する
Visual Studio を立ち上げて、ファイル > 新しいプロジェクト(Ctrl + Shift + N)を選択。
開いたテンプレートの中から「空のプロジェクト」を選択して「OK」。

ファイル > Project1.sln の保存(Ctrl + S)を選択。
  • 名前:TestPlugin
  • 場所:先ほど作った CustomPlugin ディレクトリ
  • ソリューション名:「ソリューションのディレクトリを作成」のチェックをはずしておく
で、「上書き保存」。

ソリューション エクスプローラパネル内の「ソリューション `TestPlugin`(1 プロジェクト)」と表示されているアイコンを右クリック。
追加 > 既存のプロジェクト」を選択して、
\FD3\FlashDevelop\FlashDevelop.csproj
を選択する。続けて、
\FD3\PluginCore\PluginCore.csproj
も追加しておく。

# ソリューションの設定
ソリューションのアイコンを選択した状態で、「右クリック > プロジェクトの依存関係」を選択。
「プロジェクト」に「TestPlugin」を選択。
「依存先」に「PluginCore」のみチェックを入れておく。

ソリューションパネルから、「FlashDevelop」プロジェクトを選択。
「右クリック > スタートアップ プロジェクトに設定」を選択しておく。(FlashDevelop プロジェクトが太字になる。)

「メニュー > ビルド > 構成マネージャ」を開く。
パネル下の「プロジェクトのコンテキスト」というテーブルから、「TestPlugin」の行の「プラットフォーム」箇所を選択(デフォルトではAny CPU になってると思う。)、「新規作成」を選択する。
ダイアログが開くと、以下の設定にして「OK」を押す。
  • 「新しいプラットフォーム」:x86
  • 「設定のコピー元」:Any CPU
  • 「新しいソリューション プラットフォームを作成する」のチェックをはずす。

テーブル内の TestPlugin のプラットフォームの項目が「x86」に変わるが、これを元の「Any CPU」に戻してから、閉じる。
(なぜかこれをしないと出力先が設定しても正しく反映されない。)


以降、"FlashDevelop"、"PluginCore" のプロジェクトは触らないので、ツリーは閉じた状態にしといた方が見やすい。

# TestPlugin プロジェクトの設定
ソリューションパネル内の「参照設定」を右クリック。「参照の追加」を選択。
開いたパネル内のタブから「参照」を選択。
ファイルの選択画面になるので、
\FD3\PluginCore\Bin\Debug\PluginCore.dll
を選択。

続いて、再度「参照の追加」を開く。
.NET」タブを選択。"System.Drawing", "System.Window.Forms" を追加する。(Ctrl + クリックで複数選択可)

ソリューションパネル内の「TestPlugin」プロジェクトアイコンを選択した状態で、「プロパティ」ボタンを押す。(もしくは、右クリックから「プロパティ」を選択。)
アプリケーション」タブパネルの「対象のフレームワーク」を「ソリューションパネル内の「TestPlugin」プロジェクトアイコンを選択して」に設定する。

変更すると、一度パネルが閉じるので、再度プロパティパネルを開く。

アプリケーションタブパネルの以下の設定を変更しておく。
アセンブリ名:TestPlugin
規定の名前空間:TestPlugin
出力の種類:クラスライブラリ

ビルドタブパネルの出力先のパスを以下に変更する。
..\..\FlashDevelop\Bin\Debug\Plugins\

# メインクラスの作成
ソリューションパネル内の「TestPlugin」プロジェクトアイコンを選択して、右クリック。
「追加 > クラス」を選択。
ファイル名を「PluginMain.cs」として追加。

以下のコードをソースの上部に追加。
using PluginCore;
AS3 でいう、import だと思う。(includeかな?)

クラスの宣言を以下に変更。
public class PluginMain : IPlugin
太字のところが追記した箇所。

メインクラスは "PluginCore.IPlugin" インターフェースが定義されてないといけない。

「メニュー > 表示 > クラスビュー」で、クラスビューパネルを開く。
TestPlugin のツリーを開いていくと、「IPlugin」が出てくる。
さらに下層に、「IEventHandler」というインターフェースも出てくる。
これをクリックすると定義されたメソッド、プロパティが表示される。

PluginMain クラスは、これらのインターフェースを定義しているので、AS3 同様、実装してやる必要がある。

実装が必要なものは以下。

  • void HandleEvent(object, PluginCore.NotifyEvent, PluginCore.HandlingPriority)
  • void Dispose()
  • void Initialize()
  • string Author { get; }
  • string Description { get; }
  • string Guid { get; }
  • string Help { get; }
  • string Name { get; }
  • object Settings { get; }
必要最小限実装するとこんな感じ。
PluginMain.cs


# 実行
「メニュー > デバッグ > デバッグ開始(F5)」を実行する。

FlashDevelop が開くが、実際には何も実装していないので、何も起きない。
FlashDevelop の 「Tools > Program Settings...(F10)」からSettings パネルを開く。
Plugins の中に「TestPlugin」が追加されていれば、正しくコンパイルできたことになる。


■コードメモ
追記
参照先が間違っていたので書き換えました。
PathHelper.AppDir        // C:\Program Files\FlashDevelop
PathHelper.DocDir        // C:\Program Files\FlashDevelop\Docs
PathHelper.LibraryDir    // C:\Program Files\FlashDevelop\Library
PathHelper.BaseDir       // C:\Documents and Settings\\Local Settings\Application Data\FlashDevelop
PathHelper.DataDir       // C:\Documents and Settings\\Local Settings\Application Data\FlashDevelop\Data
PathHelper.SettingDir    // C:\Documents and Settings\\Local Settings\Application Data\FlashDevelop\Settings
PathHelper.SnippetDir    // C:\Documents and Settings\\Local Settings\Application Data\FlashDevelop\Snippets
PathHelper.TemplateDir   // C:\Documents and Settings\\Local Settings\Application Data\FlashDevelop\Templates
PathHelper.UserAppDir    // C:\Documents and Settings\\Local Settings\Application Data\FlashDevelop
PathHelper.UserPluginDir // C:\Documents and Settings\\Local Settings\Application Data\FlashDevelop\Plugins

UserPluginDir の参照先は実際にはディレクトリが存在しなくて、プラグインのデータは Data ディレクトリ内に入ってるんだけども、これは仕様変更のなごりなんだろうか。
つづく

2009年1月26日
FlashDevelop のプラグインの作り方をメモ。

■参照


■導入

まだ、僕自身知識が曖昧なので、間違ってる部分もあるかと思います。ご注意ください。

FlashDevelop は Visual C# で出来ています。
上のリンク先から Visual C# 2008 Express をインストールしておきます。
また、同じく Google Code から FlashDevelop のソースコードも入手しておきます。

使うのは FlashDevelop 3 なので、"FD3" ディレクトリ以下が、使用するソースコードになります。

プラグインディレクトリ
\FlashDevelop\FD3\External\Plugins\SamplePlugin
.csproj が Visual C# のプロジェクトファイルなので、上記ディレクトリに入っている "SamplePlugin.csproj" を開く。

プロジェクトを開くと「ソリューション エクスプローラ」というパネルが表示されています。
(FlashDevelop に UI が非常に似ているのでエディタの使い方は FlashDevelop を使っていれば分かりやすいと思う。)
この中に 3 つのプロジェクトが表示されています。
  • FlashDevelop - デバッグの実行時に使用される FlashDevelop そのもの
  • PluginCore - プラグインを作る上で必須となるコアライブラリ
  • SamplePlugin - 作成中のプラグイン
基本的に "FlashDevelop" と "PluginCore" を変更することはないと思う。

まずは試しにデバッグを実行してみる。
メニューから「デバッグ > デバッグ開始(F5)」で実行。
実行すると、FlashDevelop が起動して、SamplePlugin パネルが表示される。
表示されていない場合は、「View > SamplePlugin(Ctrl + F1)」で表示される。

このサンプルはアクティブな状態のドキュメントが切り替えられたときに、パネルにファイル名を表示するだけのものです。
試しに Ctrl + N で新規ファイルを開いて、タブを切り替えると動作が分かるかと思います。

デバッグの終了は、開いた FlashDevelop を閉じるか、 Shift + F5。

SamplePlugin 構成
SamplePlugin
    +- Properties/
    |    +- AssemblyInfo.cs
    +- 参照設定/
    +- Resources/
    |    +- en_US.resX
    |    +- LocaleHelper.cs
    |
    +- PluginMain.cs
    +- PluginUI.cs
    +- Settings.cs

AssemblyInfo.cs
作成するプラグインに関する情報の定義
書き出したファイル(.dll)のプロパティ開いたときに表示される内容。

en_US.resX
メニューでの表示名、パネルのタイトル、設定での説明文が設定されたファイル。
あんまり意味が理解できてない。
多言語に対応できるようにするためにこうなってんのかな?
画像を埋め込んだりするのも、このリソースファイルってのを使うらしい。

LocaleHelper.cs
リソースファイル内の値を抜き出すためのクラスファイル
en_US.resX で設定した "名前" を GetString() に渡すと値が取得できる。

PluginMain.cs
SamplePlugin のメインクラス

PluginUI.cs
SamplePlugin パネルの UI を定義。
ツールボックスからコンポーネントをドラッグで追加とかできる。
Flex Builder と近い?(Flex Builderを使ったことがない・・・)
「表示 > コード(F7)」でソース表示。

Settings.cs
FlashDevelop の 「Tools > Program Settings...(F10)」で設定できる項目を定義する。
開くと "Plugins" のところに "SamplePlugin" が表示されている。その中の設定。

■ちょろっとソースのメモ
PluginMain.cs
//現在開いてるドキュメントのエディタへの参照
ScintillaNet.ScintillaControl sciControl = PluginBase.MainForm.CurrentDocument.SciControl;

//現在開いてるドキュメントのテキストを参照
String text = sciControl.Text;

//現在のキャレットの位置にある単語を取得
String word = sciControl.GetWordFromPosition(sciControl.SelectionStart);


FlashDevelop に適用する
メニュー下の「ソリューション構成」(FlashDevelop で Debug と Release の切り替えを行うコンボボックスみたいなとこ)を "Debug" から "Release" に変更して、ビルド > ソリューションのビルド(F6)を実行する。

SamplePlugin ディレクトリ内に obj ディレクトリが作られて、その中の Release ディレクトリに SamplePlugin.dll が作成される。

\Program Files\FlashDevelop\Plugins
FlashDevelop の "Plugins" ディレクトリ内に生成された.dll ファイルをコピーして、FlashDevelop を起動すると使えるようになります。


FlashDevelop を使って AS3 をごりごり書いてる人は、C# のソース見れば大体何をやってるのかはわかると思う。
ルールの違いが掴めれば、プラグインを作るぐらいのレベルであれば、 AS3 と大して変わらないと思う。

僕自身 C# に触れたのはこれがはじめて。


続く。

2008年11月17日
現在の Progression にはシーンオブジェクトにイベントフローが実装されていますが、 表示オブジェクトとは少し挙動が違っています。(Progression 3.0.7 現在)

useCapture や eventPhase, bubbles あたりの値が有効化されていませんので、これを実装してみました。

変更を加えたファイルを以下に置いておきます。
jp/progression/events/progression_event
jp/progression/events/SceneEvent
jp/progression/scenes/SceneObject

未だ as ファイルだと表示できなくて、拡張子を .txt に変えてますが。
リンク先を trac.progression.jp の方に変更しました。

まとめてダウンロードされる場合はこちら。
eventflow.zip

以下、解説を少し。
var sceneA:SceneObject = createScene("sceneA");
var sceneB:SceneObject = createScene("sceneB");
var sceneC:SceneObject = createScene("sceneC");

sceneA.addScene(sceneB);
trace("----");
sceneB.addScene(sceneC);
trace("----");
sceneA.removeScene(sceneB);

function createScene(name:String):SceneObject
{
    var scene:SceneObject = new SceneObject(name);
    scene.addEventListener(SceneEvent.SCENE_ADDED, eventHandler, false);
    scene.addEventListener(SceneEvent.SCENE_REMOVED, eventHandler, false);
    scene.addEventListener(SceneEvent.SCENE_ADDED, eventHandler, true);
    scene.addEventListener(SceneEvent.SCENE_REMOVED, eventHandler, true);
    return scene;
}

function eventHandler(event:Event):void 
{
    trace(event.target.name, event.currentTarget.name, event.type, event.eventPhase);
}

出力結果
sceneB sceneA sceneAdded 1
sceneB sceneB sceneAdded 2
sceneB sceneA sceneAdded 3
----
sceneC sceneA sceneAdded 1
sceneC sceneB sceneAdded 1
sceneC sceneC sceneAdded 2
sceneC sceneB sceneAdded 3
sceneC sceneA sceneAdded 3
----
sceneB sceneA sceneRemoved 1
sceneB sceneB sceneRemoved 2
sceneB sceneA sceneRemoved 3


変更したのは SceneEvent クラスと SceneObject クラスの 2 つ。

まず SceneEvent クラスに以下を追記。
override public function get target():Object 
{
    return super.target
        && progression_event::$target 
        || super.target;
}

override public function get currentTarget():Object 
{
    return super.currentTarget 
        && progression_event::$currentTarget
        || super.currentTarget;
}

override public function get eventPhase():uint 
{
    return progression_event::$eventPhase || super.eventPhase;
}

progression_event var $target:Object = null;
progression_event var $currentTarget:Object = null;
progression_event var $eventPhase:uint = 0;
ここで SceneObject から値に手を加えられるようにするために、 progression_event という namespace ファイルを jp/progression/events/ 内に追加しています。

package jp.progression.events 
{
    public namespace progression_event 
        = "http://www.progression.jp/events/progression_event";
}


dispatchEvent() にイベントオブジェクトを渡したときに target に値が設定されていると、 dispatchEvent 内で Event.clone() が呼び出されるので、 super.target が null のときは null を返すようにしています。
もし $target が設定されていて super.target も設定されている場合は $target の値を、 $target が null でも super.target が設定されている場合は super.target の値を返します。
これは、 dispatchEvent() の内部以外での clone() メソッドの呼び出しへの配慮でもあります。

次はちょっと長いですが、 SceneObject に追加した内容。
/**
 * イベントフローのための内部参照
 */
private var $parent:SceneObject;

/**
 * キャプチャ段階のイベントに登録されたリスナーを保持しておくための EventIntegrator オブジェクト
 * 
 * コンストラクタ内に以下を追記
 * $captureEvent = new EventIntegrator(this);
 */
private var $captureEvent:EventIntegrator;

override public function dispatchEvent(event:Event):Boolean 
{
    if (event is SceneEvent)
    {
        return $dispatchEvent(event as SceneEvent);
    }
    return super.dispatchEvent(event);
}

private function $dispatchEvent(event:SceneEvent):Boolean
{
    var bool:Boolean = true;
    
    if (event.eventPhase == EventPhase.AT_TARGET)
        event.progression_event::$target = this;
    
    event.progression_event::$currentTarget = this;
    
    if (event.bubbles 
        && $parent 
        && event.eventPhase <= EventPhase.AT_TARGET)
    {
        var phase1:SceneEvent = event.clone() as SceneEvent;
        phase1.progression_event::$eventPhase = EventPhase.CAPTURING_PHASE;
        phase1.progression_event::$target
            = event.progression_event::$target;
        bool = $parent.dispatchEvent(phase1);
    }
    
    if (event.eventPhase == EventPhase.CAPTURING_PHASE)
    {
        bool = $captureEvent.dispatchEvent(event);
    }
    else
    {
        bool = super.dispatchEvent(event);
    }
    
    if (event.bubbles 
        && $parent 
        && event.eventPhase >= EventPhase.AT_TARGET)
    {
        var phase3:SceneEvent = event.clone() as SceneEvent;
        phase3.progression_event::$eventPhase = EventPhase.BUBBLING_PHASE;
        phase3.progression_event::$target = event.target;
        bool = $parent.dispatchEvent(phase3);
    }
    return bool;
}

override public function addEventListener(
    type:String, listener:Function, useCapture:Boolean = false,
    priority:int = 0, useWeakReference:Boolean = false):void 
{
    if (useCapture)
    {
        $captureEvent.addEventListener(
            type, listener, false, priority, useWeakReference);
    }
    else
    {
        super.addEventListener(
            type, listener, false, priority, useWeakReference);
    }
}

override public function removeEventListener(
    type:String, listener:Function, useCapture:Boolean = false):void 
{
    if (useCapture)
    {
        $captureEvent.removeEventListener(type, listener, false);
    }
    else
    {
        super.removeEventListener(type, listener, false);
    }
}

override public function hasEventListener(type:String):Boolean 
{
    return super.hasEventListener(type)
        || $captureEvent.hasEventListener(type);
}

override public function willTrigger(type:String):Boolean 
{
    var bool:Boolean = hasEventListener(type);
    if ($parent) bool = bool || $parent.hasEventListener(type);
    return bool;
}

override public function removeAllListeners(
    completely:Boolean = false):void 
{
    super.removeAllListeners(completely);
    $captureEvent.removeAllListeners(completely);
}

override public function restoreRemovedListeners():void 
{
    super.restoreRemovedListeners();
    $captureEvent.restoreRemovedListeners();
}
ここでは EventDispatcher のメソッドをそれぞれオーバーライドして処理内容に手を加えています。
具体的には、 addEventListener() と removeEventListener() で useCapture の値で 登録するオブジェクトを分けています。これはイベント呼び出し時にイベントフェーズによる振り分けができないためです。

dispatchEvent() 内は、親シーンへ遡ってイベントを呼び出すように変更しています。

更に、 _registerScene() と _unregisterScene() にも少し修正を加えます。

_registerScene の変更箇所
// イベントフロー時の参照先を登録する
scene.$parent = scene._parent;

// イベントリスナーを登録する
//scene.addExclusivelyEventListener( SceneEvent.SCENE_ADDED, 
    dispatchEvent, false, int.MAX_VALUE, true );
//scene.addExclusivelyEventListener( SceneEvent.SCENE_REMOVED, 
    dispatchEvent, false, int.MAX_VALUE, true );
//addExclusivelyEventListener( SceneEvent.SCENE_ADDED_TO_ROOT, 
    scene.dispatchEvent, false, int.MAX_VALUE, true );
//addExclusivelyEventListener( SceneEvent.SCENE_REMOVED_FROM_ROOT, 
    scene.dispatchEvent, false, int.MAX_VALUE, true );

// イベントを送出する
scene.dispatchEvent( new SceneEvent(
    SceneEvent.SCENE_ADDED, true, false, scene ) );

// ルートシーンが存在し、変更されていれば
if ( root && previousRoot != root ) {
    // イベントを送出する
    scene.dispatchEvent( new SceneEvent(
        SceneEvent.SCENE_ADDED_TO_ROOT, true, false, scene ) );
}

_unregisterScene の変更箇所
// イベントを送出する
scene.dispatchEvent( new SceneEvent( SceneEvent.SCENE_REMOVED, true, false, scene ) );

// ルートシーンが存在せず、変更されていれば
if ( !scene._root && previousRoot != scene._root ) {
    // イベントを送出する
    scene.dispatchEvent( new SceneEvent( SceneEvent.SCENE_REMOVED_FROM_ROOT, true, false, scene ) );
}

// イベントフローのための参照を削除
scene.$parent = null;

// イベントリスナーを解除する
//scene.completelyRemoveEventListener( 
    SceneEvent.SCENE_ADDED, dispatchEvent );
//scene.completelyRemoveEventListener( 
    SceneEvent.SCENE_REMOVED, dispatchEvent );
//completelyRemoveEventListener( 
    SceneEvent.SCENE_ADDED_TO_ROOT, scene.dispatchEvent );
//completelyRemoveEventListener( 
    SceneEvent.SCENE_REMOVED_FROM_ROOT, scene.dispatchEvent );
追加・削除された子シーンにイベントリスナーの登録を行っていた処理をコメントアウトしています。
また、イベントフローのための親シーンの参照を登録・解除しています。

あとは、 dispatchEvent に渡されるイベントオブジェクトの bubbles の値を true に変更しました。
bubbles が false に設定された場合はイベントフローを発生させないようにしているためです。

以上で、表示オブジェクトのようなイベントフローの実装ができます。
ただ、 EventIntegrator での実装を、あまり理解せずに手を加えているので、どこかに不都合はあるかもしれないです。
すこし使い倒してみる必要はあるかと思います。

2008年11月 6日
役に立つかもしれない情報から、全く無意味としか思えない情報まで。
ひとつひとつエントリーするほどのものでもないので、以下にまとめて書く。


■設定されたステージサイズを取得する

stage.addEventListener(Event.ACTIVATE, activateHandler);

function activateHandler(event:Event):void
{
    event.target.removeEventListener(Event.ACTIVATE, activateHandler);	
    
    var defaultWidth:int = root.loaderInfo.width;
    var defaultHeight:int = root.loaderInfo.height;
}
これらの値はステージサイズが変更されても変わらない。 ただし、コンテンツの読み込みが完了しないうちに loaderInfo.width 等を呼び出すとエラーが吐き出されるので、使用には注意。

■レイヤーマスク

タイムライン上で設定されたマスクには不審な点がいくつかある。

  • マスクオブジェクトはマスクを解除しても表示されなくなる。ただし getRect() や getBounds() 等の矩形情報は残ってる。表示だけがなくなる。
  • マスクオブジェクトは深度 (index) が、対象オブジェクトより下に変更される。
  • 対象オブジェクトのmask, scrollRect プロパティとは無関係
  • マスクを解除する場合は "mask = null" ではなく、マスクオブジェクトをremoveChild() でステージ上から削除するか、setChildIndex() 等を用いて深度を変更する。
  • 被マスクオブジェクトの mask プロパティにオブジェクトを指定すると、2重でマスクが掛けられる。
  • AS から、別のオブジェクトを被マスクオブジェクトに隣接する深度に設定すると、そのオブジェクトもマスクの対象となる。
    もし、現在の被マスクオブジェクトの深度が一番上になっている場合、同階層に addChild() で配置されたオブジェクトも、自動的にマスク対象となってしまう。
  • マスクオブジェクトの深度を変更すると、マスクは一度解除されるが、マスクオブジェクトの1つ上の深度にオブジェクトを配置すると、マスク対象になる。
  • マスクオブジェクトを他のオブジェクト内に移動させた場合、元のマスクは解除されるが、移動先でもマスク効果は有効であるため、移動後も上記のルールが適応される。例えば、
    B.addChild( A.getChildByName("maskObject") );
    とした場合、A でのマスク効果は解除されるが、B 内では有効となる。
結局のところスクリプトからオブジェクトがレイヤーマスクか、または被マスクオブジェクトであるかを調べる方法は不明。
ActionScript とは掛け離れた部分で制御されているのかもしれない。

■scrollRect を指定したオブジェクトのサイズを調べる

function getDefaultRect(target:DisplayObject):Rectangle
{
    if(target.parent)
    {
        var path:DisplayObjectContainer = target.parent;
        var index:uint = path.getChildIndex(target);
        path.removeChild(target);
    }
    
    var bounds:Rectangle = target.transform.pixelBounds;
    bounds = new Rectangle(
            bounds.x * 0.2 - target.x, 
            bounds.y * 0.2 - target.y, 
            bounds.width * 0.2, 
            bounds.height * 0.2);
    
    if(path)
    {
        path.addChildAt(target, index);
    }
    
    return bounds;
}
transform.pixelBounds を使うと元の大きさが取得できるが、
そのままだと、親オブジェクトの変形の影響をもろに受けてしまうので、
一度 removeChild() で引き剥がした方がいい場合もある。時と場合による。

また、対象が stage 上に配置されていない場合、なぜか取得した値がすべて 5 倍になっているので、その場合は割ってやる必要がある。
さらに、AS 側で [Embed] タグを用いて埋め込んだ場合も、ステージに配置したにもかかわらず、次のフレームに移るまでは、同じく値が 5 倍になっており、 これを判定するのは面倒なので、サイズを調べる場合は、とにかく一度 removeChild() するのが無難かもしれない。

■クラスは Class クラスのインスタンスオブジェクト

trace(new Sprite() is Sprite); // true
trace(Sprite is Class);        // true
trace(Sprite is Sprite);       // false
trace(Class is Class);         // true
定義されたクラスのコンストラクタ関数と constructor は別物。
object.constructor は Class から生成されたインスタンスへの参照であって関数ではない。
trace(new Object().constructor == Object); // true
trace(Object is Class);                    // true
trace(Object is Function);                 // false
コンストラクタ関数を参照する方法は、真っ当な方法では、おそらく以下の方法しかないかと。
class ExampleClass
{
    public var constructorMethod:Function;
    
    public function ExampleClass()
    {
        constructorMethod = arguments.callee;
    }
}
ただしコンストラクタ関数からインスタンスを生成することはできない。
コンストラクタ関数が MethodClosure インスタンスであるため。
MethodClosure については次項。

■MethodClosure extends Function

Function クラスは final class なので、継承はできない。
が、定義されたクラスメソッドのコンストラクタは Function を継承した MethodClosure クラス。
ちなみに関数が MethodClosure か判別する方法は以下。
function isMethodClosure(func:Function):Boolean
{
    return func is 
        Object(arguments.callee).constructor;
}

var test1:Function = function():void {}
function test2():void {}

trace( isMethodClosure(test1) );     // false
trace( isMethodClosure(test2) );     // true

■クラス内での prototype の使用

package
{
public class PrototypeClass
{
    public function PrototypeClass()
    {
        prototype.property = "property of prototype";
    }
    
    prototype.property = null;
    
    prototype.methodProperty = function():void
    {
        trace("call methodProperty");
    }
}
}
var instance:PrototypeClass = new PrototypeClass();
Object(instance).methodProperty(); // call methodProperty
trace(instance["property"]);       // property of prototype
使い道が見当たらない。

■マウスイベントをまとめて無効にする

stage.mouseChildren = false;
先日Progressionセミナー後の懇親会で教えてもらった。

■Vector の型指定

var vector:Vector.<Object> = new Vector.<Object>();
trace(getQualifiedClassName(vector));
// output : __AS3__.vec::Vector.<Object>
var vector:Vector.<*> = new Vector.<*>();
trace(getQualifiedClassName(vector));
// output : __AS3__.vec::Vector.<*>
var vector:Vector.<*> = new Vector.<Object>();
trace(getQualifiedClassName(vector));
// output : __AS3__.vec::Vector.<Object>
var vector:Vector.<*> = new Vector.<String>();
trace(getQualifiedClassName(vector));
// output : __AS3__.vec::Vector.<String>
var vector:Vector.<*> = new Vector.<int>();
// TypeError: Error #1034: 強制型変換に失敗しました。
   Vector.<int>@1683e41 を __AS3__.vec.Vector.<*> に変換できません。
上記のように、型の指定には変数等に使用するときと同様に、 * (アスタリスク)を使うことができるが、 なぜか Number, int, uint の数値型を指定した Vector オブジェクトを代入しようとすると失敗する。

trace(new Vector.<Object>() is Vector);          // false
trace(new Vector.<Object>() is Vector.<Object>); // true
trace(new Vector.<Sprite>() is Vector.<Object>); // false
trace(new Vector.<Sprite>() is Vector.<*>);      // true
trace(new Vector.<String>() is Vector.<*>);      // true
trace(new Vector.<int>() is Vector.<*>);         // false
こういうもんなんだろうか。

上記に反して、以下はキャストしてから引数に入れないとエラーが発生する。
以下のコードはエラーが出る例。
var vector:Vector.<Object> = new Vector.<Object>();
test(vector);

function test(vector:Vector.<*>):void {}

var sprites:Vector.<Sprite> = Vector.<Sprite>([new Sprite()]);
var display1:Vector.<DisplayObject> = Vector.<DisplayObject>(sprites);
var display2:Vector.<DisplayObject> = sprites;
上記は display1 ではキャスト成功するが、display2 のようにそのまま代入しようとするとエラーが出る。

■Vector は Array とは違う

Vector は Array と似ているが、Array とは全く別物なので、以下のようなことは出来ない。
function test(...args:Vector.<*>):void {}
Error: ...残りパラメータ定義のキーワードの後に指定したパラメータで使用できるのは、Array データ型のみです。

func.apply(null, Vector.<int>([1,2,3]));
TypeError: Error #1116: Function.prototype.apply の 2 番目の引数は配列でなければなりません。

var matrix:Vector.<Number> = 
    Vector.<Number>(String("10000010000010000010").split(""));
new ColorMatrixFilter(matrix);
Error: 型 __AS3__.vec:Vector.<Number> の値が、関連しない型 Array に暗黙で型変換されています。


■Vectorオブジェクトの動的生成

動的に Vector オブジェクトを作成したい場合、下記のように変数からではエラーが出て失敗する。
var theClass:Class = Sprite;
var vector:Vector.<theClass> = new Vector.<theClass>();
一度文字列にして作成するとうまくいく。
var T:Class = Sprite;
var classPath:String = getQualifiedClassName(T).replace("::", ".");
var theClass:Class = getDefinitionByName("Vector.<" + classPath + ">") as Class;
trace( getQualifiedClassName(new theClass()) );
// output : __AS3__.vec::Vector.<flash.display::Sprite>

2008年10月21日
小さいと分かり難いんですが、赤線が curveTo で引いた線。青線が lineTo で20分割して描いてる線。
curveTo の分割数は曲線の形によって変化しています。
少ないときで 1 本。多くて 8 本くらいです。


なんだか、やたら長くなってしまった。
最初は曲線の角度から分割しようと思ってたけど、どうやって割り出せばいいかよくわからず、結局こんなことになってしまった。
一応これだと、どんだけひねっても、ほとんどずれないです。

それにしても、もうちょっとやりようはありそうなもんだけども。
とりあえず僕の低い学力では、今はここまで。

function bezierCurve(
        ax:Number, ay:Number, 
        bx:Number, by:Number, 
        cx:Number, cy:Number, 
        dx:Number, dy:Number, n:Number, t:Number):void
{
    var t1:Number = n + (t - n) * 0.5;
    var t2:Number = n + (t - n) * 0.25;
    var ax2:Number = cubicBezier(ax, bx, cx, dx, n);
    var ay2:Number = cubicBezier(ay, by, cy, dy, n);
    var dx2:Number = cubicBezier(ax, bx, cx, dx, t);
    var dy2:Number = cubicBezier(ay, by, cy, dy, t);
    
    var px:Number = cubicBezier(ax, bx, cx, dx, t1);
    var py:Number = cubicBezier(ay, by, cy, dy, t1);
    var rx:Number = getControl(ax2, px, dx2);
    var ry:Number = getControl(ay2, py, dy2);
    var qx:Number = quadraticBezier(ax2, rx, dx2, 0.25);
    var qy:Number = quadraticBezier(ay2, ry, dy2, 0.25);
    var px2:Number = cubicBezier(ax, bx, cx, dx, t2);
    var py2:Number = cubicBezier(ay, by, cy, dy, t2);
    
    if (checkPosition(qx-px2, qy-py2, 0.5))
    {
        curveTo(rx, ry, dx2, dy2);
    }
    else
    {
        bezierCurve(ax, ay, bx, by, cx, cy, dx, dy, n, t1);
        bezierCurve(ax, ay, bx, by, cx, cy, dx, dy, t1, t);
    }
}

ベジェ曲線のそれぞれの計算は以下。

//曲線が許容範囲内に収まってるかチェック
function checkPosition(x:Number, y:Number, d:Number):Boolean
{
    return (Math.abs(x) < d && Math.abs(y) < d);
}

//2次ベジェ曲線の通過点からコントロールポイントを得る
function getControl(
        a:Number, b:Number, c:Number):Number
{
    return (b * 4 - a - c) * 0.5;
}

//2次ベジェ曲線の任意の点を取得
function quadraticBezier(
        a:Number, b:Number, c:Number, t:Number):Number
{
    var s:Number = 1 - t;
    return s * s * a + 2 * s * t * b + t * t * c;
}

//3次ベジェ曲線の任意の点を取得
function cubicBezier(
        a:Number, b:Number, c:Number, d:Number, t:Number):Number
{
    var s:Number = 1 - t;
    return s * s * s * a 
        + 3 * s * s * t * b 
        + 3 * s * t * t * c 
        + t * t * t * d;
}


やっぱりソースが長い。
無駄に計算してる感が否めないので、
せめてこの半分くらいにはしたい。

2008年10月17日
FlashPlayer の 10 が正式リリースされたけども
今のところ、一番厄介なのは、おそらく Vector クラスの使用じゃないかと思うわけです。

バージョン 9 でも AS3 は使っているわけですが、9 には Vector クラスは対応していないので、 10 対応で作成したクラスを 9 でも使用したくなったときに、Vector クラスはかなりネックになってしまうんじゃないかと思うわけです。

クライアントから古いバージョンを指定されることはよくあることだと思います。

で、こんな風にすると、一応 Vector と Array をプレイヤーの状況によって使い分けれるんじゃないかなあ と、思ってみたわけです。

function getArrayOrVector(T:Class):Class
{
    var theClass:Class;
    try 
    {
        var classPath:String = getQualifiedClassName(T);
        classPath = classPath.replace("::", ".");
        theClass = getDefinitionByName
            ("Vector.<" + classPath + ">") as Class;
    }
    catch (error:Error)
    {
        theClass = Array;
    }
    
    return theClass;
}

var theClass:Class = getArrayOrVector(int);
var a:Object = new theClass();
trace(getQualifiedClassName(a));

これだと、FlashPlayer のバージョンが 9 の場合は
Array
と出力され、バージョンが 10 だと
__AS3__.vec::Vector.<int>
と出力されます。

ただ、これだと変数の型指定は Object になっちゃうので、
実際どれほどの効果があるのかは謎です。
誰か検証してくれないかなあ。

2008年10月15日
追記 ----
この記事の内容より有効な方法がタロタローグ ブログさんで掲載されています。
FlashDevelopでFlash Player 10用のswfファイルを作成する方法(最短2秒)
<補足>
playerglobal.swc ファイルは FlexSDK だと
flex_sdk_3/frameworks/libs/player/10
に入ってます。
---- 追記(ここまで)


たぶんだけど現状では Vector クラスのコードヒントは使えるけど、その他のFP10で実装されたクラスやメソッドが使えない。

FlashDevelop は Library ディレクトリ内にクラス定義がされてるんだけども
ここに新しいクラス群が追加されていないためだと思う。

なので、Shader クラスや Graphics.beginShaderFill() メソッドでもコードヒントが出るように、定義ファイルを作ってみました。

もしかしたら、すでに誰か作ってるかもしれませんがアップしときます。
AS3_for_FlashDevelop.zip

ダウンロードして解凍すると、中に"intrinsic"というディレクトリが入っているので、それを
FlashDevelop のインストールされているディレクトリ、
Program Files\FlashDevelop\Library\AS3\
の中の同名のディレクトリに上書きするとコードヒントが使えるようになります。
import とかも補完されます。


内容
display
  • ColorCorrection
  • ColorCorrectionSupport
  • Graphics
  • GraphicsBitmapFill
  • GraphicsEndFill
  • GraphicsGradientFill
  • GraphicsPath
  • GraphicsPathCommand
  • GraphicsPathWinding
  • GraphicsShaderFill
  • GraphicsSolidFill
  • GraphicsStroke
  • GraphicsTrianglePath
  • IGraphicsData
  • IGraphicsFill
  • IGraphicsPath
  • IGraphicsStroke
  • Shader
  • ShaderData
  • ShaderInput
  • ShaderJob
  • ShaderParameter
  • ShaderParameterType
  • ShaderPrecision
  • TriangleCulling

events
  • ShaderEvent

filters
  • ShaderFilter

---追記(2008.10.17)---
desktop
  • Clipboard
  • ClipboardFormats
  • ClipboardTransferMode

net
  • FileReference


ASDoc を参考に、おもいっきり手作業で作ってますので、なんか間違ってるとことかあったらすいません。
ご利用はあくまで自己責任でお願いします。

きっと、近いうちにFlashDevelop 自体、アップデートされるでしょうから
それまでの気休めぐらいに使っていただければと思います。


2008年10月 9日
エラーの意味が分からず四苦八苦してしまったのでメモ。

FlashDevelop + FlexSDK で AIR を作成する際、
error while loading initial content

というエラーが出たときは、 application.xml 内の以下を確認する。(デフォルトでは2行目)

<application xmlns="http://ns.adobe.com/air/application/1.0">

ここで指定する URL は AIR(adl.exe)のバージョンによって異なる。
adl.exe のバージョンは Windows XP だと adl.exe を右クリックして
「プロパティ」→「バージョン情報」
で確認できる。



今回の場合は 1.5 が入っていたので
<application xmlns="http://ns.adobe.com/air/application/1.5">
にすることで正常に書き出された。

ちなみに、この XML ファイルのテンプレートは (FlexSDK)/templates/air に入ってる。

2008年10月 7日
まずはデモから。

デモ

Progression ではURLを指定してシーンを変更できるので、 Flash はビデオプレイヤーのみを実装しておいて、 あとは URL でビデオの再生位置や flv のパスを指定してやる。 ってこともありだと思った。

デモの FLV はキューポイントを3箇所設定している。 で、onCuePoint のイベントを受け取ってシーンを変更すれば ブラウザの「戻る」「進む」で再生位置を変更するとかもできる。
何気にタイトルも変えてみたり。

デモでは一応Flash内にボタンを設置しているけど、 これも場合によってはなくてもいい。

今回はキューポイントの指定だけども、URLで 直接時間指定することもできる。

要は SceneObject で URL の変化が受け取れるわけだから
これにあわせていろんなことができますね。って話。


--- 追記
直接 #page3 とかに飛ぶとビデオが読み込めてなくて、
最初から再生になってますが、デモだから。という言い訳。

2008年9月 5日
先日書いた「FlashDevelop用Progressionプロジェクトテンプレート」を、 正式にリリースされた Progression3 にあわせて変更しました。

前回の Beta 2 版のプロジェクトテンプレートを入れてた方は、一度削除してから入れなおしてください。 削除しておかないと余計なファイルが含まれてしまいます。

今回のリリースで(前からあったかもですが)swc が配布されているのでこれを含めたテンプレートとなっています。

135 ActionScript 3 - AS3 Project with Progression3

あと、Air 用のプロジェクトテンプレートも作っておきました。

165 ActionScript 3 - AIR AS3 Projector with Progression3

使い方は前回のままですが

------------------------------------------

上記リンクからダウンロードしたzipを解凍すると、
中に「135 ActionScript 3 - AS3 Project with Progression3」というフォルダが入っているので、これをXPの場合以下のフォルダにコピーすると使えるようになります。
Documents and Settings\[USER]\Local Settings\Application Data\FlashDevelop\Templates\ProjectTemplates
------------------------------------------

です。

以後 Progression がアップデートされた際は lib ディレクトリ内の swc ファイルを置き換えればいいんじゃないかと思います。

どっかで誰かの役に立てば、これ幸い。

2008年9月 2日
FlashDevelopのみでProgression Frameworkを使ったオーサリングができます。

ActionScript 3 - AS3 Project with Progression3

バージョンはそれぞれ
  • FlashDevelop 3 beta 8
  • Progression Framework 3 beta 2

上記リンクからダウンロードしたzipを解凍すると、
中に「135 ActionScript 3 - AS3 Project with Progression3」というフォルダが入っているので、これをXPの場合以下のフォルダにコピーすると使えるようになります。
Documents and Settings\[USER]\Local Settings\Application Data\FlashDevelop\Templates\ProjectTemplates

Vistaの場合はよくわかりませんが、似たようなところに入れるんじゃないかと。

以前タロタローグさんとこのブログに「Progression Frameworkを、FlashDevelopだけで使ってしまおうと言う挑戦。」という記事で同様のテンプレートが公開されてましたが、「Progression Framework自体が猛スピードで変化してて、テンプレートを置いといても意味なさそうなんで、公開は止めます。」とのことで今は公開されてないです。(かわりに「FlashDevelop用のプロジェクトテンプレートを作る安易な方法」という記事が出てますが。)

実際、明後日にはProgression 3が公開されるってのに、今更なんですが、今後の参考までにプロジェクトテンプレート用のテンプレート的な気持ちでアップしときます。

あと、fl パッケージはたぶん公開しちゃいけないんだろうから(ライセンス調べろって話ですが)下記の3つだけ仮でクラスファイル入れてあります。中身は定義だけで実装されてないです。
Flash CS3 持ってる人は置き換えればDoTweenコマンドとかも使えるようになります。

  • fl.transitions.Tween
  • fl.transitions.TweenEvent
  • fl.transitions.easing.Regular
2008年8月12日
何かと AS3 の Proxy クラスは使えないという声をよく目にします。
特に目立つのが他のクラスを継承できないこと。

例えば DisplayObject の Proxy を作ったとしても、元がProxyクラスなので addChild() が使えないとか。たぶんそんなの。

今回はその辺について、ちょっと思ったことを休み前にまとめとこうかと。

Progression使いたいけど、自前で拡張したクラスも組み合わせて、 なんか有効にいろんなライブラリに手を出せないかな。と思ったのが きっかけでして、そこで一番に思い当たるのはやっぱりProxyクラスだったわけです。

で最初はProxy使った方法をいろいろごにょごにょと考えてたんですけど、 結局 addChild() や removeChild() で指定するためには、どうしても DisplayObject を 参照しなきゃいけなくなって、それが参照できる時点でProxyの役目は破綻してしまうんです。

var parentObject:DisplayObjectContainer
var childObject:Proxy

parentObject.addChild(childObject.display);

例えば上記の場合、親のDisplayObjectにProxyクラスが内包するDisplayObjectを displayというプロパティ経由で入れ子にしようとしています。

でも、これをしてしまうと、以降、親DisplayObjectからは本来隠蔽しておきたいはずの 子DisplayObjectを参照できるようになってしまい、 Proxyを通さずに直接参照・変更ができてしまいます。

そもそも Proxy は dynamic ステートメントを付けておかないと 効果を発揮しません。

つまり、頑張って DisplayObjectProxy とか EventProxy とかを作っても、 それを継承して様々なクラスに派生させていくような作り方だと、 全部ダイナミッククラスになってしまって はちゃめちゃになってしまいます。

もしこういう使い方をしたいならば、 素直にDisplayObject のサブクラスを作って、中身をすべて 内包する他のオブジェクトに委譲したほうがいいかもしれません。

ただ、DisplayObject で Proxy クラスを作成した場合でも、 結局のところ addChild には若干問題が残ります。

Sprite や MovieClip なら、委譲先のオブジェクトを DisplayObjectContainer から作成した Proxy 用クラスのコンテナ内に追加しておけば addChild() 時に画面上に現れますが、TextField や Bitmap は親オブジェクトになれないので、これらを継承したProxyクラスは addChild しても画面に表示されません。
あくまで追加されるのは Proxy クラスだからです。

addChild はまだマシな方で、ADDEDイベント発生時に内部処理で置き換えが可能ですが、 removeChild 時にはどう頑張ってもクライアント側で一工夫しないといけなくなります。

結局いろいろ試した結果、僕は addChild の問題は放棄しました。
Proxyを末端の子オブジェクトとして捉える限り、この問題は解決しないように思えたからです。

ProxyならProxyらしくコンテナ側に回してやればいいんじゃないかと。


で、以下はDisplayNodeというProxyクラスを継承したサブクラスを作ってみた場合の一例です。

var rootNode:DisplayNode = new DisplayNode(new Sprite());
rootNode.child1 = new Sprite();
rootNode.child1.grandchild1 = new Shape();
rootNode.child1.grandchild2 = new Shape();
rootNode.child1.grandchild3 = new Sprite();
rootNode.child1.grandchild3.addChild(new Bitmap());
rootNode.child2 = new Sprite();
rootNode.child2.dummy = new Sprite();
rootNode.child3 = new Sprite();
delete rootNode.child2;

trace(rootNode);

出力結果
instance148 [object Sprite]
  child1 [object Sprite]
    grandchild1 [object Shape]
    grandchild2 [object Shape]
    grandchild3 [object Sprite]
        instance153 [object Bitmap]
  child3 [object Sprite]

何をやってるかというと、
private var _target:DisplayObjectContainer;

override flash_proxy function getProperty(name:*):* 
{
    var child:DisplayObject = _target.getChildByName(name);
    if (child is DisplayObjectContainer) 
        return new DisplayNode(child as DisplayObjectContainer);
    return child;
}

override flash_proxy function setProperty(name:*, value:*):void 
{
    if (value is DisplayObject)
    {
        value.name = name;
        _target.addChild(value);
    }
}
setProperty と getProperty を使って表示オブジェクトを 参照名で addChild していく。ってもの。
child2 は delete の実行によって、内部で removeChild してます。


このクラスの中身も一応参考までにアップしておきます。
こういう使い方もあるってことで。

DisplayNode


DisplayObjectを継承したProxyを作りたいときも、なんとなくそれっぽいものまでは作る事ができます。
要はダイナミッククラスな訳ですから、以下のような処理で各メソッドの呼び出し時の処理に手を加えることも。

package 
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.utils.describeType;

dynamic public class TestProxy extends Sprite
{

public function TestProxy(target:DisplayObject) 
{
    setProxyMethods(target);
}

public function setProxyMethods(target:DisplayObject):void
{
    var data:XML = describeType(target);
    var n:uint, i:uint, name:String;
    var methods:XMLList = data.elements("method");
    n = methods.length();
    for (i = 0; i < n; i++ )
    {
        name = methods[i].@name;
        if (!this.hasOwnProperty(name))
        {
            this[name] = function():*
            {
                var func:Function = target[arguments.callee.methodName];
                return func.apply(target, arguments);
            }
            this[name].methodName = name;
        }
    }
    
    var accessor:XMLList = data.elements("accessor");
    n = accessor.length();
    for (i = 0; i < n; i++ )
    {
        name = accessor[i].@name;
        if (!this.hasOwnProperty(name))
        {
            this[name] = function():*
            {
                if (arguments.length == 1) 
                    return target[arguments.callee.propName] = arguments[0];
                return target[arguments.callee.propName];
            }
            this[name].propName = name;
        }
    }
}

}// end of class

}// end of package
var proxy:TestProxy = new TestProxy(new TextField());
proxy.appendText("hoge");
trace(proxy.text());          // 出力 : hoge
trace(proxy.getTextFormat()); // 出力 : [object TextFormat]

テキストフォーマットを吐き出すSpriteとか。

ただし、getter と setter は動的に追加できないから、やっぱり完全なProxyクラスの代用は難しいと思う。
上の例の場合はプロパティへのアクセス用メソッドを用意していて、text("hoge") みたいにして使う感じ。

TestProxy


結局のところ TestProxy みたいに無尽蔵にメソッドを追加しちゃうようなものは
実際にはあんまり使いどころがない気がする。コードヒントとか出ないし。

現在 DisplayObject を継承した Proxy 用クラスで、比較的使用頻度の高いのは以下のようなクラス。
こういうクラスを予め用意しておくと、結構役に立ってくれたりします。

SpriteProxy

このクラスはこのままインスタンスを作ってもまったく意味のないクラスなので継承しないと使えません。


これって Proxy じゃなくて Decorator な気もするけど、
その辺そんなに詳しいわけでもないので気にしない。



今回は DisplayObject と一緒に使う事に絞ってみたけど、 Proxy クラス自体はアクセス方法がかなり自由なのでいろんな使い方ができると思います。
中でも MXML みたいな使い方は得意なんじゃないかと。

あんまり多用すると後が怖いですけども。

それにしても、とりとめのない文章だなあ。

2008年8月 4日
リンケージ設定JSFLコマンド
LinkageSettings.mxp

  • クラスパスに「/」が入力できなかったのを修正
  • 参照ボタンが正常に動作していなかったので修正
  • 「ActionScriptに書き出し」にデフォルトでチェックが入るように変更
  • 「ActionScriptに書き出し」にチェックが入っていないときは「クラスファイルを作成する」を選択できないように変更
上の2つはかなり致命的な欠陥だったのに今まで気づかなかった。
自分で使えよって話なんですが。

上記以外は変わってないですが、今回の修正で結構便利度アップしたと思いますよ。

例えば
/project
  /bin
    index.fla
  /src
    Main.as
上記のようなディレクトリ構成で、index.flaを開いて作業いていた状態で
ステージ上に配置されたシンボル「HomeButton」「WorksButton」「ContactButton」の3つを選択して
このコマンドを実行した場合、
クラスパス: ../src
クラス名: demo.buttons.*
基本クラス: *
上記の設定で「クラスファイルを作成する」にチェックを入れて実行すると
/project
  /bin
    index.fla
  /src
    Main.as
    /demo
      /buttons
        HomeButton.as
        WorksButton.as
        ContactButton.as
上記のようにファイルが作成されます。
クラスファイルの記述もちょいちょい設定できます。

使い方は前回の記事のままです。
不明点があればどうぞ遠慮なく聞いてください。

以前の記事で、複数のシンボルがどうのこうのと注意事項で書いてますが、
特に気にしなくても使えると思います。

インスタンス名にシンボル名を設定するJSFLコマンド
setInstanceName.mxp

  • 先頭の文字を小文字に変換する
これはシンボル名が「TestButton」だった場合、このコマンドを実行すると、
ステージ上のインスタンス名は「testButton」になります。

変更はこれだけですが、AS3では思いのほか便利になったと思います。

上の「リンケージ設定コマンド」と併用するとさらに便利。
クラス名はシンボル名が適用されて、インスタンス名は先頭文字だけ小文字
って状況はAS3では良くあるんじゃないでしょうか。

思い当たる人は是非使ってみてくださいませ。

--追記
なんかディレクトリ構成の例が変だけど気にしないで(汗

--更に追記
Embedタグの記述箇所が変だったのと、symbolパラメータの値が正しく入力されてなかったので
再修正してアップしました。
LinkageSettings.mxp

--しつこくも更に追記
クラス作成時、インスタンス変数を追加する際に、変数の型をすべて「DisplayObject」にしていましたが
クラスの割り当てがされているインスタンスについては、設定されたクラスを追加するようにしました。
指定クラスファイルが存在しない場合は基本クラスに設定されているクラスが指定されます。
さらに基本クラスがデフォルトである場合は DisplayObject が指定されます。
(基本クラスが Sprite や MovieClip 等である場合、JSFLでは判定できないため)

また、上記変更に伴い、import 文が長く(複数行)になる場合があるので
import 文はソートした状態で書き加えられるように変更しました。(可読性向上のため)

LinkageSettings.mxp

2008年7月29日
一部更新、追加があったのでdocsも更新しときました。
といっても、このライブラリ使ってんの僕だけだったりして。

Utils
http://www.libspark.org/browser/as3/Utils/src/org/libspark/utils

asdocs
http://www.libspark.org/htdocs/as3/utils/

ダウンロード
http://www.libspark.org/svn/as3/Utils/docs/utils_docs.zip

2008年7月18日
是非挑戦してみてください。
先攻・後攻は「SETTING」ボタンから変更できます。


ルール
  • 同じ行なら何個でも取れます。
  • 間を飛ばして取ることはできません。
  • 最後の1つになったら負け


FlashDeverop + FlexSDK で作ってます。
Flash IDE は今回使ってません。
FlexSDK だと、書き出しが早くてすばらしいですね。

2008年7月14日
AS3 で FLV のメタデータの取り方が分からずに、かなり無駄に時間を費やしてしまった。。。
FLV のメタデータは NetStream から onMetaData を使って取得できるんだけども、
この onMetaData の使い方がさっぱり分からなかったので忘れないようにメモ。
経過があまりにもアホくさすぎて絶対忘れないけども。

ビデオメタデータの使用
NetStreamオブジェクトの client プロパティを指定して、
指定したオブジェクトに onMetaData メソッドを定義しておくと使える。

この client プロパティの存在に気づかずに四苦八苦してた自分が情けない。

挙句の果てに、ここ見て自前で ByteArray からメタデータ取ろうとしてしまった。

ByteArray から取得した FLV の値を出力した一例。
// FLV Header
Signature = FLV
Version = 1
Flags = 5
Offset = 9

// FLV Stream
PreviousTagSize = 0

// FLV Tag
Type = 18
BodyLength = 224
Timestamp = 0
TimestampExtended = 0
StreamId = 0

// MetaData
videodatarate = 1000
audiocodecid = 2
canSeekToEnd = true
duration = 8.866
audiodatarate = 128
framerate = 30
width = 450
videocodecid = 4
height = 400
audiodelay = 0.038

アホですよ。まったく。

ここまでやって、ちゃんと取得できることに気づいた。
そもそも何で AS3 なのに NetStream はこんな実装なんだ。
腹立たしい。アホか!

一応以下にソース残しときます。
結果的に中途半端なものになってますが、
なんか消してしまうのも勿体ない気がしてしまって。(費やした時間が。)

public function readFLV(data:ByteArray):void
{
    // FLV Header
    var Signature:String = data.readUTFBytes(3);
    var Version:uint = uint8(data);
    var Flags:uint = uint8(data);
    var Offset:uint = uint32(data);
    
    // FLV Stream
    var PreviousTagSize:uint = uint32(data);
    
    // FLV Tag
    var Type:uint = uint8(data);
    var BodyLength:uint = uint24(data);
    var Timestamp:uint = uint24(data);
    var TimestampExtended:uint = uint8(data);
    var StreamId:uint = uint24(data);
    var Body:ByteArray = new ByteArray();
    data.readBytes(Body, 0, BodyLength);
    
    
    // Body(FLV Tag Type = 0x12 : AMF)
    var a:uint = uint8(Body);// ???
    var b:uint = uint8(Body);// ???
    
    // MetaData
    readString(Body);
    var metadata:Object = readMixedArray(Body);
    
    
    trace(Signature, Version, Flags, Offset);
    trace(PreviousTagSize);
    trace(Type, BodyLength, Timestamp, TimestampExtended, StreamId);
    
    // MetaData の中身
    for (var val:String in metadata) {
        trace(val + "=" + metadata[val]);
    }
    
}

public function  uint8(data:ByteArray):uint { return data.readByte(); }
public function uint16(data:ByteArray):uint { return data.readUnsignedShort(); }
public function uint24(data:ByteArray):uint { return data[data.position++]<<16 | data[data.position++]<<8 | data[data.position++]; }
public function uint32(data:ByteArray):uint { return data.readUnsignedInt(); }

public function readNumber(data:ByteArray):Number
{
    return data.readDouble();
}
public function readBoolean(data:ByteArray):Boolean
{
    return data.readByte() == 0x01;
}
public function readString(data:ByteArray):String
{
    var len:uint = data.readByte();
    return data.readUTFBytes(len);
}
public function readObject(data:ByteArray):Object
{
    return null;
}
public function readMixedArray(data:ByteArray):Object
{
    data.readByte();
    var length:uint = data.readInt();
    var res:Object = { };
    var value:*;
    var name:String;
    var type:uint;
    var len:uint = data.length;
    for (;; ) {
        var separator:uint = data.readByte();
        name = readString(data);
        type = data.readByte();
        
        if (type == 0x09) break;
        
        switch(type) {
            case 0x00 : { value = readNumber(data); break; } // Object
            case 0x01 : { value = readBoolean(data); break; } // Object
            case 0x02 : { value = readString(data); break; } // Object
            case 0x03 : { value = readObject(data); break; } // Object
            //case 0x04 : { break; } // Movie Clip
            case 0x05 : { value = null; break; } // Object
            case 0x06 : { value = undefined; break; } // Object
            //case 0x07 : { break; } // Reference
            case 0x08 : { value = readMixedArray(data); break; } // MixedArray
            case 0x0a : { value = readArray(data); break; } // Array
            case 0x0b : { value = readDate(data); break; } // Date
        }
        res[name] = value;
    }
    return res;
}
public function readArray(data:ByteArray):Array
{
    return null;
}
public function readDate(data:ByteArray):String
{
    return null;
}
2008年7月11日
リンケージの設定と同時にクラスファイルを自動生成する
Flash CS3 用の JSFLコマンドをアップしました。

LinkageSettings.mxp

Flashのメニューから「コマンド」>「LinkageSettings」で使用できます。
このコマンドを呼び出す際は、以下の条件が必要です。

  • flaファイルが保存されたもの。
    (新規作成で開いた状態で未保存の場合は使用できません。)
  • ステージ上のシンボル、もしくはライブラリ内のシンボルを1つ以上選択した状態であること。
  • ドキュメントのActionScriptのバージョンが3であること。

まだベータ版ってことで、Macで検証できてないのと、 AS2 には使用できません。
実行すると以下のダイアログが表示されます。



特徴
  • ステージ上、もしくはライブラリ内で選択中の複数のシンボルをまとめてリンケージ設定可能
  • リンケージの設定対象は MovieClip, Bitmap, Font, Sound, Button の5種類です。
  • リンケージ設定時にクラスファイルが存在しない場合、自動で生成することができます。
  • クラスファイルの自動生成時に特定のイベントを追加しておくことができます。
  • クラスファイルの自動生成時にEmbedタグを設定しておくことができます。
  • 複数選択時、クラス名に*を使用することで、各シンボル名と同名のクラスを作成します。
    例)classes.display.*
  • 複数選択時、基本クラス名に*を使用することで、
    各アイテムのデフォルトで割り当てられるクラスを基本クラスに設定することができます。
  • 対象がムービークリップの場合、内包するインスタンス名を変数宣言しておくことができます。
  • 対象がムービークリップの場合、タイムライン上のスクリプトを調べて、クラス内に addFrameScript として設定することができます。
  • 書き出すクラスファイルのテンプレートは単独のファイルとなっているため、比較的容易に編集が可能です。
    "Commands/seyself/templates/as3_class.tmpl" がテンプレートファイルです。
    テンプレートファイル内で[XXXX]と書かれている箇所が、
    それぞれ置き換えられる場所になっているので、編集の際はご注意ください。

注意事項
  • まだ検証が十分ではありませんので、ご使用には注意してください。
    特に複数のシンボルをまとめてリンケージ設定する際に、クラス生成も同時に行うと
    予期せぬ結果になる可能性があります。
  • クラスパスは相対パスで記述してください
  • Embedタグを追加した際、自動的にswfファイルへの参照が記述されますが、
    この機能はflaファイルの位置を指しています。
    flash側でパプリッシュ先を、他のディレクトリに指定を変更した場合でも、
    flaファイルの位置を元に書き込まれます。

困ってること
  • Flash側でSWFのパブリッシュ先を変更した場合の、書き出し先の取得方法が分かりません。
  • XULがよく分からず、表示パネルの外枠がやたらデカくて困ってます。
  • Mac にて検証する環境がないため、ディレクトリの指定等がまったく分かりません。

もしどなたか Mac 環境で検証してくれるって方がおられましたら
是非以下の JSFL ファイル(DirectoryTest.jsfl)を使用して、
出力された結果を教えていただけませんでしょうか。

directory_access_test.jsfl

ちなみに「 Windows XP SP2 / Flash CS3 」での出力結果は以下のようになりました。 ご参考まで。
//==== Directory Access Test ====

■fl.configURI =
file:///C|/Documents%20and%20Settings/wada/Local%20Settings/Application%20Data/Adobe/Flash%20CS3/ja/Configuration/

■document.path =
D:\wada\00_works\2008_latter\20080709_test_commands\flash\20080709\index.fla

■fl.browseForFolderURL() =
file:///C|/flex_sdk_3/bin

■fl.browseForFileURL() =
file:///C|/Program%20Files/Adobe/Adobe%20Flash%20CS3/Flash.exe

//==== Test Complete ====

以後、ゆっくりとですが調整していく予定です。

2008年7月10日
現状 Flash CS3 では、 JSFLで画像(BitmapItem)のリンケージ設定で
「ActionScript に書き出し」の設定をしようとしても値が false のままで変更できません。
item.linkageExportForAS = true;
alert(item.linkageExportForAS); // output : false
lib.setItemProperty('linkageExportForAS', true);
alert(item.linkageExportForAS); // output : false
プロパティを直接設定しても、 setItemProperty を使っても同じです。

で、ちょっと無茶な方法ですが以下のようにスクリプトを変更します。
var item = fl.getDocumentDOM().library.getSelectedItems()[0];
if(item.itemType=="bitmap") item.linkageExportForRS = true;
item.linkageExportForAS = true;
item.linkageExportInFirstFrame = true;
こうすると、ライブラリからマウス操作でリンケージパネルを開いたとき、以下のようになります。



このように「ランタイム共有用に書き出し」が true に設定された状態で、
「ActionScript に書き出し」は設定されていないという、パネルを直接操作しても
再現出来ないようなおかしなことになってますが、このときのBitmapItem のプロパティを
出力すると以下のようになります。
linkageExportForRS = true
linkageExportForAS = undefined
linkageExportInFirstFrame = true
linkageClassName = image.jpg
linkageBaseClass = 
allowSmoothing = false
compressionType = photo
quality = -1
useImportedJPEGQuality = true
itemType = bitmap
name = items/image.jpg
linkageImportForRS = undefined
linkageIdentifier = image.jpg
linkageURL = 
linkageClassName(太字)のところを見ると、クラスが設定されています。
この状態であれば、linkageClassName、linkageBaseClass 共にスクリプトで設定しなおすことが出来ます。
linkageURL はそのまま空でもパブリッシュは可能です。

このJSFLコマンドを実行した後、リンケージパネルを変更せずに
以下の ActionScript をタイムラインに書いてプレビューしてみると、
ちゃんと書き出されてることが確認できます。
linkageClassName は JFSL に追記して "image_jpg" に変更しています。
import flash.display.Bitmap;
addChild(new Bitmap(new image_jpg(1,1)));
ただし、「ランタイム共有用に書き出し」を行ってしまうので、これを使うと
Bitmap に設定したクラス名とファイルを配置した SWF の URL が分かれば、
他のドキュメントソースファイルから「ランタイム共有用に読み込み」で読み込んでしまえる。

残念ながら linkageExportForRS を false にすると、結局 AS への書き出しも行われなくなってしまうので
今のところ対処方法はまだわかりません。無いのかもしれない。

FlashDevelop + FlexSDK とかで開発する上で、
SWF から [Embed] タグで画像を読み込む分には使えるかもしんない。
それをしないといけない状況があるかどうかなんですが。

2008年7月 9日
Spark Project の Utils ライブラリの ASDoc を書き出してアップしてみました。
HTMLでアップするとファイルが多いのでZIPに圧縮してます。

あとちょろちょろとクラスファイルを足してます。
何か無駄なところも多々あると思います。
実装が微妙なところも結構あります。EventUtil とか。

Utils
http://www.libspark.org/browser/as3/Utils/src/org/libspark/utils

utils_docs.zip
http://www.libspark.org/svn/as3/Utils/docs/utils_docs.zip


とりあえず、今こんなのが入ってるってのが把握できればと思います。

今までまったく気づかなかったことなんですが
addEventListener("enterFrame", handler);
function handler():void {}
ってすると
ArgumentError: Error #1063: _fla::MainTimeline/handler() の引数の数が一致していません。0 が必要ですが、1 が指定されました。
ってエラーが出て怒られるんだけども、
addEventListener("enterFrame", handler);
function handler():void { arguments; }
上記の場合はそのまま何事もなく実行される。
上記のようにイベントハンドラの中に「arguments」が入ってると、引数は別に定義されてなくてもいいみたい。

これは引数の数は関係ないみたいだけども、「...rest」が入ってると「arguments」が使えなくなるのでダメっぽい。
まあ、そもそも「...rest」入れてる時点で引数の数はあんまり関係なくなるけども。

じゃあ、普通に関数でも使えるかと思って試してみた。
function test():void {arguments;}
test(1, 2, 3);
普通に怒られた。
引数の数が正しくありません。0個以下であることが必要です。
って。
で少し呼び出し方を変えてみる。
function test():void {arguments;}
test.apply(null, [1, 2, 3]);
と、今度はすんなり通った。
ようはイベントの通知には apply が使われてるってことか。

もしかして dispatchEvent もこの要領で「dispatchEvent.apply」とかすれば引数勝手に増やせるかも?
とか思ったけど、やっぱりそれはダメでした。

で、結局のところ「だから何なんだ」って話しで、
特に何も得することもないんですが。


通常、外部からの呼び出しの時は引数無しだったり、個定数の引数を渡さないといけなくしておいて
内部処理のみ、内緒でこっそり引数渡してやりたい時なんかは使えるかもしれないですね。
再起処理の時のフラグとか。
2008年7月 1日
久しぶりの投稿です。
どうもご無沙汰しております。

Airでクリップボードランチャを作ってみました。
インストール、解説もろもろは以下にページを作っておきました。

AirClip [http://www.seyself.com/airclip/]

一応このアプリケーションはスニペット的な使用を想定して作ってみました。
(ショートカットとかないですけども)

テキストと画像の管理ができますが、画像管理はほとんどおまけ状態です。
というのも、クリップボードにコピーした画像データを取得しても、
アルファ情報が破棄されちゃってて透過画像をうまく管理できなかったんです。
これについて、誰か対処方法知ってたら是非とも教えてほしいです。

あと、複数の履歴を管理できるようにしようかとも思いましたが
UIが思いつかなかったので、とりあえず放置しました。


履歴1000件とかは試してないので、あんまり多くなったときにどうなるかは謎です。

僕自身、ちょいちょい使いながら手直ししていこうかなと思ってます。

何か不具合とか要望とか、コメントもらえれば追々対応しますです。
致命的過ぎない限り即日対応とかは無理ですが。


2008年6月10日
スプライン補間があんまり混雑な計算になってしまうので
いろいろ探してたら「Catmull-Rom 補間」なるものを知りました。

function CatmullRom(p0:Number, p1:Number, p2:Number, p3:Number, t:Number):Number
{
    var v0:Number = (p2 - p0) / 2;
    var v1:Number = (p3 - p1) / 2;
    var t2:Number = t * t;
    var t3:Number = t2 * t;
    return (2 * p1 - 2 * p2 + v0 + v1) * t3 + 
        ( -3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
}
t には 0.0 から 1.0 の係数が入ります。
p0 から p3 間にある点、p1、p2を通過する曲線を求めます。
得られる値は p1 から p2 までです。
Processing の curve() といっしょ。(←不確かですが...)

ただ Graphics.curveTo() で描くのはちょっと難しいっぽいです。
角っこがポコってなる。
3次ベジェをきっちり定義できれば curveTo() も使えるかも。

デモ(開曲線)


デモ(閉曲線)



参考 : http://markun.cs.shinshu-u.ac.jp/learn/cg/cg3/index5.html
2008年5月16日
FlashPlayer10が世間を賑わせてますが、僕はまだインストールしてないです。
3Dに対応したけど、世の中のFlashコンテンツが3Dだらけになったら嫌だなあ。とかぼやきつつ
もうしばらく静観してようかなと思ってます。
いろんな人が新機能についてノウハウを記事にされるのを読んでからにしようかと。
Flexも持ってないし。
まったく人任せな。

ところで、Vectorクラスなんですけども、
これって中身を型指定できるってことなんですが
var a:Array = new Vector.<String>();
みたいなことって出来るんでしょうか。

Vectorクラス自体の実装を一見しても、Array を継承してるようでもないので、
もしかしてArrayとはまったく別物なのかな? と。

個人的な要望としては
var a:String[] = ["a","b","c"];
みたいな方が都合良さげな気がするんですが。

もしかして
var v:Vector.<String> = ["a","b","c"];
とかもできないんだろうか。

さすがに
function test( arg:Vector.<String> ): Vector.<String>
{
   return arg;
}
ってことは出来るんだろうけど。

でも、やっぱり Vector が Array として認識できないと何か嫌。
認識できなくていいなら、Proxy使ってこんな実装でいいんじゃないかと。
これなら今のままでも使えるし。

まあ、Arrayより高速に処理できるってことはいいんだろうけど。


ついでに、上記の「こんな実装」を使った場合は以下のような感じ。
ArrayOf
import flash.geom.Point;

var points:ArrayOf = new ArrayOf(Point);
points[0] = new Point(1,1);
points[1] = new Point(2,2);
points.push( new Point(3,3), new Point(4,4) );

trace(points); //(x=1, y=1),(x=2, y=2),(x=3, y=3),(x=4, y=4)

var a:Array = points.toArray();
trace(a); //(x=1, y=1),(x=2, y=2),(x=3, y=3),(x=4, y=4)

var points2:ArrayOf = new ArrayOf(Point);
points2.push(new Point(5,5), new Point(6,6));

var points3:ArrayOf = points.concat(points2);


trace( points3 ); //(x=1, y=1),(x=2, y=2),(x=3, y=3),(x=4, y=4),(x=5, y=5),(x=6, y=6)
trace(points3[4]);          // (x=5, y=5)
trace(points3.shift());     // (x=1, y=1)
trace(points3.pop());       // (x=6, y=6)
trace(points3.splice(0,2)); // (x=2, y=2),(x=3, y=3)

test(points); // ok

points[0] = 1; // ArgumentError: Point と関連しない型の値は格納できません。

function test(arg:ArrayOf):void
{
    if( arg.type != Point ) throw new ArgumentError("エラー");
    trace("ok");
}
2008年5月14日
Spark Project の Utils ライブラリにコミットしました。
http://www.libspark.org/browser/as3/Utils/src/org/libspark/utils

至らない点は多々あると思うので、使い勝手のいいように変更してもらえればいいと思います。
もちろん何か言っていただければ可能な限り対応します。

コミットしたのは以下のファイル。

ArrayUtil(追記)
BitmapUtil
ColorUtil
DateUtil(追記)
MathUtil(追記)
StringUtil(追記)

(追記)は元々あったものに手を加えました。


いろんなライブラリを使ってると「ArrayUtil」とか「ColorUtil」とか
同じ名前のクラスが 3 つも 4 つもある状態になってしまったりするので
(as3corelibとか、popforgeとか、progressionとか。とかとか。)
そういうのんに含まれてるものも、こっちに書き写してしまえば
使うとき楽でいいんだけどなあ。と思う今日この頃です。
(写したら同じのが増えちゃうんですけども。。。)


ちなみに
BeInteractive!さんが「「これコミットして大丈夫なのかな...」と考える前にコミットして欲しい」って記事を
書いてくれていて、これは小心者の僕としてはコミットへの後押しになりました。
記事を書いておられるのがコメントもらった次の日だっていうのに、気づいたのが今日という僕ですが。

こっそりと感謝です。


追記::(2008.05.16)
GeomUtil
ObjectUtil
上記2点追加しました。

2008年4月24日
休み前なので立て続けですが。
たぶん休み中は更新しないです。あしからず。

Progression用のモーション系のコマンドをいくつか作りました。
せっかくなのでアップしておきます。
作ったといっても、AS2からずっと使ってる自前のモーションクラスをコマンド用に書き換えただけなんですが。
もちろん、みんなが安心、Tweenerをベースにしなおしといたんで、そのまま使うなり改良するなり、煮るなり焼くなりご自由に。

ただしProgressionのバージョンが2.1.xにバージョンアップすると使えなくなる可能性大です。
そのうち対応するとは思いますが。←僕が

あと、はじめに言い訳しておくと、パッケージ名がCroquisですが、
fladdictさんのsketchbookの名前をパクリました。すいません。(中身はパクってません)
というのも、なんかここまでいろんな便利ライブラリが出回ってると、自分でなんか作る気もしないので
とりあえずProgressionをベースに世のオープンソースなライブラリを自分用にまとめてショートカットクラスなんかにしちゃってるわけです。
sketchbookからSparkのutilsとかColorMatrixとかとか

そこまでくると、どこまで公開してもいいのか良く分からんし、あんまり大きな声じゃ言えないんですが。

んで、以下はその中の一部ってことです。はい。

ところで余談なのですが、SparkのUtilクラスってホントに勝手に書き足したやつとかコミット(?)しちゃっていいんだろうか。
あと、どれくらいUtil系そろえるつもりなんだろう。とにかく万能Utilにしちゃうんだろうか。
それとも他で出てるものとはかぶらない様にとかあるんだろか。
もしとにかく何でもってんなら、少しは貢献できるかもしれないけども。
なんかあの辺の人たち凄すぎて気後れしちゃうよ。
へむへむ。


でわでわ。以下デモになります。


ソースファイルはこちら。
croquis.zip

以下、このデモに含まれるクラス。

◆クラス一覧

基本クラス
croquis.motions.Motion

移動用コマンドクラス
croquis.motions.Linear
croquis.motions.Curve
croquis.motions.Cycle
croquis.motions.Wave
croquis.motions.Twist
croquis.motions.Bug

変形用コマンドクラス
croquis.motions.Trans

着色用コマンドクラス
croquis.motions.FillColor



◆簡易リファレンス

croquis.motions.Motion
Motion( type:String, time:Number, transition:String=null, delay:int = 0 )

Motionクラスのベースになるクラスです。
このクラスは直接インスタンスを生成することができません。
作成する場合は必ずサブクラスを作成します。

croquis.motions.Linear
Linear(target:Object, time:Number = 1.0, x:Number = 0.0, y:Number = 0.0, transition:String=null, delay:int=0)

指定座標まで直進します。
target      対象となるオブジェクト
time        移動時間
x           目標X座標
y           目標Y座標
transition  Tweenerに渡すtransitionパラメータ
delay       待機時間

croquis.motions.Curve
Curve(target:Object, time:Number = 1.0, x:Number = 0.0, y:Number = 0.0, angle:Number = 0.0, radius:Number=0.0, transition:String=null, delay:int=0)

指定座標まで弧を描いくように移動します
target      対象となるオブジェクト
time        移動時間
x           目標X座標
y           目標Y座標
angle       始点から終点までの中点からの中継点の角度
radius      始点から終点までの中点からの中継点までの半径
transition  Tweenerに渡すtransitionパラメータ
delay       待機時間

croquis.motions.Cycle
Cycle(target:Object, time:Number = 1.0, x:Number = 0.0, y:Number = 0.0, round:Number = 0, clockwise:Boolean = true, transition:String=null, delay:int=0)

指定座標を中心に回転しながら移動します
target      対象となるオブジェクト
time        移動時間
x           目標X座標
y           目標Y座標
round       回転数
clockwise   時計回り(true) 反時計回り(false)
transition  Tweenerに渡すtransitionパラメータ
delay       待機時間

croquis.motions.Wave

Wave(target:Object, time:Number = 1.0, x:Number = 0.0, y:Number = 0.0, radius:Number = 0.0, swing:Number = 0.0, transition:String=null, delay:int=0)

指定座標までの直線軸を中心に揺れながら移動します
target      対象となるオブジェクト
time        移動時間
x           目標X座標
y           目標Y座標
radius      初期振幅距離
swing       振動回数
transition  Tweenerに渡すtransitionパラメータ
delay       待機時間

croquis.motions.Twist
Twist(target:Object, time:Number = 1.0, x:Number = 0.0, y:Number = 0.0, radius:Number = 0.0, round:Number = 0.0, clockwise:Boolean = true, transition:String=null, delay:int=0)

指定座標までの直線軸を中心に回転しながら目標点に移動します。
target      対象となるオブジェクト
time        移動時間
x           目標X座標
y           目標Y座標
radius      回転半径
round       回転数
clockwise   時計回り(true) 反時計回り(false)
transition  Tweenerに渡すtransitionパラメータ
delay       待機時間

croquis.motions.Bug
Bug(target:Object, time:Number = 1.0, x:Number = 0.0, y:Number = 0.0, turnSpeed:Number=0.05, transition:String=null, delay:int=0)

不規則な動作をしながら指定座標まで移動します
target  対象となるオブジェクト
time    移動時間
x   目標X座標
y   目標Y座標
turnSpeed   向きを変える速度
transition  Tweenerに渡すtransitionパラメータ
delay   待機時間

croquis.motions.Trans
Trans(target:DisplayObject, time:Number = 1.0, scaleX:Number = 1.0, scaleY:Number = 1.0, rotation:Number=0.0, basePoint:Point=null, transition:String=null, delay:int=0)

任意の座標を中心に DisplayObject インスタンスを回転、及び拡大縮小させます
target      対象となるオブジェクト
time        移動時間
scaleX      X軸拡大縮小値
scaleY      Y軸拡大縮小値
rotation    回転角度
basePoint   任意の中心点
transition  Tweenerに渡すtransitionパラメータ
delay       待機時間

croquis.motions.FillColor
FillColor(target:DisplayObject, time:Number = 1.0, colorTransform:ColorTransform = null, transition:String = null, delay:int = 0)

ColorTransform によって DisplayObject インスタンスに着色します
target      対象となるオブジェクト
time        移動時間
colorTransform  変更対象となる色情報
transition  Tweenerに渡すtransitionパラメータ
delay       待機時間


追記:
executeボタンを押したときに前回のコマンドが実行中の場合、前回のコマンドを停止してから実行するようにしました。
上記の一覧のクラスには変更はありません。

前回はMovieClipの _x と _y のプロパティを変更して移動させましたが、
MovieClipにはその他にも様々なプロパティが定義されています。
このプロパティを変更することで、ムービークリップを回転させたり
透明度を変更したり、拡大縮小することなど、いろんなことができるようになります。

ってことでした。


それでは、他にどのようなプロパティが定義されているのか調べてみましょう。

キーボードのF1キーを押すとヘルプパネルが立ち上がるかと思います。(少なくとも初期設定の状態であれば)

ヘルプパネル 図.1

ヘルプパネルが開いたら上図のプルダウンメニューから「リファレンスガイド(ActionScript & コンポーネント)」を開きます。

選択したらスクロールバーがしばらく、ずりーっとなったあと下図のようになります。

ヘルプパネル 図.2

表示されたリストから「ActionScript 2.0 リファレンスガイド」→「ActionScript クラス」を選択します。

ヘルプパネル 図.3

FLASH CS3 を利用している場合は以下のような感じです。

ヘルプパネル 図.3-2

ActionScriptに定義されているクラスの一覧がつらつらと表示されるので、
その中から「MovieClip」の項を探して選択します。

ヘルプパネル 図.4

開いたページ内には「プロパティ一覧」「イベントの一覧」「メソッド一覧」とテーブルが並んでいます。
このプロパティ一覧に _x や _y のようなプロパティから、透明度やサイズのプロパティの解説が書かれています。
このテーブルから、MovieClipがどのようなプロパティが定義されているのかを調べることができます。
実際にはどんなプロパティがあるのかを調べるより、こういうことをしたいときにはどのようなプロパティやメソッドを用いればいいのか。といった調べ方の方が多いと思いますが、そういうときにも僕はこの一覧の中から探しています。

ちなみに前回用いた onEnterFrame は「イベントの一覧」の中にあります。

さらに特定のプロパティの詳細が知りたいときは、左の一覧から選択するか、CS3の場合はリスト内のプロパティ名の箇所がリンクになっているので、そこから詳細ページに移ることができます。
詳細ページでは簡単なサンプルソースが掲載されていたりもするので、かなり参考になります。


これまで僕も様々なFLASHの参考書を買いあさってきましたが、結局最後まで使うのはヘルプです。
ヘルプを見ればほとんどのスクリプトの説明が載ってます。
これを読んでる方が調べて、解説されていないスクリプトってのはないんじゃないかと思います。

今ではActionScriptについて書かれているブログもかなり増えましたし、
技術者向けのニュースサイトで解説もされているので、インターネットを利用しても簡単に見つけることができると思います。

分からないときは FLASH-JP のようなフォーラムで質問するのも助けになるかと思いますが、
まずは、自分で調べる力を身につけましょう。


おまけ
以下のようなサイトで ActionScript について解説されています。

fumioNonaka.com
URL : http://www.fumiononaka.com/

Flashゲーム講座 & アクションスクリプトサンプル集
URL : http://hakuhin.hp.infoseek.co.jp/main/as.html

IT Pro 「Flash CS3入門 基本からActionScriptまで」
URL : http://itpro.nikkeibp.co.jp/article/COLUMN/20071025/285488/

Flashの枝(FLASH・アニメーション・ActionScript1.0,2.0,3.0の学習サイト)
URL : http://1art.jp/

ActionScript 逆引きクイックリファレンス
URL : http://www.openspc2.org/reibun/QuickReferenceActionScript/index.html

gihyo.jp「ActionScript 3.0で始めるオブジェクト指向スクリプティング」
URL : http://gihyo.jp/dev/serial/01/as3


ここで挙げた以外にも様々なサイトがありますので、いろいろ見てみるのもいいと思います。
連載とか言いながら、かなり放っておいたら催促されてしまいました。すいません。

今回はムービークリップをActionScriptを使って操作する方法と、簡単なアニメーションについて書こうと思います。

まず新規にflaファイルを作成して、ステージ上に簡単な矩形のムービークリップを作成します。
このインスタンス名は "mc" にしておきます。

さらに同レイヤー上に下記のActionScriptを記述します。
trace( [mc._x, mc._y] );
図.1

上図の場合 mc は x が 50 の位置に、y が 30 の位置に配置されています。
この状態で、一度プレビューしてみましょう。

出力パネルには「50,30」と出力されたと思います。

何度かステージ上のmcの位置を動かしてみて、その都度プレビューしてみてください。
ほぼ期待通りの数値が出力されるかと思います。
「ほぼ」と書いたのはたまに0.05の誤差が出る場合があるからです。
プロパティパネル上では0.1単位でしか指定できませんが、
実際 FLASH 上では0.05ピクセル単位で描画されてるため
マウスで配置するとこのようなズレの生じる場合があります。
まあ、今はあまり気にしないでください。

次にこれをタイムライン上でトゥイーンアニメーションを作成してみます。
下図のような感じです。

図.2

10フレーム目のキーフレームで mc の位置を(x=450,y=30)の位置に移しています。
また、位置を把握しやすいようにガイドを追加したのと、
出力値を表示する用のテキストフィールド(ダイナミックテキスト)を配置しています。

サンプルのflaファイルはこちらからダウンロードできます。
demo2.fla

ActionScriptは以下のように書き換えました。
this.onEnterFrame = function()
{
    output.text = mc._x;
}

this はこのタイムラインを指しています。

onEnterFrame は、FLASH上でタイムラインのフレームが
次のフレームに移ったときに呼び出されるMovieClipのイベントハンドラメソッドです。
(メソッドについては第6回を参照してください。)
ここでは onEnterFrame に新たに function を代入することで、onEnterFrameの実行内容を定義しています。

output は画面下に配置したテキストフィールドのインスタンス名です。
output.text でoutputの表示するテキストを取得、変更できます。
output.text に mc._x を代入することでmcのX座標の位置をプレビュー時に表示することができます。

最後に、図の中にはありませんが、プロパティパネル内のフレームレートを 2 まで下げています。
あんまり早いと表示された文字が読み取れないので。


それではプレビューしてみましょう。
当然 mc はカクカクとですが右にスライドしていきます。

この時、画面下のテキストフィールドに表示された値に注目してみてください。
mc が移動すると同時に mc._x の値が変わっているのが分かります。

書き出したデモはこちら
demo2.swf


ここまでくれば説明する必要もないかもしれませんが
mc._x は mc のXの位置を指すMovieClipのプロパティです。
同じく _y は mc のYの位置を指します。


では、このプロパティの値を見るだけではなく、今度はActionScriptを使って変更してみましょう。

図.3

トゥイーンアニメーションは使わないので、タイムラインを1フレーム目を残し、2フレーム目以降を削除してしまいます。
また、スクリプトを以下のように1行追加しました。
this.onEnterFrame = function()
{
    mc._x = mc._x + 10;
    output.text = mc._x;
}

追加した行では、現在の mc の _x プロパティの値に 10 を足した値を mc._x に代入しなおしています。
このflaファイルはこちら。
demo3.fla

これでプレビューした状態がこちらです。
demo3.swf

mc が10ピクセルずつ右にスライドしています。

さらにスクリプトを以下のように変更してみましょう。
this.onEnterFrame = function()
{
    mc._x += 10;
    mc._y += 5;
    output.text = mc._x;
}
今度は右下に向かって斜めに移動していきます。
mc._x += 10 は変更前と同様の意味を指します。
つまりmc._x の値に10加算するということです。
さらに _y プロパティにも数値を加算することで、下方向への移動も加わるため、
斜めに移動するようになります。

ただしこのままでは(x=450, y=230)を超えてもそのまま直進し続けてしまいます。
そのため、もう少し改良して以下のようにします。
this.onEnterFrame = function()
{
    if( mc._x < 450 && mc._y < 230 ){
        mc._x += 10;
        mc._y += 5;
    }
    output.text = mc._x;
}
if() はその後の{}内の命令に条件を与えるためのものです。
今回の変更では、もし(if)mc._x の値が 450 未満であり、mc._y の値が 230 未満であるとき、
この両方の条件を満たしているときだけ{}内の命令を実行する。というものです。

さらにここではフレームレートを 30 にしておきましょう。

これをプレビューした状態がこちらです。
demo4.swf

今回はMovieClipの _x と _y のプロパティを変更して移動させましたが、
MovieClipにはその他にも様々なプロパティが定義されています。
このプロパティを変更することで、ムービークリップを回転させたり
透明度を変更したり、拡大縮小することなど、いろんなことができるようになります。

2008年4月 9日
今度はFlickrAPIと、おなじみPapervision3DとでProgressionです。

Prog de Flickr

別にPV3D使ってるからといって、シーンの切り替えとかで
ダイナミックな使い方してるわけではないです。

今回は以下のライブラリを使用しています。
Progression Framework 2.0.18
Papervision3D Beta 1.7 (20.08.07)
as3flickrlib

ソースもアップしてます。
ソースファイル一式ダウンロード
前回以上に書きなぐりのソースになってますが、
特に整理しようとも思わないので、そのままアップしちゃいます。

毎度のことですが、APIキーはご自分で取得したものをお使いください。


あと、アップしてるサンプルですが、どうもアップしたては
アクセスが集中するのか読み込みにエラく時間がかかったりして
ちゃんと使えないかも。

こなれてくるとProgressionがホントに心地良いです。

2008年4月 7日
今回は前回のエントリーでアップしたProgression de Amazonについてです。

シーンの動的生成と削除について書こうとして、削除してなかったのに気づいて一部書き換えました。
変更したのは demo.scenes.DetailScene クラスです。

ファイルをアップしなおそうとして、誤って上書きしちゃいました。
ソースファイル一式をダウンロード


DetailSceneクラスについて

このクラスは画面下部に表示された検索結果の商品一覧をクリックしたときに表示される、
詳細画面を開く際に通過するシーンクラスです。

まあ、何てことはないのですが、通過時に通知されるonDescendイベント内で移動先のシーンIDを取得して
新たにシーンオブジェクトを作成し、それを子シーンに追加しています。

こんな追加処理だけのシーンクラスを作らずに、移動元のシーンクラスのonGotoイベント内で
追加処理を実行してもよさげなものですが、それをするとURLから直接動的シーンに移動することになったときに
シーンが作成されなくなってしまうので、このように中継用のシーンを作成しています。

削除するときはonAscendイベントを使って、先ほど作成したオブジェクトを消すだけです。


なんか書こうと思ったんだけども、まったく特筆するようなことがないんだよなあ。
全部 Progression がやってくれてるし。


なもんで、このサンプルのソース見て「これ何?」って疑問のある人は質問してくれたら答えます。
ってことにしとけばきっと楽なんだ。

そういえばaccessKeyってまだ使ってないなあ。

2008年4月 4日
引き続きProgressionの話題です。
現在のProgressionのバージョンは2.0.17です。

先日からやってたデモFlashの"Progression de Amazon"。

とりあえず時間かけ過ぎて飽きてきたので、今日でこのAmazon使ったFlashは終わりにしときます。
まだタブをポチポチ押しまくったり、ブラウザの「戻る」「進む」を繰り返してるとおかしなことになったりと
まだまだ挙動不審ですが、まあ、中には取っ掛かりの手助けになる箇所もあるんじゃないかなあと思います。

Progression de Amazon

ほんとに誰かの役に立つことがあるのか、甚だ疑わしいですが、
当初の予定通り、恥ずかしいソースファイルもアップしておきます。

ソースファイル一式ダウンロード
なお、言うのが遅すぎますが今回はクラスベースでプロジェクトを作りました。
レイアウトは思いっきり直置きなんですけども。。。

一応Progressionファイルも全部入ってるので、index.flaを書き出せば動きますが、
AmazonのAPIキーだけはご自身で取得したものを使用してください。
設定場所はIndexクラスにコメント書いておきました。

Amazon Web サービスのアカウントの取得はこちら
http://www.amazon.co.jp/gp/feature.html/?docId=451209

今回Amazon API についてはこちらを参考にさせていただきました。
MEMO - Amazon API

また、相変わらずクラスファイル内にコメント全然してないです。
詳細について解説しようかと思いましたが、今日は時間も遅いので
また後日書きます。(おそらくそんなに詳しくは書けないと思いますが。)


本音は、誰か僕に綺麗なスクリプトの書き方を教えてほしいんですが。

2008年4月 3日
引き続きProgression Frameworkについて。
執筆時現在のバージョンは 2.0.17 です。
前回のデモのpreloader.flaに処理を追加してみました。
デモ(2008.04.03)

とりあえずpreloader.flaとクラスファイルをアップしときます。
preloaderソースファイル
Progressionのクラスは入ってないです。

クラスファイルの中身はこんなのです。
DemoPreloader.as
(余談だけど、hetemlって.asファイルをブラウザで見ることできないのかな?
.htaccessにAddType書いてみてもだめだったんだけども、なんでだろ?)


以下、今回けつまずいた箇所のメモ。

ExPreloaderを継承したDemoPreloaderクラス(以後Preloaderクラス) の onComplete の後、
IndexのonInitが発信されるが、今回complete後にアニメーションを加えた(これはindex.falに入れた
ほうが良いかもしれない)のと、ローディングのバーの伸び方にイージングを加えたので、
それが終わってから Progression のシーンが始まるようにしたかった。

そのため、IndexクラスからPreloaderクラスにイベント通知の登録をしようとして
Preloaderのインスタンスを参照しようとすると、ステージ上のオブジェクトが存在しないと怒られた。

これを回避するためにPreloaderクラス内のオブジェクトの参照をgetterを使って間接的に参照するようにした。

以下はIndexクラスに書いたPreloaderクラスへの参照の部分。
override protected function _onInit():void
{
    //~中略
    
    if( DemoPreloader.instance ){
        DemoPreloader.instance.addEventListener( Event.CLOSE , startContents );
    } else {
        startContents();
    }
}

private function startContents( event:Event=null ):void
{
    // 最初のシーンへ移動。
    prog.goto( prog.firstSceneId );
}

----

onProgressイベント内で、同クラスの bytesLoaded と bytesTotal の両プロパティを参照すればよいのかと思いきや
これらのプロパティは progress.swf 自身のバイト情報なのでロード進行中はすでにどちらも固定の値しか返してなかった。
なので addEventListener で一旦 progressイベントにリスナーを登録して、そこに渡されるイベント情報から
bytesLoaded と bytesTotal を読み取るようにした。
(ここで登録したリスナーにはきちんと内部のExLoaderの情報が返ってきてる。)

----

実際サーバーにアップしてみて気づいたのは、URLが変わって「index.html#/~」とかってなるところでリロードすると
Indexクラスの onInitイベントが飛ばされるみたい。詳細はわからないけども。
そのためローディングの後処理と、メインのコンテンツが同時に実行されてしまった。
これは Progression のルートに設定したシーンクラスの onLoad から Preloader の動作をキャンセルさせることで回避。

以下はルートシーンの onLoad イベント内の処理。
書いてることは Preloader が終了してなければスキップ。
override protected function _onLoad():void
{
    if (DemoPreloader.status != "close") DemoPreloader.status = "skip";
    
    addCommand( 
        new AddChild( progression.container , _cast )
    );
}

----

これはつまずいた訳ではないけども、ちょっと気になったのでボソっと。
toString がオーバーライドされてるからPreloaderクラスをtraceすると [object DocumentRoot] に。
DocumentRoot クラスから toString を消すと [object ExMovieClip] に。
コンマ数秒だけ「あれ?」って思った。w


なんか自分の失敗ばかりツラツラ書くと、Progression使うの難しく見えるかもしれないなあ。
でも、本当は気にするところが、上にあげた部分だけで、その他に気にすることが無いってところが良くできてるんだと思う。
だってプリローダーファイルを外部で用意して、コンテンツ部分と分離させようとか考えてイチから作ったらかなりの手間だと思う。
コンテンツ部分の制作時に親ファイルの存在を気にする必要もなく出来てる訳だし。
Progression使わずにローディングの部分だけでも使えるし。

あと、AS2やってた人がAS3の取っ掛かりにProgressionを使うのもいいと思う。

なかなか使いこなすまでには至らないけども、噛めば噛むほど味の出る感じがいいです、Progression。
きっとjp.niumパッケージの中身とかも便利クラスがいっぱい詰まってるんだろうと思いますが、
まだそこまで手が回りません。
2008年4月 2日
Progression のサンプルデータのページからダウンロードした、
東京てら子ワークショップキットの IndexScene クラスをちょっと図にしてみた。



ふむふむ。
2008年4月 1日
とりあえず何か作ってみないことには良し悪しも何もわからないので
とにかくざっくり作ってみた。
なんかせっかくリンクまでしてもらったのに、あのサンプルじゃ申し訳ないし。

Progression デモ(2008.03.31)

まだ画面遷移とか何もしてないので、もうちょっとチョメチョメしてからソースのほうもアップします。

で、以下、今のところの雑感など。

Progressionは大きくは「シーン」と「キャスト」の2つから構成されてるんだと思うのだけども、
シーンクラスに何を書いて、キャストクラスに何を書くかってのが悩む。
これは自分の未熟さのせいなんだけども。

ところでキャストからシーンを参照する方法が分からなかった。
そもそもそんな作り方をするのが間違いなのかもしれない。
このAmazonのやつは、すでにシーンとキャストがごちゃごちゃ。
シーンがキャストを制御するんだから、やっぱりキャストからシーンを参照するようなことは
しちゃいけなかったかもしれない。

あと、コマンドクラスをいかにウマく使うかってのもミソだと思うんだけども
これがまた不慣れなせいで、すっ飛ばして自分で関数作って実装しちゃったりする。
折角コマンドが用意されてるのにaddEventListener使いまくりだったり。
あとaddCommandで追加したコマンドの実行の仕方がわからなかったり。
結局SerialListを新たに作ってexecuteで実行とか。
きっと何か用意されてると思うんだけども。

Flash作るとき、自分はステージ上にボコボコレイアウトしていって
それをスクリプトで制御するんだけども、はじめからステージ上にオブジェクトを
配置していると、"onCastAdded"が使えなかった気がするな(気のせいかな?)。
なんか不確かなんだけども。

ExPreloaderからIndexへの遷移ももうちょっと調べてみないと。
ローディング後の後処理みたいなのを作った場合、その後処理後から
Indexへの連携の仕方が分からなかった。

ああ、帰らなきゃ。
2008年3月28日
AS3の EventDispatcher クラスをAS2でも使えるようにと思って作ったクラスです。

EventDispatcher クラス
Event クラス

サンプル用 fla ファイル
demo.fla
demo2.fla

willTriggerメソッドが、どうやって実装するか悩んだ(willTriggerの挙動自体いまいち把握してない)のでとりあえずほったらかしてます。

あと、mx.events.EventDispatcherを継承してますが、中身はまったく別物です。
ムービークリップに適応した場合、イベント通知がルートからたどっていくようになってます。(微妙ですが)

で、AS3的に「addEventListener("enterFrame", handler )」とかやりたいところですが、
元々AS2のMovieClipにそんな機能は実装されてないので、前のエントリーで書いた EventMediator クラスを使います。

こんな感じです。
import flash.events.EventDispatcher;
import flash.events.Event;

import com.seyself.events.EnterFrameBeacon;
import com.seyself.events.EventMediator;

EventDispatcher.initialize( MovieClip.prototype );

var madiator:EventMediator = new EventMediator( new EnterFrameBeacon() );

madiator.addEventListener( "enterFrame" , null );
madiator.member = [mc];   // ステージ上に配置してあるムービークリップ

mc.addEventListener( "enterFrame" , enterFrameHandler );
function enterFrameHandler( event:Event ):Void
{
    trace(event.target);// _level0.mc
}

EnterFrameBeaconクラスは、単純にenterFrameイベントを通知し続けるクラスです。
メンバーに対してイベント通知を促すクラスです。
ソースファイル

例えば Shapeオブジェクトにマウスイベントくっつけたり、
Timerオブジェクトに enterFrame イベントくっつけたりするのに使います。

まず通知元オブジェクトを登録した EventMediator オブジェクトを作成します。
作成した EventMediator オブジェクトに通知メンバーを登録します。
通知元オブジェクトがイベントを通知(dispatchEvent の実行)すると、
メンバーの各オブジェクトも同じイベントを通知するようになります。

import flash.events.Event;
import flash.net.URLLoader;
import flash.utils.Timer;
import flash.display.Sprite;

import com.seyself.events.EventMediator;

var madiator:EventMediator = new EventMediator( new Sprite() );
var urlLoader:URLLoader = new URLLoader();
var timer:Timer = new Timer(1);

madiator.addEventListener( "enterFrame" , null );
madiator.member = [urlLoader,timer];

urlLoader.addEventListener( "enterFrame" , enterFrameHandler );
timer.addEventListener( "enterFrame" , enterFrameHandler );
function enterFrameHandler( event:Event ):void
{
    trace(event.target);
    event.target.removeEventListener( "enterFrame" , arguments.callee );
    //madiator.removeEventListener( "enterFrame", enterFrameHandler );
}
上記のコードの場合、出力結果は以下のようになります。
[object URLLoader]
[object Timer]

TimerクラスやURLLoaderクラスは、もともとenterFrameイベントを持っていませんが
登録しておくと、これらのオブジェクトがenterFrameイベントを通知するようになります。

一応 fla ファイルも置いときます。
demo.fla
demo2.fla
2008年3月25日
AS3向けのフレームワーク「Progression」がなんだか便利みたいなので、自分も慣れておこうと思った。

とにかく手探りなので、まずは Wiki のチュートリアルを、と思ったら、チュートリアルもまだほとんど準備中だった。
なもんで、とりあえずリファレンスとソースを行き来しながら作ってみた。

作ってみたやつ

一応ソースファイルも一式アップしときます。
恥ずかしいソースファイルのダウンロード

まず組み立て方がよくわからなくて困った。たったこれだけのコンテンツなのに、クラスファイルが錯綜してます。

何気に、右クリックの「新規ウィンドウで開く」がすごいと思った。
Event系のクラスの toString の実装が直接文字列を返すようになってるのは何でなんだろう。

あと、イベントの順番のメモ
sceneStateChange → load → init
goto → unload → sceneStateChange
2008年3月21日
AS3を使っててAS2に戻ると、何かと不便に感じることが多いです。
AS3とAS2に互換性が無いのが、今、一番厄介に感じます。
いずれ完全にAS3に移行したときのことを考えて、少しAS2にAS3らしさを取り入れたほうがいいのかな?なんて思ったりもしますが、それが正しいのか間違ってるのかはよくわかりません。
ただAS3からAS2にクラスを逆移植することがあるのですが、Eventクラスとか、デフォルトのクラスでよく使うものはAS2にもほしい。
誰か作ってないかなあ。と思う今日この頃。
あと、個人的にProxyクラスがAS2にもほしいけど実装の仕方がわからない。

flash.utils.Dictionary
import flash.utils.Dictionary;

var dic:Dictionary = new Dictionary();
var a = {};
var b = {};
var c = {};

dic.add( a , 1 );
dic.add( b , 2 );
dic.add( c , b );

trace("length : "+dic.length);// output 3
trace("object a : "+dic.value(a));// output 1
trace("object b : "+dic.value(dic.value(c)));// output 2
dic.del(c);
trace("length : "+dic.length);// output 2
trace("has a : "+dic.has(a));// output true
trace("has b : "+dic.has(b));// output true
trace("has c : "+dic.has(c));// output false
2008年3月 7日
せっかくなので忘れないうちにメモ。

テンプレートで変数を使うには<strong>MTSetVar</strong>, <strong>MTSetVarBlock</strong>, <strong>MTSetVarTemplate</strong>などが使える。
変数の設定
<MTSetVar name="変数名" value="値">
<MTSetVarBlock name="変数名">値</MTSetVarBlock>

変数の参照
$変数名


<MTSetVarBlock name="categoryName"><$MTCategoryLabel$></MTSetVarBlock>
<MTEntries category="$categoryName">
・・・
</MTEntries>
ブログのテンプレートを構築しなおしました。
過去のエントリーのURLが変わっています。
一応以前のHTMLファイルを残していますが、過去のページに記載されているリンクが
正しく動作していない可能性があります。
その場合はお手数ですがメインページから再度アクセスしなおしてください。
2008年3月 6日
Box2Dを使った習作。


数値の入力は画面をドラッグ。
2008年2月26日
JavaScript で ByteArrayクラスを作ってみました。
まだ完全に実装してるわけではないけどもとりあえずアップしとくことに。

zip圧縮、解凍とエンコードの変換は、それぞれ以下のライブラリを使わしてもらってます。

[ecl.js]エンコード変換
URL : http://nurucom-archives.hp.infoseek.co.jp/digital/

[deflate.js]zip圧縮
URL : http://www.onicos.com/staff/iz/amuse/javascript/expert/

[inflate.js]zip解凍
URL : http://www.onicos.com/staff/iz/amuse/javascript/expert/

メソッドは
"readObject()" と "writeObject()" と "writeMultiByte()" がまだ実装してません。
"writeObject()" はほんとどうやって実装しよう・・・って感じです。
AS3版とは仕様を変更して、オブジェクトのプロパティ抜いてStringに変換とかすれば楽なんだけども。

あと、まだ配列アクセス([])できません。致命的ですが。

サンプルページとソースのダウンロードはこちら。
サンプル
ByteArray.js
ソースのダウンロード

ちゃんと動くのはFirefoxだけかも。
Safariはマルチバイトエンコードがうまくいってないっぽい。
他のブラウザは__defineGetter__が対応してないと無理だと思う。

実際このスクリプトが使える代物かというと、100%使えないと思う。

とりあえず今回実装してみて、JavaScriptでバイナリデータを読み込むことと
浮動小数点数(FloatとDouble)について、少し理解できたくらい。

でも浮動小数点数のところは、かなり力技なので、
もっと綺麗に書く方法知ってる方は是非とも教えてください。

それから、JavaScriptでクラスを書く方法も"これが正攻法"ってのが
結局わからなかったので、これも知ってる方、教えていただけると幸いです。

なんか今日はずいぶん人任せなエントリーになってしまった。

2008年2月18日
以前書いた「画像をロードしたMC 上に attachMovie」という記事に
助言をいただきまして、ちょっと試してみたので掲載しておきます。

読み込み先の"sub.swf"には「imageMC」というムービークリップが配置されてます。
var mc:MovieClip = this.createEmptyMovieClip("loadSWF",10);
var loader:MovieClipLoader = new MovieClipLoader();
listener = { onLoadComplete:function(){
    trace(mc.imageMC);                      // output 1
    mc.onEnterFrame=function(){
      trace("onEnterFrame : "+mc.imageMC);  // output 2
      delete this.onEnterFrame;
    }}, 
    onLoadInit:function(){
      trace("onLoadInit : "+mc.imageMC);    // output 3
    }};
loader.addListener( listener );
loader.loadClip( "sub.swf" , mc );
出力結果
undefined
onEnterFrame : _level0.loadSWF.imageMC
_level0.loadSWF
onLoadInit : _level0.loadSWF.imageMC
出力結果の1行目は "output 1" 、2行目は "output 2"、
3行目は sub.swf のルート1フレーム目に書かれた「 trace(this); 」の出力、
4行目が "output 3"になります。

僕は今まで onLoadInit が読み込みを開始したときのイベントだと勝手に勘違いしてました。
実際にはonLoadInitは読み込まれたswfの1フレーム目のスクリプトが実行された後に呼び出されるみたいです。
onEnterFrameは各フレームのスクリプトの一番最初に実行されるルールがここでも有効みたいなので、onLoadInitが呼び出される前(読み込まれたswfのスクリプトが実行されるよりも前)に実行されるみたいです。

それぞれ実行されるタイミングが違うので、意図的にこれらを使い分ければ便利かもしれないです。
2008年2月13日
今日は、前回のエントリー(PV3D と Box2D を組み合わせて使ってみた)で作った迷路FLASHの作り方について簡単に解説します。


迷路を生成するためにMazeクラスを作成
Maze.as

まず迷路を生成するクラスを作ります。 このクラスはプロパティ内に"1"と"0"の配列で迷路の情報を作成します。 画像は出力結果です。 このクラスは「C言語による最新アルゴリズム事典」を参考にさせてもらいました。


PV3DとMazeを組み合わせる
Cubic.as

先ほど作成したMazeクラスで生成した迷路の情報を元に、PV3DのCubeを配置します。
このCubic.asはPV3Dのサンプルについている「Cube」を元に編集したものです。
あとでボールを転がすので、試しにココでSphereクラスも使ってみます。
サイコロ柄なのは特に意味は無いです。
初めて使うので「MaterialsList」の関係とかを見るために6面を違う柄にしたかっただけです。
今回裏面は最終的に見えなくするので、無駄な処理を省くために接続面と裏面を消しています。


Box2DとMazeを組み合わせる
Ball.as

Cubeと同様に作成した迷路情報を元に四角と丸を配置します。
PV3Dが「x,y,z」の3軸なのに対して、Box2Dは「x,y」の2軸なので、z軸に対する重力は今回無視して
マウスの方向(x,y)に重力の座標を変更しています。
m_world.m_gravity.x = mouseX - 640 / 2;
m_world.m_gravity.y = mouseY - 360 / 2;
このBallクラスもBox2Dについているサンプル「HelloWorld」をもとにしています。


上記2つをさらに組み合わせる
Document.as

先ほど作成した Ball クラスと Cubic クラスを組み合わせます。
このときBallクラスで使用したDisplayObject(Sprite)はもういらないので削除します。
Box2Dは位置情報を持っているので、この情報を PV3D に反映させます。
あとはマウス座標に合わせて程よく傾ければ、傾いてる方向に転がってるように見えます。

全ソースファイルのダウンロードはこちら。
20080208_Maze.zip

2008年2月 8日
巷でウワサの(?) Papervision3DBox2DFlashAS3 を試しに使ってみた。

どちらも使うのは今回が初めてなので、ちょいちょいいろんなブログを徘徊しつつ、
探り探りですが、簡単な迷路を作って、ボールを転がす。みたいなのを作ってみました。

最初に PV3D でオブジェクトの書き出しをするのにちょっと待たないといけないです。
3秒~10秒ほどかな?(マシンにもよるのだろうけども)
ちょっと重い気がするので別ページに置いておきます。
PV3D & Box3D :: MAZE
PV3D & Box3D :: MAZE
今回触ってみて困った点は、
  • 迷路はランダムに自動生成しているが、マス目が少ないとかなり単純なものになってしまい、逆に増やすと、PV3Dがオブジェクトを生成するのに時間がかかってしまう。
  • Box2Dで円が2つのオブジェクトに挟まれると、動かなくなってしまう。
この2点でした。

2つのライブラリを触ってみた感想は

PV3Dはさすが人気があるだけのことはあるなあと思いました。
ドキュメントもあるし、みんなブログに説明書いてくれてるし、で
これぐらいの物を作るぐらいならあんまり困らなかった。

一方Box2Dの方は、(たぶん)C++からの移植みたいだけども、
まだ移植しきれていないのか、バージョンアップによる変更のせいなのか
クラスによっては変数が定義されてないものを参照してたり、パッケージ名が
違ってたりしたのが気になった。

ソースとか迷路の詳細とかは、また今度。