Cocos2d-x:計算負荷を減らす

要約

・ルートの計算を避けてgetDistanceを使うのをやめる。
・座標系は回転させていないのでconvertToWorldSpaceを使わなくても何とかなる。
 
 

fpsの低下を検知して演出を変更する

今作成しているゲームは「弾幕の器」シリーズよりもたくさんの弾を表示します。そのため古い機種では60fpsを維持できなくなってきました。なのでfpsの低下が一定時間続くと「光の演出」をOFFにする処理を追加しました。fpsの測定はupdateの引数deltaで計算可能です。具体的には以下のようなコードを書きました。

--------------------------------------------------------------------
void GameScene::update(float delta){//----deltaには前回のコールからの差(秒)が渡される
 if (delta > (1.0/40)){//---fpsが40を下回った?
  fpsDelayCnt++;
  if (fpsDelayCnt >= 40){//----40fps以下の速度低下が約1秒継続した
   //---画質を落とす処理
   this->unscheduleUpdate();//---fpsのチェックはやめる
  }
 }else{
  fpsDelayCnt=0;
 }
}
--------------------------------------------------------------------

 

弾道の計算頻度

次は計算頻度の見直しです。これまでの弾の移動とあたり判定の処理は以下のように1秒間に100回の頻度で行っていました。60fpsだから移動頻度は1/60秒のハズなのですが「1/60だと微妙に速度が揺らぐ」感じがするのです。動きが各つくのではなく、sinカーブ的に速度が緩く揺らぐ気がするのです。

--------------------------------------------------------------------
this->schedule(schedule_selector(EnemyBullet::hitTest), 0.01);
--------------------------------------------------------------------

デザインにおける「モアレ」と似たような(周波数的な)現象なのかな?と思い、数値を微妙に変えていったのですが60fps界隈では違和感は消えませんでした。結局、違和感が気にならないレベルは以下のように0.012でした。少しの変更ですが%的には約16%(100fps→83.3fps)の負荷が減ります

--------------------------------------------------------------------
this->schedule(schedule_selector(EnemyBullet::hitTest), 0.012);
--------------------------------------------------------------------

 

あたり判定の再考

「弾幕の器」でのあたり判定は「丸弾は2点間の距離」と「矩形はベクトル的な処理」に分けていました。しかし今回の弾幕ゲームでは、すでにfpsを維持するのが難しいので「矩形はベクトル的な処理」は廃止します。つまり長方形の弾は出ません、十字型の弾が登場しますが、実は緑丸にしかあたり判定がありません!
d2
矩形のあたり判定については以下の記事を参考にしてください。重そうな処理でしょ?
→参考:弾幕ゲーム第2弾:矩形のあたり判定
→参考:cocos2d-x:当たり判定のすり抜け対応
 
 

getDistanceの利用をやめる

ということで、あたり判定の処理は「2点間の距離」のみになりました。Cocos2d-xでは2点間の距離を求めるメソッド「getDistance」があり、大まかには以下のようなコードになります。

--------------------------------------------------------------------
Point shipPos = spShip->getPosition();
float shipDist = shipPos.getDistance(this->getPosition());
if(shipDist < 10){//---弾と敵の距離が10より小さくなったら被弾
 //---被弾処理
}
--------------------------------------------------------------------

getDistanceは距離を求めるため「計算にはルートが含まれます」。しかし、あたり判定はルートを省略できるためgetDistanceを使うことを廃止し以下のように書き換えました。両辺を2乗した形です。

--------------------------------------------------------------------
sqrt(x^2+y^2) = distance;
 ↓
x^2+y^2 = distance*distance
--------------------------------------------------------------------

また、Y座標だけ先に計算して範囲外だったらX座標の計算を省略できるようにしました、以下のような感じです。

--------------------------------------------------------------------
//---まずは弾と敵のY座標の距離だけを算出
float ship_y = shipPos.y;float my_y = myPos.y;
float dist_y = ship_y - my_y;
float dist_y_abs = dist_y*dist_y;

if (dist_y_abs < 10*10){//----ルートするのではなく距離の方を2乗したほうが計算負荷は低い
 //----Y座標の距離が範囲内にある時だけX座標の計算をする
 float ship_x = shipPos.x;float my_x = myPos.x;
 float dist_x = ship_x - my_x;
 float dist_x_abs = dist_x*dist_x;
 if ((dist_y_abs+dist_x_abs)<(10*10)){//---ここでもルートではなく2乗
  //---被弾処理
 }
}
--------------------------------------------------------------------

 

convertToWorldSpaceを利用するのをやめた

砲塔は敵母艦内に配置されており自弾と座標系が異なるためconvertToWorldSpaceで座標を算出し直していました。convertToWorldSpaceの処理内容を確認すると「よく分からない3次のベクトル計算(座標系が回転していてもOKな感じの式)」があったので利用するのをやめました。今回は座標系は回転していないので加算のみで対応できるため自作した方が処理が軽くなります。大まかには以下のような変更です。

--------------------------------------------------------------------
Point fortLocalPos = spFort->getPosition();//---母艦内の砲塔の位置を取得
Point fortPos = this->convertToWorldSpace(fortLocalPos);//---グローバル座標に変換
--------------------------------------------------------------------



--------------------------------------------------------------------
Point fortLocalPos = spFort->getPosition();
Point fortPos = fortLocalPos + enemyShipPos - Point(center_x,center_y);
--------------------------------------------------------------------

enemyShipPosは母艦の座標(母艦はグローバル座標に配置されている)。Cocos2d-xでは画像の中心が原点なので、最後の項のように中点座標を引く必要があります。
 
 

古い機種でも遊べるようになったと思う

上記の配慮をしなかった時と比べると、体感できるほど処理が軽くなったよ。
 
 
 

メモ

いつの日かUnity

今ゲーム制作で利用しているCocos2d-x(C++)は弾幕ゲームのようにたくさんのスプライトを動かすのに適している(動作負荷が軽い)。今後制作するカジュアル系のゲームも微妙に弾幕要素が混ざるので今後もCocos2d-xを使い続けるのだけれど、Unity向けのアイデアも色々浮かぶ。ボクセルのゲームは楽しそう。

Webデザイン

ゲーム制作の話ばかりですが、Webデザインも大切なお仕事。ということで気になった記事をメモ。ノンデザイナーズデザインブックのUI版的な記事です。
→参考:優れたUIを実現するために確認しておくべき51のチェックリスト
 

Github

Githubの説明をRPGで学ぶサイト。
→参考:ギットクエスト