▼Androidメモ▼
フライトゲーム


OpenGL ES 1.0でフライトゲームを作成する。
HelloGL10_24.png

3Dモデルファイル
以下の7つのファイルをプロジェクトのassetsに配置。
ライブラリ
3Dモデルの読み込みで利用した独自ライブラリを追加。
ソースコード
GL10FlightGame.java
package net.npaka.gl10flightgame;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

//フライトゲーム
public class GL10FlightGame extends Activity implements Runnable {
private GLSurfaceView glView;
private GLRenderer renderer;
private Thread thread;

//アクティビティ生成時に呼ばれる
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
//フルスクリーンの設定
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);

//GLサーフェイスビューの生成
renderer=new GLRenderer(this);
glView=new GLSurfaceView(this);
glView.setRenderer(renderer);
glView.setOnTouchListener(renderer);
setContentView(glView);
}

//アクティビティレジューム時に呼ばれる
@Override
public void onResume() {
super.onResume();
glView.onResume();
thread=new Thread(this);
thread.start();
}

//アクティビティポーズ時に呼ばれる
@Override
public void onPause() {
super.onPause();
glView.onPause();
thread=null;
}

//スレッドの処理
public void run() {
while(thread!=null) {
//定期処理
renderer.onTick();
//スリープ
try {
Thread.sleep(50);
} catch (Exception e) {
}
}
}
}

GLRenderer.java
package net.npaka.gl10flightgame;
import java.util.Random;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import net.npaka.gles.GLES;
import net.npaka.gles.Graphics;
import net.npaka.gles.ObjLoader;
import net.npaka.gles.Object3D;
import net.npaka.gles.Texture;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.view.MotionEvent;
import android.view.View;

