0

最近、私は Android 用のサイモン・セイズ・ゲームをやろうとしていますが、予想以上に難しくなっています。

現在、ゲームはほぼ完成しており、エンジンは問題なく動作し、ゲーム ロジックもうまく動作しています。問題は、プレーヤーがコピーできるようにシーケンスをディスプレイに表示する必要がある場合です。

サウンドは正常に動作していますが、シーケンスを実行する必要がある場合、メソッドが終了するまで何も描画されません。

各移動の間に一時停止を行う必要があると言うことが重要です。このために、私は多くのことを試しましたが、それぞれで同じ結果が得られました。

  • Thread.sleep(...);
  • SystemClock.sleep(...);
  • AsyncTask は少しだけスリープしてからフラグを立てます...
  • View.invalidate();
  • View.postInvalidate();

等々...

最良の結果は SystemClock.sleep(...) で得られます 画面には何も表示されませんが、他のすべては正常に機能します。

ボタンを描画するためにドローアブルや xml ファイルを使用していないことを説明することも重要です。代わりに、パスとペイントを使用してキャンバス上に形状を描画し、これらすべてを SurfaceView 内に描画しています。

私はここにうまく機能していないと思われるメソッドを入れています。プロジェクトにはさらにコードがありますが、機能しているようで、何も混乱していないようです。

