im trying to add a double value that represents the stamina of my player into a jTextArea after i click my north button cant seem to do it heres my code:
private void northButtonActionPerformed(java.awt.event.ActionEvent evt)
{
game.playerMove(MoveDirection.NORTH);
update();
double playerStamina = player.getStaminaLevel();
//tried this
String staminaLevel = Double.toString(playerStamina);
jTextArea1.setText("Stamina: " + staminaLevel);
}
im new here sorry if this is not right
heres the main method
public class Main
{
/**
* Main method of Lemur Island.
*
* #param args the command line arguments
*/
public static void main(String[] args)
{
// create the game object
final Game game = new Game();
// create the GUI for the game
final LemurIslandUI gui = new LemurIslandUI(game);
// make the GUI visible
java.awt.EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
gui.setVisible(true);
}
});
}
and heres the class
public class LemurIslandUI extends javax.swing.JFrame
{
private Game game;
private Player player;
/**
* Creates a new JFrame for Lemur Island.
*
* #param game the game object to display in this frame
*/
public LemurIslandUI(final Game game)
{
this.game = game;
initComponents();
createGridSquarePanels();
update();
}
private void createGridSquarePanels() {
int rows = game.getIsland().getNumRows();
int columns = game.getIsland().getNumColumns();
LemurIsland.removeAll();
LemurIsland.setLayout(new GridLayout(rows, columns));
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < columns; col++)
{
GridSquarePanel panel = new GridSquarePanel(game, row, col);
LemurIsland.add(panel);
}
}
}
/**
* Updates the state of the UI based on the state of the game.
*/
private void update()
{
for(Component component : LemurIsland.getComponents())
{
GridSquarePanel gsp = (GridSquarePanel) component;
gsp.update();
}
game.drawIsland();
}
Your class doesn't seem to be implmeneting ActionListener, therefore the action on your button will not be triggered.
Your class declaration should be:
public class LemurIslandUI extends javax.swing.JFrame implements ActionListener
And put the code for your button action inside:
public void actionPerformed(ActionEvent e) {}
Alternatively, you can use an anonymous class to implement the code for your button, instead of making your class implement the ActionListener. Something like:
final JButton button = new JButton();
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionevent)
{
//code
}
});
Try this.
jTextArea1.setText("Stamina: " + player.getStaminaLevel());
Using anything + string does auto casting to string.
Related
I am trying to make a java simulation of a train moving from station to station. I have the main code working but having trouble with the GUI. I have the basic layout with a start and stop button but as soon as the start button is selected, the main loop runs for the simulation and the GUI doesn't respond. I've been having trouble finding how to work around this. And help wpuld be much appreciated!
Here is the main simulation class:
/**
* Here is the main simulation class that runs the main loop.
* It uses instances of two classes : train and station.
* #author Ollie Jones
*
*/
public class SimEngine
{
/**
* Station object array and train object initialised.
* The line has 16 station so an array of 16 is needed.
*/
Station[] station = new Station[16];
Train train = new Train();
int forwardTimeArray[];
int backwardTimeArray[];
/**
* Constructor for objects of class SimEngine
*/
public SimEngine()
{
/**
* Here that values are initialised.
*/
train = new Train();
forwardTimeArray = new int[]{1,4,2,4,6,3,3,5,3,2,5,5,1,4,2};
backwardTimeArray = new int[]{3,2,4,5,2,2,4,3,4,2,5,2,1,4,5};
// A for loop is used to initialse the station number
for(int i=0; i<station.length; i++){
station[i] = new Station();
station[i].setStationNumber(i+1);
}
/**
* Each station name is initialised separately as
* they all have different names.
*/
station[0].setStationName("Name of 1st station");
station[1].setStationName("Name of 2nd station");
station[2].setStationName("Name of 3rd station");
station[3].setStationName("Name of 4th station");
station[4].setStationName("Name of 5ht station");
station[5].setStationName("Name of 6th station");
station[6].setStationName("Name of 7th station");
station[7].setStationName("Name of 8th station");
station[8].setStationName("Name of 9th station");
station[9].setStationName("Name of 10th station");
station[10].setStationName("Name of 11th station");
station[11].setStationName("Name of 12th station");
station[12].setStationName("Name of 13th station");
station[13].setStationName("Name of 14th station");
station[14].setStationName("Name of 15th station");
station[15].setStationName("Name of 16th station");
}
/**
* An example of a method - replace this comment with your own
*
* #param y a sample parameter for a method
* #return the sum of x and y
*/
/**
* This method stats the train simulation.
*
*/
public void start()
{
int x = 0;
System.out.println("Station Number:1"); //Print the first staion number.
while(x == 0){
int stationNumber = 0;
int time = 0;
Boolean forwards;
stationNumber = train.getStationNumber();
forwards = train.getDirection();
if (forwards == true){
time = forwardTimeArray[stationNumber-1];
sleep(time);
stationNumber = stationNumber + 1;
System.out.println("Station Nubmer:" + stationNumber);
train.setStationNumber(stationNumber);
}
else{
time = backwardTimeArray[stationNumber-2];
sleep(time);
stationNumber = stationNumber - 1;
System.out.println("Station Number:" + stationNumber);
train.setStationNumber(stationNumber);
}
if (stationNumber == 1){
forwards = true;
}
else if (stationNumber == 16){
forwards = false;
//train.setStationNumber(stationNumber-1);
}
train.setDirection(forwards);
}
}
public static void sleep(int time)
{
try{
time = time * 100;
Thread.sleep(time);
}
catch(Exception e) {}
}
public void stop()
{
System.exit(0);
}
}
Here is the sim class where the simulation is started.
public class Sim
{
private GUI gui;
private SimEngine engine;
/**
* Constructor for objects of class sim
*
*/
public Sim()
{
engine = new SimEngine();
gui = new GUI(engine);
}
/**
* Opens window if it has been closed.
*/
public void show()
{
gui.setVisable(true);
}
}
Here is the GUI, where the main issue is (i think).
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
public class GUI extends JFrame
{
// instance variables - replace the example below with your own
private JFrame frame;
private JTextField display;
private final SimEngine sim;
private JLabel infoLabel;
/**
* Constructor for objects of class GUI
*/
public GUI(SimEngine engine)
{
// initialise instance variables
makeFrame();
frame.setVisible(true);
sim = engine;
}
/**
* Creates GUI frame!
*/
public void makeFrame()
{
frame = new JFrame("Train Simulation");
JPanel contentPane = (JPanel)frame.getContentPane();
contentPane.setLayout(new BorderLayout(8,8));
contentPane.setBorder(new EmptyBorder(10,10,10,10));
display = new JTextField();
contentPane.add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel(new GridLayout(1,2));
addButton(buttonPanel, "Start", () -> sim.start());
addButton(buttonPanel, "Stop", () -> sim.stop());
contentPane.add(buttonPanel, BorderLayout.CENTER);
frame.pack();
}
private void addButton(Container panel, String buttonText, ButtonAction
action)
{
JButton button = new JButton(buttonText);
button.addActionListener(e -> {action.act(); redisplay(); });
panel.add(button);
}
private interface ButtonAction
{
/**
* act on button press.
*/
void act();
}
private void redisplay()
{
}
/**
* Makes frame visable.
*/
public void setVisable(boolean visable){
frame.setVisible(visable);
}
}
You're running your simulation on the event dispatch thread. While your calculations are happening, they are monopolizing the thread that handles UI events, so it can't process anything and the UI freezes.
Use worker threads.
It looks like you have this usecase (from the linked tutorial):
The background task can provide intermediate results by invoking SwingWorker.publish, causing SwingWorker.process to be invoked from the event dispatch thread.
As explained in the comments and in this answer, running long processes on the The Event Dispatch Thread blocks it, so it does not respond to changes.
One alternative is to use a SwingWorker which does the background processing in its doInBackground() method, publishes interim values (publish method) and is capable of updating gui (process method).
The following is a basic implementation of a SwingWorker, based on your code.
It can be copy-pasted into one file (GUI.java) and run.
Note the comments in the code:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
public class GUI extends JFrame
{
// instance variables - replace the example below with your own
private JFrame frame;
private JTextField display;
private final SimEngine sim;
private JLabel infoLabel;
/**
* Constructor for objects of class GUI
*/
public GUI(SimEngine engine)
{
// initialize instance variables
makeFrame();
frame.setVisible(true);
sim = engine;
}
/**
* Creates GUI frame!
*/
public void makeFrame()
{
frame = new JFrame("Train Simulation");
JPanel contentPane = (JPanel)frame.getContentPane();
contentPane.setLayout(new BorderLayout(8,8));
contentPane.setBorder(new EmptyBorder(10,10,10,10));
display = new JTextField();
contentPane.add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel(new GridLayout(1,2));
addButton(buttonPanel, "Start", () -> sim.start());
addButton(buttonPanel, "Stop", () -> sim.stop());
contentPane.add(buttonPanel, BorderLayout.CENTER);
frame.pack();
}
private void addButton(Container panel, String buttonText, ButtonAction action)
{
JButton button = new JButton(buttonText);
button.addActionListener(e -> {action.act(); redisplay(); });
panel.add(button);
}
void updateDisplay(String newValue){
display.setText(newValue);
}
private interface ButtonAction
{
/**
* act on button press.
*/
void act();
}
private void redisplay() { }
/**
* Makes frame visible.
*/
public void setVisable(boolean visable){
frame.setVisible(visable);
}
public static void main(String[] args) {
Sim sim = new Sim();
sim.show();
}
}
//implements Listener so it can listen to SimEngine value changes
class Sim implements Listener
{
private final GUI gui;
private final SimEngine engine;
public Sim()
{
engine = new SimEngine(this);
gui = new GUI(engine);
}
/**
* make gui visible
*/
public void show()
{
gui.setVisable(true);
}
#Override
public void valueChanged(String newValue){
gui.updateDisplay(newValue);
}
}
class SimEngine {
/**
* Station object array and train object initialized.
* The line has 16 station so an array of 16 is needed.
*/
private final Station[] station = new Station[16];
private Train train = new Train();
private final int forwardTimeArray[], backwardTimeArray[];
private final Listener listener;
//accept a listener
public SimEngine(Listener listener)
{
this.listener = listener;
train = new Train();
forwardTimeArray = new int[] {1,4,2,4,6,3,3,5,3,2,5,5,1,4,2,3}; //needs 16 values, had only 16
backwardTimeArray = new int[]{3,2,4,5,2,2,4,3,4,2,5,2,1,4,5,4};
// A for loop is used to initialize the station number and name
for(int i=0; i<station.length; i++){
station[i] = new Station();
station[i].setStationNumber(i+1);
station[0].setStationName("Station #"+(i+1));
}
}
/**
* This method starts the train simulation.
*
*/
public void start()
{
//have all background processing done by a SwingWorker so GUI does not freeze
new SimulationWorker().execute();
}
public static void sleep(int time)
{
try{
Thread.sleep(time * 300);
}
catch(Exception e) {}
}
public void stop()
{
System.exit(0);
}
class SimulationWorker extends SwingWorker<Void,Integer>{
boolean stop = false; //use if you wish to stop
//do background processing
#Override
protected Void doInBackground() throws Exception {
while(! stop){
int stationNumber = 0;
int time = 0;
boolean forwards;
stationNumber = train.getStationNumber();
forwards = train.getDirection();
if (stationNumber == 1){
forwards = true;
train.setDirection(forwards);
}
else if (stationNumber == 15){
forwards = false;
train.setDirection(forwards);
}
if (forwards == true){
time = forwardTimeArray[stationNumber+1];//time = forwardTimeArray[stationNumber-1];
sleep(time);
stationNumber = stationNumber + 1;
//System.out.println("Station Number:" + stationNumber);
train.setStationNumber(stationNumber);
}
else{
time = backwardTimeArray[stationNumber-2];
sleep(time);
stationNumber = stationNumber - 1;
//System.out.println("Station Number:" + stationNumber);
train.setStationNumber(stationNumber);
}
publish(train.getStationNumber()); //publish result (station number)
}
return null;
}
//process published information
#Override
protected void process(List<Integer> stationsList) {
for(int stationNumber : stationsList){
listener.valueChanged("Train is at "+ stationNumber); //notify listener
}
}
}
}
class Train {
private int stationNumber = 0;
private boolean forwards = true ;
public int getStationNumber() {
return stationNumber;
}
public void setDirection(boolean forwards) {
this.forwards = forwards;
}
public void setStationNumber(int stationNumber) {
this.stationNumber = stationNumber;
}
public boolean getDirection() {
return forwards;
}
}
class Station {
private int stationNumber;
private String stationName;
public void setStationNumber(int stationNumber) {
this.stationNumber = stationNumber;
}
public void setStationName(String stationName) {
this.stationName = stationName;
}
}
//an interface use by Sim to listen to SimEngine changes
interface Listener {
void valueChanged(String newValue);
}
I have been trying to create a 'catch me if you can' game: when I start it, it randomly chooses where to allocate a 'click me' button. I am not supposed to be able to click the button, the text should be re-assigned to another button before I am able to do that.
It works for a while but then it throws the following error: "java.awt.AWTEventMulticaster.mouseMoved".
I have been trying to fix the problem with removeListener() method but I don't seem to be able to find a solution. Any comments?
Here's my code:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.lang.*;
public class Game extends JFrame {
//Panels
private JPanel mainPanel = new JPanel();
// Buttons
private JButton[] buttons = new JButton[9];
private JButton theChosenButton = new JButton();
// other
private int random = 0;
public Game() {
this.setTitle("Catch me if you can");
mainPanel.setLayout(new GridLayout(3, 3));
// creates buttons
for(int i = 0; i < 9 ; i++) {
buttons[i] = new JButton();
mainPanel.add(buttons[i]);
}
// Add everything to frame
this.getContentPane().add(mainPanel);
this.setSize(400, 400);
this.setVisible(true);
}
// generates random number between 1 and 9 to be used
public int clickMeGenerator(){
random = (int) Math.floor(Math.random() * 9);
return random;
}
// randomly assigns clickMeGenerator to a button
// add mouseMoved listener to the chosen button
public void assign(){
int randomButton = this.clickMeGenerator();
theChosenButton = buttons[randomButton];
theChosenButton.addMouseMotionListener(new MouseHover());
theChosenButton.setText("Click me");
}
public void removeListener() {
theChosenButton.removeMouseMotionListener(new MouseHover());
//}
}
// inner class
class MouseHover implements MouseMotionListener {
public void mouseMoved(MouseEvent e) {
theChosenButton.setText("");
Game.this.assign();
}
public void mouseDragged(MouseEvent e) {
}
}
} // end of class
Test class:
public class GameTest {
public static void main (String args[]) {
Game myGame = new Game();
myGame.assign();
}
}
Thank you so much for your help!
Just for clarity, the "actual" error is ...
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at java.desktop/java.awt.AWTEventMulticaster.mouseMoved(AWTEventMulticaster.java:337)
at java.desktop/java.awt.AWTEventMulticaster.mouseMoved(AWTEventMulticaster.java:337)
So looking through the code...
public void assign() {
int randomButton = this.clickMeGenerator();
theChosenButton = buttons[randomButton];
theChosenButton.addMouseMotionListener(new MouseHover());
theChosenButton.setText("Click me");
}
You are repeatedly add a new MouseMotionListener to you buttons, over and over again, and...
public void removeListener() {
theChosenButton.removeMouseMotionListener(new MouseHover());
//}
}
is pointless, as you're trying to remove a new instance of MouseHover from the button, but it will never have been applied in the first place.
The first thing I would do is create an instance of MouseHover as an instance field in Game
private MouseHover mouseHover = new MouseHover();
and use it when calling addMouseMotionListener and removeMouseMotionListener.
I would then, remove the listener from the "currently" active button before adding it to the next one.
Personally, I would do this in the assign method
public void assign() {
int randomButton = this.clickMeGenerator();
if (theChosenButton != null) {
theChosenButton.removeMouseMotionListener(mouseHover);
}
theChosenButton = buttons[randomButton];
theChosenButton.addMouseMotionListener(mouseHover);
theChosenButton.setText("Click me");
}
I would also ensure that assign is called from within the Event Dispatching Thread when the class is first created, as the UI has been realised by the end of the constructor of Game, meaning the first call to assign is outside of the context of the EDT, which is not recommended.
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Game myGame = new Game();
myGame.assign();
}
});
}
Beginner Java developer. Trying to make a Tetris applet as part of my personal projects.
I'm at the point were I can draw tetris blocks onto the screen but I cannot make it vertically go downwards every second.
Code:
public class InitialScreen extends JApplet implements ActionListener {
public JPanel cards = new JPanel();
private JPanel introPanel = new JPanel();
public CardLayout c1 = new CardLayout();
public void init() {
initiateIntroScreen();
//game();
add(cards, BorderLayout.NORTH);
setSize(500, 100);
}
private void initiateIntroScreen() {
Frame title = (Frame)this.getParent().getParent();
cards.setLayout(c1);
JLabel centralWords = new JLabel("Click the following button options: 'Play' or 'Instructions'.");
JButton playBtn = new JButton("Play!");
JButton instructionsBtn = new JButton("Instructions!");
introPanel.add(centralWords);
introPanel.add(playBtn);
introPanel.add(instructionsBtn);
cards.add(introPanel,"1");
playBtn.addActionListener(this);
playBtn.addActionListener(new MainGame(cards,c1));
}
#Override
public void actionPerformed(ActionEvent e) {
setSize(300,410);
getContentPane().setBackground(Color.BLACK);
}
So this is the initial screen for the JApplet. Has two buttons. When you press the 'Play' button it goes to the Main Game Screen.
public class MainGame extends JApplet implements ActionListener {
private JPanel cards;
private CardLayout c1;
private JPanel gamePanel = new JPanel();
public MainGame(JPanel cards, CardLayout c1) {
this.c1 = c1;
this.cards = cards;
gamePanel.add(new Tetris_Block(new int[10][20]));
}
#Override
public void actionPerformed(ActionEvent e) {
JLabel scoreLbl = new JLabel("Score:");
gamePanel.add(scoreLbl);
cards.add(gamePanel,"game");
c1.show(cards,"game");
}
This is the game screen were Tetris is played. In the constructor it calls a Tetris Block.
public class Tetris_Block extends JComponent implements ActionListener {
static Color[] colors =
{darkGray, green, blue, red,
yellow, magenta, pink, cyan};
int[][] a;
int w, h;
static int horizontalPos, verticalPos = 0;
static int size = 20;
private int verticalPos1 = 1;
public Tetris_Block(int[][] a) {
this.a = a;
w = a.length;
h = a[0].length;
square_Block();
startTimer();
}
private void nextMove() {
verticalPos++;
verticalPos1++;
}
public void square_Block(){ //Horizontal || Vertical || Colour
//Horizontal never changes for this as I just want the blocks to go down.
a[0][verticalPos] = 3;
a[0][verticalPos1] = 3;
a[1][verticalPos] = 3;
a[1][verticalPos1] = 3;
}
#Override
public void actionPerformed(ActionEvent e) {
nextMove();
square_Block();
System.out.println(verticalPos);
}
public void startTimer(){
Timer timer = new Timer(1000,this);
timer.start();
}
public void paintComponent(Graphics g) {
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
g.setColor(colors[a[i][j]]);
g.fill3DRect(i * size, j * size,
size, size, true);
}
}
}
public Dimension getPreferredSize() {
return new Dimension(w * size, h * size);
}
My aim is to make the vertical position increment by 1 every second (So it goes down the window in second intervals.
I don't think the Timer function is the problem. When I print verticalPos it prints out the incremented value every second, however it's just displaying the new location onto the screen- that is the problem.
Image of window right now.
[img]http://i.imgur.com/au5fceO.png?1[/img]
Start by adding a call to repaint in you actionPerformed method of your Tetris_Block
#Override
public void actionPerformed(ActionEvent e) {
nextMove();
square_Block();
System.out.println(verticalPos);
// This is important
repaint();
}
This will schedule a paint event on the event queue which will eventually call your paintComponent method (indirectly)
This will get the block to start moving. The next problem you will have is you're not actually "removing" the block from it's previous position, so it will continue to bleed/grow down the screen
You could solve this by passing in the color of the block to square_Block, for example...
public void square_Block(int color) { //Horizontal || Vertical || Colour
//Horizontal never changes for this as I just want the blocks to go down.
a[0][verticalPos] = color;
a[0][verticalPos1] = color;
a[1][verticalPos] = color;
a[1][verticalPos1] = color;
}
And then "rest" the blocks of the current position, update the position and then set the new block colors;
#Override
public void actionPerformed(ActionEvent e) {
square_Block(0);
nextMove();
square_Block(3);
System.out.println(verticalPos);
repaint();
}
Your design here may be faulty. You need to have a game loop that runs in a separate thread. It has to be a separate thread from the main thread so the user can still click buttons. Once you have a loop in the separate thread you need to have a method that you call for every game tick. It's in that method that you update the coordinates of the blocks.
Game loop works like this:
1. Read state of the game and draw the blocks
2. Process user input.
3. Update game state
I know this is abstract but I hope it helps. Google about java games and game loops.
I'm using a GUI builder to make a simple JFrame that contains a JPanel. I want to add a random number of JButtons to the panel, is it possible for me to do this without having to write my own code for the JPanel? I ask because I am not strong with Swing layouts.
Main class:
public static void main( String[] args )
{
int buttonCount = new Random().nextInt(5)+1;
JFoo foo = new JFoo(buttonCount);
foo.setVisible(true);
}
JFoo class:
public class JFoo extends javax.swing.JFrame {
int buttonCount;
public JFoo() {
initComponents();
}
public JFoo(int buttonCount) {
this.buttonCount = buttonCount;
initComponents();
buttonCountLabel.setText("Button Count: "+buttonCount);
}
private void initComponents() {
//generated code
...
}
I have to design a batleships game for friday but the course im doing seems to have skipped a few things because although i managed all the other assignments this final project is unbelievably above my grasp but i have to do something.
i have the following GUI code which gives me my playing grids but i have absolutely no idea how to do the following things
assign a ship to some cells - and color these cells to reflect this
how to do the actual hit,miss,sunk and update the grid
i figure if i can at least do these i can duplicate the code for the cpu but im sooooooo stuck so any help is really appreciated please guys work some magic :)
/**
* BattleGui:
*
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
public class BattleGui implements ActionListener
{
// Default filename to use for saving and loading files
// Possible improvement: replace with a FileChooser
private final static String DEFAULT_FILENAME = "battlegui.txt";
private int GRID_SIZE = 8;
private JButton [] buttonArray;
public JMenuBar createMenu()
{
JMenuBar menuBar = new JMenuBar();;
JMenu menu = new JMenu("Battle Menu");
JMenuItem menuItem;
menuBar.add(menu);
// A group of JMenuItems. You can create other menu items here if desired
menuItem = new JMenuItem("New Game");
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new JMenuItem("Load Game");
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new JMenuItem("Save Game");
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new JMenuItem("Quit");
menuItem.addActionListener(this);
menu.add(menuItem);
//a submenu
menu.addSeparator();
return menuBar;
}
public Container createContentPaneCPU()
{
int numButtons = GRID_SIZE * GRID_SIZE;
JPanel grid = new JPanel(new GridLayout(GRID_SIZE,GRID_SIZE));
buttonArray = new JButton[numButtons];
for (int i=0; i<numButtons; i++)
{
buttonArray[i] = new JButton(" ");
// This label is used to identify which button was clicked in the action listener
buttonArray[i].setActionCommand("" + i); // String "0", "1" etc.
buttonArray[i].addActionListener(this);
grid.add(buttonArray[i]);
}
return grid;
}
public Container createContentPane()
{
int numButtons = GRID_SIZE * GRID_SIZE;
JPanel grid = new JPanel(new GridLayout(GRID_SIZE,GRID_SIZE));
buttonArray = new JButton[numButtons];
for (int i=0; i<numButtons; i++)
{
buttonArray[i] = new JButton(" ");
// This label is used to identify which button was clicked in the action listener
//buttonArray[i].setActionCommand("" + i); // String "0", "1" etc.
// buttonArray[i].addActionListener(this);
grid.add(buttonArray[i]);
}
return grid;
}
/**
* This method handles events from the Menu and the board.
*
*/
public void actionPerformed(ActionEvent e)
{
String classname = getClassName(e.getSource());
JComponent component = (JComponent)(e.getSource());
if (classname.equals("JMenuItem"))
{
JMenuItem menusource = (JMenuItem)(e.getSource());
String menutext = menusource.getText();
// Determine which menu option was chosen
if (menutext.equals("Load Game"))
{
/* BATTLEGUI Add your code here to handle Load Game **********/
LoadGame();
}
else if (menutext.equals("Save Game"))
{
/* BATTLEGUI Add your code here to handle Save Game **********/
SaveGame();
}
else if (menutext.equals("New Game"))
{
/* BATTLEGUI Add your code here to handle Save Game **********/
NewGame();
}
}
// Handle the event from the user clicking on a command button
else if (classname.equals("JButton"))
{
JButton button = (JButton)(e.getSource());
int bnum = Integer.parseInt(button.getActionCommand());
int row = bnum / GRID_SIZE;
int col = bnum % GRID_SIZE;
System.out.println(e.getSource());
/* BATTLEGUI Add your code here to handle user clicking on the grid ***********/
button.setBackground(Color.GREEN);
fireShot(row, col);
}
}
/**
* Returns the class name
*/
protected String getClassName(Object o)
{
String classString = o.getClass().getName();
int dotIndex = classString.lastIndexOf(".");
return classString.substring(dotIndex+1);
}
/**
* Create the GUI and show it.
* For thread safety, this method should be invoked from the event-dispatching thread.
*/
private static void createAndShowGUI()
{
// Create and set up the window.
JFrame frame = new JFrame("Battleships");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int maxGap = 20;
int ButtonWidth = 20;
int ButtonHeight = 1;
BattleGui battlegui = new BattleGui();
frame.setJMenuBar(battlegui.createMenu());
JPanel gui = new JPanel(new GridLayout(2,2,20,5));
gui.setBorder(new EmptyBorder(5,5,5,5));
//Set up components preferred size
JButton b = new JButton("Just fake button");
Dimension buttonSize = b.getPreferredSize();
gui.add(new JButton("Player"));
gui.add(new JButton("CPU"));
b.setPreferredSize(new Dimension(ButtonWidth, ButtonHeight));
gui.add(battlegui.createContentPane());
gui.add(battlegui.createContentPaneCPU());
frame.setContentPane(gui);
// Create and set up the content pane.
/*
BattleGui battlegui = new BattleGui();
frame.setJMenuBar(battlegui.createMenu());
frame.setContentPane(battlegui.createContentPane());
*/
// Display the window, setting the size
frame.setSize(800, 600);
frame.setVisible(true);
}
/**
* Sets a Gui grid square at row, col to display a character
*/
public boolean setGuiSquare(int row, int col, char c)
{
int bnum = row * GRID_SIZE + col;
if (bnum >= (GRID_SIZE*GRID_SIZE))
{
return false;
}
else
{
buttonArray[bnum].setText(Character.toString(c));
}
return true;
}
/**
* This is a standard main function for a Java GUI
*/
public static void main(String[] args)
{
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
//Deploy();
}
});
}
//************************************************************************
//*** BATTLEGUI: Modify the methods below to respond to Menu and Mouse click events
/**
* This method is called from the Menu event: New Game.
* BATTLEGUI
*/
public void NewGame()
{
System.out.println("New game selected");
}
/**
* This method is called from the Menu event: Load Game.
* BATTLEGUI
*/
public void LoadGame()
{
System.out.println("Load game selected");
}
/**
* This method is called from the Menu event: Save Game.
* BATTLEGUI
*/
public void SaveGame()
{
System.out.println("Save game selected");
}
/**
* This method is called from the Mouse Click event.
* BATTLEGUI
*/
public void fireShot(int row, int col)
{
System.out.println("Fire shot selected: at (" + row + ", " + col + ")");
}
}
I would suggest, take a step back and think about the problem domain.
You have a BattleScene, which contains BattleSquares. Each battleSquare can have atmost 1 ship, and can have a color. You also have Ship objects (which can belong to a particular player, indicates if it is damaged or not)...
BattleSquare needs to decide if it is a Hit or Miss, because it has all the information. It knows wether it has a ship or not.
/**true if had a ship, false if it was a miss
*/
public class BattleSquare{
public boolean processHit(){
if (hasShip()){
ship.setState(DESTROYED);
return true;
}
return false;
}
public void setShip(Ship ship){ .... }
public boolean hasShip() { ... } } ... methods for color too
If you isolate your code into manageable snippets, where some classes represent the model, you will be able to manage things better. You appear to be mixing everything in one class and hence are feeling lost.
Similarly, your BattleScene will contains a List of BattleSquares. Once you fire, you can individuall seek a particular BattleSquare and tell it to process itself. If it is a hit, you update the state.
Idea is that your model classes only are responsible for managing state. Your controller classes can fire events, which are intercepted by views, who update the models and refresh themselves.
hopefully it helps.