Bonsoir,
Mon problème n'est pas très facile à expliquer, je vais tenter de faire le plus simple possible.
Je developpe un jeu. Ce jeu est dans une JFrame. Au lancement, un JPanel "menu" est chargé. Suivant la zone cliquée sur ce JPanel, il cède la place à un autre. J'ai actuellement 3 JPanel : "menu" pour le menu, "options" pour les options" et enfin "PlayerSolo" pour le jeu seul. A chaque fois, il n'y a qu'un JPanel actif dans la JFrame.
Le problème, c'est quand je cherche à passer de "menu" à "PlayerSolo" puis "menu" et enfin "PlayerSolo". Lors du deuxième chargement de "PlayerSolo", il n'y a plus de boucle de jeu appelant le repaint, et donc l'écran est "figé".
Ceci est dû à une bidouille utilisée pour passer de "menu" à "PlayerSolo". En effet, je n'arrivais pas à effectuer cet enchainement en plaçant le code de lancement de "PlayerSolo" sur l'evenement "clic" dans la zone correspondant à "lancer jeu solo" dans mon menu.
J'ai donc utilisé une variable "doRefresh à true" et lors de l'initialisation du de la JFrame, je lance "PlayerSolo" en fond et non visible.
J'espère que j'ai un peu plus clairement expliqué ce que je voulais faire et ce qui ne marchait pas, voilà les codes de mes classes histoire que le tout soit encore plus tangible :
Code de la JFrame
Code du JPanel "menu"import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
import java.net.*;
public class FenetreDeJeu extends JFrame implements KeyListener , MouseListener, MouseMotionListener {
/** Quelques variables globales ... */
/** Identifiant du JPanel actif */
public String activePanel;
/** Coordonnées de la souris */
public int xMouse, yMouse;
/** Classes des JPanels */
public AboutBox about;
public Aide aide;
public Menu menu;
public Options options;
public PlayerSolo pSolo;
public Container contenu;
public FenetreDeJeu()
{
// CHARGEMENT IMAGES FOND
fondMenu = loadImages( this, ".//fondmenu.jpg" );
fondOptions = loadImages( this, ".//fondoptions.jpg" );
fondPlayerSolo = loadImages( this, ".//fondjeusolo.jpg" );
setTitle ("Baku Baku Animals");
setBounds (100, 100, 600, 420);
setResizable(false);
contenu = getContentPane();
contenu.setBackground(Color.black);
// Le menu est déclaré comme JPanel actif
menu = new Menu(fondMenu,this);
contenu.add(menu);
activePanel = new String("Menu");
// On construit les autres JPanel
aide = new Aide(this);
about = new AboutBox(this);
addKeyListener(this);
addMouseListener(this);
addMouseMotionListener(this);
//lors de la fermeture de la fenêtre le programme doit s'arrêter complètement.
addWindowListener(new WindowAdapter(){
public void windowClosing (WindowEvent e){
System.exit(0);
}
});
setVisible(true);
// Lancement de PlayerSolo en fond (si c'est fait ailleurs on ne voit qu le JPanel "menu" "PlayerSolo" tourne en fond mais n'est pas visible
pSolo = new PlayerSolo(fondPlayerSolo,this);
pSolo.play();
}
public void setActivePanel(String str){
this.activePanel = new String(str);
}
public String getActivePanel(){
return this.activePanel;
}
// FONCTION POUR RELANCER L'AFFICHAGE DU MENU VIA UN JPanel
public void relanceMenu(){
menu = new Menu(fondMenu,this);
contenu.add(menu);
activePanel = new String("Menu");
contenu.validate();
this.setVisible(true);
pSolo.play();
}
public void lanceRefreshPlayerSolo(){
pSolo.refresh();
}
/** Cette méthode est appelée dès que l'utilisateur appuie sur une touche.
* @param e : l'évènement clavier.
*/
public void keyPressed(KeyEvent e)
{
int code = e.getKeyCode();
if(this.activePanel.equals("PlayerSolo")){ // LORS D'UNE PARTIE SOLO
if(code == KeyEvent.VK_RIGHT )
pSolo.setTranslation(+1);
if(code == KeyEvent.VK_LEFT )
pSolo.setTranslation(-1);
//Le sens de rotation diffère que l'on appuie sur la flèche du haut ou celle du bas.
if(code == KeyEvent.VK_X){
pSolo.setRotation(-1);
}
if(code == KeyEvent.VK_C){
pSolo.setRotation(+1);
}
//Si on appuie sur DOWN la vitesse des boules passe a 4 pixels/frame
if(code == KeyEvent.VK_DOWN){
pSolo.setVitesseDansPartie();
}
// Sounds
if(code == KeyEvent.VK_S){
sounds = !sounds;
}
}
}
/** Cette méthode est appelée dès que l'utilisateur lâche une touche.
* @param e : l'évènement clavier.
*/
public void keyReleased(KeyEvent e)
{
}
public void keyTyped(KeyEvent e)
{
}
/** Cette méthode est appelée dès que l'utilisateur fait un clic de souris.
* Elle nous servira dans les menus.
* @param e : l'évènement souris.
*/
public void mouseClicked (MouseEvent e)
{
int x = e.getX();
int y = e.getY();
System.out.println("Coordonnée X du click : " + e.getX() + " Coordonnée Y du click : " + e.getY()) ;
if(this.activePanel.equals("Menu")){ // Lorsque c'est le menu qui est actif
if( x > 248 && x < 367 && y > 374 && y < 410){ // Bouton ABOUT
about.affiche();
}
if( x > 254 && x < 356 && y > 324 && y < 359){ // Bouton HELP
aide.affiche();
}
if( x > 219 && x < 391 && y > 274 && y < 308){ // Bouton OPTIONS
menu.detruit();
options = new Options(fondOptions,this);
contenu.add(options);
activePanel = new String("Options");
contenu.validate();
//contenu.getParent().setVisible(true);
this.setVisible(true);
//options.refresh();
}
if( x > 215 && x < 397 && y > 225 && y < 255){ // Bouton 1 vs 2
JDialog toto = new JDialog();
toto.setTitle("1Pvs2P pas encore fait");
toto.setVisible(true);
}
if( x > 211 && x < 416 && y > 175 && y < 208){ // Bouton 1 vs COM
JDialog toto = new JDialog();
toto.setTitle("1PvsCOM pas encore fait");
toto.setVisible(true);
}
if( x > 279 && x < 329 && y > 126 && y < 157){ // Bouton 1
// THEORIQUEMENT C'EST ICI QUE pSolo.play() devrait être appelé OR s'il est appelé ici l'affichage reste sur le JPanel "menu" et "pSolo" tourne derrière
activePanel = new String("PlayerSolo");
menu.detruit();
contenu.removeAll();
contenu.add(pSolo);
contenu.validate();
this.setVisible(true);
}
}
if(this.activePanel.equals("Options")){ // Lorsque c'est les options qui sont actives
if( x > 90 && x < 170 && y > 110 && y < 135){ // EASY
setNbCoupleAlimentsAnimaux(3);
}
if( x > 245 && x < 360 && y > 110 && y < 135){ // NORMAL
setNbCoupleAlimentsAnimaux(4);
}
if( x > 450 && x < 525 && y > 110 && y < 135){ // HARD
setNbCoupleAlimentsAnimaux(5);
}
if( x > 90 && x < 170 && y > 210 && y < 235){ // SLOW
setVitesseDuJeu(1);
}
if( x > 245 && x < 360 && y > 210 && y < 235){ // NORMAL
setVitesseDuJeu(2);
}
if( x > 450 && x < 525 && y > 210 && y < 235){ // FAST
setVitesseDuJeu(3);
}
if( x > 115 && x < 135 && y > 310 && y < 335){ // 1 SET
setNbSetGagnant(1);
}
if( x > 295 && x < 315 && y > 310 && y < 335){ // 2 SET
setNbSetGagnant(2);
}
if( x > 480 && x < 500 && y > 310 && y < 335){ // 3 SET
setNbSetGagnant(3);
}
if( x > 250 && x < 385 && y > 360 && y < 410){ // BACK
options.detruit();
menu = new Menu(fondMenu,this);
contenu.add(menu);
activePanel = new String("Menu");
contenu.validate();
this.setVisible(true);
}
}
}
/** Cette méthode est appelée dès que l'utilisateur bouge la souris.
* Elle nous servira pour les mouseover et faire le refresh correspondant
* @param e : l'évènement souris.
*/
public void mouseMoved(MouseEvent e)
{
int x = e.getX();
int y = e.getY();
this.xMouse = x;
this.yMouse = y;
if(this.activePanel.equals("Menu")){
menu.repaint();
}
if(this.activePanel.equals("Options")){
options.repaint();
}
}
public void mouseDragged(MouseEvent e){}
public void mousePressed (MouseEvent e){}
public void mouseReleased (MouseEvent e){}
public void mouseEntered (MouseEvent e){}
public void mouseExited (MouseEvent e){}
public static void main(String args[])
{
FenetreDeJeu fenetre = new FenetreDeJeu();
}
}
Je ne mets pas le code de "options" car il est basé sur le même principe que "menu" et fonctionne très bien. L'explication est sans doutes que "menu" comme "options" est rafraichi (méthode repaint) lors d'un mouvement de souris. Ce qui n'est pas le cas pour PlayerSolo.import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Menu extends JPanel {
private Image backGround = null;
private FenetreDeJeu fdJ;
private Boolean doRefresh;
/** Creates a new instance of Menu */
public Menu( Image backGround, FenetreDeJeu FdJ ) {
this.backGround = backGround;
this.fdJ = FdJ;
setOpaque( false );
doRefresh = true;
}
public void refresh(){
while(doRefresh){
this.Actualise();
}
}
public void paint( Graphics g )
{
if ( backGround != null )
g.drawImage( backGround, 0, 0,getSize().width, getSize().height, this );
super.paint(g);
g.setFont(fdJ.policeEcriture50);
g.setColor(Color.black);
g.drawString("Baku Baku Animals", 20, 60);
g.setFont(fdJ.policeEcriture35);
if( fdJ.xMouse > 279 && fdJ.xMouse < 329 && fdJ.yMouse > 126 && fdJ.yMouse < 157){
g.setColor(Color.white);
}
else{
g.setColor(Color.black);
}
g.drawString("1P", 277, 130);
if( fdJ.xMouse > 211 && fdJ.xMouse < 416 && fdJ.yMouse > 175 && fdJ.yMouse < 208){
g.setColor(Color.white);
}
else{
g.setColor(Color.black);
}
g.drawString("1P vs COM", 207, 180);
if( fdJ.xMouse > 215 && fdJ.xMouse < 397 && fdJ.yMouse > 225 && fdJ.yMouse < 255){
g.setColor(Color.white);
}
else{
g.setColor(Color.black);
}
g.drawString("1P vs 2P", 211, 230);
if( fdJ.xMouse > 219 && fdJ.xMouse < 391 && fdJ.yMouse > 274 && fdJ.yMouse < 308){
g.setColor(Color.white);
}
else{
g.setColor(Color.black);
}
g.drawString("OPTIONS", 215, 280);
if( fdJ.xMouse > 254 && fdJ.xMouse < 356 && fdJ.yMouse > 324 && fdJ.yMouse < 359){
g.setColor(Color.white);
}
else{
g.setColor(Color.black);
}
g.drawString("HELP", 251, 330);
if( fdJ.xMouse > 248 && fdJ.xMouse < 367 && fdJ.yMouse > 374 && fdJ.yMouse < 410){
g.setColor(Color.white);
}
else{
g.setColor(Color.black);
}
g.drawString("ABOUT", 246, 380);
}
public void Actualise()
{
try
{
Thread.sleep(10);
}catch(Exception e)
{
}
repaint();
}
public void affiche(){
this.setVisible(true);
doRefresh = true;
}
public void detruit(){
doRefresh = false;
this.setVisible(false);
fdJ.remove(this);
}
}
Code du JPanel "playerSolo"
J'ai volontairement coupé certaines fonctions et variables n'ayant pas trait au problème afin de rendre le code plus lisible.import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class PlayerSolo extends Partie {
/** Image de fond du jeu */
private Image backGround = null;
/** Variable pour savoir si on fait un refresh toutes les 10ms */
public Boolean doRefresh;
/** Variable pour savoir si le joueur a perdu */
public Boolean perdu;
/** Tableau associé au jeu */
private TableauDeBoule tableau = null;
/** Creates a new instance of PlayerSolo */
public PlayerSolo( Image backGround, FenetreDeJeu FdJ ) {
// SEMIE INITIALISATION : Le reste sera effectué quand playerSolo sera le JPanel actif, ce qui est fournit par la valeur de la méthode getActivePanel()
this.backGround = backGround;
fdj = FdJ;
setOpaque(false);
doRefresh = true;
setVisible(true);
perdu = false;
vitesseDansPartie = 0;
vitesseInitialeDesOptions = 0;
scoreTotal = 0;
combo = 0;
compteRebours = 3;
clignotageScore = 0;
}
public void setPerdu(Boolean bool){
this.perdu = bool;
}
public FenetreDeJeu getFenetreDeJeu(){
return this.fdj;
}
public void play()
{
while(doRefresh)
{
// boucle infinie du jeu doRefresh prend false que si l'on a perdu
try
{
Thread.sleep(10);
}catch(Exception e)
{
}
if(fdj.getActivePanel().equals("PlayerSolo"))
{
/** Fin d'initialisation du jeu */
if(tableau == null){
System.out.println("Initialisation");
tableau = new TableauDeBoule(200,6);
tableau.init();
vitesseInitialeDesOptions = tableau.getVitesse();
vitesseDansPartie = vitesseInitialeDesOptions;
System.out.println("Fin init tableau");
next = new CoupleBoule(tableau,tableau.getLevel());
System.out.println("Fin init next");
compteRebours = 3;
this.repaint();
}
int nbCoups = 1;
int pointsSupplementaires = 0;
/** JEU LANCE */
do{
// Code du jeu
}while( !getPerdu() );//On répète l'opération tant qu'on n'a pas perdu
// Si on a perdu
System.out.println("Nb de coup : "+nbCoups+" valeur de perdu : "+getPerdu());
doRefresh = false;
repaint();
perdu();
}
}
System.out.println("F I N D E P L A Y !");
}
public synchronized boolean getPerdu()
{
return perdu;
}
public void refresh(){
while(doRefresh){
System.out.println("Dans le While de refresh");
this.Actualise();
}
}
public void paint( Graphics g )
{
if ( backGround != null )
g.drawImage( backGround, 0, 0,getSize().width, getSize().height, this );
super.paint(g);
if(tableau != null){
g.translate(tableau.getABS0(),tableau.getORD0());
tableau.affiche(g);
g.translate(-tableau.getABS0(),-tableau.getORD0());
}
//On affiche le couple de boules qui sera le prochain couple
if(next != null)
afficheNext(g);
//On affiche le couple de boules qui descend
if(coupleBoule != null)
afficheCoupleDeBoules(g);
g.setColor(Color.black);
if(getPerdu() == true){
g.setColor(new Color(0,0,0,150));
g.fillRect(0,0,600,420);
g.setFont(fdj.policeEcriture50);
g.setColor(Color.white);
g.drawString("P E R D U !", 150, 200);
}
}
public void Actualise()
{
try
{
Thread.sleep(15);
//System.out.println("Sleep dans Actualise");
}catch(Exception e)
{
}
this.repaint();
}
public void perdu(){
final JDialog saveScore = new JDialog();
java.awt.GridBagConstraints gridBagConstraints;
JPanel mainPanel = new javax.swing.JPanel();
JLabel copyrightTextArea = new javax.swing.JLabel();
JButton ouiButton = new javax.swing.JButton();
JButton nonButton = new javax.swing.JButton();
saveScore.getContentPane().setLayout(new java.awt.GridBagLayout());
saveScore.setTitle("Congratulation, you've made "+scoreTotal);
mainPanel.setLayout(new java.awt.GridBagLayout());
mainPanel.setBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(11, 11, 12, 12)));
copyrightTextArea.setBackground(javax.swing.UIManager.getDefaults().getColor("Panel.background"));
copyrightTextArea.setText("<html>Save your score on the Internet ?</html>");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0);
mainPanel.add(copyrightTextArea, gridBagConstraints);
ouiButton.setMnemonic('Y');
ouiButton.setText("Yes");
ouiButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
saveScore.setVisible(false);
saveScore.dispose();
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
mainPanel.add(ouiButton, gridBagConstraints);
nonButton.setMnemonic('N');
nonButton.setText("No");
nonButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
saveScore.setVisible(false);
saveScore.dispose();
detruit();
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHEAST;
mainPanel.add(nonButton, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
saveScore.getContentPane().add(mainPanel, gridBagConstraints);
saveScore.setSize(new Dimension(250,100));
Rectangle parentBounds = fdj.getBounds();
Dimension size = saveScore.getSize();
// Center in the parent
int x = Math.max(0, parentBounds.x + (parentBounds.width - size.width) / 2);
int y = Math.max(0, parentBounds.y + (parentBounds.height - size.height) / 2);
saveScore.setLocation(new Point(x, y));
saveScore.setResizable(false);
saveScore.setVisible(true);
}
public void affiche(){
this.setVisible(true);
doRefresh = true;
}
public void detruit(){
// CODE SERVANT A REAFFICHER "menu" DANS LA JFRAME
perdu = false;
vitesseDansPartie = 0;
vitesseInitialeDesOptions = 0;
scoreTotal = 0;
combo = 0;
compteRebours = 3;
clignotageScore = 0;
fdj.remove(this);
fdj.removeAll();
doRefresh = true;
tableau = null;
fdj.relanceMenu();
System.out.println("Fin de détruit");
}
}
Merci pour toute aide que vous pourrez m'apporter.
P.S.: j'ai utilisé les balises "quote" à la place de "code" afin de pouvoir signaler en couleur les passages qui à mon avis posent problème dans mon code. Le rouge signale le passage de menu à playersolo et le bleu de playersolo à menu.
Partager