バスキュールサイトのツボの所
バスキュールサイトの最後のお尻の部分に、
つぼに全てが吸い込まれていくという演出があります。
仕組みとしては大したことをしてるわけではないですし
要はジニーエフェクトの亜種なんですが
今でもそれなりに反響をもらうので解説しておこうと思います。
大分前なので結構忘れちゃいましたが。

ちなみにあそこ、その場で演算して描画してるんです。
flvとか事前に作っておけば軽くていい気がするんですが。
最初はインタラクティブになにか反応させる予定だったような。
----
さて、自分の場合、大きい面積で派手に絵が動く演出を作る場合
スピードを稼ぐためにflash.filters.DisplacementMapFilterに
計算で作ったBitmapDataを食わせるということをするんですが、
(数式が苦手な人には辛いと思いますがかなりスピードが稼げます。
これはこれで面白いです。そのうち機会があればここに書きます。
まあas3なら1ピクセルづつ描画してもいけけそうですね。)
このツボ演出の場合は1ドットのスムーズさを出すために違う手段をとりました。
----
大まかに仕組みを説明すると
1.大きなキャプチャー用のムービークリップを用意
(バスキュールサイトの場合、すごく縦長です なんと10000ピクセル!)
2.必要な部分のみ、横に短冊状にスライスした状態で
個別のムービークリップにキャプチャーして画面に表示(LineBitmapsMaker.execute()部分)
3.横拡大率を線形に小さくしながら、スピードを適当に調整しつつ下に移動していく
同時に左右座標をsin波を用いてでぐちゃぐちゃ移動する(BasculeGenie._wave()部分)
となります。
1がおバカで普通やらない部分で、2がscript的に多少ややこしい部分で、3が感覚的な処理の部分です。
1,2はすぐにできたのですが、3の調整が最も時間がかかってます。
まとめ。
最近よく思うのですが、事、演出においては、
最終的にはプログラムの構成や正しさがどうのこうのはもはやどうでも良く、
それをどう使うか、どこまで愛を込められるか、が大事だと感じます。
この演出の場合は、とても重たくても思い切ってああいう風に
オチに使って、そこまでのお膳立てができているのが良かったように思います。
SEも秀逸でしたね。
--
ちなみに。
バスキュールサイトは派手なところが目立ちますが、
外部リンクを開くとpauseになるとか(最近そこらで増えてきました?)
html上に2つ縦に並んだswfを切れ目がないように演出をうまいこと繋ぐとか
他にも渋いテクニック満載なのですが、自分が作ったとこではないので
そうなんだよ、とだけ書いておきます。
あまりそういうところには触れない方がかっこいい気もしますね。
--
◆BasculeGenie.asソース一部改定
import flash.display.*;
import flash.filters.*;
import flash.geom.*;
/**
* バスキュールサイト用ジニーエフェクト
* @author harayoki
* @version 1.0
*/
class BasculeGenie{
private var _sourceMc:MovieClip;
private var _canvasMc:MovieClip;
private var _bm:LineBitmapsMaker;/*横にスライスした短冊状のビットマップを作るクラス*/
private var _theta:Number = 0;
private var _firstPos:Object = null;
private var _lastPos:Object = null;
private var _w:Number = 960;
private var _h:Number = 720;
private var _targetY:Number = 0;
private var _extendCaputureHeight:Number = 0;
private var _totalDy:Number = 0;
private var _lastDy:Number = 0;
public var yspeed:Number = 1;
public var maxyspeed:Number = 25;
public var yspeedInceaseRatio:Number = 1.05;//1.25;
public var ratio:Number = 0.03;
public var ratio2:Number = 0.01;
private var _callback:String = null;
private var _callbackRef = null;
/**
* @param キャプチャーするmovieclip
* @param 描画先movieclip
* @param キャプチャーする横幅
* @param キャプチャーする縦幅
*/
public function BasculeGenie(sourceMc:MovieClip,canvasMc:MovieClip,w:Number,h:Number){
_sourceMc = sourceMc;
_canvasMc = canvasMc;
_w = (isNaN(w)) ? _sourceMc._width : w;
_h = (isNaN(h)) ? _sourceMc._height : h;
_bm = new LineBitmapsMaker(_sourceMc,_canvasMc);
_firstPos = {};
_lastPos = {};
}
/**
* ジニー開始
* @param 吸い込まれる下へのドット数
* @param スクロールしつつキャプチャーする縦幅ドット数
* @param コールバック関数名
* @param コールバックオブジェクト
*/
public function run(targetY:Number,extendCaputureHeight:Number,cb:String,ref){
_targetY = targetY;
_extendCaputureHeight = extendCaputureHeight;
_callback = cb;
_callbackRef = ref;
var self = this;
var arr = _bm.execute(0,0,_w,_h,0,0);
_bm.setCenter(arr);
_canvasMc.onEnterFrame = function(){
self._wave();
}
_sourceMc._alpha = 50;
_sourceMc._visible = false;
_firstPos = {x:arr[0]._x,y:arr[0]._y};
}
private function _wave(){
_theta += 0.15;
ratio += 0.02;
if(ratio>2) ratio = 2;
ratio2 += 0.005;
if(ratio2>1) ratio2 = 1;
if(_theta>Math.PI*2) _theta -= Math.PI*2;
var tempSpeed = Math.floor(yspeed);
_totalDy += tempSpeed;
var dy:Number = _totalDy - _lastDy;
_lastDy = _totalDy;
if(_extendCaputureHeight>_totalDy){
var arr = _bm.execute(0,0-_totalDy,_w,0-_totalDy+dy,0,-dy);
_bm.setCenter(arr);
}
var arr:Array = _bm.getAll();
if(arr.length==0){
delete _canvasMc.onEnterFrame;
_callbackRef[_callback]();
return;
}
var maxY:Number = 0;
for(var i in arr){
var mc = arr[i];
mc._y+= tempSpeed;
mc._xscale = 100*(1 - Math.min(0.99,ratio)*mc._y/_targetY);
mc._x = mc._orgX + (Math.sin(_theta + mc._y*0.02)-0.5)*50*ratio2*(Math.sin(_theta)*0.5+2.0);
if(mc._y>_targetY){
_bm.removeOne(mc)
}else if(maxY0.2){
if(yspeed >= maxyspeed){
yspeed = maxyspeed
}else{
yspeed *= yspeedInceaseRatio;
}
}
_canvasMc._x = -(_lastPos.x-_firstPos.x);
//_canvasMc._x = lastX;
}
////////// 終了処理 //////////
public function destruct(){
}
}
◆LineBitmapsMaker.asソース 一部改定
import flash.display.*;
import flash.filters.*;
import flash.geom.*;
import com.harayoki.BitmapUtil;/*自作Bitmapユーティリティー*/
/**
* ムービークリップをキャプチャーして1行ずつ細切れのムービークリップに分解
* @author harayoki
* @version 1.0
*/
class LineBitmapsMaker{
//対象MovieClip
private var _canvas:MovieClip = null;
private var _source:MovieClip = null;
private var _mcList:Array = [];
/**
* @param キャプチャー元MoieClip
* @param 作成するムービークリップのコンテナ
*/
public function LineBitmapsMaker(sourceMc:MovieClip,canvasMc:MovieClip){
_source = sourceMc;
_canvas = canvasMc;
_mcList = [];
}
/**
* ラインごとのキャプチャーを実行
* @param コピー元座標の左上グローバルx座標
* @param コピー元座標の左上グローバルy座標
* @param コピー元座標の右下グローバルx座標
* @param コピー元座標の右下グローバルy座標
* @param コピー先座標の左上x座標(デフォルト値0)
* @param コピー先座標の左上y座標(デフォルト値0)
* @return キャプチャーして作られたMovieClipの参照を要素に持つ配列
*/
public function execute(x1:Number,y1:Number,x2:Number,y2:Number,x3:Number,y3:Number):Array{
var arr:Array = [];
//コピー元座標
var p1:Object = {x:x1,y:y1};
var p2:Object = {x:x2,y:y2};
_source.globalToLocal(p1);
_source.globalToLocal(p2);
//コピー先座標
x3 = (isNaN(x3)) ? 0 : x3;
y3 = (isNaN(y3)) ? 0 : y3;
var p3:Object = {x:x3,y:y3}
//_canvas.globalToLocal(p3);
//1ラインづつキャプチャー
for(var y=p1.y;y<p2.y;y++){
var mc:MovieClip = _getHolder();
mc._x = p3.x;
mc._y = p3.y + (y-p1.y);
var bmp:BitmapData = new BitmapData(p2.x-p1.x,1,true,0);
mc._bmp_ = bmp;
/*↓ムービークリップの一部分をキャプチャーしている*/
BitmapUtil.copyPixelFromMcArea(bmp,_source,p1.x,y,p2.x-x1,1);
mc.mc.attachBitmap(bmp,1);
arr.push(mc);
_mcList.push(mc);
mc._orgX = mc._x;
mc._orgY = mc._y;
}
return arr;
}
//アニメが楽になるように原点を真ん中にもって来る(temp)
public function setCenter(arr:Array){
for(var i in arr){
var mc:MovieClip = arr[i];
var dx:Number = mc.mc._width/2;
mc.mc._x -= dx;
mc._x = mc._orgX + dx;
mc._orgX = mc._x;
}
}
//新規のライン描画用MovieClipを得る
private function _getHolder():MovieClip{
var depth = _canvas.getNextHighestDepth();
var mc:MovieClip = _canvas.createEmptyMovieClip("mc"+depth,depth);
var mc2:MovieClip = mc.createEmptyMovieClip("mc",1);
return mc;
}
//ライン描画用MovieClipを削除する
public function removeOne(mc:MovieClip):Boolean{
var i = _mcList.length;
while(i--){
if(_mcList[i]==mc){
break;
}
}
//消す対象が見つからない
if(i==-1) return false;
var bmp:BitmapData = _mcList[i]._bmp_;
bmp.dispose();
_mcList[i].removeMovieClip();
_mcList.splice(i,1);
return true;
}
/**
* 全てのラインMovieClipの参照を得る
*/
public function getAll():Array{
return _mcList.slice();
}
/**
* 全てのラインMovieClipを消去する
*/
public function removeAll(){
var i = _mcList.length;
while(i--){
var mc = _mcList[i];
var bitmapData:BitmapData = mc._bmp_;
bitmapData.dispose();
mc.removeMovieClip();
}
_mcList = [];
}
////////// 終了処理 //////////
public function destruct(){
removeAll();
}
}