Autore Topic: Disegnare una bitmap con i Canvas, in base alla risoluzione  (Letto 2588 volte)

Offline GennyAndroid

  • Utente junior
  • **
  • Post: 116
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Ace
  • Play Store ID:
    Gennaro Petito
  • Sistema operativo:
    Windows 7
Disegnare una bitmap con i Canvas, in base alla risoluzione
« il: 11 Luglio 2012, 23:43:25 CEST »
0
Ciao ragazzi, sono quasi arrivato alla fine del mio primo gioco con l'utilizzo dei Canvas.

Adesso il mio problema è riuscire a far visualizzare un immagine nella maniera corretta su tutti i dispositivi.

Ecco un'esempio di oggetto che viene disegnato:


Codice (Java): [Seleziona]
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;

public class Cuccioli {
        private static final int BMP_COLUMNS = 3;
        private Bitmap bmp;
        private int x = 0;
        private int y = 0;
        private int xSpeed;
        private int currentFrame = 1;
        private int width;
        private int height;
        private int counterFrame = 1;

        public Cuccioli(GameView gameView, Bitmap bmp, int x,int y) {
                this.width = bmp.getWidth() / BMP_COLUMNS;
                this.height = bmp.getHeight();
                this.bmp = bmp;
                this.puntoVisibile = x;

                this.x = x;
                this.y = y;
                xSpeed = 5;
        }

        private void update(int xSpeed) {
            x-= xSpeed;
            if(counterFrame%5 == 0){
                currentFrame = ++currentFrame % BMP_COLUMNS;
            }    
            counterFrame++;
        }

        public void onDraw(Canvas canvas, int xS, int xF, int xSpeed, boolean aggiornamento) {
                if(aggiornamento)
                        update(xSpeed);        
                if(puntoVisibile+width >= xS && puntoVisibile <= xF){
                        int srcX = currentFrame * width;
                        Rect src = new Rect(srcX, 0, srcX+width, height);
                        Rect dst = new Rect(x, y, x + width, y + height);
                        canvas.drawBitmap(bmp, src, dst, null);
                }      
        }
}

La parte interessata per il disegno della bitmap è questa:

Codice (Java): [Seleziona]
Rect src = new Rect(srcX, 0, srcX+width, height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);

Così comè, sia che si tratti di una galaxy next sia che si tratti di un S2 o addirittura un tablet l'immagine che viene disegnata avrà sempre le dimensioni di 20x20

Grazie per l'attenzione aspetto vostri consigli

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Disegnare una bitmap con i Canvas, in base alla risoluzione
« Risposta #1 il: 12 Luglio 2012, 08:00:50 CEST »
0
In tutta sincerità non ho compreso il problema o la domanda...  :-[
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Disegnare una bitmap con i Canvas, in base alla risoluzione
« Risposta #2 il: 12 Luglio 2012, 08:57:18 CEST »
+1
Ci sono due modi per farlo, uno è più pratico e impiega pochissimo, l'altro è più macchinoso.

MODO MACCHINOSO:

Tu parti con un reference device e "scegli" una risoluzione, diciamo 400x300 così facciamo i calcoli in modo più semplice.
Hai il tuo sprite che è 20x20, quindi è il 5% della risoluzione orizzontale e il 6,66% della risoluzione verticale.

A questo punto tu sai che per trovare la "proporzione" giusta devi semplicemente moltiplicare la risoluzione orizzontale per 0,05 e quella verticale per 0,0666. Così le dimensioni relative del tuo sprite saranno sempre le stesse.

MA perdi l'aspect ratio, cioè se il telefono ha un aspect ratio diverso non preservi le proporzioni e ti vengono sprite schiacciati o oblunghi!

Per ovviare a questo problema devi semplicemente modificare la formula.
Nel caso specifico tu hai 400x300 che sono 4/3 cioè 1,333.
Se prendi la risoluzione orizzontale, 0,05 e la moltiplichi per 1,333 ottieni guardacaso 0,0666 (beh più o meno).

Quindi ricapitolando.

Siano sX e sY la risoluzione dello schermo in larghezza ed altezza, iX e iY la risoluzione dello sprite (altezza e larghezza) in pixel e sia 400x300 il tuo reference screen fai così.

Per prima cosa calcoli percentualeX come iX/400 (in questo caso 0,05).
Poi calcoli l'aspectratioSprite come iY/iX (in questo caso 1).

A questo punto puoi salvare questi due valori nella tua classe cucciolo.
Per quanto riguarda lo schermo calcoli la proporzione tra le coordinate reference X e quelle vere X (perchè è la coordinata dominante), per comodità fai lo stesso con Y e poi calcoli l'aspect ratio.
scalaX = sX/400;
scalaY = sY/300;
aspectratioSchermo= sY/sX;

A questo punto quello che succede è semplice.

La posizione X dello sprite (alto a destra) la trovi con posizioneX*scalaX;
La posizione Y dello sprite (alto a destra) la trovi con posizioneY*scalaY;
La dimensione X la trovi con sX*percentualeX;
La dimensione Y la trovi con sX*percentualeX*aspectratioSprite*aspectratioSchermo;

MODO SEMPLICE:

Crei un buffer con l'aspect ratio e la risoluzione di riferimento che preferisci, ci disegni tutto e poi alla fine copi (e allarghi) direttamente il buffer sullo schermo. Problema risolto.

Ovviamente dovresti fare un test per vedere l'orientamento del device e il suo aspect ratio, quindi scegliere un buffer di dimensione "compatibile".. ma è banale. Per esempio controlli che la risoluzione X sia maggiore di Y e se lo è fai un buffer da 400x300, se non lo è lo fai da 300x400.
Quindi in teoria dovresti coprire solo 4 casi:

4:3
3:4
16:9
9:16

Rer risoluzioni di 4:3 una buona scelta è appunto 400x300 oppure 640x480 o ancora 800x600.
Per risoluzioni di 16:9, non avendo senso scegliere 1600x900 potresti scegliere una 800x450 o 960x540 o ancora 640x360.

 ;-)

