English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Jeu de puzzle Android : jouer de la base à l'application, changement de gestes

Croire que chacun d'entre nous a joué à des jeux de puzzle pendant notre enfance, aujourd'hui, avec la généralisation des téléphones mobiles, un nombre croissant de jeux est jouable sur les téléphones mobiles, donc, pour relire notre enfance, j'ai écrit ce jeu de puzzle simple, et cela peut également approfondir certaines connaissances de base d'Android.
Comme d'habitude, d'abord le visuel :

Ici, pour illustrer l'effet, j'ai très peu désorganisé les images, ce qui peut être modifié dans le code.

Tout d'abord, il y a une image par défaut, qui peut être utilisée pour assembler le puzzle, ou vous pouvez choisir l'image de votre choix pour assembler le puzzle, le processus de puzzle enregistre le nombre de mouvements, et un message de sourire apparaît lorsque le jeu est gagné, indiquant la victoire et le nombre de mouvements utilisés.

ps : ceux qui sont intéressés peuvent continuer à l'étendre ici, par exemple, ajouter des options de difficulté de jeu, diviser l'image en plus petits carrés, etc.

Idée générale : découper la grande image en petits carrés, enregistrer les informations de chaque petit carré dans un tableau, afficher chaque petit carré avec un GridLayout, et marquer un petit carré comme une case vide (la case vide peut être échangée avec des cases adjacentes), ajouter des événements de clic et des événements de gestes sur chaque petit carré du GridLayout et sur tout l'écran, chaque fois qu'il y a un clic ou un geste, vérifier si le petit carré peut être déplacé, et enfin afficher un message de victoire lorsque le jeu est gagné.
Pas de temps à perdre, passons directement à la mise en œuvre étape par étape du processus de puzzle game.

1.Classe relative aux petits carrés.

C'est un ensemble de variables, de classes et de méthodes Setter et Getter pour chaque petit carré, utilisé pour gérer les informations de chaque petit carré découpé de la grande image. C'est simple, juste des variables et des méthodes Setter et Getter, voici le code~

/**
 * Created by yyh on 2016/10/21.
 */
public class GameItemView{
  /**
   * Les informations de chaque petit carré
   */
  //La position réelle de chaque petit carré en x,
  private int x=0;
  //La position réelle de chaque petit carré en y,
  private int y=0;
  //L'image de chaque petit carré,
  private Bitmap bm;
  //La position de l'image de chaque petit carré en x,
  private int p_x=0;
  //La position de l'image de chaque petit carré en y.
  private int p_y=0;
  public GameItemView(int x, int y, Bitmap bm) {
    super();
    this.x = x;
    this.y = y;
    this.bm = bm;
    this.p_x=x;
    this.p_y=y;
  }
  public int getX() {
    return x;
  }
  public void setX(int x) {
    this.x = x;
  }
  public int getY() {
    return y;
  }
  public Bitmap getBm() {
    return bm;
  }
  public void setBm(Bitmap bm) {
    this.bm = bm;
  }
  public int getP_x() {
    return p_x;
  }
  public void setP_x(int p_x) {
    this.p_x = p_x;
  }
  public int getP_y() {
    return p_y;
  }
  public void setP_y(int p_y) {
    this.p_y = p_y;
  }
  /**
   * Vérifier si la position de chaque petit carré est correcte
   * @return
   */
  public boolean isTrue(){
    if (x==p_x&&y==p_y){
      return true;
    }
    return false;
  }
}

2.La mise en page de l'interface principale

