« 3 次ベジェ曲線を curveTo() を使って描く | メイン | SceneObject のイベントフロー周りを少し細かく実装してみました »

2008年11月 6日

[as3] AS3 についていろいろメモ

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


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

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>

トラックバック(0)

このブログ記事を参照しているブログ一覧: AS3 についていろいろメモ

このブログ記事に対するトラックバックURL: http://system.seyself.com/mt-tb.cgi/519

コメントする


画像の中に見える文字を入力してください。

しばらく時間が経過すると、システム内部と表示されている文字内容に食い違いが発生するようなので、
投稿する前にページをリロードすることをお勧めします。
リロードしてもフォームの内容は維持されます。