Offline GennyAndroid

  • Utente junior
  • **
  • Post: 116
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Ace
  • Play Store ID:
    Gennaro Petito
  • Sistema operativo:
    Windows 7
Re:Disegnare una bitmap con i Canvas, in base alla risoluzione
« Risposta #3 il: 12 Luglio 2012, 13:29:07 CEST »
0
Era proprio quello che cercavo, entrambe le soluzioni sono ideali, certo come hai detto tu la prima è molto macchinosa ma voglio intraprenderla lo stesso, voglio ringraziarti, perchè quando ho aperto il posto sapevo sarebbe stato difficile ottenere una risposta esaudiente.

A questo punto provo ad eseguire quello che mi hai spiegato e ti chiedo di tenere d'occhio il post perchè in giornata se riscontrerò problemi posterò alcune domande, ancora grazie a dopo

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:Disegnare una bitmap con i Canvas, in base alla risoluzione
« Risposta #4 il: 12 Luglio 2012, 14:02:50 CEST »
0
come reference resolution usa HVGA chè è il valore 1 usato anche da google
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline GennyAndroid

  • Utente junior
  • **
  • Post: 116
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Ace
  • Play Store ID:
    Gennaro Petito
  • Sistema operativo:
    Windows 7
Re:Disegnare una bitmap con i Canvas, in base alla risoluzione
« Risposta #5 il: 12 Luglio 2012, 15:32:23 CEST »
0
Off-Topic:
Tu parti con un reference device e "scegli" una risoluzione, diciamo 400x300 così facciamo i calcoli in modo più semplice.
Hai il tuo sprite che è 20x20, quindi è il 5% della risoluzione orizzontale e il 6,66% della risoluzione verticale.

A questo punto tu sai che per trovare la "proporzione" giusta devi semplicemente moltiplicare la risoluzione orizzontale per 0,05 e quella verticale per 0,0666. Così le dimensioni relative del tuo sprite saranno sempre le stesse.

MA perdi l'aspect ratio, cioè se il telefono ha un aspect ratio diverso non preservi le proporzioni e ti vengono sprite schiacciati o oblunghi!

Sono già fermo al primo punto:
- ho scelto come reference device la risoluzione del mio Samsung Galaxy Ace ovvero 480x320
- utilizzo uno sprite 40x40
- ho calcolato le percentuali della risoluzione orizzontale e verticali : Orizzontale = 8,3333% Verticale= 12,5%

ecco quello che ho fatto fino ad adesso
GameView:
Codice (Java): [Seleziona]
public class GameView extends SurfaceView{
               
       
        //VARIABILI GENERALI
                private GameLoopThread gameLoopThread;
                private Bitmap bmp;
                Context contesto;      
                Sprite s1;

