diff --git a/src/main/java/sae/chuzzle/GestionnaireTactile.java b/src/main/java/sae/chuzzle/GestionnaireTactile.java new file mode 100644 index 0000000..3f9fecf --- /dev/null +++ b/src/main/java/sae/chuzzle/GestionnaireTactile.java @@ -0,0 +1,140 @@ +package sae.chuzzle; + +import android.view.MotionEvent; +import android.view.View; + +public class GestionnaireTactile implements View.OnTouchListener { + + private static final int NB_LIGNES = EtatJeu.NB_LIGNES; + private static final int NB_COLONNES = EtatJeu.NB_COLONNES; + private static final float SEUIL_DIRECTION_PX = 10f; + + private final VueGrille vueGrille; + private final EtatJeu etatJeu; + private final Controleur controleur; + + private float touchDebutX, touchDebutY; + private int ligneTouchee, colonneTouchee; + private Boolean estLigne; + private int indexGlissement; + private float decalagePx; + private float tailleCase; + + public GestionnaireTactile(VueGrille vueGrille, + EtatJeu etatJeu, + Controleur controleur) { + this.vueGrille = vueGrille; + this.etatJeu = etatJeu; + this.controleur = controleur; + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + + if (etatJeu.estTerminee()) { + return false; + } + + switch (event.getAction()) { + + case MotionEvent.ACTION_DOWN: + tailleCase = calculerTailleCase(); + gererDebut(event); + return true; + + case MotionEvent.ACTION_MOVE: + gererMouvement(event); + return true; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + gererFin(event.getAction() == MotionEvent.ACTION_UP); + return true; + } + + return false; + } + + private void gererDebut(MotionEvent event) { + touchDebutX = event.getX(); + touchDebutY = event.getY(); + estLigne = null; + decalagePx = 0f; + + float margeGauche = (vueGrille.getWidth() - tailleCase * NB_COLONNES) / 2f; + float margeHaut = (vueGrille.getHeight() - tailleCase * NB_LIGNES) / 2f; + + ligneTouchee = (int) ((touchDebutY - margeHaut) / tailleCase); + colonneTouchee = (int) ((touchDebutX - margeGauche) / tailleCase); + + ligneTouchee = Math.max(0, Math.min(NB_LIGNES - 1, ligneTouchee)); + colonneTouchee = Math.max(0, Math.min(NB_COLONNES - 1, colonneTouchee)); + } + + private void gererMouvement(MotionEvent event) { + float dx = event.getX() - touchDebutX; + float dy = event.getY() - touchDebutY; + + if (estLigne == null) { + if (Math.abs(dx) > SEUIL_DIRECTION_PX || Math.abs(dy) > SEUIL_DIRECTION_PX) { + estLigne = Math.abs(dx) >= Math.abs(dy); + + if (estLigne) { + indexGlissement = ligneTouchee; + } else { + indexGlissement = colonneTouchee; + } + } else { + return; + } + } + + if (estLigne) { + decalagePx = dx; + } else { + decalagePx = dy; + } + + // Affiche le glissement réel du doigt (permet la rotation multi-cases) + vueGrille.definirGlissement(estLigne, indexGlissement, decalagePx); + } + + private void gererFin(boolean estRelachement) { + + if (estLigne == null) { + vueGrille.annulerGlissement(); + return; + } + + if (tailleCase <= 1f) { + vueGrille.annulerGlissement(); + estLigne = null; + return; + } + + // Arrondi au nombre de cases le plus proche (permet ±1, ±2, ±3…) + int nbCases = (int) Math.round(decalagePx / tailleCase); + + if (nbCases != 0 && estRelachement) { + boolean accepte = etatJeu.appliquerCoup(estLigne, indexGlissement, nbCases); + if (accepte) { + controleur.rafraichirAffichage(); + controleur.verifierFinDePartie(); + } + } + + vueGrille.annulerGlissement(); + estLigne = null; + } + + private float calculerTailleCase() { + float l = vueGrille.getWidth(); + float h = vueGrille.getHeight(); + + if (l == 0 || h == 0) { + return 1f; + } + + return Math.min(l / NB_COLONNES, h / NB_LIGNES); + } +} \ No newline at end of file