スライドパズルでViewとSurfaceViewとOpenGL(GLSurfaceView)を比較
臨月妊婦の暇つぶしに、スライドパズルを例に、ViewとSurfaceViewとGLSurfaceViewの比較をメモします。アプリの画面はこんな感じ。
#ちなみに写真は、産休に入る際、職場の皆さんから頂いたお花です。
今日はSurfaceViewのソースコードまで。お腹が苦しいので、解説はまた。
package com.chiaki.example; import android.app.Activity; import android.os.Bundle; import android.view.Window; public class SlidePuzzle extends Activity { private boolean view_flg = false; private boolean surfaceview_flg = false; private boolean glsurfaceview_flg = true; private SlidePuzzle_View mSlidePuzzle_View; private SlidePuzzle_SurfaceView mSlidePuzzle_SurfaceView; private SlidePuzzle_GLSurfaceView mSlidePuzzle_GLSurfaceView; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); if (surfaceview_flg){ mSlidePuzzle_SurfaceView = new SlidePuzzle_SurfaceView(this); setContentView(mSlidePuzzle_SurfaceView); }else if (view_flg){ mSlidePuzzle_View = new SlidePuzzle_View(this); setContentView(mSlidePuzzle_View); }else if (glsurfaceview_flg){ mSlidePuzzle_GLSurfaceView = new SlidePuzzle_GLSurfaceView(this); setContentView(mSlidePuzzle_GLSurfaceView); } } }
package com.chiaki.example; import java.util.Random; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; public class SlidePuzzle_SurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable { private Random rand=new Random(); private Bitmap image; private int[] data=new int[25]; private Thread mThread; private SurfaceHolder mSurfaceHolder; public SlidePuzzle_SurfaceView(Context context) { super(context); initialize(context); for (int i=0;i<25;i++) data[i]=i; loadPicture(context); setFocusable(true); setFocusableInTouchMode(true); } private void initialize(Context context) { mSurfaceHolder = getHolder(); mSurfaceHolder.addCallback(this); mSurfaceHolder.setFixedSize(getWidth(), getHeight()); setFocusable(true); } public void loadPicture(Context ctx) { Context context= ctx; Resources r=context.getResources(); int resID=R.drawable.picture; image=BitmapFactory.decodeResource(r,resID); image = Bitmap.createScaledBitmap(image, 300, 300, true); int[] DIR={ KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT }; for (int i=99;i>=0;i--) { slidePiece(DIR[(rand.nextInt()>>>1)%4]); } } private void slidePiece(int key) { int freeIdx=0; for (; freeIdx<25; freeIdx++) { if (data[freeIdx]==24) break; } if (key==KeyEvent.KEYCODE_DPAD_UP && freeIdx/5<4) { data[freeIdx]=data[freeIdx+5]; data[freeIdx+5]=24; } else if (key==KeyEvent.KEYCODE_DPAD_DOWN && freeIdx/5>0) { data[freeIdx]=data[freeIdx-5]; data[freeIdx-5]=24; } else if (key==KeyEvent.KEYCODE_DPAD_LEFT && freeIdx%5<4) { data[freeIdx]=data[freeIdx+1]; data[freeIdx+1]=24; } else if (key==KeyEvent.KEYCODE_DPAD_RIGHT && freeIdx%5>0) { data[freeIdx]=data[freeIdx-1]; data[freeIdx-1]=24; } } @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // TODO Auto-generated method stub } @Override public void surfaceCreated(SurfaceHolder arg0) { mThread = new Thread(this); mThread.start(); } @Override public void surfaceDestroyed(SurfaceHolder arg0) { mThread = null; } @Override public void run() { Canvas canvas = null; while (mThread != null) { try { canvas = mSurfaceHolder.lockCanvas(); drawPuzzle(canvas); } finally { if (canvas != null) mSurfaceHolder.unlockCanvasAndPost(canvas); } } } public void drawPuzzle(Canvas canvas) { if (image==null) return; boolean complete=true; for (int i=0;i<25;i++) { if (data[i]!=i) complete=false; } Paint paint=new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.FILL); paint.setColor(Color.argb(255,0,0,0)); canvas.drawRect( new Rect(0,0,getWidth(),getHeight()),paint); int bx=(getWidth()-300)/2; int by=(getHeight()-300)/2; for (int i=0;i<25;i++) { int sx=data[i]%5; int sy=data[i]/5; int dx=i%5; int dy=i/5; if (!complete) { paint.setColor(Color.argb(255,255,255,255)); paint.setStyle(Paint.Style.STROKE); } if (data[i]!=24) { if (getmode() == KeyEvent.KEYCODE_DPAD_UP){ if (i <= (5*gettouchY() + gettouchX()) && i > (5*getfreeY() + getfreeX()) && (i == (5*getfreeY() + getfreeX())+5 || i == (5*getfreeY() + getfreeX())+10 || i == (5*getfreeY() + getfreeX())+15 || i == (5*getfreeY() + getfreeX())+20) && getslide_ysum() <= 60 && getslide_ysum() >= 0){ canvas.drawRect( new Rect(bx+60*dx,by+60*dy-getslide_ysum(), bx+60*dx+60,by+60*dy+60-getslide_ysum()), paint); canvas.drawBitmap(image, new Rect(60*sx,60*sy, 60*sx+60,60*sy+60), new Rect(bx+60*dx,by+60*dy-getslide_ysum(), bx+60*dx+60,by+60*dy+60-getslide_ysum()), null); }else{ canvas.drawRect( new Rect(bx+60*dx,by+60*dy, bx+60*dx+60,by+60*dy+60), paint); canvas.drawBitmap(image, new Rect(60*sx,60*sy, 60*sx+60,60*sy+60), new Rect(bx+60*dx,by+60*dy, bx+60*dx+60,by+60*dy+60), null); } if (getslide_ysum() >= 60){ for (int j=freeY;j<touchY;j++) { slidePiece(KeyEvent.KEYCODE_DPAD_UP); } s_touchX = 0; s_touchY = 0; e_touchX = 0; e_touchY = 0; slide_x = 0; slide_y = 0; slide_xsum = 0; slide_ysum = 0; reach_flg = true; } } if (getmode() == KeyEvent.KEYCODE_DPAD_DOWN){ if (i >= (5*gettouchY() + gettouchX()) && i < (5*getfreeY() + getfreeX()) && (i == (5*getfreeY() + getfreeX())-5 || i == (5*getfreeY() + getfreeX())-10 || i == (5*getfreeY() + getfreeX())-15 || i == (5*getfreeY() + getfreeX())-20) && getslide_ysum() > -60 && getslide_ysum() < 0){ canvas.drawRect( new Rect(bx+60*dx,by+60*dy-getslide_ysum(), bx+60*dx+60,by+60*dy+60-getslide_ysum()), paint); canvas.drawBitmap(image, new Rect(60*sx,60*sy, 60*sx+60,60*sy+60), new Rect(bx+60*dx,by+60*dy-getslide_ysum(), bx+60*dx+60,by+60*dy+60-getslide_ysum()), null); }else{ canvas.drawRect( new Rect(bx+60*dx,by+60*dy, bx+60*dx+60,by+60*dy+60), paint); canvas.drawBitmap(image, new Rect(60*sx,60*sy, 60*sx+60,60*sy+60), new Rect(bx+60*dx,by+60*dy, bx+60*dx+60,by+60*dy+60), null); } } if (getslide_ysum() <= -60){ for (int j=freeY;j>touchY;j--) { slidePiece(KeyEvent.KEYCODE_DPAD_DOWN); } s_touchX = 0; s_touchY = 0; e_touchX = 0; e_touchY = 0; slide_x = 0; slide_y = 0; slide_xsum = 0; slide_ysum = 0; reach_flg = true; } if (getmode() == KeyEvent.KEYCODE_DPAD_RIGHT){ if (i < (5*getfreeY() + getfreeX()) && i >= (5*gettouchY() + gettouchX()) && getslide_xsum() <= 60 && getslide_xsum() >= 0){ canvas.drawRect( new Rect(bx+60*dx+getslide_xsum(),by+60*dy, bx+60*dx+60+getslide_xsum(),by+60*dy+60), paint); canvas.drawBitmap(image, new Rect(60*sx,60*sy, 60*sx+60,60*sy+60), new Rect(bx+60*dx+getslide_xsum(),by+60*dy, bx+60*dx+60+getslide_xsum(),by+60*dy+60), null); }else{ canvas.drawRect( new Rect(bx+60*dx,by+60*dy, bx+60*dx+60,by+60*dy+60), paint); canvas.drawBitmap(image, new Rect(60*sx,60*sy, 60*sx+60,60*sy+60), new Rect(bx+60*dx,by+60*dy, bx+60*dx+60,by+60*dy+60), null); } if (getslide_xsum() >= 60){ for (int j=freeX;j>touchX;j--) { slidePiece(KeyEvent.KEYCODE_DPAD_RIGHT); } s_touchX = 0; s_touchY = 0; e_touchX = 0; e_touchY = 0; slide_x = 0; slide_y = 0; slide_xsum = 0; slide_ysum = 0; reach_flg = true; } } if (getmode() == KeyEvent.KEYCODE_DPAD_LEFT){ if (i > (5*getfreeY() + getfreeX()) && i <= (5*gettouchY() + gettouchX()) && getslide_xsum() >= -60 && getslide_xsum() <= 0){ canvas.drawRect( new Rect(bx+60*dx+getslide_xsum(),by+60*dy, bx+60*dx+60+getslide_xsum(),by+60*dy+60), paint); canvas.drawBitmap(image, new Rect(60*sx,60*sy, 60*sx+60,60*sy+60), new Rect(bx+60*dx+getslide_xsum(),by+60*dy, bx+60*dx+60+getslide_xsum(),by+60*dy+60), null); }else{ canvas.drawRect( new Rect(bx+60*dx,by+60*dy, bx+60*dx+60,by+60*dy+60), paint); canvas.drawBitmap(image, new Rect(60*sx,60*sy, 60*sx+60,60*sy+60), new Rect(bx+60*dx,by+60*dy, bx+60*dx+60,by+60*dy+60), null); } if (getslide_xsum() <= -60){ for (int j=freeX;j<touchX;j++) { slidePiece(KeyEvent.KEYCODE_DPAD_LEFT); } s_touchX = 0; s_touchY = 0; e_touchX = 0; e_touchY = 0; slide_x = 0; slide_y = 0; slide_xsum = 0; slide_ysum = 0; reach_flg = true; } } if (getmode() == -1 || getslide_ysum() == -60 || getslide_ysum() == 60 || getslide_xsum() == -60 || getslide_xsum() == 60){ canvas.drawRect( new Rect(bx+60*dx,by+60*dy, bx+60*dx+60,by+60*dy+60), paint); canvas.drawBitmap(image, new Rect(60*sx,60*sy, 60*sx+60,60*sy+60), new Rect(bx+60*dx,by+60*dy, bx+60*dx+60,by+60*dy+60), null); } } } if (complete) { paint.setTextSize(32); paint.setColor(Color.argb(255,255,0,0)); String str="Congratulations!"; int w=(int)paint.measureText(str); canvas.drawText(str,bx+(300-w)/2,by+270,paint); } } @Override public boolean onTouchEvent(MotionEvent event) { switch( event.getAction() ){ case MotionEvent.ACTION_DOWN : s_touchX = 0; s_touchY = 0; e_touchX = 0; e_touchY = 0; s_touchX = (int) event.getX(); s_touchY = (int) event.getY(); touchX=(int)(event.getX()-(getWidth()-300)/2)/60; touchY=(int)(event.getY()-(getHeight()-300)/2)/60; if (touchX<0 || 5<=touchX) return true; if (touchY<0 || 5<=touchY) return true; freeX=0; freeY=0; for (int i=0;i<25;i++) { if (data[i]==24) { freeX=i%5; freeY=i/5; break; } } if (touchX==freeX) { if (freeY<touchY) { mode = KeyEvent.KEYCODE_DPAD_UP; } else if (freeY>touchY) { mode = KeyEvent.KEYCODE_DPAD_DOWN; } } else if (touchY==freeY) { if (freeX<touchX) { mode = KeyEvent.KEYCODE_DPAD_LEFT; } else if (freeX>touchX) { mode = KeyEvent.KEYCODE_DPAD_RIGHT; } } break; case MotionEvent.ACTION_MOVE : e_touchX = (int) event.getX(); e_touchY = (int) event.getY(); slide_x = e_touchX - s_touchX; slide_y = s_touchY - e_touchY; if (getslide_x() > 60){ slide_x = 60; } if (getslide_x() < -60){ slide_x = -60; } if (getslide_y() > 60){ slide_y = 60; } if (getslide_y() < -60){ slide_y = -60; } if ((getslide_xsum() <= 60 && getslide_xsum() >=0) || (getslide_xsum() <= 0 && getslide_xsum() >= -60)){ slide_xsum =getslide_xsum() + getslide_x(); } if ((getslide_ysum() >= 0 && getslide_ysum() <= 60) || (getslide_ysum() <= 0 && getslide_ysum() >= -60)){ slide_ysum =getslide_ysum() + getslide_y(); } s_touchX = e_touchX; s_touchY = e_touchY; if (getreach_flg() == true){ s_touchX = 0; s_touchY = 0; e_touchX = 0; e_touchY = 0; slide_x = 0; slide_y = 0; slide_xsum = 0; slide_ysum = 0; mode = -1; } break; case MotionEvent.ACTION_UP : s_touchX = 0; s_touchY = 0; e_touchX = 0; e_touchY = 0; slide_x = 0; slide_y = 0; slide_xsum = 0; slide_ysum = 0; mode = -1; reach_flg = false; break; } return true; } @Override public boolean onKeyDown(int keyCode,KeyEvent event) { slidePiece(keyCode); return super.onKeyDown(keyCode,event); } public int getmode(){ return mode; } public int getslide_x(){ return slide_x; } public int getslide_y(){ return slide_y; } public int getslide_xsum(){ return slide_xsum; } public int getslide_ysum(){ return slide_ysum; } public int gettouchX(){ return touchX; } public int gettouchY(){ return touchY; } public int getfreeX(){ return freeX; } public int getfreeY(){ return freeY; } public boolean getreach_flg(){ return reach_flg; } private int slide_x; private int slide_y; private int mode = -1; private int touchX; private int touchY; private int freeX; private int freeY; private int s_touchX = 0; private int s_touchY = 0; private int e_touchX = 0; private int e_touchY = 0; private int slide_xsum = 0; private int slide_ysum = 0; private boolean reach_flg = false; }