Autore Topic: Un piccolo aiuto  (Letto 272 volte)

Offline Ibernato

  • Nuovo arrivato
  • *
  • Post: 7
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    S4 mini
  • Sistema operativo:
    windows 10
Un piccolo aiuto
« il: 25 Dicembre 2015, 18:18:35 CET »
0
Salve, dovrei sostenere l'esame di android a gennaio, però mi è venuta la voglia di creare un piccolo giochino (che secondo me è molto semplice da realizzare) però non sono molto pratico sulle classi da usare. Leggendo sul web ho visto che si usano OPENGL o SurfaceHolder e io ho iniziato a fare qualcosa con quest'ultima. Vi posto le classi e poi la domanda.

Codice (Java): [Seleziona]
public class MainActivity extends Activity {

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       // setContentView(R.layout.activity_main);
        // requesting to turn the title OFF
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        // making it full screen
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        // set our MainGamePanel as the View
        setContentView(new MainGamePanel(this));
        Log.d(TAG, "View added");
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG, "Destroying...");
        super.onDestroy();
    }

    @Override
    protected void onStop() {
        Log.d(TAG, "Stopping...");
        super.onStop();
    }

}

Codice (Java): [Seleziona]
package com.example.mitic.shootfruit;


import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class MainGamePanel extends SurfaceView implements Callback {
    private static final String TAG = MainGamePanel.class.getSimpleName();

    private MainThread thread;
    private Canon canon;

    public MainGamePanel(Context context) {
        super(context);
        // Aggiungiamo callback(this) alla superfice per intercettare gli eventi
        getHolder().addCallback(this);
        canon = new Canon(BitmapFactory.decodeResource(getResources(), R.drawable.batteria_cannone),50,50);
        thread = new MainThread(getHolder(),this);
        // Rendiamo attivo il nostro pannello di gioco in modo che possa gestire gli eventi
        setFocusable(true);
    }

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

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread.setRunning(true);
        thread.start();

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        //Il thread deve arrestarsi e aspettare che finisca
        boolean retry = true;
            while(true){
                try{
                    thread.join();
                    retry = false;
                }catch(InterruptedException e){
                    //riproviamo ad arrestare il thread
                }
            }
    }

    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            // deleghiamo la gestione degli eventi al cannone
            canon.handleActionDown((int)event.getX(), (int)event.getY());
            // Verifichiamo se il tocco avviene nella
            // parte bassa dello schermo per uscire
            if (event.getY() > getHeight() - 50) {
                thread.setRunning(false);

                ((MainActivity)getContext()).finish();
            } else {
                Log.d(TAG, "Coords: x=" + event.getX() + ",y=" + event.getY());
            }
        }

        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            if (canon.isTouched()) {
                // il droidecannone viene trascinato
                canon.setX((int)event.getX());
                canon.setY((int)event.getY());
            }
        }

        if (event.getAction() == MotionEvent.ACTION_UP) {
            // tocco rilasciato
            if (canon.isTouched()) {
                canon.setTouched(false);
            }
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //Riempiamo la "tela" di nero
        canvas.drawColor(Color.rgb(0,127,255));
        canon.draw(canvas);
    }

    public void update() {
        // controllo collisioni con la parete destra
        if (canon.getSpeed().getxDirection() == Speed.DIRECTION_RIGHT
                && canon.getX() + canon.getBitmap().getWidth() / 2 >= getWidth()) {
            canon.getSpeed().toggleXDirection();
        }
        // controllo collisioni con la parete sinistra
        if (canon.getSpeed().getxDirection() == Speed.DIRECTION_LEFT
                && canon.getX() - canon.getBitmap().getWidth() / 2 <= 0) {
            canon.getSpeed().toggleXDirection();
        }
        // controllo collisioni verso il basso
        if (canon.getSpeed().getyDirection() == Speed.DIRECTION_DOWN
                && canon.getY() + canon.getBitmap().getHeight() / 2 >= getHeight()) {
            canon.getSpeed().toggleYDirection();
        }
        // controllo collisioni verso l'alto
        if (canon.getSpeed().getyDirection() == Speed.DIRECTION_UP
                && canon.getY() - canon.getBitmap().getHeight() / 2 <= 0) {
            canon.getSpeed().toggleYDirection();
        }
        // aggiornamento del droide
        canon.update();
    }

}