L'interface principale est simple, un bouton pour changer l'image, une ImageView pour afficher l'image originale, un GridLayout pour jouer au puzzle game, et enfin, un TextView pour afficher le nombre de pas nécessaires pour terminer ce puzzle. La mise en page est la suivante :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  >
  <LinearLayout
    android:id="@"+id/ll"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    >
    <Button
      android:id="@"+id/bt_choice"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Choisir une image"
      android:adjustViewBounds="true"
      />
  </LinearLayout>
  <ImageView
    android:id="@"+id/iv"
    android:layout_below="@id/ll"
    android:adjustViewBounds="true"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/haizei"
    android:layout_marginTop="3dp"
    ></ImageView>
  !-- l'interface principale du jeu-->
  <GridLayout
    android:layout_marginTop="3dp"
    android:layout_below="@id/iv"
    android:id="@"+id/gl"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:columnCount="5"
    android:rowCount="3"
    android:adjustViewBounds="true"
    >
  </GridLayout>
  <TextView
    android:id="@"+id/tv_step"
    android:layout_below="@id/gl"
    android:layout_marginTop="3dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="已用步数:0"
    android:textSize="26sp"
    />
</RelativeLayout>

3.Ouvrir l'image et sélectionner une image

Pour configurer l'événement de clic sur le bouton, appeler la méthode startActivityForResult(Intent intent, int requestCode); pour obtenir une image.

 bt_choice.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        Intent intent= new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image",/*
        startActivityForResult(intent, CHOICE_PHOTO);//ouvrir l'album
      }
    });

Redéfinir la méthode onActivityResult(int requestCode, int resultCode, Intent data) dans l'Activity pour afficher l'image sélectionnée et initialiser le jeu. (Après avoir sélectionné l'image, il faut procéder à la coupe de l'image et au début du jeu de puzzle.)

 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode){
      case CHOICE_PHOTO:
        if (resultCode == RESULT_OK){
          //vérifier la version du système d'exploitation du téléphone
          if (Build.VERSION.SDK_INT >=19){
            handleImageOnKitKat(data);
            //obtenir l'image dans l'imageview
            BitmapDrawable bitmapDrawable = (BitmapDrawable) photo.getDrawable();
            bt_tupan = bitmapDrawable.getBitmap();
            //retirer les petits carrés du GridLayout existant,
            removeGameItem();
            //couper la nouvelle image en petits carrés et l'ajouter à GridLayout.
            setGameItem();
            //commencer le jeu
            startGame();
          }else {
            handleImageBeforeKitKat(data);
            //obtenir l'image dans l'imageview
            BitmapDrawable bitmapDrawable = (BitmapDrawable) photo.getDrawable();
            bt_tupan = bitmapDrawable.getBitmap();
             //retirer les petits carrés du GridLayout existant,
            removeGameItem();
            //couper la nouvelle image en petits carrés et l'ajouter à GridLayout.
            setGameItem();
            //commencer le jeu
            startGame();
          }
        }
    }
  }

Ensuite, voici la fonction d'implémentation de la méthode spécifique pour choisir l'image. Les commentaires sont clairs, sans entrer dans les détails. Notre point focal est l'implémentation détaillée des puzzles et des gestes. Il y a de nombreuses manières de choisir une image. Sans plus attendre, il existe des frameworks prêts à l'emploi sur le web.

 //le téléphone n'est pas supérieur à19de la méthode de récupération des données
  private void handleImageBeforeKitKat(Intent data) {
    Uri uri = data.getData();
    String imagePath = getImagePath(uri, null);
    displayImage(imagePath);
  }
  /**
   * le téléphone est supérieur à19de la méthode de récupération des données
   * @param data
   */
  @TargetApi(Build.VERSION_CODES.KITKAT)
  private void handleImageOnKitKat(Intent data) {
    String imagePath=null;
    Uri uri=data.getData();
    if (DocumentsContract.isDocumentUri(this,uri)){
      //Si l'url est de type document, traiter l'id du document.
      String docId=DocumentsContract.getDocumentId(uri);
      if ("com.android.providers.media.documents".equals(uri.getAuthority())){
        String id =docId.split(":")[1];//Extraire l'id sous forme numérique;
        String selection= MediaStore.Images.Media._ID+"="+id;
        imagePath=getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection);
      }else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())){
        Uri contenturi= ContentUris.withAppendedId(Uri.parse("content:",//downloads/public_downloads"),Long.valueOf(docId));
        imagePath=getImagePath(contenturi,null);
      }
    }else if ("content".equalsIgnoreCase(uri.getScheme())){
      //Si l'uri n'est pas de type document, traiter de manière ordinaire.
      imagePath=getImagePath(uri,null);
    }
    displayImage(imagePath);
  }
  /**
   * Affichage de l'image
   * @param imagePath //L'image du chemin.
   */
  private void displayImage(String imagePath) {
    if (imagePath != null) {
      Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
      if (isHeigthBigWidth(bitmap)) {
        Bitmap bt = rotaingImageView(bitmap);//tourner l'image90 degrés.
        Bitmap disbitmapt = ajustBitmap(bt);
        photo.setImageBitmap(disbitmapt);
      } else {
        Bitmap disbitmap = ajustBitmap(bitmap);
        photo.setImageBitmap(disbitmap);
      }
    }
  }
  /**
   * ajuster l'orientation de l'image
   * @param bitmap
   * @return
   */
  private Bitmap rotaingImageView(Bitmap bitmap) {
    //action de rotation d'image
    Matrix matrix = new Matrix();;
    matrix.postRotate(270);
    // créer une nouvelle image
    Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
        bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    return resizedBitmap;
  }
  /**
   * obtenir le chemin d'accès à l'image
   * @param externalContentUri
   * @param selection
   * @return
   */
  private String getImagePath(Uri externalContentUri, String selection) {
    String path = null;
    Cursor cursor = getContentResolver().query(externalContentUri, null, selection, null, null);
    if (cursor != null) {
      if (cursor.moveToFirst()) {
        path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
      }
    }
    cursor.close();
    return path;
  }

