先ほどのサンプルをベースに、簡単なゲームを作ってみます。
ソースはこちらで公開しています。
https://github.com/matsushima-terunao/android_ringmuns
apk はこちら。
https://github.com/matsushima-terunao/android_ringmuns/raw/master/Ringmuns/bin/Ringmuns.apk



操作方法

Start ボタンを押してゲームスタート
< > ボタン、左右のフリック、スワイプで地面を回転
v ボタン、下へのフリック、スワイプでピースを下へ移動
* ボタン、タップでピースを入れ替え
同じピースが縦横ななめ3つ並ぶと消えます。

MainActivity.java


画面をタッチしたときの処理 OnTouchEvent() が追加されています。
package com.example.ringmuns;

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;

/**
 * メインアクティビティー。
 * 
 * @author 2014/08 matsushima
 *
 */
public class MainActivity extends Activity {

	public static MainActivity activity;

	/** ビュー */
	private MyView view;

	private static final int FP = LinearLayout.LayoutParams.FILL_PARENT;
	//private static final int WC = LinearLayout.LayoutParams.WRAP_CONTENT;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main); // アクティビティーにビューを設定
		activity = this;
		// myView
		this.view = new MyView(this);
		((LinearLayout)findViewById(R.id.layout)).addView(this.view, new LinearLayout.LayoutParams(FP, FP));
		// buttonKey
		findViewById(R.id.buttonLeft).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				GameMain.keyLeft = true;
			}
		});
		findViewById(R.id.buttonRight).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				GameMain.keyRight = true;
			}
		});
		findViewById(R.id.buttonDown).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				GameMain.keyDown = true;
			}
		});
		findViewById(R.id.buttonFlip).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				GameMain.keyFlip = true;
			}
		});
		findViewById(R.id.buttonStart).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				GameMain.keyStart = true;
			}
		});
	}

	@Override
	protected void onResume() {
		super.onResume();
		view.onResume();
	}

	@Override
	protected void onPause() {
		super.onPause();
		view.onPause();
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		//System.out.println(event.toString() + "\r\n");
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_CANCEL:
			GameMain.mouseLeft = (MotionEvent.ACTION_DOWN == event.getAction());
		case MotionEvent.ACTION_MOVE:
			GameMain.mouseTime = event.getEventTime();
			GameMain.mouseX = (int)(event.getX() * 30 / view.getWidth());
			GameMain.mouseY = (int)(event.getY() * 30 / view.getWidth());
			break;
		}
		return true;
	}
}

MyView.java


今までと大きく変わりません。
package com.example.ringmuns;

import android.content.Context;
import android.opengl.GLSurfaceView;

/**
 * ビュー。
 * 
 * @author 2014/08 matsushima
 *
 */
public class MyView extends GLSurfaceView {

	public MyRenderer renderer;

	public MyView(Context context) {
		super(context);
		renderer = new MyRenderer();
		setRenderer(renderer); // レンダラーの設定
	}
}

MyRenderer.java


今までと大きく変わりません。
package com.example.ringmuns;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;

/**
 * レンダラー。
 * 
 * @author 2014/08 matsushima
 *
 */
public class MyRenderer implements Renderer {

	private GameMain controller = new GameMain();

	/** ビューポート */
	private int width, height;

