Android 如何延迟使用SurfaceView绘制和设置动画

Android 如何延迟使用SurfaceView绘制和设置动画,android,multithreading,handler,Android,Multithreading,Handler,我正在尝试构建一个简单的Simon Says游戏。我有3个随机放置的位图,它们会将动画从睡眠变为醒来再变为睡眠,我称之为亮起序列,所以当应用程序启动时,每个位图将从睡眠笑脸位图->唤醒笑脸位图-->睡眠笑脸位图转到睡眠笑脸位图,对于随机放置在屏幕上的3个位图中的每一个,笑脸的每次转换之间有1000毫秒的延迟。我得到了一个黑屏,我检查了Android监视器,它说“发送消息给一个死线程上的处理程序”。 我将点亮g的位图命名为。圆点还是好圆点。更新方法将位图图像的状态更新为睡眠位图或唤醒位图,以便根据

我正在尝试构建一个简单的Simon Says游戏。我有3个随机放置的位图,它们会将动画从睡眠变为醒来再变为睡眠,我称之为亮起序列,所以当应用程序启动时,每个位图将从睡眠笑脸位图->唤醒笑脸位图-->睡眠笑脸位图转到睡眠笑脸位图,对于随机放置在屏幕上的3个位图中的每一个,笑脸的每次转换之间有1000毫秒的延迟。我得到了一个黑屏,我检查了Android监视器,它说“发送消息给一个死线程上的处理程序”。 我将点亮g的位图命名为。圆点还是好圆点。更新方法将位图图像的状态更新为睡眠位图或唤醒位图,以便根据绘制 屏幕上的位图。我目前正在使用3个随机放置的位图。请帮忙,谢谢。我没有包括我的GoodDot类,它只是一个分配默认睡眠位图笑脸的类,并且有一个方法来检查两个位图是否在屏幕上的同一位置,当然,它跟踪位图在屏幕上的位置,所以(x,y)坐标。请帮忙,谢谢

所以游戏的第一部分是当一个新关卡启动或应用程序打开时(我稍后会担心保存状态),然后一个随机定位和随机分配的3个位图序列将亮起

第2部分:只运行run方法底部的while循环,基本上我将添加检测触摸,让玩家按正确的顺序按下位图以赢得一个关卡

以下是MainActivity类:

public class MainActivity extends Activity {

private Handler myHandler;
Canvas canvas;
Paint paint;
GameView gameView;
Bitmap restBitmap;
Bitmap awakeBitmap;
final int NUM_GOOD_DOTS = 3;
static int curPos = 0;//cur g. dot doing its light up sequence
GoodDot goodDotList[];

int screenWidth;
int screenHeight;
//The size in pixels of a place on the game board
int blockSize;
int numBlocksWide;
int numBlocksHigh;

static boolean isFirstTimeSettingUpGoodDotPosns = false;
static boolean isLightUpSequenceFinishedForCurLevel = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    gameView = new GameView(this);
    canvas = new Canvas( );
    paint = new Paint ( );
    myHandler = new Handler();
    configureDisplay();
    setContentView(gameView);

}//END METHOD: onCreate

