I am making a tower defense game.All works fine except, I want to have a JButton which will give the player the chance to choose when to start a new wave.So here is the (REALLY STRANGE) problem:
When the program runs, a new JFrame is created.In its constructor I add a GameManager, the "map" blah blah...and at the end of the JFrame constructor, my last line is gm.nextWave(); (gm is the GameManager object).It works fine, monsters are generated, walking to the rift through the path I've made, lives are lost for each one reaching it etc.But when i remove that line and instead have the JButton do it, when i click the button:
1st no monsters appear
2nd the nextWave() method seems to run, because i put a System.out.println("test") in the while loop in it and it prints the message to the console fine.
3rd the button used to call nextWave() is "stuck in".It looks as if its pressed in continiously.
And 4th the frame won't close with the "X" on the upper right.(I've set the defaultCloseOperation(JFrame.EXIT_ON_CLOSE)
in the JFrame)
Here is the JFrame code and the GameManager class.Any idea why it is "rejecting" my button??
import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JPanel; public class GameFrame extends JFrame{ private JPanel mainPanel; private JLayeredPane layers; private ImageIcon map; private JLabel mapContainer; private GameManager gm; private GlassPane glass; private JButton nextWaveButt; public GameFrame(){ //buttons nextWaveButt = new JButton("Next Wave"); nextWaveButt.setBounds(50, 600, 100, 50); nextWaveButt.addActionListener(new NewWaveListener()); //map and its container map = new ImageIcon("Images\\TDmap.png"); mapContainer = new JLabel(map); mapContainer.setBounds(0, 0, map.getIconWidth(), map.getIconHeight()); //mainPanel, contentPane, layers, adding the map to the frame mainPanel = new JPanel(); setContentPane(mainPanel); layers = new JLayeredPane(); layers.setPreferredSize(new Dimension(map.getIconWidth(),map.getIconHeight())); //adding elements to layers and mainPanel layers.add(mapContainer, new Integer(2)); layers.add(nextWaveButt, new Integer(3)); mainPanel.add(layers); //glass pane glass = new GlassPane(); setGlassPane(glass); getGlassPane().setVisible(true); //game manager gm = new GameManager(glass, layers); //typical setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setTitle("Tower Defense - Game Running"); pack(); setResizable(false); setLocation(0, 0); setVisible(true); gm.nextWave(); } class NewWaveListener implements ActionListener{ @Override public void actionPerformed(ActionEvent arg0) { gm.nextWave(); } } }
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import javax.swing.JLayeredPane; public class GameManager { private JLayeredPane layers; private ArrayList<Point> path; private ArrayList<Monster> wave; private ArrayList<Tower> towers; private boolean waveEnd; private int lives, produced, defaultIndex, //the pathIndex the first monster would be if it walked without interruptions prevIndex, //the previous "defaultIndex"----see defaultIndex description for more details defaultGameSpeed, //the default speed the game will be running at gameSpeed;//the chosen speed the game will be running at private GlassPane glass; //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- //Here go the methods /** * Creates a new GameManager which handles game events.<br> * The GameManager also holds a reference of the GlassPane and * the JLayeredPane of the game,given to it by its arguments. * @param layers * @param glass */ public GameManager(GlassPane glass, JLayeredPane layers){ this.layers = layers; this.glass = glass; towers = new ArrayList<Tower>(); gameSpeed = defaultGameSpeed = 75; lives = 20; setPath(); } //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- //Game functions /** * Makes the next wave start.Produces monsters that target the rift. * If they reach it,lives are lost.If all lives are lost the game is over. */ public void nextWave(){ waveEnd = false; produced = 1; defaultIndex = 0; prevIndex = 0; wave = new ArrayList<Monster>(); for(int i=0;i<20;i++){ wave.add(new Monster(this, "Monster")); layers.add(wave.get(i),new Integer(3)); } wave.get(0).setVisible(true); wave.get(0).setMovableOrRemoveSuppress(); while(!waveEnd){ try{ Thread.currentThread().sleep(100-gameSpeed); }catch(InterruptedException e){ e.printStackTrace(); } if(produced<20 && allowedToMakeNewMonsterMovable()){ wave.get(produced).setVisible(true); wave.get(produced).setMovableOrRemoveSuppress(); produced++; } for(Monster m:wave) if(m.isAlive()) if(m.isMovable()) m.move(); defaultIndex += wave.get(0).getDefaultSpeed(); int count = 0; for(Monster m:wave) if(m.isAlive()){ count++; break; } if(count == 0) waveEnd = true; } System.out.println("wave end"); for(Monster m:wave) layers.remove(m); layers.repaint(); } //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- //Getters /** * Returns true if the <b>wave</b> has ended<br> * (all monsters finished/killed) or false if not. * @return */ public boolean waveEnd(){ return waveEnd; } /** * Returns an ArrayList containing the monsters included in the current wave. * @return */ public ArrayList<Monster> getWave(){ return wave; } /** * Returns an ArrayList containing the towers built. * @return */ public ArrayList<Tower> getTowers(){ return towers; } /** * Returns the number of <b>lives</b> left. * @return */ public int getLives(){ return lives; } /** * Returns an ArrayList containing all <b>Points</b> included * in the <b>path</b> monsters follow to reach the Rift. * @return */ public ArrayList<Point> getPath(){ return path; } /** * Returns a reference to the game's GlassPane. * @return */ public GlassPane getGlass(){ return glass; } //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- //Setters /** * Resets the game display speed to the default. */ public void restoreDefaultSpeed(){ gameSpeed = defaultGameSpeed; } /** * Modifies the game display speed. * @param speed */ public void setGameSpeed(int speed){ gameSpeed = speed; } /** * Returns true if the GameManager is allowed to make a new Monster start moving. * @return */ private boolean allowedToMakeNewMonsterMovable(){ if(defaultIndex - prevIndex >=50){ prevIndex = defaultIndex; return true; } else return false; } /** * Reduces lives by an amount equal to the <i>lifeValue</i>. * @param lifeValue */ public void removeLife(int lifeValue){ lives -= lifeValue; } /** * Sets the <b>path</b> Monsters will follow * to get to the Rift. */ private void setPath(){ path = new ArrayList<Point>(); for(int x=0;x<163;x++){ path.add(new Point(x,12)); } for(int y=12;y<163;y++){ path.add(new Point(163,y)); } for(int x=163;x<313;x++){ path.add(new Point(x,163)); } for(int y=163;y<413;y++){ path.add(new Point(313,y)); } for(int x=313;x<563;x++){ path.add(new Point(x,413)); } for(int y=413;y>163;y--){ path.add(new Point(563,y)); } for(int x=563;x<1001;x++){ path.add(new Point(x,163)); } } }
Main:
public class Main { public static void main(String[] args) { new GameFrame(); } }