	// option
	/** 視野 */
	public static float perspectiveFovy = 45, perspectiveNearZ = 1, perspectiveFarZ = 100;
	/** 視点 */
	public static float lookAtEyeX = 0, lookAtEyeY = 0, lookAtEyeZ = 0;
	/** 視点 */
	public static float lookAtCenterX = 0, lookAtCenterY = -0.35f, lookAtCenterZ = -1;
	/** 視点 */
	public static float lookAtUpperX = 0, lookAtUpperY = 1, lookAtUpperZ = 0;
	/** 移動 */
	public static float translateX = 0, translateY = 0, translateZ = -50;
	/** 回転 */
	public static float rotateX = 0, rotateY = 0, rotateZ = 0;
	/** 照明の位置 */
	public static boolean isLightPosition = true;
	/** 照明の位置 */
	public static float[] lightPosition = {-20.0f, 20.0f, 100.0f, 1.0f};
	/** 環境光 */
	public static boolean isLightAmbient = true;
	/** 環境光 */
	public static float[] lightAmbient = {0.5f, 0.5f, 0.5f, 1.0f};
	/** 拡散光 */
	public static boolean isLightDiffuse = true;
	/** 拡散光 */
	public static float[] lightDiffuse = {1.0f, 1.0f, 1.0f, 1.0f};
	/** 鏡面光 */
	public static boolean isLightSpecular = true;
	/** 鏡面光 */
	public static float[] lightSpecular = {1.0f, 1.0f, 1.0f, 1.0f};
	/** 光無効 */
	public static float[] lightZero = {0, 0, 0, 0};
	/** 面法線 */
	public static boolean planeNormal = false;
	/** 頂点法線 */
	public static boolean vertexNormal = true;
	/** option が変更された */
	public static volatile boolean optionChanged = false;

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		gl.glEnable(GL10.GL_DEPTH_TEST); // デプスバッファを有効
		gl.glDepthFunc(GL10.GL_LEQUAL); // デプスバッファ比較: 以下
		if (isLightPosition) {
			gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_POSITION, lightPosition, 0); // 照明の位置
			gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_AMBIENT, isLightAmbient ? lightAmbient : lightZero, 0); // 環境光
			gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_DIFFUSE, isLightDiffuse ? lightDiffuse : lightZero, 0); // 拡散光
			gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_SPECULAR, isLightSpecular ? lightSpecular : lightZero, 0); // 鏡面光
			gl.glEnable(GL10.GL_LIGHTING); // ライティング有効
			gl.glEnable(GL10.GL_LIGHT0); // ライティング0有効
		}
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		this.width = width;
		this.height = height;
		gl.glViewport(0, 0, width, height); // ビューポートの設定
		gl.glMatrixMode(GL10.GL_PROJECTION); // 行列の選択: 射影
		gl.glLoadIdentity(); // 単位行列に置き換え
		GLU.gluPerspective(gl, perspectiveFovy, (float)width / height, perspectiveNearZ, perspectiveFarZ); // 視野の設定
		gl.glMatrixMode(GL10.GL_MODELVIEW); // 行列の選択: モデルビュー
		gl.glLoadIdentity(); // 単位行列に置き換え
		GLU.gluLookAt(gl, lookAtEyeX, lookAtEyeY, lookAtEyeZ, lookAtCenterX, lookAtCenterY, lookAtCenterZ, lookAtUpperX, lookAtUpperY, lookAtUpperZ); // 視点の設定
	}

	@Override
	public void onDrawFrame(GL10 gl) {
		// メイン処理。
		controller.proc();
		// 描画
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // バッファクリア: カラーバッファ, デプスバッファ
		if (optionChanged) {
			optionChanged = false;
			gl.glMatrixMode(GL10.GL_PROJECTION); // 行列の選択: 射影
			gl.glLoadIdentity(); // 単位行列に置き換え
			GLU.gluPerspective(gl, perspectiveFovy, (float)width / height, perspectiveNearZ, perspectiveFarZ); // 視野の設定
			gl.glMatrixMode(GL10.GL_MODELVIEW); // 行列の選択: モデルビュー
			gl.glLoadIdentity(); // 単位行列に置き換え
			GLU.gluLookAt(gl, lookAtEyeX, lookAtEyeY, lookAtEyeZ, lookAtCenterX, lookAtCenterY, lookAtCenterZ, lookAtUpperX, lookAtUpperY, lookAtUpperZ); // 視点の設定
			if (isLightPosition) {
				gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_POSITION, lightPosition, 0); // 照明の位置
				gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_AMBIENT, isLightAmbient ? lightAmbient : lightZero, 0); // 環境光
				gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_DIFFUSE, isLightDiffuse ? lightDiffuse : lightZero, 0); // 拡散光
				gl.glLightfv(GL10.GL_LIGHT0,  GL10.GL_SPECULAR, isLightSpecular ? lightSpecular : lightZero, 0); // 鏡面光
				gl.glEnable(GL10.GL_LIGHTING); // ライティング有効
				gl.glEnable(GL10.GL_LIGHT0); // ライティング0有効
			} else {
				gl.glDisable(GL10.GL_LIGHTING); // ライティング無効
				gl.glDisable(GL10.GL_LIGHT0); // ライティング0無効
			}
		}
		// 描画。
		controller.draw(gl);
	}
}

MyModel.java


プリミティブの頂点の持ち方を変え、色も持てるようにしました。
package com.example.ringmuns;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

/**
 * モデル。
 * 
 * @author 2014/08 matsushima
 *
 */
public class MyModel {

