I am currently making a TicTacToe program for an assignment in college. I have my board laid out with 3x3 JTextFields, each one has an action listener attached. What I need to do is create another class which will check for errors (eg a user will put a number or a letter that is NOT x or o) they should get a dialog box stating the error and the JTextField they tried to enter will return to blank. How would I go about implementing the error checking, through try - catch - finally method?
Another question, I have a GameGUI class, I also want to have a GameLogic class. How do I check from GameLogic if the game has been won? In my GameLogic I will have something like
if j1, j2 and j3 are all x or o then display dialog box "x player wins".
I will try to answer the question regarding a general board game. Your object oriented thinking of splitting into different classes is correct. What I do generally is that I have the GameLogic containing my logic and validations for the game as well as determining whether the game is over or not and so on.
The GameGUI class would then have an instance variable of the type GameLogic that's initialized on creating an object of type GameGUI. In my way of thinking, I would have the GameLogic representing the board state with 2D Array of chars. The GameGUI would be just there to relay input from the user to the GameLogic which determines if the game is over. The GameLogic should throw an Exception of the type that you want to clarify and then the GameGUI should try to update the board with the input text from the user in the JText fields, catch the error from the GameLogic (if any) and then repaint the GUI that's displayed to the user based on the input it got. I will give a sample below to clarify my point although I won't provide the actual implementation for the TicTacToe game, you can easily do it on your own.
public class GameLogic {
....
char[][]board;
public GameLogic() {
//initialize the board representation for game
}
public boolean gameOver() {
//determine if the game is over by checking the board 2D array
// 3 xs or os in a row, column, or diagonal should determine the game is over or if there are no more moves
}
public void move(char character, int x, int y) {
//update a certain position with a character should throw an Exception if the character is invalid or if the the character is valid but it's not the character that the user owns player1 plays with x for example but puts o.
//should also have the logic for the turns
}
...
}
public class GameGUI {
.....
GameLogic engine;
public GameGUI() {
engine = new GameLogic();
}
public void actionPerformed(ActionEvent e) {
// here you would get the co-ordinates of the clicked JTextButton
// then call the method move on the engine instance
try {
engine.move(character, x, y);
} catch(Exception e) {
//display the validation for the error that happened
}
//repaint the representation from the engine to be displayed on the GUI Frame that you are using
}
...
}
One more thing is that I would have declared the JTextFields as 2D Array of JTextFields and not as individual instance variables to mirror the representation in the GameLogic class. You can also avoid the validations all together if you use JButton class instead of JTextField and that the user gets the character he is playing with on the clicked button if it is his turn and the button is not already used before.
Related
I'm not sure if this would be a simple question to answer on here, just because I'm using the Standard Draw class written by Princeton University, and I'm not sure if it's a globally known class.
But I'd much appreciate any feedback from those familiar with the StdDraw library.
What I'm trying to do is fairly straight-forward; check to see if the mouse of the user clicks onto an input box I drew, and if it is clicked, clear the existing text (which simply says "input") to make an empty String.
This is what it looks like so far:
public boolean handleClick(double x, double y) {
if(!super.handleClick(x,y)){
value = false;}
else {
if(highlighted){
value = true;
StdDraw.textLeft(xCentre+0.005,yCentre," ");} //Add the label
else{
value = false;}
}
return value; //I handled it. Nobody else should.}
}//handleClick
super.handleClick(x,y) is simply a method in the super class that draws the dimensions of the box:
public void draw(){
StdDraw.setPenColor(StdDraw.WHITE);
StdDraw.filledRectangle(xCentre,yCentre,halfWidth,halfHeight);
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius(); //Default thin line.
StdDraw.rectangle(xCentre,yCentre,halfWidth,halfHeight);
}
value is simply an instance variable of this class that will return true if all conditions are satisfied:
private boolean value;
highlighted is a boolean instance variable from the super class that simply states if the box is an input or output box.
My main question would be, is the line
StdDraw.textLeft(xCentre+0.005,yCentre," ");
the right way to clear the existing text and create an empty String with StdDraw? As it's not clearing the line, but maybe there's a bug elsewhere in my code that I'm missing and this line should work?
I'm trying to put together a game, However, i'm not sure how to tackle the reset function. I have made it so that the game resets, this works, however, on game restart, the label that is supposed to display how many games the player has played does not change from 0. Heres what I have done so far.
The display and positioning of labels...
private int noGamesPlayed;
private JLabel gamesPlayed = new JLabel("Games Played = " + noGamesPlayed);
getContentPane().add(gamesPlayed);
gamesPlayed.setBounds(60,60+gridsize*boardsize,130,30);
The reset function...
public void reset(){
game.this.setVisible(false);
game.this.dispose();
new game();
updateGamesPlayed();
}
The function that is suppose to update the games played...
public void updateGamesPlayed() {
noGamesPlayed ++;
gamesPlayed.setText("" + noGamesPlayed + " Games Played");
}
Help Appreciated.
Change the noOfGamesPlayed variable to static. That field does not belong to the object, but to the class itself. Then, change the updateGamesPlayed to a static method, this way all game objects will see the same numberOfGamesPlayed count. Like that:
private static int noGamesPlayed = 0;
public static void updateGamesPlayed() {
noGamesPlayed ++;
}
Then, on the reset method, create a new game after updating the number of games played.
public void reset(){
game.this.setVisible(false);
game.this.dispose();
updateGamesPlayed();
new game();
}
You can also make it "automatic" by incrementing the noGamesPlayed on the game constructor. That way you don't need to call updateGamesPlayed.
You're creating a completely new game object, one that has its own noGamesPlayed variable and JTextField, and likely this method call is not changing the gamesPlayed JTextField in the newly displayed GUI
gamesPlayed.setText("" + noGamesPlayed + " Games Played");
but rather is updating the JTextField of the GUI that has been disposed of. Note that your reset method looks to be recursive.
One solution is to call the updateGamesPlayed(...) method of the newly created game object (note that the class should be renamed Game), and pass in the correct number as a parameter.
Myself, I'd go about resetting my game in a completely different way, by not creating a new window, but instead by updating the key model variables (the non-GUI variables and classes that determine the state of your program) and then using those variables to reset the current display.
this is a problem that I've been really struggling with
I need to create a game for some University coursework. The game is basically a 4x4 grid. When i click a button, the player should move randomly within 1 square of it's location.
There's enemy spaceships that are generated randomly over the grid, and if the player lands on the spaceship, it destroys it. if there's two enemy ships on the same sqaure and the player lands on that square, the player is destroyed.
I've created a GIU using gridlayout and the button that I need to move the player, but I'm having problems trying to figure out how to actually use the grid. I've created an element class to create objects for the grid (ie, a list of enemy ships), but I don't know how to use this class with my gridlayout. I know I also have to redraw the grid after each move to reflect the changes, but I don't know if I would need to create a custom redraw method for this.
Any push in the correct direction so I can get my program actually doing something would be really helpful.
Some time ago I created a card game that also operated based on a GridLayout. Below is some of the code that was used to drive major events:
CardPanel extends JPanel {
public CardPanel() {
setLayout(gridLayout);
placeCards(N);
chatBoxText = new JTextArea(5, 30);
}
public void placeCards(int numCards) {
for (int i = 0; i < numCards; i++) {
Card card = deck.distributeCard();
String cardImageName = card.getImageName();
JLabel jLabel = makeImage(cardImageName);
cardSet.add(new GraphicCard(card, jLabel));
add(jLabel);
jLabel.addMouseListener(this);
}
if (GameLogic.noSetsOnBoard(cardSet)) {
gridLayout.setRows(gridLayout.getRows() + 1);
placeCards(3);
}
}
public void updateCard(Integer location) {
Card card = deck.distributeCard();
String cardImageName = card.getImageName();
JLabel jLabel = makeImage(cardImageName);
cardSet.set(location, new GraphicCard(card, jLabel));
jLabel.addMouseListener(this);
}
}
The CardPanel here is an object that represents the GridLayout (you see the constructor) as well as some of those helper methods.
Further on, on particular actions, I have the following code:
cardPanel.removeAll();
// Some other logic here
for (GraphicCard card: cardSet) {
cardPanel.add(card.getJLabel());
}
cardPanel.revalidate();
cardPanel.repaint();
In short, yes, it is custom, but it is not difficult. There are better ways to do it than the above such that you do not need to empty the entire panel in order to refresh it, the logic I have omitted above merited this particular solution.
The approach I used kept track of a CardPanel object which was an abstraction that contained not only the information that each box represented (in my case a card with some values), but also the graphic element to be rendered.
This was some time ago, so I don't recall the exact details but hopefully this is helpful.
I am coding an image puzzle game and one part of the code is to compare the pieces the user has selected to the pieces of the correct image.
Each image piece is already added to a JButton as an ImageIcon.
An identifier is required to differentiate each image piece apart and also for comparision.
I am setting a setName() for each JButton created as the identifier.
The comparison starts when the user releases the mouse after he drags the puzzle pieces from the original 3x3 grid where the shuffled pieces are to the other 3x grid for matching.
I have problems removing the error from the comparison if statement.
I got the comparison idea from this SO thread - link
private JButton[] button = new JButton[9];
private JButton[] waa = new JButton[9];
private String id;
private int cc;
private String id2;
private int cc2;
// setName for each of the 9 buttons in the original 3x3 grid being created
// which stores the shuffled puzzle pieces
for(int a=0; a<9; a++){
button[a] = new JButton(new ImageIcon());
id += Integer.toString(++cc);
button[a].setName(id);
}
// setName for each of the 9 buttons in the other 3x3 grid
// where the images will be dragged to by the user
for(int b=0; b<9; b++){
waa[b] = new JButton();
id2 += Integer.toString(++cc2);
waa[b].setName(id2);
}
// check if puzzle pieces are matched in the correct place
// compare name of original 'button' array button with the name of 'waa' array buttons
button[a].addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent m){
if(m.getbutton().getName().equals (waa.getName())){
}
else{
JOptionPane.showMessageDialog(null,"Wrong! Try Again.");
}
}
}
In your mouseReleased event m.getButton() is returning the mouse button that was clicked. You'll want to do something more like this that will get you closer:
if (m.getComponent().getName().equals(waa.getName())) {
m.getComponent() returns the Component object (your JButton) that the event was fired from. From there you can do the comparison with the getName approach you are using.
There's an additional issue in that your waa variable is an array. I'm not sure how you want to compare them, whether running through the arrays and making sure the index and names match, but that's an additional issue you need to look into.
JButton uses an ActionListener to trigger notifications back to your program to indicate when it's been triggered. This allows the button to respond to different types of event, including the mouse, keyboard and program triggers.
As apart of the action API, you can supply an action command for each button. See JButton#setActionCommand
Basically you would integrate it in a simular way to your mouse listener...
public void actio Performed(ActionEvent evt) {
if (command.equals(evt.getActionCommand()) {...}
}
Depending on your requirements, it might even be easier to use the Action API
The problem you are actually having is waa is an array, therefore, it doesn't have a getName method. I'm also unclear as to why you have two arrays of buttons?
Hey guys I've come with 2 problems, both being Java Swing related. I am developing a card game in Java. I use arreays lists of type to hold the values of each card and I have a main Play() method that calls updates to the GUI using invokeLater and a Singleton approach to my GUI class.
The first question is fairly simple. I create the cards on the GUI using JLabels like so; attaching relevent listeners and adding them to the appropriate panel, in this case, the 'Human Hand Panel':
for (int i = 0; i < (HumanHand.size()); i++)
{
Card card = HumanHand.get(i);
BufferedImage cardImage = null;
try {
cardImage = ImageIO.read(new File("card/" + card + ".jpg"));
} catch (IOException e) {
e.printStackTrace();
}
JLabel picLabel = new JLabel(new ImageIcon( cardImage ));
picLabel.addMouseListener((MouseListener) me);
HumanHandDisplay.add(picLabel);
}
//HumanHandDisplay.validate();
HumanHandDisplay.updateUI();
The problem I'm having is that when the human hand is more than 7 cards or so, it creates a larger panel area and starts a new row of cards beneath. What I would like to do is, when the hand reaches a certain size, the cards start to overlap eachother (like you would hold cards in your hand). I've messed about with .validate() but gotten nowhere. Any help you can give here would be most welcome.
My second question is about using a Swing Worker to return the Human player's card selection. I have read a little bit about Swing workers but I'm unsure as to the best way to implement one in my own game. At present, using the console I have a scanner than takes the input of an int as the choice (the place of the specific card in the ArrayList). I would like this int to be selected by clicking on the card in the players hand. At the moment I use:
String name = "" + i;
picLabel.setName(name);
to set the names of the Card JLabels to the int in the for loop creating them (as shown^^), and I use:
public void mouseClicked(MouseEvent e) {
String name = ((JLabel)e.getSource()).getName();
System.out.println("Working " + name);
selection = Integer.parseInt(name);
}
To return that int when one of the cards is clicked. Here is what I've been using to call the GUI methods from Play() aswell:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
GUI.getInstance().UpdateHand();
}
});
My question is, how can I get the Play method to call a method in the GUI class, which sets up the hand with the appropriate listeners (lets call it GUIPlayerSelection() for now) then wait for the player to click a card, which then returns the int to my Play() method in my main class that represents the card selected. I'm unsure as how to use invoke and wait, as in, if I use invoke and wait, will it just wait for the cards to be set up, or will it wait for the mouseClicked() method to finish aswell? Or will I have to do something else to make sure it waits for the mouse to be clicked after the hand set-up? And how then will I return that int? I've been told to use a swing worker but if someone could explain how I can implement that in this case that would be awesome.
Thank-you in advance.
For your first question, are you having an issue getting the frame to repaint or with the layout of the cards?
If the latter, then you may want to have a look at Java Layout Managers, it describes how the content pane inside your JFrame organizes the components added to it.
If none of those will work for you (and I don't think they will with that you describe), you can use the setBounds method to manually align your JLabels.