0

私はこの問題を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の移動計算が完了すると、緑色のボールが最初に描画されます。したがって、両方の動きが同時に描かれます。

これをどのように達成するのだろうか: -プレーヤーのクリック -緑のボールが描かれる -AIが計算する -赤いボールが描かれる -など..

ウェブを検索すると、多くのゲームループの例が見つかりましたが、それらはすべて、一定のポーリングを行うスレッドが必要です..プログラム全体が順次実行されるため、これがなくても可能であるはずです..そうですか?

アドバイスを期待しています。

ありがとう、デイブ

4

3 に答える 3

2

ゲームがどのように機能するかは次のとおりです。

  1. ユーザーが行動する
  2. ゲームビューが更新されました
  3. ゲームはCPUのターンに切り替わります
  4. CPUプレイヤーの思考をシミュレートするためにスリープします(移動計算が簡単な場合)
  5. CPUの動きを計算する
  6. ゲームビューが更新されました
  7. ゲームはプレイヤーのターンに切り替わります

このようなターンベースのゲームでは、定期的なポーリングは必要ありません。スリープする必要がある唯一の場所はステップ 4 であるため、他の領域からそれを削除できます (update()単に への遅延呼び出しである古いメソッドは必要ありませんupdateGame())。

calcAIMove()これを実装する 1 つの方法は、 andの呼び出しを単に遅延switchMove()させて、Runnableand を使用するなどの方法で呼び出すことHandler.postDelayed()です。

CPU の番のときにタッチ イベントを無効にする方法がわかりません。まだ呼び出されている場合switchMove()、他の多くの問題につながる可能性があります...update()

于 2011-01-13T00:29:40.943 に答える
0

わかりましたので、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);
}

}

于 2011-01-13T08:26:28.720 に答える
0

ゲーム ループでは、TimerTask のインスタンスを使用して、greenBall と他の描画タスクの間の遅延を確保できます。Snake や LunarLander などのゲーム チュートリアルは、View を無効にする必要がある場合とその必要がある場合についての優れたリファレンスです。これが少し役立つことを願っています!

于 2011-01-13T00:01:14.657 に答える