package net.npaka.gl20actiongame; import java.util.Random; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; 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.GLES20; import android.opengl.GLSurfaceView; import android.opengl.Matrix; 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 float aspect; //アスペクト比 private boolean touchDown;//タッチダウン private Graphics g; //2D描画用グラフィックス //シーン private int scene=S_TITLE;//シーン private int init =S_TITLE;//初期化 private int msg =-1; //メッセージ private int score=0; //スコア //プレイヤー private float playerY; //Y座標 private int jumpPow; //ジャンプ力 private boolean jumpAble;//ジャンプ可
//地面 private int mapDX; //X相対位置 private int[] mapH=new int[16];//高さ //モデル private Droid droid=new Droid(); //ドロイド君 private int droidFrame; //ドロイド君のフレーム private Object3D block=new Object3D();//ブロック private Texture texture; //2D描画用テクスチャ //コンストラクタ public GLRenderer(Context context) { GLES.context=context; } //サーフェイス生成時に呼ばれる @Override public void onSurfaceCreated(GL10 gl10,EGLConfig eglConfig) { //プログラムの生成 GLES.makeProgram(); //光源色の指定 GLES20.glUniform4f(GLES.lightAmbientHandle,0.2f,0.2f,0.2f,1.0f); GLES20.glUniform4f(GLES.lightDiffuseHandle,0.7f,0.7f,0.7f,1.0f); GLES20.glUniform4f(GLES.lightSpecularHandle,0.9f,0.9f,0.9f,1.0f); //カリングの指定 GLES20.glEnable(GLES20.GL_CULL_FACE); GLES20.glCullFace(GLES20.GL_BACK); //モデルとテクスチャの読み込み try { //ドロイド君の読み込み droid.load(); droid.position.set(3.5f,1.5f*2,0.0f); droid.rotate.y=90;
//ブロックの読み込み block.figure=ObjLoader.load("block.obj"); //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) { //画面の表示領域の指定 GLES20.glViewport(0,0,w,h); aspect=(float)w/(float)h; g=new Graphics(w,h); } //毎フレーム描画時に呼ばれる @Override public void onDrawFrame(GL10 gl10) { //画面のクリア GLES20.glClearColor(0.4f,0.8f,1.0f,1.0f); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT| GLES20.GL_DEPTH_BUFFER_BIT); //デプステストと光源の有効化 GLES20.glEnable(GLES20.GL_DEPTH_TEST); GLES20.glUniform1i(GLES.useLightHandle,1); //テクスチャ行列の指定 Matrix.setIdentityM(GLES.texMatrix,0); GLES20.glUniformMatrix4fv(GLES.texMatrixHandle, 1,false,GLES.texMatrix,0); //射影変換 Matrix.setIdentityM(GLES.pMatrix,0); GLES.gluPerspective(GLES.pMatrix, 45.0f, //Y方向の画角 aspect, //アスペクト比 0.01f, //ニアクリップ 100.0f);//ファークリップ //光源位置の指定 Matrix.setIdentityM(GLES.mMatrix,0); GLES20.glUniform4f(GLES.lightPosHandle,5.0f,5.0f,5.0f,1.0f); //ビュー変換 GLES.gluLookAt(GLES.mMatrix, 2.5f,5.0f,6.0f, //カメラの視点 6.5f,5.0f,0.0f, //カメラの焦点 0.0f,1.0f,0.0f);//カメラの上方向 //ドロイド君の描画 droid.setAnimFrame(droidFrame); droid.position.y=1.5f+playerY; droid.draw(); //ブロックの描画 for (int i=mapH.length-1;i>=0;i--) { if (mapH[i]==0) continue; block.draw(); block.position.x=(mapDX/100.0f+i)*1.5f; block.position.y=mapH[i]*1.5f; if (i%2==0) { block.scale.set(1.05f,1.05f,1.05f); } else { block.scale.set(1.06f,1.06f,1.06f); } } //2Dグラフィックスの描画 g.setup2D(); drawNum(score,8,8,8); drawMsg(msg); } //定期処理 public void onTick() { //初期化 if (init>=0) { scene=init; init=-1; //タイトル if (scene==S_TITLE) { msg =1; score =0; playerY =1.5f; jumpPow =0; jumpAble=true; mapDX =0; for (int i=0;i<16;i++) mapH[i]=1; } //プレイ else if (scene==S_PLAY) { msg=-1; touchDown=false; } //ゲームオーバー else if (scene==S_GAMEOVER) { msg=2; } } //プレイ時の処理 if (scene==S_PLAY) { //スコア加算 score++;
//衝突判定 if (playerY<mapH[3]*1.5f) { init=S_GAMEOVER; jumpAble=false; } //上移動 else if (jumpPow>=0) { playerY+=jumpPow*0.03f; jumpPow--; } //下移動 else { playerY-=0.2f; jumpAble=false; if (mapH[3]!=0 && playerY<mapH[3]*1.5f) { playerY=mapH[3]*1.5f; jumpAble=true; } } //スクロール処理 mapDX-=10; if (mapDX==-100) { mapDX=0; //地面の高さを左にシフト System.arraycopy(mapH,1,mapH,0,16-1);
//地面の高さを指定 int idx=rand(6); //[14]が穴の時は[13]と同じ高さ if (mapH[14]==0) { mapH[15]=mapH[13]; } //)1/6の確率で[15]を穴 else if (idx==0) { mapH[15]=0; } //1/6の確率で[15]を[14]の高さ+1 else if (idx==1) { mapH[15]=mapH[14]+1; if (mapH[15]>4) mapH[15]=4; } //1/6の確率で[15]を[14]の高さ-1 else if (idx==2) { mapH[15]=mapH[14]-1; if (mapH[15]<1) mapH[15]=1; } }
//ジャンプ処理 if (jumpAble) { if (touchDown) { jumpAble=false; jumpPow =14; } } else { if (!touchDown) { jumpPow=-10; } } } //ゲームオーバー時の処理 else if (scene==S_GAMEOVER) { if (playerY>=-2) playerY-=0.2f; } //ドロイド君のフレーム droidFrame=(jumpAble)?(score*5+45)%180:0; }
//タッチイベントの処理 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; } else { if (playerY<-2) init=S_TITLE; } } 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,40,(num/v)*28,0,28,40); num=num%v; v/=10; } } //メッセージの描画 private void drawMsg(int msg) { if (msg<0) return; g.drawImage(texture,(g.screenW-512)/2,120, 512,80,0,80*msg,512,80); } //乱数の取得 private static Random rand=new Random(); private static int rand(int num) { return (rand.nextInt()>>>1)%num; } }
|