2012年5月17日木曜日

SurfaceView sample code:小さな画像を敷き詰め、スクロールさせる

SurfaceView sample code:小さな画像を敷き詰め、スクロールさせる

小さな画像を敷き詰め、その画像をスクロールさせようとする場合のロジックとして、取り敢えず思いつくのが、画像を4個の象限に分割して、対角線上の象限の画像を入れ替えた画像を準備し、それを敷き詰めていく、というロジックだ。

しかし、これをプログラミングするのは苦労する。コードが読み難くなる。

幸いなことに、Canvasクラスのメソッドには、マイナスの座標の値を設定できる。マイナスの座標値を設定して、画面の上端の更に上(又は左端の更に左)の、画面には表示出来ない箇所を起点とする画像を描画するようにすれば、象限分割の技法を用いることなく画像を敷き詰めることができる。

参考:ゲームの起動直後の画面を作成する

Javaのsample codeは次のとおりである。
public class MySurfaceView extends SurfaceView
    implements
    Callback,
    Runnable
    {
    //学習・実験を目的としているので。停止処理を実装していない。
    Thread t;
    int g_iX, g_iY;
    Bitmap bSource;
    
    public MySurfaceView(Context context) {
        super(context);
        g_iX = 0;
        g_iY = 0;
        t = null;
        getHolder().addCallback(this);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceCreated(SurfaceHolder h) {
        Canvas c = h.lockCanvas();
        Resources r = getResources();
        int iX, iY;
        
        //小さな画像を、画面いっぱいに敷き詰める。
        bSource = BitmapFactory.decodeResource(r, R.drawable.tilerepeat);
        for(iY=0; iY<c.getHeight(); iY+=bSource.getHeight()){
       for(iX=0; iX<c.getWidth(); iX+=bSource.getWidth()){
                c.drawBitmap(bSource, iX, iY, null);
       }
        }
        h.unlockCanvasAndPost(c);
        
        t = new Thread(this);
        t.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }
    
    @Override
    public void run() {
        while(t!=null){
            Canvas c = getHolder().lockCanvas();
            if(c!=null){
                //1回当たりのスクロールさせる程度を設定する。
                g_iX += 5;
                if(g_iX>=bSource.getWidth()) g_iX = 0;
                g_iY += 8;
                if(g_iY>=bSource.getHeight()) g_iY = 0;
                
                //画像1枚分を大目に設定する。
                int iXMax = c.getWidth() + bSource.getWidth();
                int iYMax = c.getHeight() + bSource.getHeight();
                
                for(int iY=0; iY<iYMax; iY+=bSource.getHeight()){
                    for(int iX=0; iX<iXMax; iX+=bSource.getWidth()){
                        float fX, fY;
                        
                        if(g_iX==0) fX = 0.0f;
                        else{//左端の、画面に表示されない部分から描画を開始する。
                            fX = (float)(bSource.getWidth() - g_iX) * -1;
                        }
                        fX += iX;
                        
                        if(g_iY==0) fY = 0.0f;
                        else{//上端の、画面に表示されない部分から描画を開始する。
                            fY = (float)(bSource.getHeight() - g_iY) * -1;
                        }
                        fY += iY;
                        
                        c.drawBitmap(bSource, fX, fY, null);
                    }
                }
                getHolder().unlockCanvasAndPost(c);
            }
            try {
                Thread.sleep(10);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
                t = null;
            }
        }
    }
}


上記を呼び出すのは下記のコードである。
public class StartingActivity extends Activity{
    private final String TAG = "It's me!";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        MySurfaceView sv = new MySurfaceView(this);
        setContentView(sv);
    }
}

0 件のコメント:

コメントを投稿