4. Le processus de formation des petits carrés du puzzle.}}

Regardant les petits carrés, utiliser GridLayout est le plus pratique. Donc, utiliser un GridLayout pour afficher les petits carrés coupés de la grande image, utiliser un tableau d'ImageView pour enregistrer les informations des petits carrés, et par défaut, définir le dernier petit carré comme un carré vide.

Tout d'abord, les variables nécessaires. Les commentaires sont clairs.

 /**
   * Créer plusieurs petits cadres de jeu à l'aide d'un tableau binaire
   */
  private ImageView [][] iv_game_arr=new ImageView[3][5];
  /**
   *Interface principale du jeu
   *
   */
  private GridLayout gl_game_layout;
  //Lignes et colonnes des petits carrés
  private int i;
  private int j;
  /**Variable globale pour le carré vide*/
  private ImageView iv_null_imagview;

Ensuite, il s'agit de récupérer l'image à partir d'Imageview et de couper l'image suivant un certain nombre de lignes et de colonnes (ici, le puzzle est réglé pour3rang5Colonne). Enregistrer les informations des petits carrés coupés dans un tableau d'ImageView. Définir un Tag et un écouteur d'événement de clic pour chaque petit carré.

 private void setGameItem() {
    //Ajuster la taille de l'image
    Bitmap abitmap=ajustBitmap(bt_tupan);
    int ivWidth=getWindowManager().getDefaultDisplay().getWidth()/5;//Largeur et hauteur de chaque petit carré de jeu. Couper en carré
    int tuWidth=abitmap.getWidth()/5; 
    for (int i=0;i<iv_game_arr.length;i++){
      for (int j=0;j<iv_game_arr[0].length;j++){
        //Diviser la grande image en petits carrés
        Bitmap bm=Bitmap.createBitmap(abitmap,j*tuWidth,i*tuWidth,tuWidth,tuWidth);
        iv_game_arr[i][j]=new ImageView(this);
        iv_game_arr[i][j].setImageBitmap(bm);//Définir le motif de chaque petit carré
        iv_game_arr[i][j].setLayoutParams(new RelativeLayout.LayoutParams(ivWidth, ivWidth));
        //Définir l'intervalle entre les carrés
        iv_game_arr[i][j].setPadding(2, 2, 2, 2);
        iv_game_arr[i][j].setTag(new GameItemView(i, j, bm)); //Lié aux données personnalisées
        iv_game_arr[i][j].setOnClickListener(new View.OnClickListener() {
        .......
);

Bien sûr, les images que nous choisissons ne peuvent pas toutes être de tailles standard, donc, avant de couper l'image, nous devons l'ajuster. Ajuster l'image à5:3de proportion. (Ainsi, après coupure,3rang5Seulement les petits carrés de la colonne peuvent être coupés correctement) ici, je calcule à l'avance l'intervalle entre chaque petit carré pour width.

 //Ajuster la taille de l'image
  private Bitmap ajustBitmap(Bitmap bitmap) {
    int width=getWindowManager().getDefaultDisplay().getWidth()-(iv_game_arr[0].length-1)*2;
    int heigth=width/5*3;
    Bitmap scaledBitmap=Bitmap.createScaledBitmap(bitmap, width, heigth, true);
    return scaledBitmap;
  }

Placer chaque petit carré dans le GridLayout.

 /**
   * Placer les petits carrés dans le GridLayout
   */
  private void startGame() {
    tv_step.setText("Nombre de pas utilisés : 0");
    for (i = 0; i <iv_game_arr.length; i++){
      for (j = 0; j <iv_game_arr[0].length; j++){
        gl_game_layout.addView(iv_game_arr[i][j]);
      }
    }
    //Définir le dernier carré en tant que carré vide défini.
    setNullImageView(iv_game_arr[i-1][j-1]);

5. Processus de clic et de jugement des gestes des petits carrés

C'est le cœur du jeu de puzzle, comprendre les règles de déplacement et de changement des petits carrés, c'est aussi comprendre le jeu de puzzle.

Pour l'événement de clic, d'abord obtenir diverses informations du carré cliqué (position, motif) et des informations de position du carré vide, juger si le carré cliqué est adjacent au carré vide, si oui, échanger les données de déplacement (en utilisant TranslateAnimation pour réaliser l'animation de déplacement), sinon pas d'opération.
a. Méthode de jugement de l'adjacence entre le carré cliqué et le carré vide

/**
   *  Juger si le carré cliqué actuel est adjacent à un carré vide.
   * @param imageView Le carré cliqué actuel
   * @return true : adjacent. false : non adjacent.
   */
  public boolean isAdjacentNullImageView(ImageView imageView){
    //Obtenir la position actuelle du carré vide et la position du carré cliqué
    GameItemView null_gameItemView = (GameItemView) iv_null_imagview.getTag();
    GameItemView now_gameItem_view = (GameItemView) imageView.getTag();
   if(null_gameItemView.getY()==now_gameItem_view.getY()&&now_gameItem_view.getX()+1==null_gameItemView.getX()){//Le bloc cliqué est au-dessus du bloc vide
      return true;
    }else if(null_gameItemView.getY()==now_gameItem_view.getY()&&now_gameItem_view.getX()==null_gameItemView.getX()+1){//Le bloc cliqué est en dessous du bloc vide
      return true;
    }else if(null_gameItemView.getY()==now_gameItem_view.getY()+1&&now_gameItem_view.getX()==null_gameItemView.getX()){//Le bloc cliqué est à gauche du bloc vide
      return true;
    }else if(null_gameItemView.getY()+1==now_gameItem_view.getY()&&now_gameItem_view.getX()==null_gameItemView.getX(){ ////Le bloc cliqué est à droite du bloc vide
      return true;
    }
    return false;
  }

b. Ensuite, si les carrés sont adjacents, entrez dans la méthode d'échange de données du carré
Il y a une méthode de surcharge ici, animation ou non. Les échanges de données sans animation sont prévus pour le mélange des pièces du jeu à l'initialisation. Voici le code de remplacement principal. Après chaque échange, il faut vérifier si le jeu est gagné (c'est-à-dire si le puzzle est terminé~).

    //Obtenir les données du carré cliqué lié
      GameItemView gameItemView = (GameItemView) itemimageView.getTag();
      //Définir le motif du carré vide en tant que carré cliqué
      iv_null_imagview.setImageBitmap(gameItemView.getBm());
      //Obtenir les données du carré vide lié
      GameItemView null_gameItemView = (GameItemView) iv_null_imagview.getTag();
      //Échanger des données (transférer les données du bloc cliqué au bloc vide)}
      null_gameItemView.setBm(gameItemView.getBm());
      null_gameItemView.setP_x(gameItemView.getP_x());
      null_gameItemView.setP_y(gameItemView.getP_y());
      //Définir le bloc cliqué comme bloc vide.
      setNullImageView(itemimageView);
      if (isStart){
        isGameWin();//Lorsque cela réussit, une boîte de dialogue contextuelle apparaîtra.
      }

c.les paramètres d'animation lors de l'échange
Lorsque l'animation est configurée, d'abord juger la direction de déplacement, configurer une animation de déplacement différente selon la direction, puis écouter la fin de l'animation, effectuer des opérations d'échange de données. C'est-à-dire que après b., si les blocs adjacents entrent dans la méthode d'échange de données de bloc, puis exécuter l'animation.

 //1.créer une animation, configurer la direction, la distance de déplacement
//juger la direction, configurer l'animation
    if (itemimageView.getX()>iv_null_imagview.getX()){//Le bloc cliqué est au-dessus du bloc vide
      //descendre
      translateAnimation = new TranslateAnimation(0.1f,-itemimageView.getWidth(),0.1f,0.1f);
    }else if (itemimageView.getX()<iv_null_imagview.getX()){//Le bloc cliqué est en dessous du bloc vide
      //monter
      boolean f=itemimageView.getX()<iv_null_imagview.getX();
      //Log.i("click block","sssssssssssssssssssssssss"+f);
      translateAnimation = new TranslateAnimation(0.1f,itemimageView.getWidth(),0.1f,0.1f);
    }else if (itemimageView.getY()>iv_null_imagview.getY()){//Le bloc cliqué est à gauche du bloc vide
      //déplacer à droite
      translateAnimation=new TranslateAnimation(0.1f,0.1f,0.1f,-itemimageView.getWidth());
    else if(itemimageView.getY()<iv_null_imagview.getY()){//Le bloc cliqué est à droite du bloc vide
      //Déplacer vers la gauche
      translateAnimation=new TranslateAnimation(0.1f,0.1f,0.1f,itemimageView.getWidth());
    }
    //2.Définir divers paramètres d'animation
    translateAnimation.setDuration(80);
    translateAnimation.setFillAfter(true);
    //3.Définir l'écouteur d'animation
    translateAnimation.setAnimationListener(new Animation.AnimationListener() {
      @Override
      public void onAnimationStart(Animation animation) {
        isAminMove=true;
      }
      @Override
      public void onAnimationEnd(Animation animation) {
        //La fin de l'animation, échanger les données
        ......
      }
 //L'exécution de l'animation
    itemimageView.startAnimation(translateAnimation);

La procédure de clic est terminée, passons à l'événement de détection des gestes. C'est-à-dire que non seulement vous pouvez déplacer le carré en cliquant dessus, mais vous pouvez également le déplacer avec des gestes.

One. Créer un objet gestuelle
Effectuer les opérations liées aux gestes dans la méthode onFling.

 //Créer un objet gestuelle
    gestureDetector =new GestureDetector(this, new GestureDetector.OnGestureListener() {
      @Override
      public boolean onDown(MotionEvent e) {
        return false;
      }
      @Override
      public void onShowPress(MotionEvent e) {
      }
      @Override
      public boolean onSingleTapUp(MotionEvent e) {
        return false;
      }
      @Override
      public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
      }
      @Override
      public void onLongPress(MotionEvent e) {
      }
      @Override
      public boolean onFling(MotionEvent e1, MotionEvent e2float velocityX, float velocityY) {
      //Opérations liées aux gestes
      ......
  }

Puis nous faisons des opérations spécifiques dans la méthode onFling

Deux. Déterminer la direction du déplacement du geste
Obtenir différentes directions de déplacement en fonction de différentes valeurs de retour.

 /**
   * Augmenter le glissement du geste, déterminer si le glissement du geste est vertical ou horizontal
   * @param start_x Point de départ du geste en x
   * @param start_y Point de départ du geste en y
   * @param end_x Point final du geste en x
   * @param end_y Point final du geste en y
   * @return 1Haut 2Bas 3Gauche 4Droite
   */
  public int getDirctionByGesure(float start_x,float start_y,float end_x,float end_y){
    boolean isLeftOrRight =(Math.abs(end_x-start_x)>Math.abs(end_y-start_y))?true:false; //Est-ce que c'est une direction latérale
    if(isLeftOrRight){//Gauche et droite
      boolean isLeft=(end_x-start_x)>0?false:true;
      if(isLeft){
        return 3;
      }else {
        return 4;
      }
    }else{//Haut et bas
      boolean isUp=(end_y-start_y)>0?false:true;
      if (isUp){
        return 1;
      }else {
        return 2;
      }
    }
  }

Trois. Déterminer si le déplacement est possible en fonction du bloc vide et de la direction du déplacement, puis procéder au déplacement.
Comme c'est un geste, le déplacement doit certainement être des blocs autour du bloc vide, donc la clé est de déterminer la direction du bloc vide à déplacer, puis de déterminer si le déplacement est possible en fonction de la direction, puis de procéder au déplacement. (La méthode changeDateByImageView() est l'opération spécifique de données d'échange et de déplacement de blocs. C'est la méthode de l'événement de clic.)

/**Redéfinir la méthode changeByDirGes(int type);
   * Déplacer les blocs adjacents au bloc vide en fonction de la direction du geste.
   * @param type Valeur de retour de la direction 1Haut 2Bas 3Gauche 5Droite
   * @param isAnim Si il y a une animation true: il y a une animation, false: il n'y a pas d'animation
   */
  public void changeByDirGes(int type,boolean isAnim){
    //1Obtenir la position actuelle du bloc vide.
    GameItemView null_gameItemView = (GameItemView) iv_null_imagview.getTag();
    int new_x=null_gameItemView.getX();
    int new_y=null_gameItemView.getY();
    //2Selon la direction, définir les coordonnées des positions adjacentes correspondantes.
    if (type==1){//Cela signifie que le bloc vide est au-dessus du bloc à déplacer.
      new_x++;
    }else if (type==2){//Le bloc vide est en dessous du bloc à déplacer
      new_x--;
    }else if (type==3){//Le bloc vide est à gauche du bloc à déplacer
      new_y++;
    }else if (type==4){//Le bloc vide est à droite du bloc à déplacer
      new_y--;
    }
    //3Juger de l'existence de cette nouvelle coordonnée
    if(new_x>=0&&new_x<iv_game_arr.length&&new_y>=0&&new_y<iv_game_arr[0].length){
      //Il existe, peut être déplacé et échanger des données
      if(isAnim){//Il y a une animation
        changeDateByImageView(iv_game_arr[new_x][new_y]);
      }else{
        changeDateByImageView(iv_game_arr[new_x][new_y],isAnim);
      }
    }else{
      //Ne rien faire
    }
  }

Très bien, l'événement de geste est terminé avec succès~

Il y a deux points à noter ici.1Tout d'abord, définir la méthode onTouchEvent() de l'Activity actuelle, transférer l'événement de toucher à la gestion des gestes, puis également définir la méthode dispatchTouchEvent(), dans laquelle il faut également transférer l'événement de geste vers le bas, sinon sans transférer l'événement de geste vers le bas, dans le GridLayout, seul l'événement de clic peut être déclenché et l'événement de geste ne fonctionne pas.2Doit ajouter un drapeau pour indiquer si l'objet est en train de se déplacer. Si l'objet est en train de se déplacer, ne rien faire, sinon à chaque clic sur le petit bloc, même pendant le déplacement, cela déclenche l'événement de clic et déclenche à nouveau le déplacement d'animation, ce qui peut entraîner une mauvaise expérience utilisateur.

 @Override
  public boolean onTouchEvent(MotionEvent event) {
    return gestureDetector.onTouchEvent(event);
  }
  @Override
  public boolean dispatchTouchEvent(MotionEvent ev) {
    gestureDetector.onTouchEvent(ev);
    return super.dispatchTouchEvent(ev);
  }

6Méthode pour mélanger les blocs au début du jeu et afficher un Toast à la fin du jeu.

Le code est simple, mettons directement le code, dont le Toast pop est un Toast avec une animation personnalisée View.

 //Mélanger l'ordre des images de manière aléatoire
  public void randomOrder(){
    //Nombre de désordres, pour faciliter les tests, il est réglé très petit.
    for (int i=0;i<5;i++){
      //Échanger des données selon le geste, sans animation.
      int type = (int) (Math.random()*4)+1;
      // Log.i("sssssssssfdfdfd", "Nombre d'échanges"+i+"valeur de type"+type);
      changeByDirGes(type, false);
    }
  }
  /**
   * Méthode de jugement de la fin du jeu
   */
  public void isGameWin(){
    //Indicateur de victoire du jeu
    boolean isGameWin =true;
    //Parcourir chaque petit carré
    for (i = 0; i <iv_game_arr.length; i++){
      for (j = 0; j <iv_game_arr[0].length; j++){
        //Ne pas juger des carrés vides, sauter
        if (iv_game_arr[i][j]==iv_null_imagview){
          continue;
        }
        GameItemView gameItemView= (GameItemView) iv_game_arr[i][j].getTag();
        if (!gameItemView.isTrue()){
          isGameWin=false;
          //Sortir de la boucle interne
          break;
        }
      }
      if (!isGameWin){
        //Sortir de la boucle externe
        break;
      }
    }
    //Selon une variable commutatrice, jugez si le jeu est terminé, et donnez un提示when it is.
    if (isGameWin){
      // Toast.makeText(this, "Victoire de jeu", Toast.LENGTH_SHORT).show();
      ToastUtil.makeText(this, "Félicitations, vous avez gagné le jeu, il a fallu ",+step+"étape", ToastUtil.LENGTH_SHORT, ToastUtil.SUCCESS);
      step=0;
    }
  }

Très bien, la partie importante est terminée, il y a encore un Toast personnalisé View ici, une explication détaillée du Toast sera dans l'article suivant, ici nous expliquons simplement le processus d'implémentation du Toast personnalisé.
Tout d'abord, créez une classe SuccessToast (le sourire inclut l'œil gauche, l'œil droit et l'arc du sourire). Nous fournissons le processus central. Utilisons l'animation pour réaliser le processus de dessin dynamique du sourire.

 @Override
  protected void onDraw(Canvas canvas) {}}
    super.onDraw(canvas);
    mPaint.setStyle(Paint.Style.STROKE);
    //Dessiner l'arc de sourire
    canvas.drawArc(rectF, 180, endAngle, false, mPaint);
    mPaint.setStyle(Paint.Style.FILL);
    if (isSmileLeft) {
    //Si c'est un œil gauche, dessiner l'œil gauche
      canvas.drawCircle(mPadding + mEyeWidth + mEyeWidth / 2, mWidth / 3, mEyeWidth, mPaint);
    }
    if (isSmileRight) {
    //Si il y a un œil, dessiner l'œil droit.
      canvas.drawCircle(mWidth - mPadding - mEyeWidth - mEyeWidth / 2, mWidth / 3, mEyeWidth, mPaint);
    }
  }
 /**
   * Méthode de début de l'animation
   * @param startF Valeur de début
   * @param endF Valeur de fin
   * @param time Durée de l'animation
   * @return
   */
  private ValueAnimator startViewAnim(float startF, final float endF, long time) {
    //Configurer les valeurs de début et de fin de valueAnimator.
    valueAnimator = ValueAnimator.ofFloat(startF, endF);
    //Configurer la durée de l'animation
    valueAnimator.setDuration(time);
    //Configurer l'interpolateur. Contrôler la vitesse de variation de l'animation
    valueAnimator.setInterpolator(new LinearInterpolator());
    //Configurer l'écouteur. Écouter les changements de valeur de l'animation et agir en conséquence.
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator valueAnimator) {
        mAnimatedValue = (float) valueAnimator.getAnimatedValue();
        //si la valeur de value est inférieure à 0.5
        if (mAnimatedValue < 0.5) {
          isSmileLeft = false;
          isSmileRight = false;
          endAngle = -360 * (mAnimatedValue);
          //si la valeur de value est comprise entre 0.55et 0.7entre
        } else if (mAnimatedValue > 0.55 && mAnimatedValue < 0.7) {
          endAngle = -180;
          isSmileLeft = true;
          isSmileRight = false;
          //autres
        } else {
          endAngle = -180;
          isSmileLeft = true;
          isSmileRight = true;
        }
        //redessiner
        postInvalidate();
      }
    });
    if (!valueAnimator.isRunning()) {
      valueAnimator.start();
    }
    return valueAnimator;
  }

Ensuite, créez un fichier success_toast_layout.xml pour terminer la mise en page de toast. La mise en page est de gauche à droite (une vue de sourire à gauche, un TextView d'indication à droite).

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@"+id/root_layout"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:background="#00000000"
  android:orientation="vertical">
  <LinearLayout
    android:id="@"+id/base_layout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="25dp"
    android:layout_marginLeft="30dp"
    android:layout_marginRight="30dp"
    android:layout_marginTop="25dp"
    android:background="@drawable"/background_toast"
    android:orientation="horizontal">
    <LinearLayout
      android:id="@"+id/linearLayout"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:gravity="center">
      <com.example.yyh.puzzlepicture.activity.Util.SuccessToast
        android:id="@"+id/successView"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_gravity="center_vertical|left"
        android:layout_margin="10px"
        android:gravity="center_vertical|left" />
    </LinearLayout>
    <TextView
      android:id="@"+id/toastMessage"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:gravity="center_vertical"
      android:padding="10dp"
      android:text="New Text" />
  </LinearLayout>
</LinearLayout>

最后新建一个ToastUtil类,管理自定义的Toast.

/**
 * Created by yyh on 2016/10/25.
 */
public class ToastUtil {
  public static final int LENGTH_SHORT = 0;
  public static final int LENGTH_LONG = 1;
  public static final int SUCCESS = 1;
  static SuccessToast successToastView;
  public static void makeText(Context context, String msg, int length, int type) {
    Toast toast = new Toast(context);
    switch (type) {
      case 1: {
        View layout = LayoutInflater.from(context).inflate(R.layout.success_toast_layout, null, false);
        TextView text = (TextView) layout.findViewById(R.id.toastMessage);
        text.setText(msg);
        successToastView = (SuccessToast) layout.findViewById(R.id.successView);
        successToastView.startAnim();
        text.setBackgroundResource(R.drawable.success_toast);
        text.setTextColor(Color.parseColor("#FFFFFF"));
        toast.setView(layout);
        break;
      }
    }
    toast.setDuration(length);
    toast.show();
  }
}

Ainsi, vous pouvez appeler ce Toast personnalisé dans ManiActivity.
Bien, terminé.

Code source du jeu :Jeu de puzzleprocessus de réalisation
gitHub:Jeu de puzzle.

Voici la totalité du contenu de cet article, j'espère qu'il vous aidera dans vos études et que vous soutiendrez également le tutoriel de cri.

Déclaration : le contenu de cet article est tiré du réseau, propriété de l'auteur original, contribué et téléchargé par les utilisateurs d'Internet. Le site web ne détient pas de droits de propriété, n'a pas été édité par l'homme et n'assume aucune responsabilité juridique. Si vous trouvez du contenu suspect de violation de droits d'auteur, veuillez envoyer un e-mail à notice#w.3Pour signaler une violation, veuillez envoyer un e-mail à codebox.com (remplacez # par @) et fournir des preuves pertinentes. Une fois vérifié, le site supprimera immédiatement le contenu suspect de violation de droits d'auteur.

Vous pourriez aussi aimer