ラスターエフェクトのサンプル集(Flash 8 以降)
・ | ラスタースクロールについて |
・ | サインカーブで波打つビットマップ |
・ | サインカーブで伸縮するビットマップ |
・ | ドットを拡大してモザイクをかける |
・ | 前の画面を半透明にして重ねるブラー |
・ | 投影変換をかけたレースゲーム風の地面 |
ラスタースクロールについて
■ラスタースクロールとは?
テレビゲーム機内で、スプライトや背景を設定すると1フレームの映像が完成します。
この完成ビットマップ映像をラスターと呼ぶことにします。
このラスターをブラウン管モニタに出力すればユーザーに映像が届けられます。
ブラウン管モニタは、電子銃を走査する事で描画されます。
電子銃の移動の仕方ですが、まず最左上が開始位置となります。ここから右端まで走査して1行目を描画します。右端まで移動したら次の行の左端まで移動します。ここから右端まで走査して2行目を描画します。
これを下端まで繰り返して1画面が描画されます。最右下まで移動したら、最左上に戻ります。
電子銃の動き |
右端から次の行の左端まで移動する時間内を水平帰線区間(Hブランク)といいます。
この、ほんの僅かな時間内に、ラスター全体の座標を変更(スクロール)することができます。
ハードウェアによっては、移動だけでなく回転や拡大縮小もできます。
横1行描画するごとにラスターの姿勢を変更することができます。
このような方法を駆使して実現するエフェクトは、ラスタースクロールと呼ばれます。
なお、電子銃が右下から左上まで移動する時間内を垂直帰線区間(Vブランク)といいます。
Flash で、ビットマップの姿勢を変更しながら横1行ずつ描画すれば、テレビゲーム機のラスタースクロールを擬似的に再現することができそうです。
サインカーブで波打つビットマップ
サンプル表示(別窓) |
サンプルをダウンロード
考え方 |
サインカーブで伸縮するビットマップ
サンプル表示(別窓) |
サンプルをダウンロード
考え方 |
ドットを拡大してモザイクをかける
サンプル表示(別窓) |
サンプルをダウンロード
考え方 |
前の画面を半透明にして重ねるブラー
サンプル表示(別窓) |
サンプルをダウンロード
考え方 |
投影変換をかけたレースゲーム風の地面
サンプル表示(別窓) |
サンプルをダウンロード
■考え方
スーパーファミコン版のマリオカート風の地面を作ります。
透視投影変換式を使って、Flash のスクリーン座標の中央から下へかけて、1行ずつ奥行き z 座標を求めます。 z 値を参考にして 1 行ずつビットマップをスケーリングして描画していきます。
透視投影変換式を使って、Flash のスクリーン座標の中央から下へかけて、1行ずつ奥行き z 座標を求めます。 z 値を参考にして 1 行ずつビットマップをスケーリングして描画していきます。
■透視投影変換式
透視投影変換式
var angle = 1 ~ 180 くらいまでの好きな値; // 視野角
var fov = 1 / Math.tan( angle * 0.5 * Math.PI / 180); // 視点からの距離
var width = 解像度の幅か高さの大きい方の数値 * 0.5; //
var height = width * 1.0; // アスペクト比
スクリーン上のx座標 = 3次元のx座標 / 3次元のz座標 * fov * width;
スクリーン上のy座標 = 3次元のy座標 / 3次元のz座標 * fov * height;
例)ライブラリに登録した "source" に投影変換をかけて _root に描画
// 注.この講座にあるベクトルと行列の関数を使用しています。
#include "vec2d.as"
#include "mtx33.as"
var SOURCE_BITMAP = "source"; // ソースビットマップのリンケージ名
var RENDER_MOVIECLIP = _root; // 描画ターゲット
var CAMERA_HEIGHT = 10; // カメラの高さ
var SCREEN_WIDTH = 640; // 解像度(幅)
var SCREEN_HEIGHT = 480; // 解像度(高さ)
var CAMERA_ANGLE = 60; // 視野角
var SCREEN_SIZE = (SCREEN_WIDTH > SCREEN_HEIGHT) ? SCREEN_WIDTH : SCREEN_HEIGHT; // スクリーンの解像度の大きい方
var SCREEN_SIZE_HALF = Math.floor(SCREEN_SIZE * 0.5); // スクリーンの解像度の大きい方(半分)
var SCREEN_FOV = 1 / Math.tan(CAMERA_ANGLE * 0.5 * Math.PI / 180); // カメラから投影スクリーンまでの距離
var SCREEN_WIDTH_HALF = Math.floor(SCREEN_WIDTH / 2.0);
var SCREEN_HEIGHT_HALF = Math.floor(SCREEN_HEIGHT / 2.0);
// ビットマップデータ確保
var bmpData = flash.display.BitmapData.loadBitmap (SOURCE_BITMAP);
// 1行ごとの行列をあらかじめ作成
var mtxData = new Array();
for(var i=0;i < SCREEN_HEIGHT_HALF;i++){
// スクリーン系 y 座標に位置する 3次元座標系の奥行き z 座標
var z = CAMERA_HEIGHT * SCREEN_FOV * SCREEN_SIZE_HALF / (i + 1);
// 投影変換で施されるスケール値
var scale = 1.0 / z * SCREEN_FOV * SCREEN_SIZE_HALF;
mtxData[i] = Mtx33Translate(-SCREEN_WIDTH_HALF, i - z);
mtxData[i] = Mtx33ScalePost(-scale,1.0,mtxData[i]);
mtxData[i] = Mtx33TranslatePost(SCREEN_WIDTH_HALF,0,mtxData[i]);
}
// カメラ行列用パラメータ
CameraPos = Vec2dCreate(SCREEN_WIDTH_HALF,SCREEN_HEIGHT_HALF); // カメラの座標 (ビットマップの2D座標上と同じ)
CameraSpd = Vec2dCreate(0,0); // カメラの移動量(ビットマップの座標方向と同じ)
CameraRot = 0; // カメラの向き (ビットマップのx方向を 0 度として時計回りに 360 度回転で指定)
CameraMatrix = Mtx33Create(); // カメラ行列
onEnterFrame = function (){
var i
// カメラ操作 ---------------------------------------------------------
if(Key.isDown(Key.UP)){
// 前方向に移動量を加算
var spd = Vec2dTransformVector(1,0,Mtx33Rotate(CameraRot));
spd = Vec2dScale(spd,0.5);
CameraSpd = Vec2dAdd(CameraSpd,spd);
}
if(Key.isDown(Key.DOWN)){
// 後方向に移動量を加算
var spd = Vec2dTransformVector(-1,0,Mtx33Rotate(CameraRot));
spd = Vec2dScale(spd,0.5);
CameraSpd = Vec2dAdd(CameraSpd,spd);
}
if(Key.isDown(Key.LEFT)) CameraRot -= 2.0; // 左回転
if(Key.isDown(Key.RIGHT)) CameraRot += 2.0; // 右回転
CameraSpd = Vec2dScale(CameraSpd,0.90); // 摩擦
CameraPos = Vec2dAdd(CameraPos,CameraSpd); // 移動量を座標に加算
// カメラ行列 ---------------------------------------------------------
CameraMatrix = Mtx33Translate(-CameraPos.x,-CameraPos.y);
CameraMatrix = Mtx33RotatePost(-CameraRot + 90,CameraMatrix);
CameraMatrix = Mtx33TranslatePost(SCREEN_WIDTH_HALF,SCREEN_HEIGHT_HALF,CameraMatrix);
// クリーンアップ
RENDER_MOVIECLIP.clear();
// ビットマップデータから1行ずつカメラ変換をかけて描画 ---------------
for(i=0;i < SCREEN_HEIGHT_HALF;i++){
var d = (i) / SCREEN_HEIGHT_HALF * 255;
RENDER_MOVIECLIP.beginBitmapFill(bmpData, Mtx33Transform(CameraMatrix,mtxData[i]),false,true);
RENDER_MOVIECLIP.moveTo(0, SCREEN_HEIGHT_HALF + i);
RENDER_MOVIECLIP.lineTo(0, SCREEN_HEIGHT_HALF + i + 1);
RENDER_MOVIECLIP.lineTo(SCREEN_WIDTH, SCREEN_HEIGHT_HALF + i + 1);
RENDER_MOVIECLIP.lineTo(SCREEN_WIDTH, SCREEN_HEIGHT_HALF + i);
RENDER_MOVIECLIP.endFill();
}
};