Parlez-vous Android ?

Game Development

By Excilys

Alexandre THOMAS

@AleksThomas

althomas@excilys.com

Développeur Android et JEE chez Excilys.

Formateur Android.

http://androidkickstartr.com

AndroidAnnotations

http://androidannotations.org/

Talks

  • 2012: Devoxx France, Devoxx Anvers, PAUG, Open World Forum.
  • 2013: DevConfRussia, DroidCon Paris.

Sommaire

  1. Introduction
  2. Android et les jeux-vidéos
  3. Graphics
  4. Multitouch API
  5. Système de fichiers
  6. Audio
  7. Les Bitmaps
  8. Bonus: Accéléromètre et KeyEvents
  9. Projet SpaceShip

Introduction

Publiée par NBC News.

http://www.android.com/devices/
http://www.ouya.tv/

Les jeux vidéos sous Android

En règle générale,

  • Une activity
  • Une view
  • Gestion manuel des changements de configuration

<activity android:name=".MainActivity"
android:screenOrientation="portrait"
android:configChanges="keyboard|keyboardHidden|orientation">

Cycle de vie

onResume = resume the game

onPause = pause the game

Graphics

Première méthode


public class CustomView extends View {
    // ...
 
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
 
        // make your changes
        canvas.drawRect(...);
        canvas.drawPath(...)
 
        canvas.restore();
    }
}
						

Important: Le rendu est fait sur l'UIThread.

La bonne méthode

SurfaceView


  • Vue contenant un objet Surface.
  • Permet d'effectuer le rendu sur un thread différent
  • SurfaceHolder

Code

Récupérer le canvas utilisé pour dessiner sur la "Surface"


							Canvas canvas = getHolder().lockCanvas()
						

Affichage de la "Surface" à l'écran


							getHolder().unlockCanvasAndPost(Canvas canvas)
						

Savoir si la surface est prête


SurfaceHolder.Callback.surfaceCreated(SurfaceHolder holder)
SurfaceHolder.Callback.surfaceDestroyed(SurfaceHolder holder)
						
ou

							boolean isCreated = holder.getSurface().isValid();
						

Exercice

Relatif au projet "Spaceship" !


Exercice

Exercices d'entraînement.

Exercice

Dessiner dans une SurfaceView

  1. Commencez par créer une nouvelle application Android.
  2. Créez une vue custom héritant de SurfaceView en partant du code diponible ici.
  3. Dessinez une forme (rectangle, cercle, ligne...) afin de vérifier que votre vue est fonctionnelle.
  4. Dessiner un triangle qui représentera notre "spaceship" en utilisant un Path.



N'oubliez pas d'effectuer le rendu dans un autre thread.

Multitouch API

uses-feature


<uses-feature android:name="android.hardware.touchscreen.multitouch" 
	android:required="true"/>						
						

Permet de vérifier que le device est compatible.


Autres exemples:


<uses-feature android:name="android.hardware.bluetooth" />
<uses-feature android:name="android.hardware.camera" />
						


// Récupérer le type d'action
int action = event.getActionMasked();

// Récupérer l'index
int actionIndex = event.getActionIndex();

// Récupérer l'id du pointeur
int pointerId = event.getPointerId(actionIndex);
						

Actions possibles


switch (action) {
	case MotionEvent.ACTION_UP:
	    // premier touch uniquement
	case MotionEvent.ACTION_POINTER_UP:
	    // autres touch
	case MotionEvent.ACTION_DOWN:
	    // premier touch uniquement
	case MotionEvent.ACTION_POINTER_DOWN:
	    // autres touch
	case MotionEvent.ACTION_MOVE:
	    // tous les touch
}
						

Versions inférieures à l'api 8

La classe MotionEventCompat, disponible dans la librairie support-v4, intégre la nouvelle API.

Exercice

Multitouch

  1. Dessinez autant de cercles qu'il y a de doigts en contact de l'écran.
  2. Supprimez-les au fur et à mesure que l'utilisateur enlève ses doigts.
  3. Bonus: faites en sorte que l'utilisateur puisse déplacer les cercles.


Veillez à avoir compris la différence entre actionIndex et pointerId

Exercice

Intégrons le multitouch à notre jeu

  1. Faites en sorte que le triangle avance vers le premier doigt de l'utilisateur.
  2. Dessinez un cercle à l'endroit où l'utilisateur posera son 2e doigt.

Système de fichiers

Les Ressources


  • Ressources du dossier res/: layout, values, animator, anim, drawables...
  • Assets