	/** 頂点座標 */
	private static final float[][] vertices = {
		{
			-0.8f,-0.8f, 0.8f,  0.8f,-0.8f, 0.8f, -0.8f,0.8f, 0.8f,  0.8f,0.8f, 0.8f,
			 0.8f,-0.8f,-0.8f, -0.8f,-0.8f,-0.8f,  0.8f,0.8f,-0.8f, -0.8f,0.8f,-0.8f,
		}, {
			0,1.2f,0, -1,0,1, 1,0,1, 1,0,-1, -1,0,-1, 0,-1.2f,0,
		}, {
			-1.0f,1.2f,0, -1.0f,-1.2f,0, 1.0f,-1.2f,0, 1.0f,1.2f,0,
			-0.6f,0.7f, 0.5f, -0.6f,-0.7f, 0.5f, 0.6f,-0.7f, 0.5f, 0.6f,0.7f, 0.5f,
			-0.6f,0.7f,-0.5f, -0.6f,-0.7f,-0.5f, 0.6f,-0.7f,-0.5f, 0.6f,0.7f,-0.5f,
		}, {
			-0.6f,1.0f,-0.6f, -0.6f,1.0f,0.6f, 0.6f,1.0f,0.6f, 0.6f,1.0f,-0.6f,
			-1.0f,0.5f,-1.0f, -1.0f,0.5f,1.0f, 1.0f,0.5f,1.0f, 1.0f,0.5f,-1.0f,
			0.0f,-1.2f,0.0f,
		}, {
			-0.6f, 1.0f,-0.6f, -0.6f, 1.0f,0.6f, 0.6f, 1.0f,0.6f, 0.6f, 1.0f,-0.6f,
			-1.0f, 0.0f,-1.0f, -1.0f, 0.0f,1.0f, 1.0f, 0.0f,1.0f, 1.0f, 0.0f,-1.0f,
			-0.6f,-1.0f,-0.6f, -0.6f,-1.0f,0.6f, 0.6f,-1.0f,0.6f, 0.6f,-1.0f,-0.6f,
		}, { // KIND_FLUSH
			0,0.6f,0, -0.5f,0,0.5f, 0.5f,0,0.5f, 0.5f,0,-0.5f, -0.5f,0,-0.5f, 0,-0.6f,0,
		}, { // KIND_FLOOR
			0,0,0,
			3 * GameMain.WIDTH * (float)Math.sin(2 * Math.PI * 0.5 / 7), 0, 3 * GameMain.WIDTH * (float)Math.cos(2 * Math.PI * 0.5 / 7),
			3 * GameMain.WIDTH * (float)Math.sin(2 * Math.PI * 1.5 / 7), 0, 3 * GameMain.WIDTH * (float)Math.cos(2 * Math.PI * 1.5 / 7),
			3 * GameMain.WIDTH * (float)Math.sin(2 * Math.PI * 2.5 / 7), 0, 3 * GameMain.WIDTH * (float)Math.cos(2 * Math.PI * 2.5 / 7),
			3 * GameMain.WIDTH * (float)Math.sin(2 * Math.PI * 3.5 / 7), 0, 3 * GameMain.WIDTH * (float)Math.cos(2 * Math.PI * 3.5 / 7),
			3 * GameMain.WIDTH * (float)Math.sin(2 * Math.PI * 4.5 / 7), 0, 3 * GameMain.WIDTH * (float)Math.cos(2 * Math.PI * 4.5 / 7),
			3 * GameMain.WIDTH * (float)Math.sin(2 * Math.PI * 5.5 / 7), 0, 3 * GameMain.WIDTH * (float)Math.cos(2 * Math.PI * 5.5 / 7),
			3 * GameMain.WIDTH * (float)Math.sin(2 * Math.PI * 6.5 / 7), 0, 3 * GameMain.WIDTH * (float)Math.cos(2 * Math.PI * 6.5 / 7),
		}
	};
	/** 頂点インデックス */
	private static final int[][][] points = {
		{{0,1,2,3}, {4,5,6,7}, {5,0,7,2}, {1,4,3,6}, {2,3,7,6}, {5,4,0,1}},
		{{0,1,2}, {0,2,3}, {0,3,4}, {0,4,1}, {1,5,2}, {2,5,3}, {3,5,4}, {4,5,1}},
		{{0,4,3,7}, {1,5,0,4}, {2,6,1,5}, {3,7,2,6}, {4,5,7,6},  {3,11,0,8}, {0,8,1,9}, {1,9,2,10}, {2,10,3,11}, {9,8,10,11}},
		{{0,1,3,2},  {0,4,1,5}, {1,5,2,6}, {2,6,3,7}, {3,7,0,4},  {4,8,5}, {5,8,6}, {6,8,7}, {7,8,4}},
		{{0,1,3,2},  {0,4,1,5}, {1,5,2,6}, {2,6,3,7}, {3,7,0,4},  {4,8,5,9}, {5,9,6,10}, {6,10,7,11}, {7,11,4,8}},
		{{0,1,2}, {0,2,3}, {0,3,4}, {0,4,1}, {1,5,2}, {2,5,3}, {3,5,4}, {4,5,1}}, // KIND_FLUSH
		{{0,1,2}, {0,2,3}, {0,3,4}, {0,4,5}, {0,5,6}, {0,6,7}, {0,7,1}}, // KIND_FLOOR
	};
	/** 面の色 */
	private static final float[][][] colors = {
		{{0.5f,0,0,1}},
		{{0,0.5f,0,1}},
		{{0,0,0.5f,1}},
		{{0.5f,0,0.5f,1}},
		{{0,0.5f,0.5f,1}},
		{{1,1,0,1}}, // KIND_FLUSH
		{{0.5f,0,0,1}, {0.5f,0.5f,0,1}, {0,0.5f,0,1}, {0,0.5f,0.5f,1}, {0,0,0.5f,1}, {0.5f,0,0.5f,1}, {0.5f,0.5f,0.5f,1}}, // KIND_FLOOR
	};
	/** 頂点バッファ */
	private static FloatBuffer[] vertexBuffer = new FloatBuffer[vertices.length];
	/** 面法線ベクトル */
	private static float[][] normalVectors = new float[vertices.length][];