class GameView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private SurfaceHolder surfaceHolder;//this lets us access the canvas but still need to use Canvas class
    private Thread myThread;

    public GameView(Context context) {
        super(context);
        myThread = new Thread();
        surfaceHolder = getHolder();
        surfaceHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        myThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder,
                               int format, int width, int height) {
        // What do I enter here???
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        while (retry) {
            try {
                myThread.join();
                retry = false;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isLightUpSequenceFinishedForCurLevel = false;
    }

    protected void drawSomething ( ) {
        Log.i ("curPos so far:", "" + curPos );

        if (surfaceHolder.getSurface().isValid() ) {
            canvas = surfaceHolder.lockCanvas();

            if (isFirstTimeSettingUpGoodDotPosns == false) {

                //assign random posns to bitmaps
                //  as they are NOT on same spot on screen!
                Random r = new Random();
                for (int i = 0; i < NUM_GOOD_DOTS; i++) {
                    goodDotList[i] = new GoodDot(1, 1, restBitmap);
                    goodDotList[i].setGoodDotX((r.nextInt(3) + 1) * blockSize);
                    goodDotList[i].setGoodDotY((r.nextInt(3) + 1) * blockSize);
                }

                //this method ensures no bitmaps land on same position 
                //   on screen
                gameView.assignProperPosnForGoodDots();

                isFirstTimeSettingUpGoodDotPosns = true;
            }

            canvas.drawColor(Color.BLACK);//the background
            paint.setColor(Color.argb(255, 255, 255, 255));
            paint.setStrokeWidth(3);

            // for loop to draw all g. dots
            for (int i = 0; i < NUM_GOOD_DOTS; i++) {

                canvas.drawBitmap(goodDotList[i].getBitmap(),
                        goodDotList[i].getGoodDotX(), goodDotList[i].getGoodDotY(), paint);
            }

            //this method called is only for testing
            drawGrid(canvas);
            surfaceHolder.unlockCanvasAndPost(canvas);
    }//END IF BLOCK: For valid surfaceHolder
 }//END METHOD: drawSomething

    //this method is only for testing to see the grid that each bitmap is inside a block
    private void drawGrid ( Canvas canvas ) {

        //var to draw horizontal line part of grid
        float rowStartX = 0; float rowStartY = 0;
        float rowEndX = screenWidth;  float rowEndY = 0;

        //var to draw vertical line part of grid
        int colStartX = 0; int colStartY = 0;
        int colEndX = 0;  int colEndY = screenHeight;

        // Log.d("NUM BLOCKS HIGH", "Value:" + numBlocksHigh );

        //draw the horizontal lines
        for ( int i  = 0; i < numBlocksHigh; i++ ) {
            canvas.drawLine ( rowStartX, rowStartY, rowEndX, rowEndY , paint );
            rowStartY += blockSize;
            rowEndY += blockSize;
        }

        //draw the vertical lines
        for ( int i  = 0; i < numBlocksWide; i++ ) {
            canvas.drawLine ( colStartX, colStartY, colEndX, colEndY , paint );
            colStartX += blockSize;
            colEndX += blockSize;
        }
    }//END METHOD: drawGrid

    //Each g. dot goes thru 3 states: rest, light up/awake, rest
    public void update() {

        switch ( goodDotList [ curPos ].getGoodDotState() ) {
            case 1:
                goodDotList[ curPos ].setBitmap( restBitmap );
                break;
            case 2:
                goodDotList[ curPos ].setBitmap( awakeBitmap );
                break;
            case 3:
                goodDotList[ curPos ].setBitmap( restBitmap );
                break;
            default:
                break;
        }

        //Go to next g. dot once 3 states finished for a given g. dot
        if ( goodDotList [ curPos ].getGoodDotState() > 3 ) {
            curPos++;
        }
        else {
            goodDotList [ curPos ].setGoodDotState(
                    goodDotList [ curPos ].getGoodDotState() + 1 );
        }
    }//END METHOD: update

    //this method makes sure no GOOD DOTS land on same spot
    public void assignProperPosnForGoodDots ( ) {

        int curGdotPos = 0;
        Random rand = new Random ();
        boolean isHitFound = false;

        while ( curGdotPos < NUM_GOOD_DOTS ) {

            for (int j  = curGdotPos + 1; j < NUM_GOOD_DOTS; j++ ) {

                if ( goodDotList [ curGdotPos ].checkForHit( NUM_GOOD_DOTS, goodDotList [ j ] ) ) {
                    goodDotList[curGdotPos].setGoodDotX( (rand.nextInt(3) + 1) * blockSize  )  ;
                    goodDotList[curGdotPos].setGoodDotY( ( rand.nextInt(3) + 1) * blockSize  );
                    isHitFound = true;
                    break;
                }
            }//END INNER FOR LOOP

            if ( isHitFound ) {
                curGdotPos = 0;
                isHitFound = false;//reset for next round
            }
            else
                curGdotPos++;
        }//END WHILE LOOP
    }//END METHOD: assignProperPosnForGoodDots

    @Override
    public void run() {

        if (curPos < NUM_GOOD_DOTS) {
            Log.i("hi", "hi, more g. dots to light up!");
            gameView.update();
            gameView.drawSomething();
        }
        if ( curPos < NUM_GOOD_DOTS ) {
            myHandler.postDelayed(this, 1000);
        }
        else {
            isLightUpSequenceFinishedForCurLevel = true;
        }

        while ( isLightUpSequenceFinishedForCurLevel )
            gameView.drawSomething( );
    }

}//END INNER CLASS: GameView

/**
 * BELOW are Main Activity Life Cycle Call Back methods!
 */
@Override
protected void onStop() {
    super.onStop();
    Log.d("onStop", "Main Activity's onStop called");
    gameView.surfaceDestroyed( gameView.getHolder() );
    this.finish();
}

@Override
protected void onResume() {
    super.onResume();
    Log.d("onResume", "Main Activity's onResume called");

    gameView = new GameView(this);
    setContentView(gameView);
    gameView.surfaceCreated( gameView.getHolder() );
}

@Override
protected void onPause() {
    super.onPause();
    Log.i("onPause", "Main Activity's onPause called");
    gameView.surfaceDestroyed( gameView.getHolder() );
}

public void configureDisplay() {
    //find out the width and height of the screen
    Display display =
            getWindowManager().getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    screenWidth = size.x;
    screenHeight = size.y;

    //Determine the size of each block/place on the game board
    blockSize = screenWidth/10;

    //Determine how many game blocks will fit into the
    //height and width
    //Leave one block for the score at the top
    numBlocksWide = 10;
    numBlocksHigh = ( ( screenHeight ) ) / blockSize;

    //Load and scale bitmaps
    restBitmap = BitmapFactory.decodeResource(getResources(),
            R.drawable.good_dot_rest_state );
    awakeBitmap = BitmapFactory.decodeResource(getResources(),
            R.drawable.good_dot_light_up_state );

    //scale the bitmaps to match the block size
    restBitmap = Bitmap.createScaledBitmap( restBitmap,
            blockSize  , blockSize , false);
    awakeBitmap = Bitmap.createScaledBitmap( awakeBitmap,
            blockSize , blockSize , false);

    goodDotList = new GoodDot[ NUM_GOOD_DOTS ];

  //initialize g. dots w coordinate (0,0)
    for ( int i = 0; i < NUM_GOOD_DOTS; i++ )
        goodDotList [ i ] = new GoodDot( 0, 0, restBitmap );

}//END METHOD: configureDisplay

}//END CLASS: MainActivity
公共类MainActivity扩展活动{
私有处理器myHandler;
帆布;
油漆;
GameView GameView;
位图;
位图唤醒位图;
最终整型数良好点=3;
静态int curPos=0;//cur g.dot执行其点亮顺序
GoodDot goodDotList[];
int屏幕宽度;
屏幕高度;
//游戏板上某个位置的大小(以像素为单位)
整块大小;
内特诺姆洛克斯威德;
int numBlocksHigh;
静态布尔值isFirstTimeSettingUpGoodDotPosns=false;
静态布尔值isLightUpSequenceFinishedForCurLevel=false;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
gameView=新gameView(此);
canvas=newcanvas();
油漆=新油漆();
myHandler=新处理程序();
配置显示();
setContentView(gameView);
}//结束方法:onCreate
类GameView扩展SurfaceView实现SurfaceHolder.Callback,Runnable{
private SurfaceHolder SurfaceHolder;//这允许我们访问画布,但仍然需要使用canvas类
私有线程读取;
公共游戏视图(上下文){
超级(上下文);
myThread=新线程();
surfaceHolder=getHolder();
surfaceHolder.addCallback(this);
}
@凌驾
已创建的公共空白表面(表面持有人){
myThread.start();
}
@凌驾
公共空间表面变更(表面持有人,
整数格式、整数宽度、整数高度){
//我该在这里输入什么???
}
@凌驾
公共空间表面覆盖(表面覆盖物持有人){
布尔重试=真;
while(重试){
试一试{
myThread.join();
重试=错误;
}捕捉(中断异常e){
e、 printStackTrace();
}
}
isLightUpSequenceFinishedForCurLevel=false;
}
受保护的某物(){
Log.i(“迄今为止的curPos:,”+curPos);
if(surfaceHolder.getSurface().isValid()){
canvas=surfaceHolder.lockCanvas();
如果(isFirstTimeSettingUpGoodDotPosns==false){
//将随机POSN分配给位图
//因为它们不在屏幕上的同一位置!
随机r=新随机();
对于(int i=0;i