Проблема с представлением Invalidate () и обработчиком - PullRequest
0 голосов
/ 13 января 2011

Я пытаюсь решить эту проблему уже более 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 ]

2 голосов
/ 13 января 2011

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

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

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

Oneспособ реализовать это - просто отложить вызов на calcAIMove() и switchMove(), поместив его в Runnable и используя Handler.postDelayed() или аналогичный.

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

0 голосов
/ 13 января 2011

хорошо, поэтому ответ, предоставленный 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);
}

}

0 голосов
/ 13 января 2011

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

...