サイトトップ

Director Flash 書籍 業務内容 プロフィール

ActionScript 3.0 for 3D

□05 配列に型指定を加えた厳格なクラス − Vectorクラス

Vectorクラスは、Arrayクラスつまり配列と同じく、複数の値を納めるオブジェクトです。Vectorインスタンスは、予め定めたひとつのデータ型の値をエレメント(要素)としてもつことができます。エレメントのデータ型が厳密に指定されることにより、その処理が最適化されたいわば厳格な配列と考えられます。

Maniac! 05-001■Vectorクラスという名前
Vectorというクラス名は、複数の値をひとつの組として扱う、数学の抽象的なベクトルの捉え方からつけられたものと想像されます。3次元空間の座標を扱うVector3Dクラスとは、直接関わりがありません。


05-01 Vectorクラスと配列(Arrayクラス)の比較
Vectorクラスを配列(Arrayクラス)と比べると、その役割や性質がわかりやすいでしょう(表05-001)。なお、本書ではArrayクラスの基本的な知識を前提としています。Arrayクラスのプロパティやメソッドについておわかりにならない点がある場合には、[ヘルプ]や参考書をお読みください。

表05-001■Vectorクラスを配列(Arrayクラス)と比べると
比較項目 内容
似ているところ ・複数のインデックス化したエレメントを扱える
・ほぼ同じプロパティやメソッドを備える
異なるところ ・すべてのエレメントにひとつのデータ型が指定される
・エレメントのインデックスは連番(密)でなければならない
優れたところ ・処理が最適化されている
・データ型を決めてエレメントが扱える

まず、Vectorクラスは、Arrayクラス(配列)ときわめて似た仕組みを保っています。第1に、Vectorクラスのインスタンスには、配列と同じく、複数の値に整数インデックスをつけてエレメントとして納められます。第2に、VectorクラスのプロパティやメソッドはArrayクラスとほとんどが同じで、lengthプロパティやpush()pop()slice()sort()といったメソッドを備えています。

つぎに、Vectorインスタンスはおもにふたつの点で、配列とは扱いが異なります。第1に、すべてのエレメントがひとつのデータ型で指定されます。したがって、他の型のデータをエレメントにすることはできません。第2に、エレメントのインデックスは連番、つまり密(dence)でなければなりません。Vector.lengthプロパティの値より大きいインデックスには、エレメントが加えられません。

そして、Vectorクラスにはエレメントにひとつのデータ型が指定され、エレメントが密であるということから、処理において大きくふたつ利点が生まれます。第1に、処理が最適化されています。Vectorインスタンスのエレメントへのアクセスは、配列よりもずっと高速です。第2は、データ型が厳格に扱われます。[Strictモード]では、データ型が合うかどうかをコンパイラが調べます。Vectorエレメントにデータ型の合わない値を設定したり、取出したエレメントを異なる型のデータとして扱うことが避けられます。

Tips 05-001■[ActionScript 3.0の詳細設定]の[Strictモード]
[Strictモード]は、コンパイラ警告を示すデフォルトの設定です。[ファイル]メニューの[パブリッシュ設定]で[Flash]タブからActionScript 3.0の[設定]ボタンをクリックし、[ActionScript 3.0の詳細設定]ダイアログボックスで選択できます(図001)。

図05-001■[ActionScript 3.0の詳細設定]ダイアログボックスで[Strictモード]を設定

[ファイル]メニューの[パブリッシュ設定]で[Flash]タブからActionScript 3.0の[設定]ボタンをクリックし、[ActionScript 3.0の詳細設定]ダイアログボックスで選択。

[イラスト] Vectorクラスのよいところは、速くて厳格。

05-02 Vectorインスタンスの生成とデータ型指定
Vectorクラスのインスタンスは、ActionScript 3.0の原則どおり、コンストラクタメソッドを呼出して生成します(シンタックス05-001)。ただし、エレメントのデータ型を指定するために、少し変わった記述になります。

シンタックス05-001■Vectorクラスのコンストラクタメソッド
Vector()コンストラクタ
文法 Vector(length:uint = 0, fixed:Boolean = false)
概要

指定したベース型のエレメントが納められるVectorインスタンスを生成する。コンストラクタおよびVectorデータ型の指定には、エレメントのデータ型となるベース型をドット(.)に続く山括弧<>内に記述する。