	// 種別
	public static final int KIND_DROP_CNT = 5;
	public static final int KIND_FLUSH = 5;
	public static final int KIND_FLOOR = 6;

	/** 種別 */
	public int kind;
	/** 消去済み */
	public boolean deleted;
	/** 座標 */
	public float x, y, z;
	/** 角度 */
	public float b;

	/**
	 * モデルを構築。
	 */
	{
		for (int k = 0; k < vertices.length; ++ k) {
			// 頂点数
			int vert_cnt = 0;
			for (int p = 0; p < points[k].length; ++ p) {
				vert_cnt += points[k][p].length;
			}
			// 頂点バッファ
			ByteBuffer buf = ByteBuffer.allocateDirect(vert_cnt * 3 * 4);
			buf.order(ByteOrder.nativeOrder());
			vertexBuffer[k] = buf.asFloatBuffer();
			// 面法線ベクトル
			normalVectors[k] = new float[points[k].length * 3];
			for (int p = 0; p < points[k].length; ++ p) {
				// 頂点バッファ
				for (int v = 0; v < points[k][p].length; ++ v) {
					vertexBuffer[k].put(vertices[k][points[k][p][v] * 3 + 0]);
					vertexBuffer[k].put(vertices[k][points[k][p][v] * 3 + 1]);
					vertexBuffer[k].put(vertices[k][points[k][p][v] * 3 + 2]);
				}
				// 面法線ベクトル
				float vx1 = vertices[k][points[k][p][1] * 3 + 0] - vertices[k][points[k][p][0] * 3 + 0];
				float vx2 = vertices[k][points[k][p][2] * 3 + 0] - vertices[k][points[k][p][0] * 3 + 0];
				float vy1 = vertices[k][points[k][p][1] * 3 + 1] - vertices[k][points[k][p][0] * 3 + 1];
				float vy2 = vertices[k][points[k][p][2] * 3 + 1] - vertices[k][points[k][p][0] * 3 + 1];
				float vz1 = vertices[k][points[k][p][1] * 3 + 2] - vertices[k][points[k][p][0] * 3 + 2];
				float vz2 = vertices[k][points[k][p][2] * 3 + 2] - vertices[k][points[k][p][0] * 3 + 2];
				float nx = vy1 * vz2 - vy2 * vz1;
				float ny = vz1 * vx2 - vz2 * vx1;
				float nz = vx1 * vy2 - vx2 * vy1;
				float nr = (float)Math.sqrt(nx * nx + ny * ny + nz * nz);
				normalVectors[k][p * 3 + 0] = nx / nr;
				normalVectors[k][p * 3 + 1] = ny / nr;
				normalVectors[k][p * 3 + 2] = nz / nr;
			}
			vertexBuffer[k].position(0);
		}
	}

