技術評論社より発売された拙著
アニメーションの重さを測るふたつの物差し
アニメーションが重いとか軽いとかいわれるとき、
ベクターグラフィックスが軽いといわれるのは、
他方、
- ベクターグラフィックス
- 数学的なデータ→容量は小さい
- ビットマップに変換
(ラスタライズ) して描画→CPU負荷が高い
- ビットマップグラフィックス
- ピクセルごとのデータ→容量は大きい
- ピクセルをスクリーンに映す→CPU負荷が低い
![図1 ベクターグラフィックスとビットマップグラフィックス 図1 ベクターグラフィックスとビットマップグラフィックス](/assets/images/dev/serial/01/as3/0058/00101.png)
![図1 ベクターグラフィックスとビットマップグラフィックス 図1 ベクターグラフィックスとビットマップグラフィックス](/assets/images/dev/serial/01/as3/0058/00102.png)
とくにPCの環境では、
平行移動のアニメーションではDisplayObject.cacheAsBitmapプロパティをtrueにする
まずは、
![図2 [ライブラリ]のMovieClipシンボルに[クラス]を定める 図2 [ライブラリ]のMovieClipシンボルに[クラス]を定める](/assets/images/dev/serial/01/as3/0058/00201.gif)
![図2 [ライブラリ]のMovieClipシンボルに[クラス]を定める 図2 [ライブラリ]のMovieClipシンボルに[クラス]を定める](/assets/images/dev/serial/01/as3/0058/thumb/TH800_00202.gif)
メインタイムラインに書くフレームアクションは、
つぎに、
// フレームアクション: メインタイムライン
var nStageHeight:int = stage.stageHeight;
var nCount:uint = 500;
var instances:Vector.<MovieClip> = new Vector.<MovieClip>(nCount);
for (var j:uint = 0; j < nCount; j++) {
var _mc:MovieClip = new MyClass();
instances[j] = _mc;
addChild(_mc);
_mc.x = Math.random() * stage.stageWidth;
_mc.y = Math.random() * stage.stageHeight;
}
addEventListener(Event.ENTER_FRAME, xMove);
function xMove(eventObject:Event):void {
for (var i:uint = 0; i < nCount; i++) {
var instance:MovieClip = instances[i];
instance.y += 5;
if (instance.y > nStageHeight) {
instance.y -= nStageHeight;
}
}
}
アニメーションの速さを確かめるので、
![図3 フレームレートを120FPSに設定 図3 フレームレートを120FPSに設定](/assets/images/dev/serial/01/as3/0058/thumb/TH800_003.gif)
[ムービープレビュー]
![図4 数多くのインスタンスが下に向かってスクロールする 図4 数多くのインスタンスが下に向かってスクロールする](/assets/images/dev/serial/01/as3/0058/004.gif)
アニメーションするインスタンスは、
以下のスクリプト2では、
// フレームアクション: メインタイムライン
var nStageHeight:int = stage.stageHeight;
var nCount:uint = 500;
var instances:Vector.<MovieClip> = new Vector.<MovieClip>(nCount);
for (var j:uint = 0; j < nCount; j++) {
var _mc:MovieClip = new MyClass();
instances[j] = _mc;
addChild(_mc);
_mc.x = Math.random() * stage.stageWidth;
_mc.y = Math.random() * stage.stageHeight;
_mc.cacheAsBitmap = true;
}
addEventListener(Event.ENTER_FRAME, xMove);
function xMove(eventObject:Event):void {
for (var i:uint = 0; i < nCount; i++) {
var instance:MovieClip = instances[i];
instance.y += 5;
if (instance.y > nStageHeight) {
instance.y -= nStageHeight;
}
}
}
回転のアニメーションをビットマップでキャッシュする
気をつけてほしいのは、
function xMove(eventObject:Event):void {
for (var i:uint = 0; i < nCount; i++) {
var instance:MovieClip = instances[i];
instance.rotation += 5; // インスタンスの回転を追加
instance.y += 5;
if (instance.y > nStageHeight) {
instance.y -= nStageHeight;
}
}
}
[ムービープレビュー]
もっとも、
本稿ではもちろん、
BitmapDataオブジェクト.draw(描画もとオブジェクト, 変換Matrixオブジェクト)
ビットマップのイメージを描くBitmapDataインスタンスは、
new BitmapData(幅, 高さ, 透明設定, 背景色)
BitmapDataインスタンスの幅と高さは、
![図5 MovieClipインスタンスの寸法でもっとも大きいのは対角線 図5 MovieClipインスタンスの寸法でもっとも大きいのは対角線](/assets/images/dev/serial/01/as3/0058/005.gif)
BitmapData.
![図6 BitmapData.draw()メソッドのデフォルトは左上角を基準点にして描画する 図6 BitmapData.draw()メソッドのデフォルトは左上角を基準点にして描画する](/assets/images/dev/serial/01/as3/0058/006.gif)
MovieClipインスタンスを0度から1度刻みで359度まで回し、
var _mc:MovieClip = new MyClass();
var nWidth:Number = _mc.width;
var nHeight:Number = _mc.height;
var nDiagonal:Number = Math.sqrt(nWidth * nWidth + nHeight * nHeight);
var nMaxDegrees:uint = 360;
var nRotation:uint = 0;
var rotationData:Vector.<BitmapData> = new Vector.<BitmapData>(nMaxDegrees);
for (var i:uint = 0; i < nMaxDegrees; i++) {
var myBitmapData:BitmapData = new BitmapData(nDiagonal, nDiagonal, true, 0x0);
var myMatrix:Matrix = new Matrix();
myMatrix.rotate(i / 180 * Math.PI);
myMatrix.translate(nDiagonal / 2, nDiagonal / 2);
myBitmapData.draw(_mc, myMatrix);
rotationData[i] = myBitmapData;
}
MovieClipインスタンス
Matrixオブジェクトの扱いは前回の第57回
キャッシュしたBitmapDataオブジェクトを使った回転のアニメーション
前ページでVectorオブジェクトに納めたBitmapDataエレメントを用いて、
まず、
もっとも、
// フレームアクション: メインタイムライン
var _mc:MovieClip = new MyClass();
var nWidth:Number = _mc.width;
var nHeight:Number = _mc.height;
var nStageHeight:int = stage.stageHeight;
var nDiagonal:Number = Math.sqrt(nWidth * nWidth + nHeight * nHeight);
var nMaxDegrees:uint = 360;
var nRotation:uint = 0;
var nCount:uint = 500;
// var instances:Vector.<MovieClip> = new Vector.<MovieClip>(nCount);
var instances:Vector.<Bitmap> = new Vector.<Bitmap>(nCount);
var rotationData:Vector.<BitmapData> = new Vector.<BitmapData>(nMaxDegrees);
for (var i:uint = 0; i < nMaxDegrees; i++) {
var myBitmapData:BitmapData = new BitmapData(nDiagonal, nDiagonal, true, 0x0);
var myMatrix:Matrix = new Matrix();
myMatrix.rotate(i / 180 * Math.PI);
myMatrix.translate(nDiagonal / 2, nDiagonal / 2);
myBitmapData.draw(_mc, myMatrix);
rotationData[i] = myBitmapData;
}
for (var j:uint = 0; j < nCount; j++) {
// var _mc:MovieClip = new MyClass();
var myBitmap:Bitmap = new Bitmap(); // インスタンス名変更
myBitmap.bitmapData = rotationData[nRotation];
instances[j] = myBitmap;
addChild(myBitmap);
// _mc.x = Math.random() * stage.stageWidth;
myBitmap.x = Math.random() * stage.stageWidth - nDiagonal / 2;
// _mc.y = Math.random() * stage.stageHeight;
myBitmap.y = Math.random() * stage.stageHeight - nDiagonal / 2;
}
addEventListener(Event.ENTER_FRAME, xMove);
function xMove(eventObject:Event):void {
nRotation += 5;
nRotation %= nMaxDegrees;
for (var i:uint = 0; i < nCount; i++) {
// var instance:MovieClip = instances[i];
var instance:Bitmap = instances[i];
instance.bitmapData = rotationData[nRotation];
instance.y += 5;
if (instance.y > nStageHeight) {
instance.y -= nStageHeight;
}
}
}
Bitmapインスタンス共通の回転角は変数
ただ、
![図7 数多くのインスタンスが回りながら下にスクロールする 図7 数多くのインスタンスが回りながら下にスクロールする](/assets/images/dev/serial/01/as3/0058/007.gif)
オブジェクトを使い回す
ここまで、
for (var i:int = 0; i
このとき、
var myPoint:Point = new Point();
for (var i:int = 0; i
オブジェクトによっては、
for (var i:uint = 0; i < nMaxDegrees; i++) {
var myBitmapData:BitmapData = new BitmapData(nDiagonal, nDiagonal, true, 0x0);
var myMatrix:Matrix = new Matrix(); // オブジェクトの新規作成
myMatrix.rotate(i / 180 * Math.PI);
myMatrix.translate(nDiagonal / 2, nDiagonal / 2);
myBitmapData.draw(_mc, myMatrix);
rotationData[i] = myBitmapData;
}
最適化を目指すなら、
// フレームアクション: メインタイムライン
var _mc:MovieClip = new MyClass();
var nWidth:Number = _mc.width;
var nHeight:Number = _mc.height;
var nStageHeight:int = stage.stageHeight;
var nDiagonal:Number = Math.sqrt(nWidth * nWidth + nHeight * nHeight);
var nMaxDegrees:uint = 360;
var nRotation:uint = 0;
var nCount:uint = 500;
var instances:Vector.<Bitmap> = new Vector.<Bitmap>(nCount);
var rotationData:Vector.<BitmapData> = new Vector.<BitmapData>(nMaxDegrees);
var myMatrix:Matrix = new Matrix(); // ループ外に出す
for (var i:uint = 0; i < nMaxDegrees; i++) {
var myBitmapData:BitmapData = new BitmapData(nDiagonal, nDiagonal, true, 0x0);
// var myMatrix:Matrix = new Matrix();
myMatrix.identity(); // 初期化
myMatrix.rotate(i / 180 * Math.PI);
myMatrix.translate(nDiagonal / 2, nDiagonal / 2);
myBitmapData.draw(_mc, myMatrix);
rotationData[i] = myBitmapData;
}
for (var j:uint = 0; j < nCount; j++) {
var myBitmap:Bitmap = new Bitmap();
instances[j] = myBitmap;
addChild(myBitmap);
myBitmap.bitmapData = rotationData[nRotation];
myBitmap.x = Math.random() * stage.stageWidth - nDiagonal / 2;
myBitmap.y = Math.random() * stage.stageHeight - nDiagonal / 2;
}
addEventListener(Event.ENTER_FRAME, xMove);
function xMove(eventObject:Event):void {
nRotation += 5;
nRotation %= nMaxDegrees;
for (var i:uint = 0; i < nCount; i++) {
var instance:Bitmap = instances[i];
instance.bitmapData = rotationData[nRotation];
instance.y += 5;
if (instance.y > nStageHeight) {
instance.y -= nStageHeight;
}
}
}
特別編の前回第56回
my_array.length = 0; // エレメントがなくなる
初期化の仕方はオブジェクトによって異なる。使い回せそうだと思ったら、
この特別編の次回
今回解説した次のサンプルファイルがダウンロードできます。
- スクリプト2~4のサンプルファイル
(CS5形式/約33KB)