        public GameView(final Context context, AttributeSet attrs) {
                super(context, attrs);
                this.contesto = context;
                gameLoopThread = new GameLoopThread(this);
                getHolder().addCallback(new SurfaceHolder.Callback() {

                        public void surfaceDestroyed(SurfaceHolder holder) {
                                boolean retry = true;
                                gameLoopThread.setRunning(false);
                                while (retry) {
                                        try {
                                                gameLoopThread.join();
                                                retry = false;
                                        } catch (InterruptedException e) {}
                                }
                        }

                        public void surfaceCreated(SurfaceHolder holder) {             
                                bmp = BitmapFactory.decodeResource(getResources(), R.drawable.sprite);
                                s1 = new Sprite(bmp, getWidth()/2, getHeight()/2);
                               
                                gameLoopThread.setRunning(true);
                                gameLoopThread.start();                        
                        }

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

        @Override
        protected void onDraw(Canvas canvas) {         
                s1.onDraw(canvas);     
               
                Paint paint = new Paint();
                paint.setColor(Color.CYAN);
                canvas.drawLine(getWidth()/2, 0, getWidth()/2, getHeight(), paint);
                canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, paint);
               
                canvas.drawText("Misure Reference device: "+getWidth()+"x"+getHeight(), 10, 26, paint);
                canvas.drawText("Misure Sprite: 40x40", 10, 40, paint);
                canvas.drawText("Percentuale della Risoluzione Orizzontale: 8,3333%", 10, 54, paint);
                canvas.drawText("Percentuale della Risoluzione Verticale: 12,5%", 10, 68, paint);
        }      
}

Classe Sprite:
Codice (Java): [Seleziona]
public class Sprite {
       
        private Bitmap bmp;
        private int x = 0;
        private int y = 0;
        private int width;
        private int height;

        public Sprite(Bitmap bmp, double x, double y) {
                this.width = bmp.getWidth();
                this.height = bmp.getHeight();
                this.bmp = bmp;
                this.x = (int) x;
                this.y = (int) y;
        }

        public void onDraw(Canvas canvas) {
                Rect src = new Rect(0, 0, width, height);
                Rect dst = new Rect(x, y, x + width, y + height);
                canvas.drawBitmap(bmp, src, dst, null);
        }
}

480x320

1280x752


non ho ben capito come applicare le due percentuali alle dimensioni dello sprite

Offline GennyAndroid

  • Utente junior
  • **
  • Post: 116
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Ace
  • Play Store ID:
    Gennaro Petito
  • Sistema operativo:
    Windows 7
Re:Disegnare una bitmap con i Canvas, in base alla risoluzione
« Risposta #6 il: 12 Luglio 2012, 16:07:47 CEST »
0
Nel frattempo ho provato a sperimentare una soluzione tutta mia, in pratica all'interno della classe Sprite faccio la proporzione fra la risoluzione dello schermo e quella della bitmap in questo modo:

Codice (Java): [Seleziona]
public class Sprite {  
       
        private Bitmap bmp;
        private int x = 0;
        private int y = 0;
        private int width;  
        private int height;
        private GameView gameView;

        public Sprite(GameView gameView, Bitmap bmp, double x, double y) {
                this.gameView = gameView;
                this.width = 40*gameView.getWidth()/480;
                this.height = 40*gameView.getHeight()/320;
                //this.width = bmp.getWidth();
                //this.height = bmp.getHeight();
               
                this.bmp = bmp;
                this.x = (int) x;
                this.y = (int) y;
        }

        public void onDraw(Canvas canvas) {
                Rect src = new Rect(0, 0, bmp.getWidth(), bmp.getHeight());
                Rect dst = new Rect(x, y, x + width, y + height);
                canvas.drawBitmap(bmp, src, dst, null);
        }
}

ottenendo questo risultato:

480x320

1280x752


Ovviamente per adesso è sgranata perchè ho inserito solo la bitmap per la cartella drawable mdpi.

Che ne pensate è giusto fare in questo modo?

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Disegnare una bitmap con i Canvas, in base alla risoluzione
« Risposta #7 il: 12 Luglio 2012, 17:01:43 CEST »
+1
Si è praticamente la stessa cosa   ;-)

Per quanto riguarda il primo post hai calcolato 8.33% e 12.5% e quindi nella classe sprite del primo post devi mettere:

this.width = gameView.getWidth()*0.0833;
this.height = gameView.getHeight()*0.125;


Offline GennyAndroid

  • Utente junior
  • **
  • Post: 116
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Ace
  • Play Store ID:
    Gennaro Petito
  • Sistema operativo:
    Windows 7
Re:Disegnare una bitmap con i Canvas, in base alla risoluzione
« Risposta #8 il: 12 Luglio 2012, 17:21:48 CEST »
0
Si è praticamente la stessa cosa   ;-)

Per quanto riguarda il primo post hai calcolato 8.33% e 12.5% e quindi nella classe sprite del primo post devi mettere:

this.width = gameView.getWidth()*0.0833;
this.height = gameView.getHeight()*0.125;

Ok perfetto sei un genio, grazie, aspetto a mettere risolto perchè vorrei provare ad implementare il discorso per non compromettere l'aspect ratio