IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

AWT/Swing Java Discussion :

Jeu d'échecs : utilisation de MouseListener


Sujet :

AWT/Swing Java

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2014
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Apprenti

    Informations forums :
    Inscription : Octobre 2014
    Messages : 70
    Points : 35
    Points
    35
    Par défaut Jeu d'échecs : utilisation de MouseListener
    Bonsoir à tous,

    Actuellement en L3 info spécialité développement, j'ai voulu me lancer de mon côté dans la réalisation d'un jeu d'échec. J'ai pour l'instant commencé à implémenter les classes suivantes :

    - une classe abstraite Piece dont hériteront toutes les pièces. La classe Piece implémente les méthodes déplacer (que j'ai découpé pour l'instant en déplacement horizontal et vertical seulement, je pense créer ensuite une méthode déplacement en diagonale), une méthode deplacementCorrect redéfinie dans chacune des classes héritant de Piece et une méthode prendre, elle aussi à redéfinir.

    - une classe Square qui représente une case dans l'échiquier. Je lui attribue une couleur, un booléen pour savoir si elle est occupée, une coordonnée X et une coordonnée Y ainsi qu'un JPanel sur lequel je compte afficher la pièce.

    - une classe Pion qui me sert pour l'instant de test, elle n'implémente qu'une fonction deplacementCorrect pour l'instant, prenant en compte les spécificités d'un pion pour se déplacer.

    - enfin une classe Fenetre, elle possède un tableau de Square[8][8] faisant office d'échiquier. Ses méthodes initFrame et initChessboard permettent de créer la fenêtre et de colorier les cases de l'échiquier. Je tiens à préciser que la méthode displayPiece(Piece piece) est vouée à disparaître, elle me sert simplement pour l'instant car je ne souhaite n'afficher qu'une pièce et réussir à la faire se déplacer.

    A terme, je sais qu'une classe comme joueur qui possédera une liste de pièce est nécessaire mais je ne m'y suis pas encore attelé pour le moment.

    Ma principale interrogation se situe au niveau de l'interface graphique. J'en ai déjà fait quelques une auparavant (un 2048 par exemple, c'était donc simpliste, les mouvements ne se géraient qu'au clavier ou encore un launcher pour une société mais la encore, il n'y avait pas de MouseListener) mais je n'ai jamais utilisé réellement l'interface MouseListener. Je ne sais pas où mettre l'implémentation des méthodes de cette interface dans mon code. J'ai essayé d'associer à chaque JPanel un mouseListener en faisant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     chessboard[i][j].getSquare().addMouseListener(new MouseListener() { ... }
    mais je n'y arrive pas. Je peux sélectionner la pièce mais je ne peux pas la déplacer car forcément, lorsque je clique sur un autre JPanel, je ne l'ai plus. Peut être que l'on peut faire de cette manière mais que mon code est mauvais, je ne sais pas.

    J'ai parcouru la discussion suivante http://www.developpez.net/forums/d13...chiquier-java/ et j'ai vu que la personne utilisait une classe privée, est-ce une bonne manière de faire ?

    N'étant qu'au début de mon projet, je suis ouvert à toute remarque car je préfère partir dans la direction la plus "propre" possible. Mes interrogations sont surtout au niveau de la partie graphique car il me semble que la partie fonctionnelle (les pièces, les mouvements) est assez claire, même si je sais que certains préféreraient utiliser une classe Deplacement.
    En bref, n'importe quelle remarque, qu'elle porte sur le fonctionnel ou l'IHM m'intéresse. N'hésitez donc pas à me dire si quelque chose vous fait hurler

    Ci-joint les 4 classes que j'ai pour l'instant implémenté.

    Classe Square (une case)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    package fonctionnel;
     
    import javax.swing.ImageIcon;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
     
    public class Square 
    {
    	private Piece piece;
    	private boolean black, occupied;
    	private int positionX, positionY;
    	private JPanel square; 
     
     
    	public Square(int positionX, int positionY, boolean black, boolean occupied) 
    	{
    		this.black = black;
    		this.occupied = occupied;
    		this.positionX = positionX;
    		this.positionY = positionY;
    		square = new JPanel();
    	}
     
    	public JPanel getSquare() {
    		return square;
    	}
     
    	public void setSquareImage(String nomImage) 
    	{
    		square.removeAll();
    		square.add(new JLabel(new ImageIcon(nomImage)));
    	}
    	public boolean isBlack() {
    		return black;
    	}
     
    	public void setBlack(boolean black) {
    		this.black = black;
    	}
     
    	public boolean isOccupied() {
    		return occupied;
    	}
     
    	public void setOccupied(boolean occupied) {
    		this.occupied = occupied;
    	}
     
    	public int getPositionX() {
    		return positionX;
    	}
     
     
    	public void setPositionX(int positionX) {
    		this.positionX = positionX;
    	}
     
     
    	public int getPositionY() {
    		return positionY;
    	}
     
     
    	public void setPositionY(int positionY) {
    		this.positionY = positionY;
    	}
     
    	public Piece getPiece()
    	{
    		return piece;
    	}
     
    	public void setPiece(Piece piece) {
    		this.piece = piece;
    		this.occupied = true; // C'est pas forcément beau, à voir si on garde comme ça 
    	}
    }
    Classe Piece
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    package fonctionnel;
     
     
    public abstract class Piece
    {
    	protected String nomImage;
    	protected int positionX, positionY;
    	protected final int value;
    	protected boolean black;
     
    	public Piece(int valeur, int positionX, int positionY, boolean estNoir, String nom)
    	{
    		this.value = valeur;
    		this.positionX = positionX;
    		this.positionY = positionY;
    		this.black = estNoir;
    		this.nomImage = nom;
    	}
     
    	public boolean deplacer(Square board[][], int departX, int departY, int arriveeX, int arriveeY)
    	{
     
    		// la méthode renverra un boolean pour savoir si le déplacement a pu être effectué
    		if(deplacementCorrect(board, departX, departY, arriveeX, arriveeY))
    		{
    			board[departX][departY].setOccupied(false);
    			board[arriveeX][arriveeY].setPiece(board[departX][departY].getPiece());// on déplace la pièce sur la case suivante
    			board[arriveeX][arriveeY].setSquareImage(board[arriveeX][arriveeY].getPiece().getNom()); // On affiche la pièce sur la nouvelle case
    			board[departX][departY].getSquare().removeAll(); // Suppression de l'image de la pièce
    			board[departX][departY].setPiece(null); // on indique que la case dont par la pièce est désormais vide
    			board[arriveeX][arriveeY].setOccupied(true); 
    			board[departX][departY].getSquare().repaint();
    			return true;
    		}	
    		return false;
    	}
     
    	protected abstract boolean deplacementCorrect(Square board[][], int departX, int departY, int arriveeX, int arriveeY);
     
     
    	// Méthode générique qui pourrait être réutilisé pour les pions, les tours, les reines et les rois
    	// Un déplacement horizontal effectue un déplacement sur les abscisses
    	protected boolean deplacementHorizontal(Square board[][], int departX, int departY, int arriveeX)
    	{
    		if(departX > arriveeX) // déplacement vers le bas
    		{
    			for(int i = departX-1; i > arriveeX; i--) // On part de la case à gauche de celle que l'on souhaite déplacer
    			{
    				if(board[i][departX].isOccupied()) // Si elle est occupée le déplacement est impossible
    				{
    					return false; // gérer le cas où l'on souhaite prendre la pièce
    				}
    			}
    			return true; 
    		}
    		else // déplacement vers le haut
    		{
    			for(int i = departX + 1; i <= arriveeX; i++)
    			{
    				if(board[i][departX].isOccupied())
    					return false;
    			}
    			return true;
    		}
    	}
     
    	// Un déplacement vertical effectue un déplacement sur les ordonnées
    	protected boolean deplacementVertical(Square board[][], int departX, int departY, int arriveeY)
    	{
    		if(departY > arriveeY) // déplacement vers la gauche
    		{
    			for(int i = departY - 1; i > arriveeY; i--)
    			{
    				if(board[i][departY].isOccupied())
    					return false;
    			}
    			return true;
    		}
    		else // déplacement vers la droite
    			for(int i = departY + 1; i < arriveeY; i++) 
    			{
    				if(board[i][departY].isOccupied())
    					return false;
    			}
    			return true;
    	}
     
    	protected void prendre()
    	{
     
    	}
     
    	public int getPositionX() {
    		return positionX;
    	}
     
    	public void setPositionX(int positionX) {
    		this.positionX = positionX;
    	}
     
    	public int getPositionY() {
    		return positionY;
    	}
     
    	public void setPositionY(int positionY) {
    		this.positionY = positionY;
    	}
     
    	public String getNom() {
    		return nomImage;
    	}
     
    	public void setNom(String nom) {
    		this.nomImage = nom;
    	}
    }
    Classe Pawn
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    package fonctionnel;
    public class Pawn extends Piece
    {
    	public Pawn(int positionX, int positionY, boolean estNoir)
    	{
    		super(1, positionX, positionY, estNoir, "pion");
    		//if(estNoir)
    		//	nom = "Images//" + nom + "Noir.jpg";
    		//else
    			nomImage = "Images//" + nomImage + "Blanc.jpg";
    	}
     
    	@Override
    	protected boolean deplacementCorrect(Square board[][], int departX, int departY, int arriveeX, int arriveeY)
    	{
    		if(deplacementVertical(board, departX, departY, arriveeX) && (arriveeY - departY) == 1) // un pion ne peut se d�placer que d'une case
    		{
    			return true;
    		}
     
    		return false;
    	}
     
    	private void evoluer()
    	{
     
    	}
    }
    Classe Fenetre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
     
    package interfaceGraphique;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.GridLayout;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
     
    import javax.swing.BorderFactory;
    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
     
    import fonctionnel.Square;
    import fonctionnel.Piece;
     
     
    public class Fenetre implements MouseListener{
     
    	private final int dimension = 8;
    	private JFrame frame = new JFrame("Echecs");
    	private Square chessboard[][] = new Square[dimension][dimension];
     
     
    	public Fenetre() 
    	{
    		initChessboard();
    		initFrame();
    		frame.addMouseListener(this);
    	}
     
    	private void initFrame()
    	{
    		frame.setSize(800, 800);
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		frame.setResizable(false);
    		frame.setLocationRelativeTo(null);
    		frame.setLayout(new GridLayout(8,8,1,1));
    		frame.setVisible(true);
    	}
     
    	private void initChessboard()
    	{
    		for(int j = dimension -1; j >= 0; j--)// boucle ordonnées
    		{
    			for(int i = 0; i < dimension ; i++) // boucle abscisses
    			{
    				if((i + j) % 2 == 0) // permet d'obtenir un vrai 1/2 ce que  (j%2) ne permettait pas
    				{
    					chessboard[i][j] = new Square(i, j, true, false);
    					chessboard[i][j].getSquare().setBackground(new Color(128, 64, 0));
    				}
    				else
    				{
    					chessboard[i][j] = new Square(i, j, false, false);
    					chessboard[i][j].getSquare().setBackground(new Color(250,224,124));
    				}
    				chessboard[i][j].getSquare().setPreferredSize(new Dimension(50,50));
    				chessboard[i][j].getSquare().setBorder(BorderFactory.createLineBorder(Color.BLACK));
    				final int x = i, l = j;
     
    				chessboard[i][j].getSquare().addMouseListener(new MouseListener() {
     
    					Piece p;
    					@Override
    					public void mouseReleased(MouseEvent e) {}
     
    					@Override
    					public void mousePressed(MouseEvent e) {}
     
    					@Override
    					public void mouseExited(MouseEvent e) {}
     
    					@Override
    					public void mouseEntered(MouseEvent e) {}
     
    					@Override
    					public void mouseClicked(MouseEvent e) 
    					{
    						if(p == null)
    						{
    							p = chessboard[x][l].getPiece();
    						}
    						else
    						{
    							try
    							{
    								if(chessboard[x][l].getPiece() == null)
    								{	
    									System.out.println("ok");
    									chessboard[x][l].getPiece().deplacer(chessboard, x, l, x, l+1);		
    									frame.revalidate();
    									p = null;
    								}
    								else
    								{
    									System.out.println("case non vide");
    								}
    							}
    							catch(Exception ex){
    								System.out.println("case vide");
    								System.out.println("x : " + x + " y : " + l);
    							}
    						}
    					}
    				});
    				frame.add(chessboard[i][j].getSquare());
    			}
    		}
    	}
     
    	public void displayPiece(Piece piece)
    	{
    		chessboard[piece.getPositionX()][piece.getPositionY()].getSquare().add(new JLabel(new ImageIcon("Images/pionBlanc.jpg")));
    		frame.revalidate();
    	}
     
    	public Square getASquare(int i, int j) // ne retourne qu'une case de notre tableau, utilise pour set une piece
    	{
    		return chessboard[i][j];
    	}
     
    	@Override
    	public void mouseClicked(MouseEvent e) {
    		// TODO Auto-generated method stub
     
    	}
     
    	@Override
    	public void mousePressed(MouseEvent e) {
    		// TODO Auto-generated method stub
     
    	}
     
    	@Override
    	public void mouseReleased(MouseEvent e) {
    		// TODO Auto-generated method stub
     
    	}
     
    	@Override
    	public void mouseEntered(MouseEvent e) {
    		// TODO Auto-generated method stub
     
    	}
     
    	@Override
    	public void mouseExited(MouseEvent e) {
    		// TODO Auto-generated method stub
     
    	}
    }
    Mon petit main de test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    	public static void main(String[] args) 
    	{		
    		Fenetre fenetre = new Fenetre();
    		Pawn pion = new Pawn(4,1,true);
    		fenetre.displayPiece(pion);
    		fenetre.getASquare(pion.getPositionX(), pion.getPositionY()).setPiece(pion);
     
    	}
    Merci d'avance pour votre aide

    PS : J'ai finalement décidé pour ce projet de développer en utilisant la langue anglaise sauf pour les commentaires, si certaines variables ont encore un nom français, c'est un oubli de ma part

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,
    Citation Envoyé par snyler Voir le message
    J'ai essayé d'associer à chaque JPanel un mouseListener en faisant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     chessboard[i][j].getSquare().addMouseListener(new MouseListener() { ... }
    mais je n'y arrive pas. Je peux sélectionner la pièce mais je ne peux pas la déplacer car forcément, lorsque je clique sur un autre JPanel, je ne l'ai plus.
    Si tu veux faire un déplacement du type "je clique sur un pion, puis je clique sur case, et le pîon va sur cette case", tu est obligé de gérer un état, qui te permet de savoir que quand tu cliques sur une case, il y a un pion en attente de déplacement, avec un algorithme du type :
    Code pseudocode : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    clic sur pion :
    si pion en attente de déplacement alors annuler déplacement en attente
    sinon déplacement en attente égal le pion cliqué
    Code pseudocode : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    clic sur case :
    si pion en attente de déplacement alors 
       déplacer pion en attente dans case cliquée
       rendre case d'origine vide
    fin si
    Il te faut donc que ton état (une variable) soit accessible depuis le mouselistener du pion et celui de la case. Au lieu de mettre une instance de MouseListener différente sur chaque pion et chaque case, tu peux utiliser une instance unique. Ou alors utiliser des classes internes et mettre l'état dans la classe parente, mais c'est plus compliqué si tu fais des classes séparées : le plus simple étant d'avoir un contrôleur unique. Ce contrôleur (une classe) peut avoir en variable membre l'état en question, va connaitre l'ensemble des pions et cases, et va leur affecter le et les mouselisteners, de manière à ce qu'ils aient tous accès à cet état. Quelque chose comme ça (rapidement écrit, donc abrégé) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    public class Controller {
        private List<Piece> pieces;
        private List<Square> squares;
        private Map<Piece, Square> locations; // pour mémoriser l'emplacement de chaque pièce (à initialiser au départ) 
        private Piece move;
     
         /*...*/
     
        // a appeler pour chaque piece
        public void addMouseListener(final Piece piece] {
              piece.addMouseListener(new MouseAdapter() { // MouseAdapter t'éviter d'avoir à mettre toutes les méthodes vides que tu n'utilises pas
                     public void mouseClicked(MouseEvent event) {
                             if ( move==null ) {
                                  move=piece;
                             }
                             else {
                                  move=null; // annulation
                             }
                             // updateDisplay(); // ou autre...
                     }
              });
        }
        // a appeler pour chaque case
        public void addMouseListener(final Square square] {
              square.addMouseListener(new MouseAdapter() { // MouseAdapter t'éviter d'avoir à mettre toutes les méthodes vides que tu n'utilises pas
                     public void mouseClicked(MouseEvent event) {
                             if ( move!=null ) {
                                  Sqaure currentSquare=locations.get(piece);
                                  if ( moveIsAllowed(square, move, currentSquare) {
                                     if ( moveIsCapture(square, move, currentSquare ) {
                                               // ...
                                     }
                                     square.setPiece(move); // déplacement
                                     currentSquare.setPïece(null); // supprimer piece depuis la case de départ
                                      locations.put(piece, square); // mémorise l'emplacement de la piece
                                      // updateDisplay(); // ou autre...
                                  }
                                  else {
                                       // afficher message "déplacement interdit"
                                  }
                             }
                     }
              });
        }
     
    }
    Tu peux utilser un MouseAdapter unique, en utilisant event.getSource() pour récupérer la pièce ou case à traiter.

    Autrement, si tu veux faire un déplacement continu, soit opter pour une technique de drag and drop, soit simuler un drag and drop simple, en passant par le GlassPane, ou un JLayer.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2014
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Apprenti

    Informations forums :
    Inscription : Octobre 2014
    Messages : 70
    Points : 35
    Points
    35
    Par défaut
    Tout d'abord, merci pour ta réponse.

    Citation Envoyé par joel.drigo Voir le message
    Salut,

    Si tu veux faire un déplacement du type "je clique sur un pion, puis je clique sur case, et le pîon va sur cette case", tu est obligé de gérer un état, qui te permet de savoir que quand tu cliques sur une case, il y a un pion en attente de déplacement
    C'est exactement ce que je souhaitais faire, l'algo que tu proposes est celui que je voulais mettre en place mais je ne voyais justement pas comment y arriver sans utiliser une instance unique de listener.

    Dans ce que tu proposes il y a des choses que je comprends et d'autres que je comprends moins. Par exemple, je ne comprends pas pourquoi chaque Piece a besoin d'un MouseListener. Ne peut-on pas avoir qu'un listener sur chaque case et à partir de cette case nous serons à même de récupérer la pièce grâce à la méthode getPiece() ?
    Pourtant, je comprends bien qu'il faut une variable "intermédiaire" nous permettant de savoir quelle pièce nous souhaitons déplacer (chose que je n'arrivais pas à mettre en place avec la solution que j'avais commencé à imaginer) est nécessaire.

    En fait, j'ai du mal à visualiser comment l'écouteur peut faire son travail sur une pièce qui au final n'est pas un élément graphique contrairement à Square qui contient un JPanel. Ma question est peut être simpliste mais j'avoue ne pas savoir, ayant toujours utilisé des listener que sur des boutons, des panels ou des frames.

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Je suis parti du principe que la pièce était un élément graphique (c'est bien quelque chose qu'on voit, n'est-ce-pas ?). Il y a différents moyens de faire bien sûr : on peut faire un JPanel ou un JLabel pour une case, et la pièce est juste une image qu'on affiche dans ce composant. On peut également faire un JPanel pour la case, et un JLabel pour la pièce : dans ce cas, on peut rendre le JLabel cliquable : dans ce cas, le clic est capté par le JLabel et la case qui contient une pièce ne reçoit pas de clic. Personnellement, j'aurais tout fait avec un seul panel et du dessin Java2D, bien plus libre pour faire tout ce qu'on veut, donc j'aurais eu un seul écouteur pour l'ensemble de l'échiquier). C'est dans cet esprit que j'ai écrit l'algorithme. Maintenant, si seule ta classe Square est un JPanel, l'écouteur sera bien techniquement sur la case, et il devra simplement tester :
    Code pseudocode : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    une case est cliquée :
    si il y a une pièce dans cette case alors
        traiter un clic de pièce
    sinon
        traiter un clic de case
    fin si
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2014
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Apprenti

    Informations forums :
    Inscription : Octobre 2014
    Messages : 70
    Points : 35
    Points
    35
    Par défaut
    De mon côté j'étais parti du principe suivant. Une case possède les attributs suivants
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    boolean occupee, black;// connaitre la couleur d'une case et si elle est occupée par une pièce ou non
    int positionX, positionY; // connaitre la place de la case sur l'échiquier
    JPanel square; // le panel qui permettra d'afficher la case en le coloriant et s'il n'est pas vide de superposer un JLabel dessus contenant le dessin de la pièce 
    Piece piece; // la pièce contenue par cette case
    Je peux donc savoir si une case est vide et je comptais donc faire grâce au listener quelque chose ressemblant à ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    if(square.getPiece() == null) // la case est vide, il doit s'agir d'un mouvement
    {
    	if(pieceIntermediaire != null) // on vérifie que l'on a bien une pièce à faire bouger
    		{
    			// executer mouvement
    			// vider case dont part la pièce
    			pieceIntermediaire.setPiece(null);
    		}
    }
    else
    {
    	if(pieceIntermediaire == null) // aucune pièce n'a encore été sélectionnée
    	{
    		pieceIntermediaire = square.getPiece(); // manière simpliste, il faudra vérifier que c'est bien la pièce du joueur mais on en est pas encore là
    	}
    	else // on veut se déplacer sur une case occupée par une pièce
    	{
    		// vérifier si capture est possible ou s'il s'agit d'une pièce alliée
    	}
    }
    Je pense donc que cette ébauche est correcte dans les grandes lignes, maintenant c'est sur l'utilisation du listener que je bloque. Est-il possible de conserver l'idée du JPanel en superposant simplement un JLabel quand la pièce est dessus ou est-ce impossible de faire de cette manière la ?
    Comment faire pour conserver la pièce dans une variable pour la déplacer en utilisant simplement un JPanel pour chaque case ?

    Je suis désolé car j'ai l'impression que tu as déjà répondu à ma question dans une de tes réponses mais je n'arrive pas bien à comprendre.

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par snyler Voir le message
    Je peux donc savoir si une case est vide et je comptais donc faire grâce au listener quelque chose ressemblant à ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    if(square.getPiece() == null) // la case est vide, il doit s'agir d'un mouvement
    {
    	if(pieceIntermediaire != null) // on vérifie que l'on a bien une pièce à faire bouger
    		{
    			// executer mouvement
    			// vider case dont part la pièce
    			pieceIntermediaire.setPiece(null);
    		}
    }
    else
    {
    	if(pieceIntermediaire == null) // aucune pièce n'a encore été sélectionnée
    	{
    		pieceIntermediaire = square.getPiece(); // manière simpliste, il faudra vérifier que c'est bien la pièce du joueur mais on en est pas encore là
    	}
    	else // on veut se déplacer sur une case occupée par une pièce
    	{
    		// vérifier si capture est possible ou s'il s'agit d'une pièce alliée
    	}
    }
    => au lieu de pieceIntermediaire.setPiece(null);, à priori pieceIntermediaire=null (puisque pieceIntermediaire = square.getPiece()).

    Citation Envoyé par snyler Voir le message
    Est-il possible de conserver l'idée du JPanel en superposant simplement un JLabel quand la pièce est dessus ou est-ce impossible de faire de cette manière la ?
    Comment faire pour conserver la pièce dans une variable pour la déplacer en utilisant simplement un JPanel pour chaque case ?
    Oui. Pas en superposant, mais en mettant le JLabel dans le JPanel.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2014
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Apprenti

    Informations forums :
    Inscription : Octobre 2014
    Messages : 70
    Points : 35
    Points
    35
    Par défaut
    Citation Envoyé par joel.drigo Voir le message
    => au lieu de pieceIntermediaire.setPiece(null);, à priori pieceIntermediaire=null (puisque pieceIntermediaire = square.getPiece()).


    Oui. Pas en superposant, mais en mettant le JLabel dans le JPanel.
    En effet je m'étais trompé pour pieceIntermediaire et je me suis mal exprimé pour le JLabel car dans mon code je l'ai bien ajouté au JPanel, je ne l'ai pas superposé dessus.

    Donc je pense que si l'on décide de poursuivre dans cette voie (n'avoir que des JPanel pour les case), nous n'avons besoin d'un mouseListener que pour les cases. J'ai essayé d'ajouter ton code à mon projet avec la classe Controller (j'ai mis en commentaires le listener pour les pièces) mais je ne comprends pas comment on va utiliser ce code. Je comprends le mécanisme algorithmique, la démarche que l'on doit suivre pour déplacer une pièce mais c'est l'implémentation du listener et l'endroit où on doit le placer dans le code que je n'arrive pas à comprendre. Je ne vois pas comment la classe Controller va être utilisée et comment nous allons associer chaque case avec le listener contenu dans la classe Controller.

    Comme je l'ai dit je n'ai que très peu utilisé l'interface MouseListener, seulement une fois pour une calculatrice mais j'avais mis tout le code dans une seule classe (j'étais jeune, pas taper ) donc je ne sais pas comment on gère cela dans une autre classe, n'ayant jamais été confronté à cette problématique.

  8. #8
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Un exemple vaut mieux un long discours :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    public class ChessExample {
     
    	private static final int PREFERRED_SIZE = 64;
     
    	private static final Color WHITE_SQUARE = new Color(0xFC,0xFC,0xFF);
    	private static final Color BLACK_SQUARE = new Color(0x03,0x03,0x00);
    	private static final Color SELECTION_COLOR = new Color(0xFF,0xA4,0x77);
    	public static final ImageIcon BLACK_PAWN = new ImageIcon(ChessExample.class.getResource("blackpawn.png"));
    	public static final ImageIcon WHITE_PAWN = new ImageIcon(ChessExample.class.getResource("whitepawn.png"));
     
    	public static void main(String[] args) {
     
    		JFrame frame = new JFrame("Démo");
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		frame.setResizable(false);
     
    		GameBoard gameboard = new GameBoard(8,8);
    		for(int i=0;i<8; i++) {
    			gameboard.setPiece(1,i,new Pawn(Player.BLACK));
    			gameboard.setPiece(6,i,new Pawn(Player.WHITE));
    		}
    		frame.add(gameboard);
     
    		frame.pack();
    		frame.setLocationRelativeTo(null);
    		frame.setVisible(true);
     
    	}
     
    	public static class GameBoard extends JPanel {
     
    		private static final long serialVersionUID = 1L;
     
    		private final int nbColumns;
    		private final int nbLines;
    		private final Controller controller;
     
    		public GameBoard(int nbColumns, int nbLines) {
    			super(new GridLayout(nbLines, nbColumns));
     
    			this.nbColumns=nbColumns;
    			this.nbLines=nbLines;
    			this.controller = new Controller(this); // le contrôleur doit avoir acces à la vue et au modèle
    			setPreferredSize(new Dimension(nbColumns*PREFERRED_SIZE,nbLines*PREFERRED_SIZE));
    		}
     
    		public int getNbLines() {
    			return nbLines;
    		}
     
    		public int getNbColumns() {
    			return nbColumns;
    		}
     
    		public void setPiece(int column, int line, Piece piece) {
    			controller.setPiece(column, line, piece);
    		}
     
    		public Square getSquare(int column, int line) {
    			return controller.getSquare(column, line);
    		}
     
    	}
     
    	public enum Player {
    		WHITE,
    		BLACK;
    	}
     
    	public enum PieceType {
    		PAWN(WHITE_PAWN,BLACK_PAWN),
    		/*KING,
    		QUEEN,
    		ROOK,
    		BISHOP,
    		KNIGHT*/
    		;
     
    		private final ImageIcon whiteImage;
    		private final ImageIcon blackImage;
     
    		private PieceType(ImageIcon whiteImage, ImageIcon blackImage) {
    			this.whiteImage=whiteImage;
    			this.blackImage=blackImage;
    		}
     
    		public ImageIcon getImage(Player player) {
    			switch(player) {
    			case BLACK:
    				return blackImage;
    			case WHITE:
    				return whiteImage;
    			default:
    				throw new IllegalStateException("Unknown player "+player);
    			}
    		}
     
    	}
     
    	public static abstract class Piece {
     
    		private final Player player;
    		private final PieceType type;
    		public Piece(PieceType type, Player player) {
    			this.type=type;
    			this.player=player;
    		}
     
    		public PieceType getType() {
    			return type;
    		}
     
    		public Player getPlayer() {
    			return player;
    		}
     
    		public ImageIcon getImage() {
    			return getType().getImage(player);
    		} 
     
    	}
     
    	public static class Pawn extends Piece {
    		public Pawn(Player player) {
    			super(PieceType.PAWN,player);
    		}
    	}
     
    	public static class Square extends JPanel {
     
    		private static final long serialVersionUID = 1L;
     
    		private final Color color;
    		private final int column;
    		private final int line;
    		private Piece piece; 
     
    		public Square(int column, int line, Color color) {
    			super(new BorderLayout()); // centrer la pièce
    			this.color=color;
    			setBackground(color);
    			this.column=column;
    			this.line=line;
    			setPreferredSize(new Dimension(PREFERRED_SIZE, PREFERRED_SIZE));
    		}
     
    		public int getLine() {
    			return line;
    		}
     
    		public int getColumn() {
    			return column;
    		}
     
    		public void setPiece(Piece piece) {
    			this.piece=piece;
    			if ( piece==null ) {
    				removeAll();
    			}
    			else {
    				add(new JLabel(piece.getImage()));
    				revalidate();
    			}
    		}
     
    		public Piece getPiece() {
    			return piece;
    		}
     
    		public boolean isEmpty() {
    			return piece==null;
    		}
     
    		public void setSelection(boolean selection) {
    			setBackground(selection?SELECTION_COLOR:color);
    		} 
     
    	}
     
    	public static class Controller {
     
    		private final GameBoard board;
    		private final Square[][] squares;
    		private Square currentMove;
     
    		public Controller(GameBoard board) {
    			this.board=board;
    			this.squares=new Square[board.getNbLines()][board.getNbColumns()];
    			final int nbPieces=board.getNbLines()*board.getNbColumns();
    			for(int i=0; i<nbPieces; i++) {
    				final int line = i/board.getNbColumns();
    				final int column = i%board.getNbColumns();
    				final Square square = new Square(column, line, i%2==line%2?WHITE_SQUARE:BLACK_SQUARE);
    				board.add(square);
    				squares[line][column]=square;
    			}
    			MouseAdapter mouseAdapter = new MouseAdapter() {
     
    				@Override
    				public void mouseClicked(MouseEvent e) {
    					Square square = (Square) e.getSource();
    					if ( !square.isEmpty() ) {
    						if ( isMoving() ) {
    							if ( square.getPiece()==currentMove.getPiece() ) {
    								// cancel move
    								stopMove();
    								board.repaint();
    							}
    							else if ( square.getPiece().getPlayer()==currentMove.getPiece().getPlayer() ) {
    								JOptionPane.showMessageDialog(board, "Une pièce à vous est déjà dans cette case","Mouvement impossible", JOptionPane.WARNING_MESSAGE);
    							}
    							else if ( moveIsAllowed(currentMove.getPiece(), currentMove, square) ) {
    								doCapture(square);
    								moveTo(currentMove, square);
    								stopMove();
    								board.repaint();
    							}
    						}
    						else {
    							startMove(square);
    							board.repaint();
    						}
    					}
    					else if ( isMoving() ) {
    						moveTo(currentMove, square);
    						stopMove();
    					}
    				}
     
    			};
    			for(Square[] line : squares) {
    				for(Square square : line) {
    					square.addMouseListener(mouseAdapter);
    				}
    			}
    		}
     
    		/**
                     * Cette méthode ne teste pas si la pièce à le droit de se trouver dans cette case
                     * @param column
                     * @param line
                     * @param piece
                     */
    		public void setPiece(int column, int line, Piece piece) {
    			if ( squares[column][line].isEmpty() ) {
    				squares[column][line].setPiece(piece);
    			}
    			else {
    				throw new IllegalStateException("Case occupée");
    			}
    		}
     
    		private void moveTo(Square fromSquare, Square toSquare) {
    			final Piece piece = fromSquare.getPiece();
    			if ( piece==null ) throw new IllegalStateException("Pas de pièce dans la case de départ");
    			if ( moveIsAllowed(piece, fromSquare, toSquare) ) {
    				toSquare.setPiece(piece);
    				fromSquare.setPiece(null);
    			}
    			else {
    				JOptionPane.showMessageDialog(board, "Ce mouvement n'est pas autorisé par les règles des Echecs","Mouvement impossible", JOptionPane.WARNING_MESSAGE);
    			}
    		}
     
    		private void stopMove() {
    			if ( currentMove!=null ) {
    				currentMove.setSelection(false);
    				currentMove=null;
    			}
    		} 
     
    		private void doCapture(Square square) {
    			// TODO
    			square.setPiece(null); // temp
    		}
     
    		private boolean moveIsAllowed(Piece piece, Square fromSquare, Square toSquare) {
    			return true; // TODO
    		}
     
    		public Square getSquare(int column, int line) {
    			return squares[line][column];
    		}
     
    		public boolean isMoving() {
    			return currentMove!=null;
    		}
     
    		private void startMove(Square square) {
    			if ( currentMove!=null ) {
    				stopMove();
    			}
    			currentMove=square;
    			square.setSelection(true);
    		}
     
    	} 
     
    }
    Images attachées Images attachées   
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2014
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Apprenti

    Informations forums :
    Inscription : Octobre 2014
    Messages : 70
    Points : 35
    Points
    35
    Par défaut
    Citation Envoyé par joel.drigo Voir le message
    Un exemple vaut mieux un long discours :
    Merci mais je n'en demandais pas tant, j'aurais simplement voulu savoir où adapter le MouseListener dans mon code.

    Dans tous les cas merci pour ton aide, j'étudierai ton code ce week end

  10. #10
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2014
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Apprenti

    Informations forums :
    Inscription : Octobre 2014
    Messages : 70
    Points : 35
    Points
    35
    Par défaut
    J'ai pu prendre le temps cette après midi de regarder de plus près ton code et je pense avoir compris ce que tu faisais. J'ai néanmoins plusieurs interrogations (ce sont de réelles interrogations, en aucun cas une critique, je souhaite simplement bien comprendre).

    Tout d'abord, j'ai une question à propos des énumérations. Je sais en principe ce que c'est mais je n'en ai jamais utilisé. Je suppose que l'avantage de les utiliser ici est que l'on souhaite définir toutes les pièces car elles ne changeront jamais et que cela simplifie donc leur définition. Néanmoins, j'ai l'impression que pour les pièces cela fait beaucoup de choses à définir, en l'occurrence l'image de chaque pièce, comme tu as commencé à le faire avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     	public static final ImageIcon BLACK_PAWN = new ImageIcon(ChessExample.class.getResource("blackpawn.png"));
    	public static final ImageIcon WHITE_PAWN = new ImageIcon(ChessExample.class.getResource("whitepawn.png"));
     
    	public enum PieceType {
    		PAWN(WHITE_PAWN,BLACK_PAWN),
    		/*KING,
    		QUEEN,
    		ROOK,
    		BISHOP,
    		KNIGHT*/
    Ne pouvons-nous pas plutôt ajouter un champ String image dans la classe Piece et lors de l'initialisation de la pièce en question définir une seule ImageIcon ? Nous pourrions connaitre la couleur à donner à la pièce grâce à la valeur de Player.

    Aussi, j'ai l'impression que chaque pièce a une whiteimage et une blackimage, que tu initialises à chaque fois les deux et que tu choisis celle que tu retournes en fonction de la valeur de player, c'est cela ? Si c'est le cas, est-ce que n'utiliser qu'une seule variable comme je l'évoquais plus tôt n'est pas plus simple ?


    Ce ne sont absolument pas des remarques, je ne remets pas en question ton code mais comme je l'ai dit je suis encore novice en Java donc j'essaie de comprendre au maximum en comparant avec ce qu'il me serait semblé juste de faire.

  11. #11
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    En ce qui concerne l'enumération PieceType, en réalité, s'il y avait une classe à supprimer, ce serait plutôt Pawn. L'énumération suffit à définir ce qu'est un pion, une reine, un roi..., et c'est bien plus propre que de faire des classes pour ça, qui supposerait d'une part qu'on puisse éventuellement avoir le besoin de définir des pions de comportements différents par exemple (spécialisation), ou avec des attributs différents multiples (or ici, à part la "couleur", dont on sait qu'il n'y en aura jamais que 2,e t qu'elle ne change pas la nature du pion, il n'y a que la position qui puisse être variable, et la position ne concerne pas la nature de pion, mais juste une instance de pièce sur l'échiqier. Pourquoi alors stocker x fois n informations (dans x classes), alors que seulement 1 peut être différente ? Et encore, dans mon programme, je peux tout faire sans stocker la position dans la pièce (ce qui est une absurdité de modèle : la seule raison pour laquelle on pourrait stocker la position dans la pièce serait une notion de cache, pour éviter d'avoir à parcourir l'échiquier pour retrouver la position d'une pièce si nécessaire)). Pour reconnaitre un pion, il est bien plus propre de tester son type, que de faire un instance of (moins on en a, mieux c'est). Il s'agit ici d'implémenter le pattern singleton en résumé : il y a un pion, c'est un pion, et rien d'autre n'est un pion, et il est inutile d'avoir n pions, en tant que pion.

    Pour les images, quelle alternative aurais-tu ? Passer directement le path de l'image dans la pièce ? Genre new Pawn("blackpawn.png") ? Tout d'abord, il est toujours mieux d'utiliser des constantes pour ce qui ne varie pas, mais qu'on peut avoir à changer à l'envie, ou au besoin : l'interêt d'avoir des constantes, c'est qu'elles sont situées à un endroit bien identifiable, facile à repérer et à modifier, voire à remplacer.
    Il s'agit bien entendu d'un POC, dont le but était de montrer comment gérer le MouseListener. Donc j'ai tout mis dans une seule classe : dans un programme réel, j'aurais fait une classe dédiée pour les images. Ce qui m'aurait permis le cas échéant de la remplacer rapidement, sans toucher au code d'instanciation des pièces. Dans l'optique d'un programme plius générique, j'aurais même introduit un troisième niveau de classe de rendu de pièces, de manière à permettre facilement par la suite, la déclinaison de jeux de pièces différents. En tout cas, là, tout est au début du programme, donc pour modifier le nom des images, ou les couleurs, ou autre, inutile de farfouiller dans le code, il suffit de se concentrer sur 8 lignes au début du programme.
    Enfin, le fait d'avoir des ImageIcon est un moyen rapide de garantir le chargement unique des ressources (et au final, c'est de ça qu'on a besoin pour les JLabel). Mais c'est vrai que j'aurais pu passer des path aux valeurs d'enum, et faire le chargement des ImageIcon dans leur constructeur. C'est également parce que j'utilise des ressources, et non des fichiers externes que j'utilise des ImageIcon sans aucune gestion d'erreur. En tout cas, ça évite d'avoir 8 fois la même image dans 8 instances de classe Pawn ! Et celà 2 fois, 1 fois par "couleur" !
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  12. #12
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2014
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Apprenti

    Informations forums :
    Inscription : Octobre 2014
    Messages : 70
    Points : 35
    Points
    35
    Par défaut
    Pour reconnaitre un pion, il est bien plus propre de tester son type, que de faire un instance of (moins on en a, mieux c'est)
    Avec la façon dont j'avais commencé, je n'avais jamais prévu d'utiliser instance of pour reconnaître une pièce, on m'a toujours dit qu'il fallait mieux éviter. J'étais parti du principe que toutes les pièces (pion, roi, tour ...) hériteraient de pièce et qu'elles redéfiniraient les méthodes de déplacement contenue dans la classe Piece. Ainsi, j'aurais à chaque fois fait square.getPiece().deplacer();. Néanmoins si tu souhaites supprimer la classe Pawn, j'en déduis que tu ne comptes pas faire de classe pour les autres pièces. Dans ce cas, comment pensais-tu gérer les déplacements ? En créant une classe Deplacement et en y implémentant les méthodes de déplacement de chaque pièce, ainsi nous saurions quelle méthode utiliser en appelant une méthode contenue dans Deplacement qui, en testant le type de la pièce, appellerait la méthode correspondante ?

    Pour ce qui est de l'image, j'aurais cherché à me débrouiller en disant que l'image de la pièce vaut son type + la couleur attribuée (dans le cas présent, la valeur de player) +".jpg" et ainsi éviter de définir une variable pour chaque image de chaque pièce. Nous n'aurions eu alors qu'à adapter le nom de l'image.C'est comme cela que j'aurais fait mais je ne sais pas ce que cela vaut et je pense en effet, comme tu l'as expliqué, que l'utilisation des constantes est plus simple.

  13. #13
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Pour le déplacement, les classes Pawn, King, etc... sont justifiées, justement pour pouvoir définir des méthodes différentes. Bien qu'on puisse mettre aussi la méthode déplacement dans l'enum, mais avec une implémentation pas objet certes, avec un switch, ou par injection de fonction (lambda ou pas), ce qui peut avoir l'avantage d'isoler complètement le déplacement de chaque pièce dans une classe à part.
    Mais ça n'empêche pas d'avoir à pouvoir tester le type d'une pièce à un moment donné.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  14. #14
    Nouveau membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Octobre 2014
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Apprenti

    Informations forums :
    Inscription : Octobre 2014
    Messages : 70
    Points : 35
    Points
    35
    Par défaut
    D'accord, je vais donc continuer à utiliser différentes classes pour définir chacune des méthodes de déplacement.

    Merci beaucoup pour ton aide et pour tes explications.

Discussions similaires

  1. Projet Jeu d'échec
    Par Layla dans le forum Langage
    Réponses: 10
    Dernier message: 23/12/2010, 14h06
  2. L'empereur de Chine et le jeu d'échecs
    Par momo1367 dans le forum Pascal
    Réponses: 1
    Dernier message: 04/01/2008, 03h08
  3. Serveur de jeu d'échec en PHP
    Par S_Xavier dans le forum Langage
    Réponses: 3
    Dernier message: 20/10/2007, 16h02
  4. Fonction d'évaluation d'un jeu de dames utilisant l'algorithme du min/max
    Par elron8 dans le forum Algorithmes et structures de données
    Réponses: 4
    Dernier message: 31/01/2007, 12h04
  5. Jeu d'échec borland soap
    Par rpoulin dans le forum Web & réseau
    Réponses: 2
    Dernier message: 20/10/2005, 06h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo