このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。
package jp.ac.dendai.c.jtp.flightsample;
import android.app.Activity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
public class MainActivity extends Activity {
private MyGLView glView;
private ScoreView scoreView;
@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);
}
@Override
public void onStart() {
super.onStart();
scoreView = new ScoreView(this);
glView = new MyGLView(this, scoreView);
setContentView(glView);
addContentView(scoreView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
}
@Override
public void onResume() {
super.onResume();
glView.onResume();
glView.threadstart();
}
@Override
public void onPause() {
super.onPause();
glView.onPause();
glView.threadpause();
}
}
package jp.ac.dendai.c.jtp.flightsample;
public interface Constant {
float MaxV = 0.2f;
float EYEDIS = 2.0f;
float boxsize = 2.0f;
float[] red = {1.0f, 0.0f, 0.0f, 1.0f};
float[] blue = {0.0f, 0.0f, 1.0f, 1.0f};
float[] yellow = {1.0f, 1.0f, 0.0f, 1.0f};
float[] green = {0.0f, 0.8f, 0.0f, 1.0f};
float[] brown = {0.8f, 0.4f, 0.0f, 1.0f};
float[] lightpos = {10.0f, 10.0f, 10.0f, 0.0f};
float[][] colorList = {red, blue, yellow};
long tic = 10;
float acc = 0.0005f;
float bacc = 0.0005f;
float YukaSIZE = 100;
float YukaY = -5;
float YukaZERO = 0;
float AreaRatio = 0.9f;
int turnAngle = 2;
}
package jp.ac.dendai.c.jtp.flightsample;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
public class ScoreView extends View{
private final Context context;
private int score =0;
public ScoreView(Context context) {
super(context);
this.context=context;
}
@Override
protected void onDraw(Canvas canvas) {
Point p = new Point();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
display.getSize(p);
Paint paint = new Paint();
paint.setAntiAlias(true);
int fontsize = (p.x-200)/20+10;
paint.setTextSize(fontsize);
paint.setColor(Color.WHITE);
canvas.drawText("SCORE:" + Integer.toString(score), 10, fontsize, paint);
}
public void clear(){
score =0;
}
public void add(int point){
score += point;
}
public void update(){
invalidate();
}
}
package jp.ac.dendai.c.jtp.flightsample;
import android.content.Context;
import android.opengl.GLSurfaceView;
public class MyGLView extends GLSurfaceView implements Runnable {
private MyRenderer renderer;
private Thread thread;
private final Object lock;
public MyGLView(Context context, ScoreView scoreView) {
super(context);
lock = new Object();
this.renderer = new MyRenderer(lock,scoreView);
setRenderer(renderer);
setOnTouchListener(renderer.getOnTouchListener());
}
@Override
public void run() {
double previous = (double) System.currentTimeMillis();
double now;
while (thread != null) {
synchronized (lock) {
now = System.currentTimeMillis();
float tstep = (float) ((now - previous) / Constant.tic);
renderer.tick(tstep);
}
previous = now;
try {
Thread.sleep(Constant.tic);
} catch (Exception ignored) {
}
}
}
public void threadpause(){
thread = null;
}
public void threadstart(){
thread = new Thread(this);
thread.start();
}
}
package jp.ac.dendai.c.jtp.flightsample;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
import android.view.MotionEvent;
import android.view.View;
import java.util.Iterator;
public class MyRenderer implements Renderer {
private final Object lock;
private final ScoreView score;
private Angle screen;
private volatile Position touch;
private Scene scene = Scene.S_START;
private Anata anata;
private DrawList<Drawable> list;
public MyRenderer(Object lock, ScoreView scoreView){
this.lock = lock;
score = scoreView;
synchronized (lock) {
list = new DrawList<Drawable>();
list.add(new Yuka());
list.add(new Box(Constant.red, new Vect(1.0f, 1.0f, 1.0f), 2.0f));
list.add(new Box(Constant.blue, new Vect(4.0f, 1.0f, 4.0f), 2.0f));
list.add(new Box(Constant.yellow, new Vect(8.0f, 1.0f, 8.0f), 2.0f));
}
touch = new Position();
anata = new Anata();
}
@Override
public void onSurfaceCreated(GL10 gl10,EGLConfig eglConfig) {
//光源位置の指定
gl10.glLightfv(GL10.GL_LIGHT0,GL10.GL_POSITION, Constant.lightpos,0);
//デプステストと光源の有効化
gl10.glEnable(GL10.GL_DEPTH_TEST);
gl10.glEnable(GL10.GL_LIGHTING);
gl10.glEnable(GL10.GL_LIGHT0);
}
@Override
public void onSurfaceChanged(GL10 gl10,int w,int h) {
gl10.glViewport(0,0,w,h);
screen = new Angle(w,h);
}
@Override
public void onDrawFrame(GL10 gl10) {
//画面の初期化
gl10.glClearColor(0.8f,0.8f,1.0f,1.0f);
gl10.glClear(GL10.GL_COLOR_BUFFER_BIT|
GL10.GL_DEPTH_BUFFER_BIT);
//射影変換
gl10.glMatrixMode(GL10.GL_PROJECTION);
gl10.glLoadIdentity();
GLU.gluPerspective(gl10,
60.0f, //Y方向の画角
screen.ratio(),//アスペクト比
0.01f, //ニアクリップ
100.0f); //ファークリップ
//ビュー変換
gl10.glMatrixMode(GL10.GL_MODELVIEW); //行列演算ターゲットの指定
gl10.glLoadIdentity(); //行列の単位行列化
anata.setLookAt(gl10);
synchronized (lock) {
list.draw(gl10);
}
}
//定期処理
public void tick(float tstep) {
switch (scene) {
case S_START:
touch.setInvalid();
anata.init();
score.clear();
break;
case S_PLAY:
if(touch.isValid()){
if(touch.isInLeft(screen)){
anata.turnLeft();
}else if(touch.isInRight(screen)){
anata.turnRight();
}
anata.speedUp(tstep);
}else {
anata.speedDown(tstep);
}
anata.goForward(tstep);
synchronized (lock){
boolean changed=false;
Iterator<? extends Drawable> i = list.iterator();
while(i.hasNext()){
Drawable d = i.next();
if(d instanceof Touchable){
Touchable t = (Touchable)d;
if(t.isContained(anata.getPostion())){
anata.reverseVelocity();
t.die();
i.remove();
score.add(10);
changed=true;
}
}
}
if(changed){
list.add(Box.createBox());
}
}
break;
}
}
//タッチイベントの処理
//タッチされた座標を取得、離れたときに—1を格納
public View.OnTouchListener getOnTouchListener(){
return new MyOnTouchListener();
}
class MyOnTouchListener implements View.OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
score.update();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
switch (scene) {
case S_START:
scene = Scene.S_PLAY;
break;
case S_PLAY:
touch.set(event.getX(),event.getY());
break;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
touch.setInvalid();
break;
}
return true;
}
}
}
package jp.ac.dendai.c.jtp.flightsample;
public enum Scene {
S_START ,
S_PLAY
}
package jp.ac.dendai.c.jtp.flightsample;
public class Position {
private float x;
private float y;
private boolean valid;
public Position(){
x=-1;
y=-1;
valid=false;
}
public void setX(float _x){
x=_x;
}
public void setY(float _y) {
y = _y;
}
public void setInvalid() {
valid = false;
}
public boolean isValid() {
return valid;
}
public boolean isInLeft(Angle screen) {
return x < (float)screen.getW() / 3;
}
public boolean isInRight(Angle screen) {
return x > (float)screen.getW() * 2 / 3;
}
public void set(float _x, float _y) {
x=_x;
y=_y;
valid=true;
}
}
package jp.ac.dendai.c.jtp.flightsample;
public class Angle {
private int w;
private int h;
public Angle(int w, int h) {
this.h = h;
this.w = w;
}
public Angle(Angle a) {
this.w=a.w;
this.h=a.h;
}
public int getW() {
return w;
}
public int getH() {
return h;
}
public void addW(int i) {
w+=i;
}
public void addH(int i) {
h+=i;
}
private static float toRadian(float angle) {
return (float)(angle*Math.PI/180);
}
public Vect getVect() {
float fw = toRadian(w);
float fh = toRadian(h);
return new Vect((float) (Math.cos(fw) * Math.cos(fh)),
(float) Math.sin(fh),
(float) (Math.sin(fw) * Math.cos(fh)));
}
public float ratio() {
return (float)w/h;
}
}
package jp.ac.dendai.c.jtp.flightsample;
public class Vect {
private float x;
private float y;
private float z;
public Vect(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vect(Vect v) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public float getZ() {
return z;
}
public void mul(float e) {
x*=e;
y*=e;
z*=e;
}
public void sub(Vect v) {
x-=v.x;
y-=v.y;
z-=v.z;
}
public void add(Vect v) {
x+=v.x;
y+=v.y;
z+=v.z;
}
public float squareOfDistance(Vect v){
return sq(v.getX()-x)+sq(v.getY()-y)+sq(v.getZ()-z);
}
private float sq(float v) {
return v*v;
}
}
package jp.ac.dendai.c.jtp.flightsample;
import javax.microedition.khronos.opengles.GL10;
public interface Drawable {
void draw(GL10 gl10);
}
package jp.ac.dendai.c.jtp.flightsample;
import java.util.ArrayList;
import javax.microedition.khronos.opengles.GL10;
public class DrawList<E extends Drawable > extends ArrayList<E> {
public void draw(GL10 gl10){
for(E d: this){
d.draw(gl10);
}
}
}
Touchable.java
package jp.ac.dendai.c.jtp.flightsample;
public interface Touchable extends Drawable{
boolean isContained(Vect v);
void die();
boolean isAlive();
}
package jp.ac.dendai.c.jtp.flightsample;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
public abstract class AbstractDrawable implements Drawable{
protected final float[][] materialColors;
protected float[] vertexs;
public AbstractDrawable(float[][] floats) {
materialColors = floats;
}
//float配列をFloatBufferに変換
protected FloatBuffer makeFloatBuffer(float[] array) {
FloatBuffer fb= ByteBuffer.allocateDirect(array.length * 4).order(
ByteOrder.nativeOrder()).asFloatBuffer();
fb.put(array).position(0);
return fb;
}
//byte配列をByteBufferに変換
protected ByteBuffer makeByteBuffer(byte[] array) {
ByteBuffer bb=ByteBuffer.allocateDirect(array.length).order(
ByteOrder.nativeOrder());
bb.put(array).position(0);
return bb;
}
protected void setColor(GL10 gl10, float[] color){
gl10.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_AMBIENT, color, 0);
gl10.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_DIFFUSE, color, 0);
}
}
package jp.ac.dendai.c.jtp.flightsample;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
public class Box extends AbstractDrawable implements Touchable {
//インデックスバッファの生成
private static final byte[] indexs = new byte[]{
0,1,2,
2,1,3,
2,3,6,
6,3,7,
6,7,4,
4,7,5,
4,5,0,
0,5,1,
1,5,3,
3,5,7,
0,2,4,
4,2,6,
};
private final Vect center;
private final float size;
private boolean alive;
public Box(float[] materialcolor, Vect v, float _size) {
super(new float[][]{materialcolor});
alive = true;
size=_size;
float mx = v.getX() - _size;
float my = v.getY() - _size;
float mz = v.getZ() - _size;
//頂点バッファの生成
vertexs=new float[]{
v.getX(), v.getY(), v.getZ(), //頂点0
v.getX(), v.getY(), mz, //頂点1
mx, v.getY(), v.getZ(), //頂点2
mx, v.getY(), mz, //頂点3
v.getX(), my, v.getZ(), //頂点4
v.getX(), my, mz, //頂点5
mx, my, v.getZ(), //頂点6
mx, my, mz, //頂点7
};
center = new Vect(v.getX()-_size/2,v.getY()-_size/2,v.getZ()-_size/2);
}
public static Box createBox(){
float[] color = Constant.colorList[((int) (Math.random() * Constant.colorList.length))];
float rx= randomPosition();
float ry= randomPosition();
return new Box(color, new Vect(rx,1.0f,ry),Constant.boxsize);
}
private static float randomPosition() {
return (float) ((Math.random()*2* Constant.YukaSIZE-Constant.YukaSIZE)*Constant.AreaRatio);
}
@Override
public void die(){
alive=false;
}
@Override
public boolean isAlive(){
return alive;
}
//ボックスの描画
@Override
public void draw(GL10 gl10) {
gl10.glEnableClientState(GL10.GL_VERTEX_ARRAY);
setColor(gl10,materialColors[0]);
//バッファ変換
FloatBuffer vertexBuffer = makeFloatBuffer(vertexs);
ByteBuffer indexBuffer = makeByteBuffer(indexs);
//頂点バッファの指定
gl10.glVertexPointer(3,GL10.GL_FLOAT,0,vertexBuffer);
//面の描画
gl10.glDrawElements(GL10.GL_TRIANGLES,
indexBuffer.capacity(),GL10.GL_UNSIGNED_BYTE,indexBuffer);
}
@Override
public boolean isContained(Vect v){
return center.squareOfDistance(v)<size*size;
}
}
package jp.ac.dendai.c.jtp.flightsample;
import android.opengl.GLU;
import javax.microedition.khronos.opengles.GL10;
public class Anata {
private Vect spec;
private Angle specAngle;
private Angle eyeAngle;
private float velocity;
void setLookAt(GL10 gl10){
eyeAngle = new Angle(specAngle);
Vect eye = new Vect(spec);
Vect vect = eyeAngle.getVect();
vect .mul(Constant.EYEDIS);
eye.sub(vect);
GLU.gluLookAt(gl10,
eye.getX(), eye.getY(), eye.getZ(),
spec.getX(), spec.getY(), spec.getZ(),
0.0f, 1.0f, 0.0f);
}
public void init(){
velocity=0;
setAngle(new Angle(-90, 0));
setVect(new Vect(0, 0, 50));
}
public void setAngle(Angle angle) {
specAngle = angle;
}
public void speedUp(float tstep){
velocity+=Constant.acc*tstep;
if(velocity>Constant.MaxV){
velocity=Constant.MaxV;
}
}
public void speedDown(float tstep){
float oldvelocity=velocity;
if(velocity>0) {
velocity -= Constant.bacc * tstep;
}else if(velocity <0){
velocity += Constant.bacc * tstep;
}
if(velocity*oldvelocity<0){
velocity=0;
}
}
public void setVect(Vect vect) {
spec=vect;
}
public void turnLeft() {
specAngle.addW(-Constant.turnAngle);
}
public void turnRight() {
specAngle.addW(Constant.turnAngle);
}
public void goForward(float tstep) {
Vect d = eyeAngle.getVect();
d.mul(velocity * tstep);
spec.add(d);
}
public Vect getPostion() {
return spec;
}
public void reverseVelocity() {
velocity=-velocity;
}
}
package jp.ac.dendai.c.jtp.flightsample;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
public class Yuka extends AbstractDrawable {
//インデックスバッファの生成
//3つの頂点で三角形を作成
private static final byte[] indexs = new byte[]{
0,1,2,
2,1,3,
2,3,4,
4,3,5,
1,6,3,
3,6,7,
3,7,5,
5,7,8,
};
//コンストラクタ
public Yuka() {
super(new float[][]{Constant.green, Constant.brown});
//頂点バッファの生成
vertexs = new float[] {
Constant.YukaSIZE, Constant.YukaY, Constant.YukaSIZE, //頂点0
Constant.YukaZERO, Constant.YukaY, Constant.YukaSIZE, //頂点1
Constant.YukaSIZE, Constant.YukaY, Constant.YukaZERO, //頂点2
Constant.YukaZERO, Constant.YukaY, Constant.YukaZERO, //頂点3
Constant.YukaSIZE, Constant.YukaY, -Constant.YukaSIZE, //頂点4
Constant.YukaZERO, Constant.YukaY, -Constant.YukaSIZE, //頂点5
-Constant.YukaSIZE, Constant.YukaY, Constant.YukaSIZE, //頂点6
-Constant.YukaSIZE, Constant.YukaY, Constant.YukaZERO, //頂点7
-Constant.YukaSIZE, Constant.YukaY, -Constant.YukaSIZE, //頂点8
};
}
//描画
@Override
public void draw(GL10 gl10) {
//頂点配列の有効化
gl10.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//バッファ変換
FloatBuffer vertexBuffer = makeFloatBuffer(vertexs);
ByteBuffer indexBuffer = makeByteBuffer(indexs);
//頂点バッファの指定
gl10.glVertexPointer(3,GL10.GL_FLOAT,0,vertexBuffer);
//面の描画
setColor(gl10, materialColors[0]);
indexBuffer.position(0);
gl10.glDrawElements(GL10.GL_TRIANGLES,
6,GL10.GL_UNSIGNED_BYTE,indexBuffer);
//面の描画
setColor(gl10, materialColors[1]);
indexBuffer.position(6);
gl10.glDrawElements(GL10.GL_TRIANGLES,
6,GL10.GL_UNSIGNED_BYTE,indexBuffer);
//面の描画
setColor(gl10, materialColors[1]);
indexBuffer.position(12);
gl10.glDrawElements(GL10.GL_TRIANGLES,
6,GL10.GL_UNSIGNED_BYTE,indexBuffer);
//面の描画
setColor(gl10, materialColors[0]);
indexBuffer.position(18);
gl10.glDrawElements(GL10.GL_TRIANGLES,
6,GL10.GL_UNSIGNED_BYTE,indexBuffer);
}
}