0

センサーを使ってアンドロイドでゲームを作ることを学ぼうとしています。私がやろうとしているのは、加速度センサーを使用して画面内をボールが動くようにすることです。実際、私はその一部をやりました。x と y の加速度が変化すると、ボールが画面内を移動します。しかし、私の問題は、滑らかに見えないことです。ボールが連続したパスで画面に描かれていないようです。このアプリのクラスを使用しSurfaceView、メイン スレッドとは別のスレッドで描画を行いました。
コードの下の部分は私のMainActivityクラスのもので、センサー関連の部分です:

@Override
    public void onSensorChanged(SensorEvent event) {
        // TODO Auto-generated method stub
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            long actualTime = System.currentTimeMillis();
            long delta_t = actualTime - lastUpdate;

            lastUpdate = actualTime;

            ax = event.values[0];
            ay = event.values[1];

            if (ax > 0) {
                isleft = true;
                delta_x = (float) (0.005 * ax * delta_t * delta_t);

            }
            if (ax < 0) {
                isleft = false;
                delta_x = (float) (-0.005 * ax * delta_t * delta_t);

            }
            if (ay > 0) {
                isdown = true;
                delta_y = (float) (0.005 * ay * delta_t * delta_t);

            }
            if (ay < 0) {
                isdown = false;
                delta_y = (float) (-0.005 * ay * delta_t * delta_t);

            }

            getBallPos();
        }

    }

    private void getBallPos() {
        delta_x /= 10000;
        delta_y /= 10000;

        for (int i = 1; i <= 10000; i++) {
            if (isleft)
                ballview.setX_loc(ballview.getX_loc() - delta_x);

            if (!isleft)
                ballview.setX_loc(ballview.getX_loc() + delta_x);

            if (isdown)
                ballview.setY_loc(ballview.getY_loc() + delta_y);

            if (!isdown)
                ballview.setY_loc(ballview.getY_loc() - delta_y);
        }

    }

コードの下の部分はBallGame、拡張するクラスからSurfaceViewのもので、別のスレッドで描画を行います。

    @Override
        public void run() {
            // TODO Auto-generated method stub
            while (isItOk) {
                if (!holder.getSurface().isValid()) {
                    continue;
                }
                canvas = holder.lockCanvas();
                canvas.drawARGB(255, 150, 150, 10);
                // canvas.drawLine(lineStartX, lineStartY, lineEndX, lineEndY,
                // paint);
                checkBoundaries();
                canvas.drawBitmap(ball, x_loc, y_loc, null);
                holder.unlockCanvasAndPost(canvas);

            }
        }

        private void checkBoundaries() {

            if (x_loc > canvas.getWidth() - ballWidth) {
                x_loc = canvas.getWidth() - ballWidth;

            }
            if (y_loc > canvas.getHeight() - ballHeight) {
                y_loc = canvas.getHeight() - ballHeight;

            }
            if (x_loc < 0) {
                x_loc = 0;

            }
            if (y_loc < 0) {
                y_loc = 0;

            }
        }

前もって感謝します。

4

1 に答える 1

1

次の 2 つの問題があると思います。

まず、メソッドでボールの位置を更新していることですonSensorChanged。このメソッドはシステムによって呼び出され、呼び出しが一定の頻度で行われることは保証されていません。この場合、ボールの動きはこれらの呼び出しに依存します。より良い方法は、値を書き込むためのメソッドと読み取り用のスレッドを描画するための両方の方法でアクセスできる変数として最後axを保存することだと思います。次に、一定の頻度でキャンバスを再描画できる描画スレッドでボールの位置を計算できます。ayonSensorChanged

これは、ループ中にスレッドを描画するという 2 番目の問題につながります。キャンバスが再描画される頻度は制御されません。システムにとって大きな負荷です。より良い方法は、リフレッシュ レート (たとえば、毎秒 50 フレーム) を選択し、この頻度で描画を更新することです。Thread.sleep()関数を呼び出すことができるwhileループの最後で実行できます。while ループの開始時にフレーム描画がいつ開始されたかを測定しlong frameStartTime = System.currentTimeMillis()、while ループの終了時に呼び出すことができます。

long sleepTime = refreshInterval-(System.currentTimeMillis()-frameStartTime );
もし (睡眠時間 > 0) {
    Thread.sleep(sleepTime);
}

(50 fps の場合、refreshInterval = 1000/50 = 20 ms)。

この呼び出しは、フレームのリフレッシュ間隔からボールの描画に使用された時間を引いた時間だけスレッドをスリープさせます。適切なリフレッシュ レートを選択すると、システムの負荷が低くなり、再描画により多くの時間を割くことができます。

于 2013-08-25T17:06:01.060 に答える