2007年9月アーカイブ


AS2だと BezierSegment クラスは用意されていないけど、CS3の以下のディレクトリ
Adobe Flash CS3\ja\Configuration\ActionScript 3.0\Classes\fl\motion
の中に入ってる BezierSegment.as をコピーして少し書き換えればAS2でも使えます。

・packageの記述を削除
・int を Number に書き換え
・for each を for in に書き換え
・function の引数のデフォルト値を削除

swfファイルがココに置いているので、これをダウンロードして WindowSWF フォルダに入れれば Flash 内で
「ウィンドウ」→「他のパネル」から開けます。
AS3 の Math.max と Math.min ってパラメータ2つじゃないんだ。ってことに今気づいたよ。
trace( Math.max( 10, 20, 30 ) );//出力 30
先のエントリーで書いていたことが出来るか試してみたら、出来た。

そのまんまなんだけど、バイナリ型で読み込んだSWFファイルを
一度 compress を実行した後、配列から1バイトずつ取り出して文字列として結合。
それを SharedObject に保存。

使うときはその逆。びっくりするほど簡単だった。
ByteArrayUtil というクラスとして作成しておいた。
各クラスファイルは以下にあります。
使用している自作クラス
com.seyself.utils.ByteArrayUtil
com.seyself.data.BinaryData
内部でもろもろクラスを使用しているので、試してみる場合はココからまるごとSVNで落としてもらった方がいいかも。

ByteArrayUtil クラスの使用例
import flash.display.Loader;
import flash.utils.ByteArray;
import flash.net.SharedObject;

import com.seyself.data.BinaryData;
import com.seyself.utils.ByteArrayUtil;

var so:SharedObject = SharedObject.getLocal( "binary_to_string" );

//SharedObject にデータが保存されている場合
if( so.data.hasOwnProperty("savedata") ){
  trace( "--load to local data" );
  toStringCallback( so.data.savedata );
}
//SharedObject にデータが保存されていない場合
else {
  trace( "--load to file data" );
  var binaries:BinaryData = new BinaryData();
  binaries.complete = loadComplete;
  binaries.load( "example.swf" );    //外部SWFファイルをバイナリ形式で読み込む
}

//変換中に呼び出される関数です。
var progress = function( parcent:Number )
{
  //parcent : Number - 現在の変換率が渡されます。
  trace("completed convert percentage : "+parcent);
}

//外部からの読み込みが完了すると呼び出される関数です。
function loadComplete()
{
  ByteArrayUtil.toString( binaries.bytes , toStringCallback, progress );
}

//ByteArray から文字列への変換が完了したときに呼び出されます。
function toStringCallback( code:String ):void
{
  so.data.savedata = code;
  ByteArrayUtil.toBinary( so.data.savedata , toBinaryCallback , progress );
}

//文字列から ByteArray への変換が完了したときに呼び出されます。
function toBinaryCallback( binary:ByteArray )
{
  //Loaderインスタンスに、変換されたByteArrayを読み込ませる。
  var loader:Loader = new Loader();
  this.addChild( loader );
  loader.loadBytes( binary );
}
AIR はインストールを前程として作成するので、一度配布してしまうと修正が難しい。
今まで Web 上での公開を前程としたものばかり作っていると、少し不便に感じるかもしれない。

で AIR を作るときはこういう機能が必要なんじゃないかと思った。

・自動でアップデートのチェックと、アナウンス。
これは一般的なソフトウェアなら大体備えている機能。
これが無いと一度インストールしたソフトウェアのアップデートの有無をユーザーが知る確立はほぼ無いに等しく思う。

・土台のみ AIR で作成し、中身の実装は外部SWF化する。
こっちの方が今まで Flash をやってた人には馴染みが深いと思う。
可能かどうかはまだ試していないので分からないけども、外部SWFの方はサーバーに置いておけば
そちらを更新すれば、エンドユーザー側は自動的に反映される。
ただし、毎度毎度読み込んでいたのでは ブラウザで閲覧するのとなんら変わりがないので
サーバーから読み込んだ SWF ファイルは ByteArray から文字列化して SharedObject に保存しておく。
次回起動時からは、バージョン情報のみ最初に確認して、アップデートがあった場合のみサーバからダウンロードして更新。アップデートが無い場合や、オフライン時は SharedObject から復元する。
みたいな実装が出来るといいかなあと。


どちらにしても、公開前の制作段階で、後々の更新のことを踏まえておかないと痛い目にあう気がする。
流行に乗っかってブログパーツを作ってみました。
一応管理ツールを AIR で作ってみました。
詳細は以下のページで。
http://gokigen-kun.seyself.com/
ウィンドウを最小化
stage.window.minimize();
ウィンドウを最大化
stage.window.maximize();
ウィンドウを元のサイズに戻す
stage.window.restore();
ウィンドウを閉じる
stage.window.close();
ウィンドウをドラッグする
stage.window.startMove();
ライブラリ内のシンボルや画像などの素材を探すために使います。
LibrarySearch.png

ファイルはこちら
LibrarySearch.mxp

検索を実行すると、下のリストにマッチする名前のアイテムを表示します。
それらの中から、目的のアイテムを選択すると、ライブラリ内で、そのアイテムが選択されます。
フォルダ内にある場合は、フォルダも開きます。

同時に選択したアイテムのリンケージ情報も出力パネルに出力します。
AS2、AS3両対応。

Flash 8 と CS3 で確認しています。

AS3の場合
[Library Item] : contents/main
    AS3.0 クラス : Main
    AS3.0 基本クラス : flash.display.MovieClip
    ActionScript に書き出し : true
    最初のフレームに書き出し : false

