今回は[Androidの館]を参考に今作っているSurfaceViewを使った簡単なゲームで、ゲームクリアもしくはゲームオーバー時に別アクティビティ(今回具体的に言えばタイトルのアクティビティ)に
飛ばす処理を作ろうとしています。しかし、Intentを渡そうにもうまくいかず、下記サイトを参考に組んだところ、該当箇所を通った瞬間一瞬タイトル画面に戻りますがその後フリーズし、
『Android』その物が強制終了してシャットダウンすると言う悪夢のような物が出来上がりました。
https://groups.google.com/forum/#!topic ... Z19WJQbJ_0
そこでお伺いしたいのですが、ゲームクリア時にタイトルのアクティビティに飛ぶといったような処理を組み込もうと思うならどんな実装をすればいいでしょうか?
一部のだけですがソースコードをあげます。
また、OSが強制終了したコードは即刻消してしまったのでありません。
GameMgr.java
package jp.denpa.testaplcation;
import java.util.ArrayList;
import java.util.LinkedList;
import jp.denpa.testaplication.data.Enemy;
import jp.denpa.testaplication.data.Collision;
import jp.denpa.testaplication.data.Player;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
public class GameMgr {
//ゲームステータス
private enum GameStatus{
GAME_NORMAL, //継続中
GAME_CLEAR, //クリア
GAME_OVER, //ゲームオーバー
};
private LinkedList<Task> mTaskList = new LinkedList<Task>(); //タスクリスト(基本的に一つしか存在せず、タスクという機能が共通しているオブジェクトを突っ込む)
private ArrayList<Enemy> mEnemyList = new ArrayList<Enemy>(); //エネミーリスト(敵のオブジェクトを突っ込む)
private Player mPlayer; //当たり判定やパラメータ変更などでオブジェクトの情報がいるので変数名で指名できるようにする必要がある。
private GameStatus mStatus = GameStatus.GAME_NORMAL; //ゲームの状態
private Timer mTimer;
//コンストラクタ
GameMgr(){
mPlayer = new Player();
mTimer = new Timer(100, 30);
mEnemyList.add(new Enemy());
mEnemyList.add(new Enemy());
mEnemyList.add(new Enemy());
mEnemyList.add(new Enemy());
mEnemyList.add(new Enemy());
mEnemyList.add(new Enemy());
mTaskList.add(mPlayer);
mTaskList.add(new FpsController());
mTaskList.add(mTimer);
}
//コンストラクタを通さない初期化(リソースがらみなどでコンストラクタで処理できない初期化など)(onLoadと言うメソッド名の方がいいか?)
public boolean onInit(){
//プレイヤーの初期化
mPlayer.onInit();
//エネミーリストの初期化
for(int i = 0; i < mEnemyList.size(); i++){
if(mEnemyList.get(i).onInit() == false){
mEnemyList.remove(i); //初期化失敗したらそのオブジェクトを消す
}
mEnemyList.get(i).setPos((MainActivity.mDispSize.x / (mEnemyList.size() + 1)) * (i + 1), (MainActivity.mDispSize.y / 3));
}
return true;
}
public boolean onUpdate(){
//ゲーム継続中以外なら更新しない
if(mStatus != GameStatus.GAME_NORMAL){
return true;
}
//タスクリストの更新
for(int i = 0; i < mTaskList.size(); i++){
if(mTaskList.get(i).onUpdate() == false){ //更新失敗なら
mTaskList.remove(); //そのタスクを消す
i--;
}
}
//エネミーリストの更新
for(int i = 0; i < mEnemyList.size(); i++){
if(mEnemyList.get(i).onUpdate() == false){
mEnemyList.remove(i); //更新失敗したらそのオブジェクトを消す(不必要になったら更新でfalseを返すようにする)
}
}
//当たり判定
CollisionCheck();
return true;
}
public void onDraw(Canvas c){
c.drawColor(Color.WHITE); //背景を白で塗りつぶし
//タスクリスト描画
for(int i = 0; i < mTaskList.size(); i++){
mTaskList.get(i).onDraw(c); //描画する
}
//エネミーリスト描画
for(int i = 0; i < mEnemyList.size(); i++){
mEnemyList.get(i).onDraw(c); //敵の描画
}
}
//privateメソッド--------------------------------------------------------------------
//当たり判定処理
private void CollisionCheck(){
//プレイヤーが死んでたらゲームオーバーテロップ出して当たり判定しない。
if(mPlayer.getLife() <= 0){
//ゲームオーバーテロップを一度だけ生成(配置の関係上、一回しかここを通らない)
mTaskList.add(new Telop("GAME OVER", MainActivity.mDispSize.x / 2, MainActivity.mDispSize.y / 2, Color.RED, 50));
mStatus = GameStatus.GAME_OVER;
mTimer.onPause();
return;
}
//敵が全滅してたらゲームクリアテロップ出して当たり判定しない
if(mEnemyList.size() == 0){
mTaskList.add(new Telop("GAME CLEAR", MainActivity.mDispSize.x / 2, MainActivity.mDispSize.y / 2, Color.GREEN, 50));
mStatus = GameStatus.GAME_CLEAR;
mTimer.onPause();
return;
}
for(int i = 0; i < mEnemyList.size(); i++){
if(Collision.circleToCircle(mPlayer.getCircle(), mEnemyList.get(i).getCircle())){
mEnemyList.get(i).setColor(Color.RED);
mEnemyList.get(i).isHit(0, mPlayer.getMoveVec());
mPlayer.setColor(Color.YELLOW);
mPlayer.isHit(0, mEnemyList.get(i).getMoveVec());
}else{
mEnemyList.get(i).setColor(Color.BLACK);
mPlayer.setColor(Color.CYAN);
}
}
}
}
GameSurfaceView.java
//ゲームを作る最小限の構成をまとめたクラス
//参考元↓
//http://dixq.net/Android/s02_01.html
package jp.denpa.testaplcation;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable{
private GameMgr mGameMgr = new GameMgr(); //
private Thread mThread; //スレッド
//コンストラクタ
public GameSurfaceView(Context context) {
super(context);
getHolder().addCallback(this);
}
//メインループとかの処理を突っ込む場所
@Override
public void run() {
//Initを入れるとしたらここか・・・(コンストラクタはオブジェクトが生成される前に通る場所なのでリソース関連で問題を[十中八九]起こす)
//例:コンストラクタで画面サイズを取得して初期座標の決定=>無理
mGameMgr.onInit();
//ゲームのメインループ
while(mThread != null){
mGameMgr.onUpdate();
// if(mGameMgr.getGameStatus() != GameMgr.GameStatus.GAME_NORMAL){
// Intent intent = new Intent(getContext(), TitleActivity.class);
// getContext().startActivity(intent);
// }
onDraw(getHolder());
}
}
//ゲームの描画処理を書く
private void onDraw(SurfaceHolder holder){
//キャンバスクラスを使い描画する
Canvas c = holder.lockCanvas(); //キャンバスをロック
if(c == null){return;}
//ゲームの描画処理
mGameMgr.onDraw(c);
holder.unlockCanvasAndPost(c); //キャンバスのロックを外す
}
//解像度情報変更通知
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//別スレッドでメインループを作る
mThread = new Thread(this);
mThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//スレッドの破棄
mThread = null;
}
}
package jp.denpa.testaplcation;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;
public class MainActivity extends Activity {
public static Display mDisplay; //ディスプレイ情報
public static Point mDispSize; //ディスプレイサイズ(ステータスバーも含めた画面全体描画領域)
public static Point mViewSize; //ビューサイズ(実際にコンテンツが描画される領域)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// タイトルバーを隠す
requestWindowFeature(Window.FEATURE_NO_TITLE); //なお、このメソッドはSetContantViewを通る前に指定すること(しないとエラー)
// ステータスバーを隠す
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new GameSurfaceView(this));
mDispSize = new Point();
mViewSize = new Point();
//ディスプレイ情報の取得
mDisplay = getWindowManager().getDefaultDisplay();
mDisplay.getSize(mDispSize); //ディスプレイサイズの格納
//センサーの初期化
AcSensor.Inst().onCreate(this);
}
//xmlで指定した高さや幅はOnCreate時に取得すると0しか取得できない。
//しかしOnWindowFocusChangedメソッド内で取得するとアプリ起動時にViewSizeが取得できる
@Override
public void onWindowFocusChanged(boolean hasForcus){
super.onWindowFocusChanged(hasForcus);
//Viewサイズを取得する
//描画用[xml]の情報を取得
// RelativeLayout rl = (RelativeLayout) findViewById(R.id.relativeLayout1);
// mViewSize.x = rl.getWidth();
// mViewSize.y = rl.getHeight();
}
//アクティビティが動き始めるとき
@Override
protected void onResume(){
super.onResume();
//アクティビティが動くときセンサーを動かし始める
AcSensor.Inst().onResume();
}
//アクティビティが一時停止する時
@Override
protected void onPause(){
super.onPause();
//アクティビティ中断時センサーを停止
AcSensor.Inst().onPause();
}
}
Intentを作って該当のActivityへ飛ばすという処理をした部分でした(該当個所のソースコードは危険を感じたので消しました。)