//レンダラー
public class GLRenderer implements
GLSurfaceView.Renderer,View.OnTouchListener {
//シーン定数
private final static int
S_TITLE =0,
S_PLAY =1,
S_GAMEOVER=2;
private final static int[] MSG_W={56,38,60,86,86};

//システム
private float aspect; //アスペクト比
private boolean touchDown;//タッチダウン
private float touchX; //タッチX座標
private Graphics g; //2D描画用グラフィックス

//シーン
private int scene=S_TITLE;//シーン
private int init =S_TITLE;//初期化
private int msg =-1; //メッセージ
private int score=0; //スコア
private int tick=0; //時間経過

//モデル
private Object3D jet=new Object3D(); //ジェット
private Object3D tree=new Object3D(); //ツリー
private Object3D floor=new Object3D();//床
private Texture texture; //2D描画用テクスチャ

//位置
private float jetPX; //ジェットの位置のX座標
private float jetRZ; //ジェットの回転のZ座標
private float[] treeX=new float[32];//ツリーのX座標
private float[] treeZ=new float[32];//ツリーのZ座標

//コンストラクタ
public GLRenderer(Context context) {
GLES.context=context;
}

//サーフェイス生成時に呼ばれる
@Override
public void onSurfaceCreated(GL10 gl10,EGLConfig eglConfig) {
GLES.gl=(GL11)gl10;

//光源の設定
makeLight(gl10);

try {
//モデルの読み込み
jet.figure=ObjLoader.load("jet.obj");
jet.rotate.set(0,180,0);
jet.position.set(0,0.5f,0);
tree.figure=ObjLoader.load("tree.obj");
tree.scale.set(3.0f,3.0f,3.0f);
floor.figure=ObjLoader.load("floor.obj");
floor.scale.set(2.0f,1.0f,2.0f);

//2D描画用テクスチャの読み込み
texture=Texture.createTextureFromAsset("sprite.png");
} catch (Exception e) {
android.util.Log.e("debug",e.toString());
for (StackTraceElement ste:e.getStackTrace()) {
android.util.Log.e("debug"," "+ste);
}
}
}

//画面サイズ変更時に呼ばれる
@Override
public void onSurfaceChanged(GL10 gl10,int w,int h) {
//ビューポートの指定
gl10.glViewport(0,0,w,h);
aspect=(float)w/(float)h;
g=new Graphics(w,h);
}

//毎フレーム描画時に呼ばれる
@Override
public void onDrawFrame(GL10 gl10) {
//画面のクリア
gl10.glClearColor(0.4f,0.8f,1.0f,1.0f);
gl10.glClear(GL10.GL_COLOR_BUFFER_BIT|
GL10.GL_DEPTH_BUFFER_BIT);

//デプステストと光源の有効化
gl10.glEnable(GL10.GL_DEPTH_TEST);
gl10.glEnable(GL10.GL_LIGHTING);

//射影変換
gl10.glMatrixMode(GL10.GL_PROJECTION);
gl10.glLoadIdentity();
GLU.gluPerspective(gl10,
40.0f, //Y方向の画角
aspect, //アスペクト比
0.01f, //ニアクリップ
100.0f);//ファークリップ

//ビュー変換
float angle=(float)((90+jetRZ)*Math.PI/180);
GLU.gluLookAt(gl10,
0.0f,4.0f,9.0f, //カメラの視点
0.0f,1.0f,0.0f, //カメラの焦点
(float)Math.cos(angle),(float)Math.sin(angle),0.0f);//カメラの上方向

//モデル変換
gl10.glMatrixMode(GL10.GL_MODELVIEW);

//モデルの描画
for (int i=0;i<32;i++) {
if (treeZ[i]!=-999) {
tree.position.set(treeX[i],0.0f,treeZ[i]);
tree.draw();
}
}
jet.draw();
gl10.glDisable(GL10.GL_LIGHTING);
gl10.glColor4f(0.3f,0.5f,0.0f,1.0f);
floor.draw();

//2D描画
g.loadIdentity();
drawNum(score,8,7,7);
drawMsg(msg);
}

//光源の設定
private void makeLight(GL10 gl10) {
gl10.glEnable(GL10.GL_LIGHT0);
gl10.glLightfv(GL10.GL_LIGHT0,GL10.GL_AMBIENT,new float[]{0.2f,0.2f,0.2f,1.0f},0);
gl10.glLightfv(GL10.GL_LIGHT0,GL10.GL_DIFFUSE,new float[]{0.7f,0.7f,0.7f,1.0f},0);
gl10.glLightfv(GL10.GL_LIGHT0,GL10.GL_SPECULAR,new float[]{0.9f,0.9f,0.9f,1.0f},0);
gl10.glLightfv(GL10.GL_LIGHT0,GL10.GL_POSITION,new float[]{5.0f,5.0f,5.0f,0.0f},0);
}

//定期処理
public void onTick() {
//初期化
if (init>=0) {
scene=init;
init=-1;
//タイトル
if (scene==S_TITLE) {
msg=0;
score=0;
jetPX=0;
jetRZ=0;
for (int i=0;i<32;i++) treeZ[i]=-999.0f;
}
//プレイ
if (scene==S_PLAY) {
msg=-1;
score=0;
}
//ゲームオーバー
else if (scene==S_GAMEOVER) {
msg=3;
tick=0;
}
}

//プレイ時の処理
if (scene==S_PLAY) {
//スコア加算
score++;

//ツリーの出現と移動
for (int i=0;i<32;i++) {
//木の移動
if (treeZ[i]!=-999) {
treeZ[i]+=0.5f;
if (treeZ[i]>3) treeZ[i]=-999.0f;
if (-1<=treeZ[i] && treeZ[i]<=1 &&
-2<=treeX[i] && treeX[i]<=2) {
init=S_GAMEOVER;
}
}
//木の出現
else if (rand(100)==0) {
treeX[i]=rand(20)-10;
treeZ[i]=-24.0f;
}
}

//ジェットの移動
if (touchDown) {
float dx=0.0f;
if (touchX<g.screenW/2) {
dx=0.2f;
if (jetRZ>=-45) jetRZ-=2;
} else {
dx=-0.2f;
if (jetRZ<=45) jetRZ+=2;
}
jetPX+=dx;
for (int i=0;i<32;i++) {
if (treeZ[i]!=999.0f) treeX[i]+=dx;
}
} else {
if (jetRZ<0) jetRZ+=2;
if (jetRZ>0) jetRZ-=2;
}
}
tick++;
}

//タッチイベントの処理
public boolean onTouch(View v,MotionEvent event) {
int action=event.getAction();
if (action==MotionEvent.ACTION_DOWN) {
if (scene==S_TITLE) {
init=S_PLAY;
} else if (scene==S_PLAY) {
touchDown=true;
touchX=event.getX();
} else {
if (tick>=20) init=S_TITLE;
}
} else if (action==MotionEvent.ACTION_MOVE) {
if (scene==S_PLAY) touchX=event.getX();
} else if (action==MotionEvent.ACTION_UP) {
if (scene==S_PLAY) touchDown=false;
}
return true;
}

//数字の描画
private void drawNum(int num,int len,int x,int y) {
int v=10;
for (int i=2;i<len;i++) v=v*10;
for (int i=0;i<len;i++) {
g.drawImage(texture,x+i*28,y,28,28, 7*(num/v),0,7,7);
num=num%v;
v/=10;
}
}

//メッセージの描画
private void drawMsg(int msg) {
if (msg<0) return;
g.drawImage(texture,(g.screenW-MSG_W[msg]*4)/2,120,
MSG_W[msg]*4,16*4,0,7+16*msg,MSG_W[msg],16);
}

//乱数の取得
private static Random rand=new Random();
private static int rand(int num) {
return (rand.nextInt()>>>1)%num;
}
}



−戻る−