var 変数:Vector.<ベース型> = new Vector.<ベース型>()
引数

length:uint ― Vectorインスタンスの長さ(エレメント数)を示す0以上の整数。0より大きい数値が指定されると、その数だけベース型のデフォルト値(Tips 05-002「データ型とデフォルト値」)でエレメントが加えられる。この引数のデフォルト値は0。

fixed:Boolean ― Vectorインスタンスの長さが固定されるかどうかを示すブール(論理)値。trueが指定されると、初期値の長さを変えることはできない。デフォルト値はfalse


Tips 05-002■データ型とデフォルト値
ActionScript 3.0で使われるデータ型と、そのデータ型を指定した場合のデフォルト値および取りうる値は、次表05-002のとおりです([ヘルプ]の[ActionScript 3.0のプログラミング] > [ActionScript言語とシンタックス] > [データ型] > [データ型の記述]参照)。

表05-002■データ型とデフォルト値
データ型 デフォルト値
Boolean false trueまたはfalse
int 0 32ビット符号付き整数
Null 型指定に用いることはできない null
Number NaN 64ビット浮動小数点数
String null 16ビット文字列
uint 0 32ビット符号なし整数
void undefined undefined
クラス(リファレンス型データ) null クラスのインスタンス

[*筆者用参考]Tips 02-015「数値のデータ型

Vectorクラスのコンストラクタメソッドは、ドット(.)に続く山括弧<>内に「ベース型」と呼ばれるエレメントのデータ型を指定します。なお、山括弧<>でベース型を指定する記述は、「型パラメータシンタックス」といいます。コンストラクタの呼出しには、必ずベース型を記述しなければなりません。ベース型を指定しないと、ランタイムエラーが生じます。ベース型には、変数宣言や関数定義のデータ型と同じく、どのようなクラスでも指定することができます。

変数の宣言や関数の定義でデータ型としてVectorクラスを指定するときも、型パラメータシンタックスでベース型を指定する必要があります。たとえば、エレメントが整数(int型)のVectorインスタンス(長さ0)を生成して、変数myVectorに代入するステートメントはつぎのようになります。

var myVector:Vector.<int> = new Vector.<int>();

Vector型データの代入式の両辺は、ベース型まで厳密に一致しなければなりません。つまり、ベース型が整数(int型)のVectorインスタンスは、数値(Number型)のVectorの変数には代入できません。また、ベース型をSpriteで指定したVectorインスタンスは、スーパークラスであってもDisplayObjectをベース型とするVectorの変数に設定することもできません。したがって、つぎのふたつのステートメントは、いずれもランタイムエラーになります(図05-002)。

var myVector:Vector.<Number> = new Vector.<int>();
var myObjects:Vector.<DisplayObject> = new Vector.<Sprite>();
図05-002■ベース型の異なるVectorデータ型の変数には代入できない
ベース型の異なるVectorデータ型の変数に代入しようとすれば、ランタイムエラーになる。

Vectorインスタンスのベース型に、Vectorデータ型を指定することもできます。その場合、ベース型として記述したVectorにも、さらにベース型の指定が入れ子で必要になります。たとえば、ベース型が整数(int)のVectorデータをエレメントとするVectorインスタンスは、つぎのように生成して、変数myVectorに代入できます。

var myVector:Vector.<Vector.<int>> = new Vector.<Vector.<int>>();

05-03 Vectorエレメントの操作
Vectorエレメントの設定および取得は、配列と同じく配列アクセス演算子([])を使って行えます。インスタンスの長さは、Vector.lengthプロパティで扱います。また、Vectorクラスのメソッドにも、Arrayと同じようにエレメントの値を設定あるいは取得できるものがあります。基本的なメソッドとして、シンタックス05-002に4つを掲げました。ただし、コンストラクタの第2引数にtrueが指定された、長さの変えられないVectorインスタンスには、長さの変更をともなうこれらのメソッドは用いることができません。