	/**
	 * モデルを描画。
	 * 
	 * @param gl
	 */
	public void draw(GL10 gl) {
		gl.glPushMatrix();
		gl.glTranslatef(x + MyRenderer.translateX, y + MyRenderer.translateY, z + MyRenderer.translateZ); // 移動
		gl.glRotatef(MyRenderer.rotateX, 1, 0, 0); // 回転: x軸
		gl.glRotatef(b + MyRenderer.rotateY, 0, 1, 0); // 回転: y軸
		gl.glRotatef(MyRenderer.rotateZ, 0, 0, 1); // 回転: z軸
		gl.glFrontFace(GL10.GL_CCW); // 全面: 反時計回り
		gl.glEnable(GL10.GL_CULL_FACE); // 片面を表示しない
		gl.glCullFace(GL10.GL_BACK); // 裏面を表示しない
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // 頂点配列を有効
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer[kind]); // xyz, float, padding なし, vertexBuffer
		if (MyRenderer.vertexNormal) {
			gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); // 法線配列を有効
			gl.glNormalPointer(GL10.GL_FLOAT, 0, vertexBuffer[kind]); // xyz, float, padding なし, vertexBuffer
		} else {
			gl.glDisableClientState(GL10.GL_NORMAL_ARRAY); // 法線配列を無効
		}
		int point = 0;
		for (int p = 0; p < points[kind].length; ++ p) {
			if (p < colors[kind].length) {
				gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT_AND_DIFFUSE, colors[kind][p], 0);
			}
			if (MyRenderer.planeNormal) {
				gl.glNormal3f(normalVectors[kind][p * 3 + 0], normalVectors[kind][p * 3 + 1], normalVectors[kind][p * 3 + 2]); // 面法線ベクトル
			}
			gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, point, points[kind][p].length); // 0120 1231 // プリミティブを描画
			point += points[kind][p].length;
		}
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // 頂点配列を無効
		gl.glDisable(GL10.GL_CULL_FACE); // 片面を表示しないを無効
		gl.glPopMatrix();
	}
}

GameMain.java


ゲーム本体の処理です。
package com.example.ringmuns;

import javax.microedition.khronos.opengles.GL10;

import android.os.Handler;
import android.widget.TextView;

/**
 * ゲームメイン。
 * 
 * @author 2014/08 matsushima
 *
 */
public class GameMain {

	/** タッチ時間のしきい値 */
	private static final long TOUCH_TIME = 300;
	/** タッチ移動量のしきい値 */
	private static final float TOUCH_DISTANCE = 1;
	/** models のカラム数 */
	public static final int COLS = 7;
	/** models の行数 */
	public static final int ROWS = 15;
	/** model の幅 */
	public static final float WIDTH = 2.5f;

	/** ゲーム状態 */
	enum State {
		/** game over */
		GAME_OVER,
		/** 落下中 */
		DROPPING,
		/** 着地後固定前 */
		DROPPED,
		/** 判定中 */
		JUDGING,
		/** 判定後 */
		JUDGED,
	}

	/** ゲーム状態 */
	private State state = State.GAME_OVER; // game over
	/** ゲーム状態基準時刻 */
	private long stateTime = 0;
	/** 判定回数 */
	private int judgeCount;
	/** 得点 */
	private int score;
	/** スピード */
	private int speed;

	/** キー */
	public static boolean keyLeft, keyRight, keyDown, keyFlip, keyStart;
	/** マウス */
	public static boolean mouseLeft, mouseLeftPrev;
	/** マウス */
	public static long mouseTime, mouseLeftDownTime;
	/** マウス */
	public static int mouseXLeftDown, mouseYLeftDown, mouseXPrev, mouseYPrev, mouseX, mouseY;

	/** 行列 */
	private MyModel[][] models = new MyModel[COLS][ROWS];
	/** ドロップ */
	private MyModel[] dropModels = new MyModel[3];
	/** 次のドロップ */
	private MyModel[] nextModels = new MyModel[3];
	/** 床 */
	private MyModel floor;
	/** ドロップカウント */
	private int dropCount;
	/** ドロップ座標 */
	private int dropX;
	/** ドロップ座標 */
	private float dropY;
	Handler handler = new Handler();

	public GameMain() {
		floor = new MyModel();
		floor.kind = MyModel.KIND_FLOOR;
		floor.y = -ROWS * WIDTH + WIDTH / 4;
	}

