はじめまして。今回のエンジニアブログを担当する大原です。
今回はこの業界にいたら、どこかで出会うエフェクト効果、
擬似ラスタスクロールの実現方法について、書きたいと思います。
■ラスタスクロールとは?
海の中にいるようなゆらぎや、2Dなのに奥行きがあるように表現するなど、
画像を走査線単位で加工する技術です。
はるか昔からある技術で、レースゲームで奥行きの表現や曲がっている道路の表現したり、
暗黒なトンネル、炎のゆらぎなど、多種多様な所で使われます。
■なぜ”擬似”ラスタスクロールなのか?
昔のテレビ画面では、画面に電子銃を当て、走査線上を順番に光が通ることで絵を写してました。
その原理を応用し、走査線毎に書き始めをずらしてあげる事で、波打った表現をしてたのが、本当のラスタスクロールなのです。
しかし、cocos2d-xでは、現在どの走査線を表示させているという情報を取ることができません。
むしろ今時のディスプレイは走査線単位で表示処理を行なっているのでしょうか・・・
そのため、同様の表現をするために擬似的に表現するしかないのです。
■cocos2d-xで擬似ラスタスクロールを実現してみよう
cocos2d-xのHelloWorldで使われている「HelloWorld.png」を横に
波打たせてみたいと思います。
以下が実装ソースになります。
bool HelloWorld::init() { if ( !CCLayer::init() ) { return false; } m_pai = 0; // ラスタスクロール対象テクスチャ m_pRasta = CCTextureCache::sharedTextureCache()->addImage("HelloWorld.png"); m_pRasta->retain(); // Lineを管理する配列クラス m_pTextureLines = CCArray::create(); m_pTextureLines->retain(); //<*POINT*>テクスチャを千切りにする for(int line = 0 ; line < m_pRasta->getPixelsHigh() ; line++) { //1ライン毎にテクスチャ分割する m_pTextureLines->addObject( CCSprite::createWithTexture( m_pRasta, CCRectMake(0, line , m_pRasta->getPixelsWide(),1 ) ) ); } //スプライトを親に追加する for(int i = 0 ; i < m_pTextureLines->count() ; i++) { this->addChild( static_cast<CCSprite*>(m_pTextureLines->objectAtIndex(i)) ); } //ラスタスクロール移動イベント this->schedule( schedule_selector(HelloWorld::gameLogic), 1.0 / 60.0 ); return true; }
<POINT>
「HelloWorld.png」を千切りのように、画像の横幅*縦1ピクセルの矩形をスプライトとしてたくさん保持します。
CCSprite::createWithTexture()でテクスチャ内でスプライトにしたい領域を指定することができます。
/* * ラスタスクロールイベント */ void HelloWorld::gameLogic() { //画面サイズの取得 CCSize size = CCDirector::sharedDirector()->getWinSize(); m_pai+=5; //角度加算 //角度を360位内に収める if(m_pai>360) { m_pai -= 360; } double position_x = size.width/2; double position_y = size.height/2 + 160; double wave_x = 15; //波の最大値 double rad; //ラジアン角を保持 double add_x; //算出される加算移動値 //<*POINT*>Line毎にX座標を設定する for(int y_index = 0 ;y_index < m_pTextureLines->count(); y_index++ ) { //1Line毎の角度 rad = (M_PI/180) * ( m_pai + y_index * 5 ); //1Line毎のX加算値 add_x = wave_x * cos(rad); //1Lineスプライト取り出し CCSprite *sprite = static_cast<CCSprite*>(m_pTextureLines->objectAtIndex(y_index)); //1Lineスプライトの配置決定 sprite->setPosition(ccp(add_x + position_x,position_y - y_index)); } }
<POINT>Line毎に角度を増やす事で、少しずつ座標がずれていく形になります。
なぜラジアン角でX座標の加算値を割り出しているかというと、なめらかな波曲線にするためです。単純に1Line毎に1ピクセルずつ加算するとノコギリのようなギザギザな波形になってしまい、見た目上あまりかっこ良くないからです。
擬似ラスタスクロールは、スプライトをたくさん使う事になってしまうため、機種によっては表現しきれないかもしれません。そのため、テクスチャを動的に変更できるのであれば、テクスチャを加工したほうが、よりよいでしょう。