Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Déplacement d'une bille via les
accéléromètres et la dalle tactile

Ce tuto vous montre comment animer une bille à l'écran en tenant compte des informations retournées par vos accéléromètres. Il vous suffira de pencher votre périphérique Android dans différentes directions pour déplacer la bille. La seconde partie de ce tuto vous montre comment déplacer la bille grâce à la dalle tactile : appuyez sur la bille avec votre doigt pouis déplacez le pour repositionner la bille.

Voici la vidéo expliquant les différents codes présentés. Vous retrouverez ces codes à la suite de la vidéo.


Déplacement d'une bille via les accéléromètres et la dalle tactile

Utilisation des accéléromètres

Notez que l'exemple ci-dessous présuppose qu'une image nommée blueball.png a été placée dans le répertoire drawable-mdpi. Si vous souhaitez gérer différentes densités d'écran, il est aussi possible d'utiliser les autre répertoires "drawable" (ldpi, hdpi, xhdpi, xxhpdi et xxxhdpi). Si vous manquez d'inspiration pour l'image de la bille, vous pouvez faire une recherche sur un moteur de recherche. Vous y trouverez certainement votre bonheur.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
package com.infinisoftware.megaball;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.view.View;

public class BallView extends View implements SensorEventListener {

    private Paint paint = new Paint();
    private Bitmap ballBitmap;
    
    private int imageWidth;
    private int imageHeight;
    private int currentX;
    private int currentY;
    

    public BallView( Context context ) {
        super( context );
        this.init( context );
    }
    
    public BallView( Context context, AttributeSet attrSet ) {
        super( context, attrSet );
        this.init( context );
    }

    private void init( Context context ) {
        this.ballBitmap = 
                BitmapFactory.decodeResource(getResources(), R.drawable.blueball );
        this.imageWidth = ballBitmap.getWidth();
        this.imageHeight = ballBitmap.getHeight();
    }
    
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        this.currentX = (getWidth() - this.imageWidth) / 2;
        this.currentY = (getHeight() - this.imageHeight) / 2;    
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawBitmap( this.ballBitmap, this.currentX, this.currentY, this.paint );
    }
    
    private void moveImage( float x, float y ) {
        this.currentX += (int) x; 
        this.currentY += (int) y;                
        
        if ( this.currentX < 0 ) {
            this.currentX = 0;
        } else if ( this.currentX + this.imageWidth > this.getWidth() ){
            this.currentX = this.getWidth() - this.imageWidth;
        }

        if ( this.currentY < 0 ) {
            this.currentY = 0;
        } else if ( this.currentY + this.imageHeight > this.getHeight() ){
            this.currentY = this.getHeight() - this.imageHeight;
        }

        this.invalidate();
    }
    
    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {
    }
    
    @Override
    public void onSensorChanged(SensorEvent event) {
        float x = event.values[0]; 
        float y = event.values[1]; 
        //float z = event.values[2]; 
        
        this.moveImage( -x*5, y*5 );
    }


}
Aquisition des données des accéléromètres et déplacement de la bille

Intégration du widget dans une activité

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
package com.infinisoftware.megaball;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.os.Bundle;

public class MainActivity extends Activity { 
    
    private BallView ballView;
    private SensorManager sensorManager = null;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ballView = new BallView( this );
        setContentView( ballView );
        
        sensorManager = (SensorManager) getSystemService( SENSOR_SERVICE );
        
        /* --- For verify if accelerometers are present into the device ---
        List<Sensor> sensors = sensorManager.getSensorList( Sensor.TYPE_ALL );
        for( Sensor sensor : sensors ) {
            Log.i( "DEBUG", sensor.getName() + " --- " + sensor.getVendor() );
        } */
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener( 
                ballView, 
                sensorManager.getDefaultSensor( Sensor.TYPE_ACCELEROMETER ), 
                sensorManager.SENSOR_DELAY_GAME );
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener( ballView );
    }
    
}
Intégration du widget dans une activité.

Les méthodes onResume et onPause permettent d'enregistrer notre widget ballView au niveau du SensorManager si l'activité est en cours d'affichage et de désabonner le widget quand l'activité passe en arrière plan. Cela permet d'économiser la batterie quand l'application n'est pas visible (moins d'appels de méthodes).

Affichage du résultat

Jouez à pivoter votre périphérique afin de faire déclencher les accéléromètres et déplacer la bille sur l'écran.

Ajout d'événements pour permettre un déplacement via la dalle tactile

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
 97 
 98 
 99 
 100 
 101 
 102 
 103 
 104 
 105 
 106 
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 
 115 
 116 
 117 
 118 
 119 
 120 
 121 
 122 
 123 
 124 
 125 
 126 
 127 
 128 
 129 
 130 
 131 
 132 
 133 
 134 
 135 
 136 
 137 
 138 
package com.infinisoftware.megaball;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

public class BallViewWithGesture extends View 
        implements SensorEventListener, GestureDetector.OnGestureListener {

    private Paint paint = new Paint();
    private Bitmap ballBitmap;
    private Vibrator vibrator;
    private GestureDetector gestureDetector;

    private int imageWidth;
    private int imageHeight;
    private int currentX;
    private int currentY;
    

    public BallViewWithGesture( Context context ) {
        super( context );
        this.init( context );
    }
    
    public BallViewWithGesture( Context context, AttributeSet attrSet ) {
        super( context, attrSet );
        this.init( context );
    }

    private void init( Context context ) {
        this.vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        this.gestureDetector = new GestureDetector( context,  this );  
                
        this.ballBitmap =
                BitmapFactory.decodeResource(getResources(), R.drawable.blueball );
        this.imageWidth = ballBitmap.getWidth();
        this.imageHeight = ballBitmap.getHeight();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        this.currentX = (getWidth() - this.imageWidth) / 2;
        this.currentY = (getHeight() - this.imageHeight) / 2;    
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawBitmap( this.ballBitmap, this.currentX, this.currentY, this.paint );
    }
    
    private void moveImage( float x, float y ) {
        this.currentX += (int) x; 
        this.currentY += (int) y;                
        
        if ( this.currentX < 0 ) {
            this.currentX = 0;
        } else if ( this.currentX + this.imageWidth > this.getWidth() ){
            this.currentX = this.getWidth() - this.imageWidth;
        }

        if ( this.currentY < 0 ) {
            this.currentY = 0;
        } else if ( this.currentY + this.imageHeight > this.getHeight() ){
            this.currentY = this.getHeight() - this.imageHeight;
        }

        this.invalidate();
    }
    
    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {
    }
    
    @Override
    public void onSensorChanged(SensorEvent event) {
        float x = event.values[0]; 
        float y = event.values[1]; 
        //float z = event.values[2]; 
        
        this.moveImage( -x*5, y*5 );
    }

    @Override  
    public boolean onTouchEvent(MotionEvent event) {  
          return this.gestureDetector.onTouchEvent(event);  
    }  

    @Override
    public boolean onDown(MotionEvent event) {
        this.vibrator.vibrate( 20 );        // Time in ms
        return true;
    }

    @Override
    public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void onLongPress(MotionEvent arg0) {
        // TODO Auto-generated method stub
    }

    @Override
    public boolean onScroll(MotionEvent srcEvent, MotionEvent destEvent, float x, float y) {
        this.moveImage(-x, -y);
        return true;
    }

    @Override
    public void onShowPress(MotionEvent arg0) {
        // TODO Auto-generated method stub
    }

    @Override
    public boolean onSingleTapUp(MotionEvent arg0) {
        // TODO Auto-generated method stub
        return false;
    }

}
Ajout des événements relatifs au tactile