	/**
	 * メイン処理。
	 */
	public void proc() {
		try {
			long curTime = System.currentTimeMillis();
			// 移動処理
			int dx = 0, dy = 0;
			boolean flip = false;
			// key
			if (keyLeft) {
				keyLeft = false;
				dx = -1;
			}
			if (keyRight) {
				keyRight = false;
				dx = 1;
			}
			if (keyDown) {
				keyDown = false;
				dy = 1;
			}
			if (keyFlip) {
				keyFlip = false;
				flip = true;
			}
			// mouse up down
			if (mouseLeft) {
				if (!mouseLeftPrev) {
					// ダウン
					mouseLeftDownTime = mouseTime;
					mouseXLeftDown = mouseXPrev = mouseX;
					mouseYLeftDown = mouseYPrev = mouseY;
				}
			} else {//if (!mouseLeft) {
				if (mouseLeftPrev) {
					// アップ
					if (mouseTime - mouseLeftDownTime < TOUCH_TIME
							&& Math.abs(mouseX - mouseXLeftDown) < TOUCH_DISTANCE
							&& Math.abs(mouseY - mouseYLeftDown) < TOUCH_DISTANCE) {
						// タッチ時間のしきい値未満 and 移動なし -> タップ
						flip = true;
					}
				}
			}
			// mouse move
			if ((mouseLeft && mouseLeftPrev) || (!mouseLeft && mouseLeftPrev)) {
				if (Math.abs(mouseX - mouseXLeftDown) >= Math.abs(mouseY - mouseYLeftDown)) {
					int x = (mouseX - mouseXLeftDown) / 3;
					// タッチ時間のしきい値未満 ? フリック : スワイプ
					if (mouseTime - mouseLeftDownTime < TOUCH_TIME) {
						x = (0 == x ? 0 : x > 0 ? 1 : -1);
					}
					dx = -(x - (mouseXPrev - mouseXLeftDown) / 3);
					mouseX = mouseXLeftDown + x * 3;
				} else {
					int y = mouseY - mouseYLeftDown;
					// タッチ時間のしきい値未満 ? フリック : スワイプ
					if (mouseTime - mouseLeftDownTime < TOUCH_TIME) {
						y = (0 == y ? 0 : y > 0 ? 1 : -1);
					}
					dy = y - (mouseYPrev - mouseYLeftDown);
					mouseY = mouseYLeftDown + y;
				}
			}
			mouseLeftPrev = mouseLeft;
			mouseXPrev = mouseX;
			mouseYPrev = mouseY;
			// 移動
			float dropYPrev = dropY;
			for (int i = 0; i < dy; ++ i) {
				if (State.DROPPING == state) { // 落下中
					dropYPrev = dropY;
					dropY = (curTime - stateTime) / speed;
					if (dropY > dropYPrev + 1) {
						dropY = dropYPrev + 1;
					}
					if ((dropY + 2 >= ROWS - 1) || (null != models[dropX][(int)dropY + 2 + 1])) {
						// 着地
						dropY = (float)(int)dropY;
						state = State.DROPPED; // 着地後固定前
						stateTime = curTime;
					} else {
						stateTime -= speed;
					}
				} else if (State.DROPPED == state) { // 着地後固定前
					// 着地後1秒経過
					stateTime = curTime - 1000;
					break;
				}
			}
			for (int i = 0; i < Math.abs(dx); ++ i) {
				if ((State.DROPPING == state) || (State.DROPPED == state)) { // 落下中 // 着地後固定前
					if (null != models[(dropX + COLS + (dx >= 0 ? 1 : -1)) % COLS][(int)dropY + 2]) {
						break;
					}
				}
				dropX = (dropX + COLS + (dx >= 0 ? 1 : -1)) % COLS;
			}
			if (flip) {
				MyModel model = dropModels[2];
				dropModels[2] = dropModels[1];
				dropModels[1] = dropModels[0];
				dropModels[0] = model;
			}

			// ゲーム状態別処理
			switch (state) {
			case GAME_OVER: // game over
				if (keyStart) {
					state = State.DROPPING; // 落下中
					stateTime = curTime;
					mouseLeft = mouseLeftPrev = false;
					score = 0;
					speed = 1000;
					dropCount = 1;
					dropX = 0;
					dropY = 0;
					models = new MyModel[COLS][ROWS];
					for (int i = 0; i < 3; ++ i) {
						dropModels[i] = new MyModel();
						dropModels[i].kind = (int)(Math.random() * MyModel.KIND_DROP_CNT);
						dropModels[i].b = i * 50;
						nextModels[i] = new MyModel();
						nextModels[i].kind = (int)(Math.random() * MyModel.KIND_DROP_CNT);
					}
				}
				break;
			case DROPPING: // 落下中
				// 着地判定
				dropY = (curTime - stateTime) / speed;
				if (dropY > dropYPrev + 1) {
					dropY = dropYPrev + 1;
				}
				if ((dropY + 2 >= ROWS - 1) || (null != models[dropX][(int)dropY + 2 + 1])) {
					// 着地
					dropY = (float)(int)dropY;
					state = State.DROPPED; // 着地後固定前
					stateTime = curTime;
				}
				break;
			case DROPPED: // 着地後固定前
				if (stateTime + 1000 > curTime) {
					if ((dropY + 2 >= ROWS - 1) || (null != models[dropX][(int)dropY + 2 + 1])) {
						// 着地後1秒未満
					} else {
						// 着地後再離陸
						state = State.DROPPING; // 落下中
						stateTime = curTime - (long)(dropY * speed);
					}
				} else {
					// 着地後1秒経過
					System.out.println("d4:" + dropY);
					for (int i = 0; i < 3; ++ i) {
						models[dropX][(int)dropY + i] = dropModels[i];
						dropModels[i] = null;
					}
					state = State.JUDGING; // 判定中
					stateTime = curTime - 500;
					judgeCount = 1;
				}
				break;
			case JUDGING: // 判定中
				if (stateTime + 500 > curTime) {
					break;
				}
				// 消去判定
				int deleteCnt = 0;
				if ((null != models[dropX][(int)dropY]) && (MyModel.KIND_FLUSH == models[dropX][(int)dropY].kind)) {
					// drop flush
					if (dropY + 2 + 1 >= ROWS) {
						// 地面
						deleteCnt = 100;
					} else {
						// 直下と同じ種類を消去
						int kind = models[dropX][(int)dropY + 2 + 1].kind;
						for (int x = 0; x < COLS; ++ x) {
							for (int y = 0; y < ROWS; ++ y) {
								if ((null != models[x][y]) && (kind == models[x][y].kind)) {
									models[x][y].deleted = true;
									++ deleteCnt;
								}
							}
						}
					}
				} else {
					final int[] dirs = {1,0, 0,1, 1,1, -1,1}; // 右, 下, 右下, 左下
					for (int d = 0; d < dirs.length; d += 2) {
						for (int x = 0; x < COLS; ++ x) {
							for (int y = 0; y < ROWS; ++ y) {
								int x1 = (x + COLS + dirs[d] * 1) % COLS;
								int x2 = (x + COLS + dirs[d] * 2) % COLS;
								int y1 = y + dirs[d + 1] * 1;
								int y2 = y + dirs[d + 1] * 2;
								if (y2 < ROWS
										&& null != models[x][y]
										&& null != models[x1][y1]
										&& null != models[x2][y2]
										&& models[x][y].kind == models[x1][y1].kind
										&& models[x][y].kind == models[x2][y2].kind) {
									deleteCnt += 3;
									models[x][y].deleted = true;
									models[x1][y1].deleted = true;
									models[x2][y2].deleted = true;
								}
							}
						}
					}
				}
				// 判定後消去あり ? flush : game over or new drop
				if (deleteCnt > 0) {
					// flush
					for (int x = 0; x < COLS; ++ x) {
						for (int y = 0; y < ROWS; ++ y) {
							if ((null != models[x][y]) && (models[x][y].deleted)) {
								models[x][y].kind = MyModel.KIND_FLUSH;
							}
						}
					}
					state = State.JUDGED; // 判定後
					stateTime = curTime;
				} else {
					// game over 判定
					for (int x = 0; x < COLS; ++ x) {
						if (null != models[x][2]) {
							state = State.GAME_OVER; // game over
							return;
						}
					}
					// new drop
					++ dropCount;
					boolean flush = (0 == dropCount % 100);
					for (int i = 0; i < 3; ++ i) {
						dropModels[i] = nextModels[i];
						dropModels[i].b = i * 50;
						nextModels[i] = new MyModel();
						nextModels[i].kind = (flush ? MyModel.KIND_FLUSH : (int)(Math.random() * MyModel.KIND_DROP_CNT));
					}
					state = State.DROPPING; // 落下中
					stateTime = curTime;
					mouseLeft = mouseLeftPrev = false;
					dropY = 0;
				}
				score += deleteCnt * 100 * judgeCount;
				speed = Math.max(100, 1000 - score / 100);
				final String textScore = "" + score;// + "," + speed;
				handler.post(new Runnable() {
					@Override
					public void run() {
						((TextView)MainActivity.activity.findViewById(R.id.textView1)).setText(textScore);
					}
				});
				break;
			case JUDGED: // 判定後
				if (stateTime + 500 > curTime) {
					break;
				}
				// 消されたものを詰める
				for (int x = 0; x < COLS; ++ x) {
					for (int y = ROWS - 1; y >= 0; ) {
						if (null == models[x][y]) {
							break;
						} else if (MyModel.KIND_FLUSH != models[x][y].kind) {
							-- y;
						} else {
							for (int i = y; i >= 1; -- i) {
								models[x][i] = models[x][i - 1];
							}
							models[x][0] = null;
						}
					}
				}
				state = State.JUDGING; // 判定中
				stateTime += 500;
				++ judgeCount;
				break;
			}
			keyLeft = keyRight = keyDown = keyFlip = keyStart = false;
		} catch (RuntimeException e) {
			System.out.println(e.toString());
			e.printStackTrace(System.out);
			throw e;
		}
	}