Codice (Java): [Seleziona]
package com.example.mitic.shootfruit;

import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;

public class MainThread extends Thread{

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

    // Numero desiderato di FPS
    private final static int    MAX_FPS = 60;
    // Numero massimo di FPS da saltare
    private final static int    MAX_FRAME_SKIPS = 5;
    // Periodo frame
    private final static int    FRAME_PERIOD = 1000 / MAX_FPS;

    //SurfaceHolder per accedere alla superficie fisica
    private SurfaceHolder surfaceHolder;
    //L'attuale view che cattura gli input e disegna sulla superficie
    private MainGamePanel gamePanel;
    //flag booleano per lo stato di gioco
    private boolean running;

    public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
        super();
        this.surfaceHolder = surfaceHolder;
        this.gamePanel = gamePanel;
    }

    public void setRunning (boolean running) {
        this.running = running;
    }

    @Override
    public void run() {
        Canvas canvas;
        Log.d(TAG, "Starting game loop");

        long beginTime;         // il tempo quando inizia il ciclo
        long timeDiff;          // tempo impiegato per il ciclo
        int sleepTime;          // ms per lo stato di sleep (può essere <0)
        int framesSkipped;      // numero di frame saltati

        sleepTime = 0;

        while (running) {
            canvas=null;
            //Proviamo a bloccare la "tela" per la modifica dei pixel sulla superficie
            try {
                canvas = this.surfaceHolder.lockCanvas();
                synchronized (surfaceHolder) {
                    beginTime = System.currentTimeMillis();
                    framesSkipped = 0;  // resettiamo i frame saltati
                    // Aggiornamento dello stato di gioco
                    this.gamePanel.update();
                    // disegna la "tela" (canvas) nel pannello
                    this.gamePanel.onDraw(canvas);
                    // Calcoliamo quanto tempo prende il ciclo
                    timeDiff = System.currentTimeMillis() - beginTime;
                    // Calcoliamo sleepTime
                    sleepTime = (int)(FRAME_PERIOD - timeDiff);

                    if (sleepTime > 0) {
                        // Caso ottimale se > 0
                        try {
                            // mandiamo il thread a dormire per un breve periodo
                            // molto utile per risparmiare batteria
                            Thread.sleep(sleepTime);
                        } catch (InterruptedException e) {}
                    }

                    while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
                        // Abbiamo bisogno di recuperare
                        this.gamePanel.update(); // aggiornamento senza rendering
                        sleepTime += FRAME_PERIOD;      // aggiungere frame period per il controllo del frame successivo
                        framesSkipped++;
                    }
                }
            } finally {
                // Se scatta l'eccezione la superficie non viene lasciata
                // in uno stato incoerente
                if (canvas != null) {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            } //fine finally
        }
    }
}

Così il background dell'applicazione si crea facendo setCOntentView(new MainGamePanel(this)) però se io voglio impostare un file xml e poi disegnare il canvas come si fa? Ho provate a fare setContentView(R.layout.miofile.xml) e istanziato la classe MainGamePanel ma non mi crea poi l'immagine che dovrei disegnare con il canvas.
COmunque per essere più preciso vorrei capire come usare layout xml e canvas insieme. Nel mio layout sotto devono esserci due button a sinistra per muovere a destra e snistra ed un pulsante shoot per sparare. Poi nel mio canvas c'è un cannone e in alto degli oggetti che scendono e poi quando vengono colpiti dal proiettile scompaiono e ricompaiono sopra.
Spero sia stato chiaro.
« Ultima modifica: 25 Dicembre 2015, 20:23:11 CET da Ibernato »