これは、私たちが行っていることの最も重要なメソッドを持つ surfaceView クラスです。

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {

//Elementos del thread
public MySurfaceThread thread;
public boolean touched;
public boolean reproduciendo;
public boolean juega;
public boolean despierta;
public boolean llamaPausa;


//Colores
public int mediumOrchid = 0xBA55D3;
public int crimson = 0xDC143C;
public int gold = 0xFFD700;
public int cornFlowerBlue = 0x6495ED;
public int limeGreen = 0x32CD32;

public int darkOrchid = 0x9932CC;
public int fireBrick = 0xB22222;
public int goldenRod = 0xDAA520;
public int midNightBlue = 0x191970;
public int mediumSeaGreen = 0x3CB371;

public int[]colores = {mediumOrchid, crimson, gold, cornFlowerBlue, limeGreen};
public int[]tocados = {darkOrchid, fireBrick, goldenRod, midNightBlue, mediumSeaGreen};


//Coordenadas de pulsación
PointF click;

public int indice = 0;
public int repId;


private int correctas;
private Vector<Integer> secuencia = new Vector<Integer>();
private Random aleatorio;


//Sonido
SoundPool mp;
int idBell1;
int idBell2;
int idBell3;
int idBell4;


Activity padre;


public MySurfaceView(Context context, SoundPool mpObj, Random rnd) {
    super(context);
    getHolder().addCallback(this);
    aleatorio = rnd;

    //Soundloop
    mp = mpObj;
    idBell1 = mp.load(context, R.raw.sy01, 1);
    idBell2 = mp.load(context, R.raw.sy02, 1);
    idBell3 = mp.load(context, R.raw.sy04, 1);
    idBell4 = mp.load(context, R.raw.sy06, 1);


}



@Override
public void surfaceCreated(SurfaceHolder holder) {
    thread = new MySurfaceThread(getHolder(), this);
    thread.setRun(true);
    thread.start();
    Log.e("surfaceCreated", "Creado");






}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {

    boolean retry = true;
    //Detenemos el hilo
    thread.setRun(false);
    while (retry){
        try{
            thread.join();
            retry = false;
        }
        catch (InterruptedException e){}
    }

}


 @Override
public  void onDraw(Canvas canvas){
    if(reproduciendo){Log.e("onDraw", "Entro a onDraw desde repsec");}
    //Fondo negro
    canvas.drawColor(Color.BLACK);

    //Creamos el pinceles
    Paint pincel = new Paint();
    pincel.setAntiAlias(true);
    pincel.setStyle(Paint.Style.FILL);

    if (touched){//Activates when user is touching the screen
        int id = quePieza(click, canvas);
        //Log.e("onDraw", touched + " " + id);
        if(id != -1) colores[id] = tocados[id];
    }

    if(reproduciendo){//Activates when sequence must be shown, just changes colours in the  color array conveniently
        Log.e("onDraw", "repId = " + repId);
        if(repId != -1){colores[repId] = tocados[repId];}
        repId = -1;
        correctas++;
        Log.e("onDraw", "Correctas = " + correctas);
    }
    //Pintamos las piezas
    for(int i = 0; i < colores.length; i++){
        pincel.setColor(Color.rgb(Color.red(colores[i]), Color.green(colores[i]), Color.blue(colores[i])));
        pintarPiezas(i, canvas, pincel);//Paint each button according to an int code (0 to 4)
    }

    //Pintamos el texto
    pincel.setColor(Color.WHITE);
    dibujarTexto(canvas, pincel);

    //Reestablecemos colores originales
    resetColor();
    //Log.e("onDraw", "He terminado de pintar");



}

これは、ディスプレイにシーケンスを表示するためのメソッドです。

public void reproducirSecuencia(final Canvas canvas){
    reproduciendo = true;
    //TODO: HACER QUE ESTO FUNCIONE!!
    Log.e("reproducirSecuencia", "Entro a reproducir");

    int i = 0;

    while(i < secuencia.size()){

        Object o = secuencia.elementAt(i);
        int num = 0;
        if (o instanceof Integer) {num = (Integer) o;}


        SystemClock.sleep(1000);
            i++;
            reproducirSonido(num);
            repId = num;
            onDraw(canvas);
            i++;



        //Log.e("reproducirSecuencia", "repId = " + repId);
        //Log.e("reproducirSecuencia", "Invoco a pintarPiezas");





        //SystemClock.sleep(1000);
        //try {Thread.sleep(1000);}
        //catch (InterruptedException e) {e.printStackTrace();}
    }

    reproduciendo = false;
}

最後に、これはゲーム スレッドで実行されている主なメソッドです。

public void Play(Canvas canvas){


    /*if(juega){
        int piezaTocada = quePieza(click, canvas);
        reproducirSonido(piezaTocada);
        juega = false;
    }
    onDraw(canvas);*/

    onDraw(canvas);

    if (secuencia.isEmpty()){//Creamos el primer movimiento
        crearMovimiento();
        reproducirSecuencia(canvas);
    }
    else{//Sigue el juego
        if(juega){//Esperamos a que haya una jugada
            int piezaTocada = quePieza(click, canvas);//Method to find which button was pressed
            //¿Coincide con lo que buscamos?
            if(piezaTocada != 0){//Que no se cuente el botón central en el modo classic
                reproducirSonido(piezaTocada);
                if(esCorrecto(piezaTocada, secuencia.elementAt(indice), canvas)){//Check if user's move was correct or not
                    //Aumentamos el indice
                    indice++;
                    juega = false;//Acabamos con la jugada
                    if(indice > secuencia.size() - 1){//Hemos hecho toda la secuencia, ponemos un nuevo elemento y reiniciamos
                        //SystemClock.sleep(3000);

                        indice = 0;
                        crearMovimiento();

                        int buc = 0;
                        reproducirSecuencia(canvas);
                    }

                }
                else{//No es correcto...
                    gameOver(canvas);
                }
            }
        }
    }
}

シーケンスの再生中にブロックされているように見えるため、Thread クラスも入れています。

public class MySurfaceThread extends Thread {

private SurfaceHolder surface;
private MySurfaceView view;
private boolean run;
public boolean pausa;


//Metodo constructor
public MySurfaceThread(SurfaceHolder sh, MySurfaceView v){
    this.surface = sh;
    this.view = v;
}



public synchronized void pausar() {
    pausa = true;
}

public synchronized void reanudar() {
    pausa = false;
    notify();
}

public synchronized void detener() {
    run = false;
    if (pausa) reanudar();
}


public void setRun(boolean r){
    this.run = r;
}



public  void run(){





    //...
    //Creamos un canvas
    Canvas canvas;
    //Mientras run sea true pintamos
    while (run){


        canvas = null;
        try {

            canvas = surface.lockCanvas(null);
            //Usamos syncro
            synchronized (surface){

                if(canvas != null){//Si el canvas existe pintamos
                    view.Play(canvas);

                }
                while (pausa) {
                    try {
                        wait();
                    }
                    catch (Exception e) {
                    }
                }
            }
        }
        finally {
            if (canvas != null){
                //Liberamos el canvas y el soundPool
                surface.unlockCanvasAndPost(canvas);
            }
        }


    }

}

}

これが私の最初のアプリであり、最初の 1 年間のコーディングと数か月の Android での試行であるため、できるだけ明確な回答をいただければ幸いです。

どうもありがとう!

ルイス。

4

1 に答える 1

1

ダメダメダメ。メイン スレッドでスリープしないでください。UI がブロックされます。これは、まさにあなたが経験していることです。1 つのサウンドを再生してから、タイマーを設定する必要があります。タイマーが切れたら、次のサウンドを再生し、別のタイマーを設定します。

タイマーを設定する簡単な方法の 1 つは、Handler.sendMessageAtTime

于 2013-09-01T17:21:22.680 に答える