	private long drawTime = System.currentTimeMillis();

	/**
	 * 描画。
	 * 
	 * @param gl
	 */
	public void draw(GL10 gl) {
		floor.b = -360f * dropX / COLS;
		floor.draw(gl);
		for (int x = 0; x < COLS; ++ x) {
			float tx = (float)Math.sin(2 * Math.PI * (x - dropX) / COLS) * WIDTH * 2;
			float tz = (float)Math.cos(2 * Math.PI * (x - dropX) / COLS) * WIDTH * 2;
			for (int y = 0; y < ROWS; ++ y) {
				if (null != models[x][y]) {
					models[x][y].x = tx;
					models[x][y].y = -y * WIDTH;
					models[x][y].z = tz;
					models[x][y].b += floor.b;
					models[x][y].draw(gl);
					models[x][y].b -= floor.b;
				}
			}
		}
		long bTime = System.currentTimeMillis();
		float vb = (bTime - drawTime) * 360f / 2000f;
		drawTime = bTime;
		for (int i = 0; i < 3; ++ i) {
			if (null != dropModels[i]) {
				dropModels[i].x = 0;
				dropModels[i].y = -(dropY + i) * WIDTH;
				dropModels[i].z = WIDTH * 2;
				dropModels[i].b += vb;
				dropModels[i].b += floor.b;
				dropModels[i].draw(gl);
				dropModels[i].b -= floor.b;
			}
		}
		for (int i = 0; i < 3; ++ i) {
			if (null != nextModels[i]) {
				nextModels[i].x = WIDTH * 4;
				nextModels[i].y = -i * WIDTH;
				nextModels[i].z = 0;
				nextModels[i].b = 0;
				nextModels[i].draw(gl);
			}
		}
	}
}