Les Assets


  1. Bien plus flexible.
  2. Liberté des sous-dossiers.

Your project/
|_ assets/
   |_music/
   |_bfx/
   |_image/
|_src/
|_res/
					

Code


try {
    // à partir d'un Context on récupère l'AssetManager
    AssetManager assetManager = getAssets();

    // plusieurs méthodes à disposition pour charger un fichier 
    InputStream inputStream = assetManager.open("dir1/file_name");
    AssetFileDescriptor fd = assetManager.openFd("dir1/file_name");

} catch (IOException e) {
    Log.e(TAG, "problem during files loading", e);
}

Audio

Types de STREAM


  • STREAM_TYPE = flux
  • VOICE_CALL, MUSIC, NOTIFICATIONS...

  • Contrôle du volume:
    Activity.setVolumeControlStream (int streamType)

Musique de fond

On va utiliser le MediaPlayer.


try {
    // on set le fichier audio
    mediaPlayer.setDataSource(...);

    // on prépare l'audio
    mediaPlayer.prepare();

    // on commence à jouer l'audio
    mediaPlayer.start();
    mediaPlayer.pause();
    mediaPlayer.stop();

} catch (IOException e) {
    Log.e(TAG, "Problem during audio loading", e);
}
						

Documentation

Sound effects

Besoin de jouer plusieurs son rapidement et simultanément.

SoundPool

  • Chargement en mémoire,
  • Peu de latence,
  • Jouer simultanément.

// Création d'un SoundPool
// 10 = nb max de sons joués simultanément
// STREAM_MUSIC = type de stream sur lequel seront joué les sons
SoundPool soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, O);
AssetFileDescriptor fd = assetManager.openFd("path_to_the_file");

// pré-charge le son
sound1 = soundPool.load(fd, 1);

// ...

// on joue le son correspondant à l'ID donné
soundPool.play(sound1, 1, 1, 0, 0, 1);
						

Exercice

Faites du bruit !

  1. Créer une nouvelle classe SoundFXManager pour charger/jouer vos sons SFX.
  2. Créer une nouvelle classe MusicPlayer, responsable de jouer la musique de fond.


bfxr.net, pour générer des sons de jeux en ligne.

dig.ccmixter.org, pour télécharger des musiques de jeux libres de droit.

Audio Focus

Être un bon citoyen Android


AudioManager am = ...;

// On demande le focus de l'audio
am.requestAudioFocus(AudioManager.OnAudioFocusChangeListener l, int streamType, ...);

// On restitue le focus de l'audio
am.abandonAudioFocus(AudioManager.OnAudioFocusChangeListener l);
						

Code



// AudioManager.OnAudioFocusChangeListener
@Override
public void onAudioFocusChange(int focusChange) {
    if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
        // Récupération du son suite à une perte
        // on continue de jouer si on revient d'une pause
        // ou on rejoue le son depuis le début si c'était un stop
        // ou encore on restitue le niveau de volume
        // tout dépend du type de AUDIOFOCUS_LOSS
    } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
        // perte de l'audio focus pour une longue durée
        // mettre en stop
    } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
        // perte de l'audio focus pour une petite durée
        // mettre en pause
    } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
        // perte de l'audio focus pour une petite durée et 
        // possibilité de jouer un son en même temps
        // Baisser le volume
    }
}
						

Les bitmaps

Créer un bitmap


BitmapFactory.decodeFile("path_name");
//...
BitmapFactory.decodeFileDescriptor(aFileDescriptor);
//...
BitmapFactory.decodeResource(res, R.drawable.my_bitmap);
						

Dessiner un bitmap

Utiliser le canvas!


// Dessiner un bitmap
Canvas.drawBitmap(...);
						

Libérer un bitmap

Versions inférieures à Honeycomb 3.0 (Api 11)

Quand un Bitmap est inutilisé -> Bitmap.recycle()

Native heap vs Dalvik's heap.

Recycler un bitmap

Depuis Honeycomb: on peut recycler un bitmap.


BitmapFactory.Options options = new BitmapFactory.Options();
options.inBitmap = recycledBitmap;
// ...
BitmapFactory.decodeFile("my_file_path", options);
// ou
BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
// ...
						

Exercice

Ajouter des images.

http://opengameart.org/

http://www.cgtextures.com/

http://untamed.wild-refuge.net/rmxpresources.php?characters

http://www.lostgarden.com/

Accéléromètre et Key events (Facultatif)

THE END

Merci pour votre attention