シンタックス05-002■Vectorクラスの長さのプロパティとエレメントを設定または取得するメソッド
Vector.lengthプロパティ
文法 length:uint
プロパティ値 Vectorインスタンスの長さで、最後エレメントのインデックスに1を加えた整数。プロパティ値を減らすと、その値のインデックス以降のエレメントはインスタンスから削除される。プロパティ値を増やした場合には、ベース型のデフォルト値(前掲Tips 05-002「データ型とデフォルト値」)で新たなエレメントが加えられる。
Vector.push()メソッド
文法 push(... args):uint
概要 インスタンスに対して引数の値を最後のエレメントに加え、その新たな長さの整数を返す。
引数 ... args ― インスタンスに加えられる不定数のベース型の値。
戻り値 引数のエレメントが加えられた後のインスタンスの長さを表す0以上の整数。
Vector.pop()メソッド
文法 pop():T
概要 インスタンスの最後のエレメントを削除して、その値を返す。Vector.lengthプロパティの値は1差引かれる。
引数 なし。
戻り値 インスタンスの最後のエレメントの値。データ型は、ベース型の指定による。
Vector.unshift()メソッド
文法 unshift(... args):uint
概要 インスタンスに対して引数の値を最初のエレメントに加え、その新たな長さの整数を返す。すでにインスタンスに納められていたエレメントのインデックスは、加えた数だけ繰下がる。
引数 ... args ― インスタンスに加えられる不定数のベース型の値。
戻り値 引数のエレメントが加えられた後のインスタンスの長さを表す0以上の整数。
Vector.shift()メソッド
文法 pop():T
概要 インスタンスの最初のエレメントを削除して、その値を返す。Vector.lengthプロパティの値は1差引かれる。他のエレメントのインデックスは、1ずつ繰上がる。
引数 なし。
戻り値 インスタンスの最初のエレメントの値。データ型は、ベース型の指定による。

たとえば、Vector.push()メソッドや配列アクセス演算子[]を使って、Vectorインスタンスのエレメントをつぎのように設定したり、取得することができます。

var myVector:Vector.<int> = new Vector.<int>();
myVector.push(0);
myVector.push(2);
myVector[1] = 1;
trace(myVector.length);   // 出力: 2 ←インスタンスの長さ
// myVector[5] = 5;     // インデックスが長さを超えるためエラー
var n:int = myVector.pop();
trace(myVector.length);   // 出力: 1
// var my_str:String = myVector[0];   // データ型が一致しないためエラー

Vectorインスタンスのエレメントは密(連番)でなければなりません。したがって、インスタンスの長さつまりVector.lengthプロパティの値より大きなインデックスにはエレメントが加えられません(図05-003)。また、Vectorインスタンスから取出されたエレメントは、ベース型で指定したデータ型の値として扱われます。

図05-003■Vector.lengthプロパティの値を超えるインデックスにはエレメントが加えられない
Vector.lengthプロパティの値を超えるインデックスにエレメントを加えようとすれば、エラーになる。

Maniac! 05-002■配列も連番の方がアクセスは速い
配列エレメントも密つまり連番の方が、アクセスは速くなります。たとえば、つぎのようなArrayインスタンスを作成すると、インデックス0から2までは連番ですのでエレメントは密です。しかし、インデックス1000のエレメントは密ではありません。

var my_array:Array = new Array();
my_array.push(0);
my_array.push(1);
my_array.push(2);
my_array[1000] = 1000;

すると、インデックス0から2までのエレメントの方が、インデックス1000のエレメントより速くアクセスできます。

my_array[2]   // アクセスが速い
my_array[1000]   // アクセスは遅い

前掲シンタックス04-011「Matrix3Dクラスのその他のメソッド」でご紹介したMatrix3D.decompose()メソッドは、Matrix3Dインスタンスの平行移動と回転、および伸縮の3つの変換の情報を取出し、それらをVector3Dオブジェクトの3つのエレメントとして納めたVectorインスタンスで返しました。つぎのフレームアクションで定義した関数xTraceComposedInfo()は、メソッドから得たVectorインスタンスから3つのVector3Dオブジェクトを取出し、その情報をtrace()関数で[出力]します。なお、回転の値はラジアン角から度数に置換えました。