activity_main.xml


特に大きく変わりません。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="0dp"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.ringmuns.MainActivity" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_margin="0dp"
        android:layout_marginLeft="34dp"
        android:layout_marginTop="21dp"
        android:orientation="vertical"
        android:padding="0dp" >

        <LinearLayout
            android:id="@+id/layout"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:orientation="vertical" >
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >

            <TextView
                android:id="@+id/textView1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1" />

            <TextView
                android:id="@+id/textView2"
                android:layout_width="30dp"
                android:layout_height="wrap_content"
                android:layout_weight="0" />

            <Button
                android:id="@+id/buttonStart"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:minHeight="48dp"
                android:text="start" />

            <TextView
                android:id="@+id/TextView01"
                android:layout_width="30dp"
                android:layout_height="wrap_content"
                android:layout_weight="0" />

            <Button
                android:id="@+id/buttonLeft"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="0"
                android:text="&lt;" />

            <Button
                android:id="@+id/buttonDown"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="0"
                android:text="v" />

            <Button
                android:id="@+id/buttonFlip"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="0"
                android:text="*" />

            <Button
                android:id="@+id/buttonRight"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="0"
                android:text=">" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/optionLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

        </LinearLayout>
    </LinearLayout>

</RelativeLayout>

← 1-4. Android で OpenGL その2
↑ 一覧