AS2の場合
[Library Item] : main
    識別子 : main
    AS2.0 クラス : Main
    ActionScript に書き出し : true
    最初のフレームに書き出し : false
ステージ上のアイテムをライブラリ内から探すショートカット用コマンドも。
ItemSearch.mxp
更新と言っても、ちょっとドキュメント追記したくらいなんだけども。

ソースはココ
ドキュメントはココ
なんとなく思ったこと。

ActionScript のクラスを作るときって、もちろん Flash のオーサリングを前提にして作る。
今まで何度も他の人が作った fla ファイルを修正依頼なんかで見てきたりしたんだけど、
Flash のオーサリング方法は結構人それぞれで、スクリプトの書き方も、それによって
大幅に違ってたりする。

ステージ上に何も配置しないで、すべて attachMovie とかでレイアウトすらスクリプトで指定する人もいれば、
コンテンツを細切れにして、どんどん外部SWF化してたり、
flaファイル内ですべてレイアウトして、それに対してスクリプトで操作を加える作り方だったり。
すべてを 1 フレームに収めてしまう人もいれば、コンテンツ毎にフレームを区切って作成する人もいるし、
「シーン」機能を使ってコンテンツ毎にシーンを作成する人もいる。

作り方が人それぞれだから、そこに書かれたスクリプトの使い方も人それぞれ。

僕はというと、
「flaファイル内ですべてレイアウトして、それに対してスクリプトで操作を加える作り方」で、
「コンテンツ毎にフレームを区切って作成する人」なわけ。

デザイン画像をガイドレイヤーに配置して、その上からパーツを配置していく。
そこにスクリプトを埋め込んで操作を加えていく。
だから、座標やスケールなどの指定は、絶対値よりも相対値を用いることが多い。

X座標 -10 からフェードインしてきて、 +10 に向かってフェードアウト

みたいな。

こういうレイアウト指向(?)なものに適したクラスを作っていくと
もっと作業が楽になるんじゃないかと思った。

めもめも。
先のエントリーに引き続き。

ステージ上に配置したムービークリップのインスタンス名には
シンボル名をそのままインスタンス名に使うことが多々ある。

AS3ではリンケージの設定に「クラス」と「基本クラス」があって、
「クラス」の方には1つのクラスにつき、1つのシンボルにしか割り当てられない。
そのため、CustomButtonクラスのようなものを作って、複数のボタンの「クラス」に
同じクラスを割り当てようとすると、このクラスを継承したサブクラスをボタンの数だけ
用意しなければならなくなる。

そうした無駄にクラスが増えてしまうことを回避するために「基本クラス」を使う。

この「基本クラス」を使うときに僕がハマってしまったのが、「基本クラス」は
そのままクラスを割り当てればいいのだけれど、「クラス」の方はデフォルトでは
シンボル名が入るようになっている。

親切なことに、Flashはパブリッシュ時に、存在しないクラスを勝手に生成してくれるから
そのまま気にせず書き出しても普通は問題ない。
このクラスの定義がクラスパス内に見つからなかったため、
定義は書き出し時に SWF ファイル内に自動生成されます。
って警告されるやつ。

で、これをステージ上に配置して、インスタンス名をシンボル名と同じ名前に設定すると
たちまちコンパイルエラーが出てしまう。

しかも、このコンパイルエラーが曲者で、
1046: 型が見つからないか、コンパイル時定数ではありません。
と出力されるが、はじめはこのエラーが何を指しているのかがメチャクチャ分かりにくい。

実際エラーを起こす原因は、クラス名と同じ名前のインスタンスがステージ上に存在するから。

例えば「startButton」というシンボルを作成して、そこに
クラス : startButton
基本クラス : CustomButton
と設定した場合。(「クラス」にはデフォルトで入力されているシンボル名のまま)

これをステージ上に配置して、当然のようにインスタンス名を「startButton」にする。

この状態で書き出すと上記のようなコンパイルエラーが発生する。

手っ取り早く回避するには「クラス」の定義名を「 シンボル名 + Class 」とかにすることかなあ。
[Strict モード] を選択すると、警告がエラーとして報告されます。これは、それらのエラーが存在する場合は、コンパイルに成功しないことを意味しています。

[Warnings モード] を選択すると、ActionScript 2.0 コードを ActionScript 3.0 に更新するときに非互換性を検出するのに役立つ、追加の警告が報告されます。
AS2の時と同様にオーサリングしてたら、プレビューしたときにコンパイルエラーで 怒られまくったのでメモ。

例えば box というシンボル(ムービークリップ)を作成して、
さらに、その内部にテキストフィールドを配置して、インスタンス名を tf とする。

box内のタイムラインに以下のスクリプトを記述。
tf.text = "TextField";
これで一度パブリッシュしてみると、うまく書き出される。

次にムービークリップ box のリンケージの設定を
クラス : BoxClass
基本クラス : flash.display.MovieClip
と設定する。

BoxClass の中身は以下の通り。
package
{
import flash.display.MovieClip;
dynamic public class BoxClass extends MovieClip
{
  public function BoxClass(){}
}
}
ちなみにパブリッシュ設定の ActionScript 3.0 「設定」 内の
ステージのインスタンスを自動宣言にはチェックを入れておく。

これで書き出すと以下のコンパイルエラーが出力される。
説明:1046: 型が見つからないか、コンパイル時定数ではありません。 : TextField。
タイムラインかクラスファイル内に
import flash.text.TextField;
が必要とのこと。

つづく…
import fl.controls.TextInput;
import flash.text.TextFormat;

var itext:TextInput = new TextInput();
this.addChild( itext );
var tf:TextFormat = new TextFormat();
tf.color = 0x666666;
tf.size = 14;
tf.font = "Verdana";
itext.setStyle("textFormat", tf);