スクリプト05-001■Matrix3D.decompose()メソッドの戻り値の情報を[出力]する
    // フレームアクション
    // タイムラインにMovieClipインスタンスmy_mcを配置
  1. my_mc.z = 0;
  2. var myMatrix3D:Matrix3D = my_mc.transform.matrix3D;
  3. myMatrix3D.prependRotation(30, Vector3D.Y_AXIS);
  4. xTraceComposedInfo(myMatrix3D);
  5. function xTraceComposedInfo(targetMatrix3D:Matrix3D):void {
  6.   var composedVector:Vector.<Vector3D> = targetMatrix3D.decompose();
  7.   var translationVector3D:Vector3D = composedVector[0];
  8.   var rotationVector3D:Vector3D = composedVector[1];
  9.   var scaleVector3D:Vector3D = composedVector[2];
  10.   var radiansToDegrees:Number = 180 / Math.PI;
  11.   rotationVector3D.x *= radiansToDegrees;
  12.   rotationVector3D.y *= radiansToDegrees;
  13.   rotationVector3D.z *= radiansToDegrees;
  14.   trace("translation: " + translationVector3D.toString());
  15.   trace("rotation: " + rotationVector3D.toString());
  16.   trace("scale: " + scaleVector3D.toString());
  17. }

タイムラインにはMovieClipインスタンスmy_mcを配置してあります。また、インスタンスのDisplayObject.transformプロパティから取出したTransform.matrix3Dプロパティに対して、Matrix3D.prependRotation()メソッドによりy軸で30度の回転を加えています。関数xTraceComposedInfo()により[出力]される情報は、配置してあったMovieClipインスタンスの状態によって変わります(図05-004)。

図05-004■MovieClipインスタンスの平行移動・回転・伸縮の情報が[出力]される

[出力]パネルに平行移動と回転、および伸縮の情報が表示される。回転の値は、ラジアン角から度数に置換えられている。

Tips 05-003■Vector3Dインスタンスの座標値を実数倍する
Vector3DインスタンスのVector3D.xVector3D.y、およびVector3D.zの各プロパティに同じ数値を掛合わせるときには、Vector3D.scaleBy()メソッドにその掛合わせる数値を渡して呼出すことにより処理することもできます(後述Column 06シンタックス06-007)。すると、前掲スクリプト05-001の第11〜13行目は、つぎの1行のステートメントで置換えられます。

rotationVector3D.scaleBy(radiansToDegrees);

前述05-02「Vectorインスタンスの生成とデータ型指定」のとおり、Vector()コンストラクタには、インスタンスに納めるエレメントの値を引数として渡せません。したがって、Arrayクラスのようにコンストラクタメソッドから、エレメントをもったインスタンスはつくることができないのです。けれども、Vector.push()Vector.unshift()メソッドには、複数の値をエレメントに加えられますので、さほど困ることはないでしょう。

var myVector:Vector.<int> = new Vector.<int>();
myVector.push(0, 1, 2);   // 複数のエレメントを加える
trace(myVector);

Vector.push()Vector.unshift()メソッドによりVectorにエレメントを加えるとき、引数の値のデータ型はコンパイル時には確認されません。そして、ランタイム(実行時)に、引数値をVectorインスタンスのベース型に変換しようとします。その結果、成功すればその値をエレメントとして加えます。

たとえば、以下のフレームアクションは、DisplayObjectをベース型とするVectorインスタンスに、Vector.push()メソッドでSpriteとMovieClipインスタンスを加えます。そして、Vectorインスタンスをtrace()関数で[出力]します。すると、とくにエラーはなく、[出力]パネルにはつぎのようにインスタンスの情報が表示されます

[object Sprite],[object MovieClip]

var myVector:Vector.<DisplayObject> = new Vector.<DisplayObject>();
myVector.push(new Sprite(), new MovieClip());
trace(myVector);

引数値をVectorインスタンスのベース型に変換できなかったときには、「強制型変換に失敗」した旨のランタイムエラーを返します。たとえば、前述のDisplayObjectをベース型とするVectorインスタンスには、Objectインスタンスはエレメントとして加えられません(図05-005)。

図05-005■引数値をVectorインスタンスのベース型に変換できないとランタイムエラーになる
DisplayObjectをベース型とするVectorインスタンスには、Objectインスタンスはエレメントとして加えられない。

Tips 05-004■ベース型をプリミティブ型で指定した場合の強制型変換
Vectorインスタンスのベース型を数値や文字列などのプリミティブ型で指定した場合は、変換すべき適切な値がなければベース型データのデフォルト値にしてしまうようです。そのため、データ型の一致しない値をメソッドの引数に指定しても、ランタイムエラーは発生しません。

たとえば、ベース型として整数(int型)を指定したVectorインスタンスに、Vector.push()メソッドで引数に文字列の数字を渡せば数値に、オブジェクト(たとえばSpriteインスタンス)を渡すと整数のデフォルト値0がエレメントとして加えられます(図05-006)。

