Проблема с представлением Invalidate() и обработчиком

Я пытаюсь решить эту проблему в течение более 2 дней и стал довольно отчаянным.

Я хочу написать настольную игру в стиле "шашки" для Android. Сам игровой движок довольно полный, но у меня проблемы с обновлением просмотров.

Я написал небольшой пример класса, чтобы продемонстрировать мою проблему:

public class GameEngineView extends View {

private static final String TAG = GameEngineView.class.getSimpleName();

private int px;
private int py;
private int cx;
private int cy;

private boolean players_move;
private int clickx;
private int clicky;

Random rgen;

private RefreshHandler mRedrawHandler = new RefreshHandler();

class RefreshHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {            
        GameEngineView.this.update();
        GameEngineView.this.invalidate();
        Log.d(TAG, "invalidate()");            
    }

    public void sleep(long delayMillis) {
        this.removeMessages(0);
        sendMessageDelayed(obtainMessage(0), delayMillis);
    }
};

public GameEngineView(Context context) {
    super(context);
    setFocusable(true);
    players_move = true;
    rgen = new Random();
}

public void update() {
    updateGame();
    Log.d(TAG, "update -> sleep handler");
    mRedrawHandler.sleep(100);
}

public void updateGame() {
    if(players_move) {
        px = clickx;
        py = clicky;
    } else {
        calcAIMove();
        switchMove();
    }        
}

public void switchMove() {
    players_move = !players_move;
}

public void calcAIMove() {
    for(int i = 0; i < 20000; i++) {
        cx = rgen.nextInt(getWidth());
        cy = rgen.nextInt(getHeight());
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.d(TAG, "event");
    int eventaction = event.getAction();
    if(eventaction == MotionEvent.ACTION_DOWN) {
        Log.d(TAG, "action_down");
        clickx = (int) event.getX();
        clicky = (int) event.getY();
        switchMove();
        update();
    }
    return super.onTouchEvent(event);
}

@Override
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Paint green = new Paint();
    green.setColor(Color.GREEN);
    Paint red = new Paint();
    red.setColor(Color.RED);
    canvas.drawColor(Color.BLACK);
    canvas.drawCircle(px, py, 25, green);
    canvas.drawCircle(cx, cy, 25, red);
}

}

Функция calcAIMove() просто сжигает время, чтобы имитировать реальную оценку позиции в настольной игре.

Теперь моя проблема заключается в следующем: если игрок щелкает (делает ход), зеленый шар сначала рисуется, когда вычисление хода ai завершено. Итак, оба хода нарисованы одновременно.

Интересно, КАК это сделать: -Клики игрока -Зеленый шар нарисован -А я рассчитываю -Красный шар нарисован -и так далее..

При поиске в Интернете я нашел много примеров игровых циклов, но им всем нужен поток с постоянным опросом... это должно быть возможно без этого, так как вся программа работает последовательно... верно?

Надеюсь на совет.

спасибо Дэйв

3 ответа

Решение

Вот как ваша игра может работать:

  1. пользователь делает ход
  2. вид игры обновлен
  3. игра переключается на ход процессора
  4. сон для симуляции мышления игрока процессора (если вычисление хода тривиально)
  5. вычислить движение процессора
  6. вид игры обновлен
  7. игра переключается на ход игрока

В пошаговой игре, подобной этой, нет необходимости в постоянном опросе. Единственное место, где вы должны спать - это шаг 4, так что вы можете удалить его из других областей (старый не нужен) update() метод, который является просто отложенным вызовом updateGame()).

Один из способов реализовать это - просто отложить вызов calcAIMove() а также switchMove() положив его в Runnable и используя Handler.postDelayed() или похожие.

Я не вижу, как вы отключаете сенсорные события, когда наступает очередь процессора, что может привести к множеству других проблем, если switchMove() а также update() все еще называют...

В вашем игровом цикле вы можете использовать экземпляр TimerTask, чтобы обеспечить определенную задержку между greenBall и некоторыми другими задачами рисования. Учебные пособия по игре, такие как Snake и LunarLander, являются отличными справочными материалами о том, когда и если вам нужно аннулировать свой вид. Надеюсь, это немного поможет!

Хорошо, так что ответ, предоставленный antonyt, помог мне решить эту проблему. Я предоставляю исправленный код для других заинтересованных.

public class GameEngineView extends View {

private static final String TAG = GameEngineView.class.getSimpleName();

private int px;
private int py;
private int cx;
private int cy;

private boolean players_move;
private int clickx;
private int clicky;

Random rgen;

/**
 * Create a simple handler that we can use to cause animation to happen.  We
 * set ourselves as a target and we can use the sleep()
 * function to cause an update/invalidate to occur at a later date.
 */
private RefreshHandler mRedrawHandler = new RefreshHandler();

class RefreshHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        GameEngineView.this.update();
    }

    public void sleep(long delayMillis) {
        this.removeMessages(0);
        sendMessageDelayed(obtainMessage(0), delayMillis);
    }
};

public GameEngineView(Context context) {
    super(context);
    setFocusable(true);
    players_move = true;
    rgen = new Random();
}

public void update() {
    if(players_move) {
        Log.d(TAG, "new player x");
        px = clickx;
        py = clicky;
        GameEngineView.this.invalidate();
        switchMove();
        mRedrawHandler.sleep(100);
    } else {
        Log.d(TAG, "new ai x");
        calcAIMove();
        GameEngineView.this.invalidate();
        switchMove();            
    }

    Log.d(TAG, "update -> sleep handler");        
}


public void switchMove() {
    players_move = !players_move;
}

public void calcAIMove() {
    for(int i = 0; i < 100000; i++) {
        cx = rgen.nextInt(getWidth());
        cy = rgen.nextInt(getHeight());
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.d(TAG, "event");
    int eventaction = event.getAction();
    if(players_move && eventaction == MotionEvent.ACTION_DOWN) {
        Log.d(TAG, "action_down");
        clickx = (int) event.getX();
        clicky = (int) event.getY();
        update();
    }
    return super.onTouchEvent(event);
}

@Override
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawColor(Color.BLACK);
    Paint green = new Paint();
    green.setColor(Color.GREEN);
    Paint red = new Paint();
    red.setColor(Color.RED);

    canvas.drawCircle(px, py, 25, green);
    canvas.drawCircle(cx, cy, 25, red);
}

}

Другие вопросы по тегам