アンドロイドプログラミングの館を参考にゲームを作っている者です。
開発に詰まってしまったので、質問させてください。
自動的に跳ねる自機を操って足場を踏みつつ上に進んでいく、いわゆる普通のジャンプゲームを作成しようとしているのですが、
跳ねて上に行くたびに動作が止まることが多くなってしまいました。
Logcatを見るに、GCが頻繁に行われているようでした。
アンドロイドプログラミングの館のイライラ棒を元にしたので、ランダム生成の足場をnew Barrcade()でプレイ中にたびたび作成、ArrayList<Barricade>に入れるという方法で作りました。
GC対策を調べてみたのですが、new などを使うとメモリが圧迫されるそうなので、おもにこれが原因という認識で大丈夫でしょうか?
あと、これの対策としてあらかじめ配列に決められた数のBarrcadeを作っておく(龍神録で見かけたようなC言語スタイル?)を試してみたのですが、ローディングの時点でTimeOutエラーかGCの大量発生が出てしまい、ゲームを開始することすらできませんでした。
OutOfMemoryErrorの表記がないところが若干引っかかっているのですが・・・
DDMSでメモリがどう割り当てられているかもチェックしてみたのですが、いまいち原因が分からずじまいで・・・
どなたか原因がわかる方いらっしゃいましたらご指摘お願いいたします。
ここを記述してもらわないと答えようがない、というのがありましたら教えていただけるとありがたいです。
ローディング関係のコードは整えしだい記述する予定です。
androidアプリで動作が重い
-
rei
Re: androidアプリで動作が重い
連投すいません。
結局最初に配列を用意し、メモリを確保する方法で多少GCを減らすことができました。
しかし、いまだにスクロール(=足場が生成されるタイミング)等でカクつきが起こることがあります。
・GCを減らすにはnewを使ったオブジェクト生成を減らす、といった対策であっているのかどうか
・アンドロイドのゲームアプリでのおすすめのfpsはどれくらいか(今のところ60で作っています)
の二点について知っている方がいましたら教えていただけるとありがたいです。
よろしくお願いいたします。
結局最初に配列を用意し、メモリを確保する方法で多少GCを減らすことができました。
しかし、いまだにスクロール(=足場が生成されるタイミング)等でカクつきが起こることがあります。
・GCを減らすにはnewを使ったオブジェクト生成を減らす、といった対策であっているのかどうか
・アンドロイドのゲームアプリでのおすすめのfpsはどれくらいか(今のところ60で作っています)
の二点について知っている方がいましたら教えていただけるとありがたいです。
よろしくお願いいたします。
- Dixq (管理人)
- 管理人
- 記事: 1662
- 登録日時: 15年前
- 住所: 北海道札幌市
- 連絡を取る:
Re: androidアプリで動作が重い
確かにGCを繰り返すとカクつきの原因になりますが、頻度によると思います。
今GCで何msかかったか表示されていませんか?もし60fpsで動作しているのなら16ms以内に終わっていればカクつきの原因にはならないでしょう。
足場を生成するときに何をしていますか?画像のロード等は行っていませんか?
どこにどれくらいの時間がかかっているか測定しないとボトルネックの抽出は難しいと思います。
また、PSPが30FPSですから30FPSで作っても問題ないと思いますが、60FPSの方がよりヌルヌル動くように見せることができるでしょうね。
今GCで何msかかったか表示されていませんか?もし60fpsで動作しているのなら16ms以内に終わっていればカクつきの原因にはならないでしょう。
足場を生成するときに何をしていますか?画像のロード等は行っていませんか?
どこにどれくらいの時間がかかっているか測定しないとボトルネックの抽出は難しいと思います。
また、PSPが30FPSですから30FPSで作っても問題ないと思いますが、60FPSの方がよりヌルヌル動くように見せることができるでしょうね。
-
rei
Re: androidアプリで動作が重い
ご回答ありがとうございます。
足場の生成は、
のみですので多分余計なことは行われていないと思うのですが・・・
試しに30FPSで動かしてみたところ、FPSがひどくても25あたりまでしか落ち込まないようでしたので、60FPSの時よりかはマシになりそうです。
どうしても改善しないようであれば、30FPSで作ってみようと思います。
もうひとつ質問なのですが、例えば当たり判定の矩形を返すメソッドを作ったとして、返す値を
return new Rect(...);
としていたのを、
return barrRect; (barrRectは足場の生成時に作っておき、ずっと保存しておく)
とするとGCは行われにくくなったりするのでしょうか?
一回のGCで72msほど止まっているようでした。今GCで何msかかったか表示されていませんか?もし60fpsで動作しているのなら16ms以内に終わっていればカクつきの原因にはならないでしょう。
画像とその読み込み動作はstaticにして、あらかじめGameMgrのコンストラクタ内で全て済ませてあります。足場を生成するときに何をしていますか?画像のロード等は行っていませんか?
足場の生成は、
//足場をセッティング
public void setVisible( float x, float y, float w, float h, int setkind ){
visible = 1;
_pt[0].x = x; _pt[0].y = y;
_pt[1].x = x+w; _pt[1].y = y;
_pt[2].x = x+w; _pt[2].y = y+h;
_pt[3].x = x; _pt[3].y = y+h;
kind = setkind;
}
のみですので多分余計なことは行われていないと思うのですが・・・
試しに30FPSで動かしてみたところ、FPSがひどくても25あたりまでしか落ち込まないようでしたので、60FPSの時よりかはマシになりそうです。
どうしても改善しないようであれば、30FPSで作ってみようと思います。
もうひとつ質問なのですが、例えば当たり判定の矩形を返すメソッドを作ったとして、返す値を
return new Rect(...);
としていたのを、
return barrRect; (barrRectは足場の生成時に作っておき、ずっと保存しておく)
とするとGCは行われにくくなったりするのでしょうか?
- Dixq (管理人)
- 管理人
- 記事: 1662
- 登録日時: 15年前
- 住所: 北海道札幌市
- 連絡を取る:
Re: androidアプリで動作が重い
たかが数える程度のインスタンスの生成・破棄で70msレベルのGCで困ることが生じるとは思えません。
オブジェクトが持つ変数も知れてる程度なんですよね?
ボトルネックがどこなのか、突き止める必要がありそうです。
どこか大きなリソースの解放・確保をしているところはありませんか?
オブジェクトが持つ変数も知れてる程度なんですよね?
ボトルネックがどこなのか、突き止める必要がありそうです。
どこか大きなリソースの解放・確保をしているところはありませんか?
-
rei
Re: androidアプリで動作が重い
返信が大幅に遅れてしまい申し訳ありません。
しばらくGCの原因を突き止めるべくいろいろと試行錯誤していたのですが、
どうやら原因が描画処理にあるらしいということがわかりました。
新たに簡易逃げゲー(避けゲー?)のような、おってくる敵からひたすら逃げるゲームを作ってみたのですが
敵が増えるたびに動作がカクカクするようになりました。
しかし、敵が増えても常にカクつくわけではなく、画面上に存在している(=描画を行っている)敵が複数いると動作が重くなるようでした。
当たり判定のチェックや動く向き等の更新は画面外にいる場合でも行っているため、描画処理が処理落ちの原因であることはほぼ間違いなさそうです。
以上が描画処理となりますが、Bitmapを多用すると処理が重くなるとの話を耳にしたことがあるのですが
上記のコードの中でBitmapのおかしな使い方の箇所等あったりしますでしょうか?
やはり一度の描画で二回Bitmapを用意するのがだめなのでしょうか・・・。
また、画像を使ったゲームを作ったことのある方がいましたら
どのように描画しているかお聞かせくださるとありがたいです。
ちなみに以前にも記述しましたが、
使う画像はあらかじめimgに読み込んであり、描画処理中に再読み込み等は行っておりません。
ご意見お願いいたします。
しばらくGCの原因を突き止めるべくいろいろと試行錯誤していたのですが、
どうやら原因が描画処理にあるらしいということがわかりました。
新たに簡易逃げゲー(避けゲー?)のような、おってくる敵からひたすら逃げるゲームを作ってみたのですが
敵が増えるたびに動作がカクカクするようになりました。
しかし、敵が増えても常にカクつくわけではなく、画面上に存在している(=描画を行っている)敵が複数いると動作が重くなるようでした。
当たり判定のチェックや動く向き等の更新は画面外にいる場合でも行っているため、描画処理が処理落ちの原因であることはほぼ間違いなさそうです。
public void onDraw( Canvas c ){
//画面上の相対座標を計算する
int cx = (int)(_cir._x - BackGround.getBg_X());
int cy = (int)(_cir._y - BackGround.getBg_Y());
if(cx<-SIZE) cx += Config.STAGESIZE;
if(cy<-SIZE) cy += Config.STAGESIZE;
//画面内に入っていたら
if(cx<480+SIZE && cy<800+SIZE) {
//c.drawCircle( cx, cy, _cir._r, _paint );
int h = 0;
if(movestyle==1) {
h = cnt/10%2;
}else if(movestyle==2) {
if(cnt%100 < 40) h = 1;
else h = 0;
}
Bitmap tex = Bitmap.createBitmap(img, //画像切り出し
imgWidth*(cnt/6%3), imgHeight*(h), imgWidth, imgHeight);
Matrix m = new Matrix(); //画像を回転させるマトリックスを作成
//回転の角度をセット
m.setRotate(angle, tex.getWidth()/2, tex.getHeight()/2);
Bitmap tmp = Bitmap.createBitmap //※1回転したビットマップを作成
(tex, 0, 0, imgWidth, imgWidth, m, true);
int s = (int)( SIZE* Math.cos((angle%90)/180*Config.PI) + SIZE* Math.sin((angle%90)/180*Config.PI) );
c.drawBitmap(tmp,
new Rect(0, 0, tmp.getWidth(), tmp.getHeight()),
new Rect(cx-s, cy-s, cx+s, cy+s),
null);
}
}
上記のコードの中でBitmapのおかしな使い方の箇所等あったりしますでしょうか?
やはり一度の描画で二回Bitmapを用意するのがだめなのでしょうか・・・。
また、画像を使ったゲームを作ったことのある方がいましたら
どのように描画しているかお聞かせくださるとありがたいです。
ちなみに以前にも記述しましたが、
使う画像はあらかじめimgに読み込んであり、描画処理中に再読み込み等は行っておりません。
ご意見お願いいたします。
Re: androidアプリで動作が重い
ビットマップ画像から一部を抜き出し回転させて描画するコードはこんな感じです。
// Rect rcSrc = new Rect();
// Rect rcDst = new Rect();
// Matrix mat = new Matrix();
int w = 100; // 描画する幅
int h = 100; // 描画する高さ
int sx = 0; // 画像内の左上座標X
int sy = 0; // 画像内の左上座標Y
int dx = 50; // 描画先の左上座標X
int dy = 50; // 描画先の左上座標Y
float angle = 45.0f; // 回転角度(度)
rcSrc.set(sx,sy,sx+w,sy+h);
rcDst.set(dx,dy,dx+w,dy+h);
mat.setRotate(angle, dx+w/2, dy+h/2);
canvas.save();
canvas.setMatrix(mat);
canvas.drawBitmap(bmp, rcSrc, rcDst, null);
canvas.restore();
-
rei
Re: androidアプリで動作が重い
また返信が大幅に遅れてしまい申し訳ありません・・・
ISLeさんの方法で画像の回転を試したところ、GCの回数が大幅に減り、動作も快適になりました。
効率の良い回転方法もわかったので、大変参考になりました。
ご回答いただき本当にありがとうございました!
ISLeさんの方法で画像の回転を試したところ、GCの回数が大幅に減り、動作も快適になりました。
効率の良い回転方法もわかったので、大変参考になりました。
ご回答いただき本当にありがとうございました!