図05-006■ベース型が整数の場合文字列の数字は数値にオブジェクトは整数0に変換

ランタイムエラーは発生しない。

Flash Player 10からは、エレメントのデータ型がひとつで、連番のインデックスに値を納めるときには、ArrayよりVectorクラスのインスタンスを使う方がよいでしょう。前述05-01「Vectorクラスと配列(Arrayクラス)の比較」のとおり、Vectorクラスは処理が最適化され、データ型が厳格に扱えるからです。[ヘルプ]の[ActionScript 3.0言語およびコンポーネントリファレンス]で[Vector]の冒頭にも、つぎのように説明されています。

すべてのエレメントが同じデータ型を持つ配列を使用する場合は、Vector インスタンスが推奨されます。

また、ActionScript 3.0に新たに備わるメソッドは、引数や戻り値に複数の値があるときは、Vectorインスタンスで扱う場合が増えると思われます。すでにご紹介したMatrix3D.decompose()Matrix3D.recompose()メソッド(前掲シンタックス04-011)がその例ですし、後の07「三角形分割によるテクスチャマッピング − Graphics.drawTriangles()メソッド」で解説するGraphics.drawTriangles()メソッドも3つの引数すべてがVectorインスタンスで指定されます。エレメントのデータ型が指定できるので、値の扱いに確実さが増すからです。



Column 05 Vectorインスタンスの型変換
グローバル関数Vector()を使うと、Vectorエレメントのベース型を変えたり、配列をVectorインスタンスに変換できます(シンタックス05-003)。この関数により、Vectorクラスの制約をいくつか避けられることがあります。

シンタックス05-003■Vector()関数
Vector()関数
文法 Vector(sourceArray:Object):Vector.<T>
概要 ArrayまたはVectorインスタンスのエレメントを指定されたベース型に変換して、新たなVectorオブジェクトとして返す。エレメントのデータ型が指定のベース型に変換できないときはエラーになる。
引数 sourceArray:Object ― エレメントのベース型を変換して、新たなVectorオブジェクトにするArrayまたはVectorインスタンス。
戻り値 エレメントを指定のベース型に変換した新たなVectorオブジェクト。

まず、前述05-02「Vectorインスタンスの生成とデータ型指定」のとおり、Vector型の変数にVectorインスタンスを代入するとき、ベース型も厳密に一致させなければなりませんでした。けれども、Vectorインスタンスのエレメントが、変数に指定したVectorデータのベース型に変換できる場合には、Vector()関数を使って代入できます。

var mySprites:Vector.<Sprite> = new Vector.<Sprite>();
mySprites.push(new Sprite());
var myObject:Vector.<DisplayObject> = Vector.<DisplayObject>(mySprites);

つぎに、Vectorクラスのコンストラクタメソッドには、エレメントの値を引数に渡してインスタンスが生成できませませんでした。しかし、Vector()関数を使えば、リテラル記述の配列をVectorインスタンスに変換することができます。つまり、予めエレメントの備わったVectorインスタンスを、1行の記述で生成することが可能です。たとえば、つぎのステートメントにより、ベース型を整数とする3つのエレメントの納められたVectorインスタンスが生成できます(図05-007)。

var myVector:Vector.<int> = Vector.<int>([0, 1, 2]);
図05-007■整数の配列をベース型が整数のVectorインスタンスに変換
エレメントを指定のベース型に変換して、新たなVectorインスタンスとして返す。

Word 05-001■リテラル
リテラル」とは、プログラム(のソースコード)に直接記載される値を示します。変数から値を取出したり、関数(メソッド)の戻り値を受取るのではなく、文字列(String型)や数値(Number/int/uint型)を直接記述する場合がその典型です。たとえば、つぎの代入式の右辺値は、いずれもリテラルです。

var product_str:String = "Flash CS3 Professional";
var nPlayerVersion:int = 9;

値をリテラルで記述できるデータの例としては、このほか論理(ブーリアン)値(Boolean型)や配列(Array型)、XML(XML型)、Object(Object型)などが挙げられます(なお、ヘルプ[ActionScript 3.0のプログラミング] > [ActionScript言語とシンタックス] > [シンタックス]の「リテラル」の項参照)。

[Prev/Next]


作成者: 野中文雄
作成日: 2009年12月25日


Copyright © 2001-2009 Fumio Nonaka.  All rights reserved.