ImageIcon Updating for Hangman GUI Java - java

For my group project we are doing a fairly standard Hangman GUI game.
I have created a series of .png files depicting a flower that wilts as the game progresses with wrong guesses.
I have got the code to insert the ImageIcon into a JLabel, and that works fine. But I don't know how to code for the image changing when a wrong answer is guessed.
I am thinking I should create an array of the series of images and iterate through it according to the guessesLeft variable that keeps track of the number of guesses a user still has to correctly guess the puzzle.
Any ideas?

I'd recommend you to link each image to the number of guesses.
Then make method updateScore that will update user score (or guesses left) and work with images. Something like:
public class ImagedScore {
private final int guessesLeft;
private final Image image;
//getters&constructor
}
public class MainClass {
ImagedScore[] imagedScoreArray;
//constructors, other methods and data, etc.
updateScore(int score) {
ImagedScore imagedScore = imagedScoreArray[score];
//checks or other way to find proper ImagedScore object
this.score = score;
this.image = imagedScore.getImage;
}
}

Related

Assign random class object (image) to ImageView

I'm developing a card game, based on higher wins.
From my first question here assign int value to image for compare I've rewritten my code but now I'm stuck on randomization of cards and assignment to ImageView.
I have a class card.
public class Card{
private int cardValue;
#DrawableRes
private int image;
public Card(int cardValue, #DrawableRes int image){
this.cardValue = cardValue;
this.image = image;
}
public int getCardValue()
{
return cardValue;
}
#DrawableRes
public int getCardImage()
{
return image;
}
//Cards
Card ash = new Card(20, R.drawable.ash_card);
Card atlas = new Card(23, R.drawable.atlas_card);
Card banshee = new Card(14, R.drawable.banshee_card);
and so on....
In MainActivity:
I have array of this cards:
//Creating array of the cards
ArrayList<Card> cards = new ArrayList<>();
Now I need to randomize four cards from this array and assign each one to IV.
final Random random1 = new Random();
//Generate random indexes for cards
int RandomCard1 = random1.nextInt(cards.size());
int RandomCard2 = random1.nextInt(cards.size());
int RandomCard3 = random1.nextInt(cards.size());
int RandomCard4 = random1.nextInt(cards.size());
//Generate the card from RandomCard
Card drawableCard1 = cards.get(RandomCard1);
Card drawableCard2 = cards.get(RandomCard2);
Card drawableCard3 = cards.get(RandomCard3);
Card drawableCard4 = cards.get(RandomCard4);
I'm using this, because I have flip animation for each card (maybe there is a better way to do it, but it works for me). So now I just need to assign a card to IV, but this won't work.
//Deal my cards
card1.setImageResource(drawableCard1);
card2.setImageResource(drawableCard2);
card3.setImageResource(drawableCard3);
card4.setImageResource(drawableCard4);
I can't use setImageResource for class object. I've been stuck here for days, trying to figure it out but with no luck. Should I do randomizing differently (f.e. with Collections.shuffle?). Or is there any way how to do it?
Thank you.
You actually have two different problems:
the simplest is that your cards are not showing since setImageResource requires the int representing the resource id as parameter, you'll just need to call:
//Deal my cards
card1.setImageResource(drawableCard1.getCardImage());
card2.setImageResource(drawableCard2.getCardImage());
card3.setImageResource(drawableCard3.getCardImage());
card4.setImageResource(drawableCard4.getCardImage());
Now if the UI is correctly set up you'll see the images.
The second problem (I don't know if it's intended behavior) is that some cards could be given repeatedly, since the algorithm just generates a number within the bound and repetitions could occur.
A possible solution is, as you suggested, using Collections.shuffle() on the deck at the beginning so that it would simulate the initial deck shuffling and start dealing the cards in the exact order in which they are contained in your shuffled deck.
How to deal cards
Currently, if we consider our deck to be the entire List of Card objects, the way in which the dealer is picking the next card to give is by choosing a random card in any position of the deck (list) and put it on the table (for example). This idea could be extended by removing the picked card from the deck (which is something that at the moment is not implemented), but the dealing style wouldn't represent what happens in reality.
Solution
The solution would be shuffling the cards at the beginning of the game (Collections.shuffle()) and start picking the card in the exact order in which they are contained in the list. In fact, since it's already shuffled, the dealer can pick the 0-th, 1-st, 2-nd
etc. card and put them on the table (or give them to the players). The Random object, in this case, wouldn't be needed. A simple cycle could be implemented to select the next card the dealer will pick.

How do you make variables made inside a method available to all other methods in a class?

I'm a coding newb and want to learn some more java. I'm currently taking an introductory programming course in high school and am just trying to play around outside of class. This program I'm creating is supposed to print out a few instructions and questions in the console, to which I want to retrieve user input using a scanner and variable. The goal of the program is for the user to be able to create a 'drawing' based on pure instinct, then this drawing is displayed after the fact.
Here's my problem. I'm asking the user and storing the information in variables that are native to the main method, but I need to use this information in the paintComponent method.
I tried adding static in front of the variable such as:
static int emptyRectW1 = kboard.nextInt(); but this just shows the error "Illegal modifier for parametic emptyRectW1; only final is permitted."
I knew it was a long shot trying that out, but that's the best I've got.
I'm using Java Eclipse as my IDE.
Thanks for any help, looks like the only way to learn is to mess up and have somebody else point out my mistake! :)
Here's the code:
import java.util.Scanner;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BlindDrawing extends JPanel {
public static void main (String[] args) {
Scanner kboard = new Scanner(System.in);
System.out.println("Welcome to the Blind Drawing Game!");
System.out.println("In this game, you will be asked questions about how to construct an image using rectangles and ovals. You will be asked the shape's dimensions and position. The origin (0,0) is the top left corner.");
System.out.println("First you're making an empty rectangle, how wide do you want it to be?");
int emptyRectW1 = kboard.nextInt();
System.out.println("What about the height?");
int emptyRectH1 = kboard.nextInt();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0,0,emptyRectW1, emptyRectH1);
}
}
Update: In the comments an example was requested, so here's a simple one. This is just a simple demonstration of the ideas I talk about; it does not build on the above code. The reason is that, as others have noted, there are additional things you'd want to correct about the structure of that code. Rather than try to address them in detail, or give an example that encourages them, I'll just focus on the points I was making in my original answer:
public class SampleObject {
private int aValue;
protected void getVAlue() {
Scanner kboard = new Scanner(System.in);
System.out.println("Enter a value:");
aValue = kboard.nextInt();
}
protected void printValue() {
System.out.println("The value is " + aValue);
}
public void processValue() {
System.out.println("Welcome");
getValue();
printValue();
}
public static void main(String[] args) {
SampleObject sampleObject = new SampleObject();
sampleObject.processValue();
}
}
Some styles would have the main method in a separate "application class"; some frameworks have such a thing, wich might have responsibilities like handling outside messages requesting the app shut down, or whatver.
And generally as your applications get beyond simple exercises, you'll want to have more than just one class/object - each with distinct responsibilities that make up your application's functionality.
But for now, this should show how instance data woriks, and how to bootstrap a collection of objects rather than doing lots of processing in a static main method.
Good luck!
As a general answer to the question: variables defined inside a method are not available to other methods, and this is by design of the language. (Some advanced features twist this rule a little, but not in the way you want; and those things are a bit down the road from where you are anyway.)
To share state among methods, you add data members (sometimes called fields) to the class itself. Then values can be assigned in one method and read in another, or whatever, throughout the class.
However, as soon as you try to use that advice you're going to run into another problem, because main() is (and must be) static and your other method isn't (and probably shouldn't be). So you're going to do one of two things to fix that - the easy thing, or the right thing.
The easy thing would be to add static data members - making the data belong to the class rather than an instance of the object. The non-static methods could still see those. But this is leading you in the wrong direction.
The right thing is to do nothing more than bootstrap your application in the main method. What this means is, create object instances that can collaborate to carry out your program's function, and then set those objects in motion. Then all the actual work - like prompting for user input, etc. - should happen in (generally non-static) methods of those objects.
It's a very surface explanation, but really this isn't the place for an in-depth programming lesson. If your curiosity is getting ahead of the coursework, there certainly are good tutorials for OO programming and Java online (or at your local book store... though I may be dating myself with that suggestion).
Good luck.
The simple answer: pass the information obtained in the main method into the BlindDrawing object via either a method or a constructor's parameters.
But having said that you really don't want to mix a linear console type application with an event driven GUI app. Choose one or the other and stick with it. Here you can get the information you need via JOptionPanes if you need to get them before launching the main GUI application, and then again pass them into the main GUI application as described above -- via constructor parameters.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.*;
public class BlindDrawing extends JPanel {
private Rectangle rectangle;
public BlindDrawing(Rectangle rectangle) {
setPreferredSize(new Dimension(1000, 800));
this.rectangle = rectangle;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (rectangle != null) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.draw(rectangle);
}
}
private static void createAndShowGui(Rectangle rect) {
BlindDrawing mainPanel = new BlindDrawing(rect);
JFrame frame = new JFrame("BlindDrawing");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
String message = "Enter 4 numbers for X, Y, Width, and Height, separated by a space";
String title = "Get Rectangle Coordinates";
int messageType = JOptionPane.PLAIN_MESSAGE;
String input = JOptionPane.showInputDialog(null, message, title, messageType);
String[] tokens = input.split("\\s+");
if (tokens.length == 4) {
int x = Integer.parseInt(tokens[0]);
int y = Integer.parseInt(tokens[1]);
int width = Integer.parseInt(tokens[2]);
int height = Integer.parseInt(tokens[3]);
Rectangle rect = new Rectangle(x, y, width, height);
SwingUtilities.invokeLater(() -> createAndShowGui(rect));
}
}
}
EDIT
You asked in comments:
What I don't understand are the ones towards the bottom that have tokens. I don't really understand what these tokens do, if you could clarify, that would be great!
The question for me is: how can we most easily allow the user to enter for ints to use in a Swing application, but to sub-divide this even further we can ask for solutions that are most easy for the coder and solutions that are most easy for the user. In general you will want to prefer going after the latter.
The easiest for the coder is to create a simple console application and have the user enter the numbers using String prompts and a Scanner object that has been initialized to the standard input or System.in. As I've mentioned, while this is easy for the coder, it does not work well for the user since console applications and GUI applications don't play nice together as one is structured in a linear fashion while the other is much more free-flowing and event driven. If you want to get data later on while the program runs, and you again have the user enter information through the console, you risk either freezing the Swing application, rendering it useless, or updating the Swing application inappropriately in a background thread.
My solution above is a compromise where we prompt the user for a single String by using a JOptionPane.showInputDialog(...). This will give the user a prompt, and allow him to enter a single String into a text field. Here I ask the user to enter four numbrers separated, each separated by a space, and I think that you understand this part, but one problem with it is, once you get that String, which I call input, how do you extract the four numbers out of it.
One way is to split the String into an array of Strings (which I call tokens) using String's split(...) method. A simple way to do this is like so:
String[] tokens = input.split(" ");
This will split the input String into an array of sub-strings by splitting on a single space. It doesn't work so well if the user accidentally uses more than one space between his numbers, or if he uses different "white-space" to separate the numbers. I instead used:
String[] tokens = input.split("\\s+");
This uses something called regular expressions or "regex" for short to split the String. \\s represents any white-space character, and the + means that we'll split on one or more white-space characters. So if the user puts 2 or 3 spaces between his numbers, this still will work.
Another possible way to split this String is to put it into a Scanner and then "scan" for ints. Here we don't Scan with the standard input, with System.in, but rather we scan the entered String, here input. For example:
// get our line of input same as we did before
String input = JOptionPane.showInputDialog(null, message, title, messageType);
// create a Scanner object that scans through the line
Scanner inputScanner = new Scanner(input);
// extract the four numbers from the line
int x = inputScanner.nextInt();
int y = inputScanner.nextInt();
int width = inputScanner.nextInt();
int height = inputScanner.nextInt();
// close the Scanner so we don't waste resources
inputScanner.close();
There are still problems with this since all these solutions fail if the user enters 2 or 3 numbers and not 4, or if the user enters non-numeric input, and there are other ways of checking for this and correcting, such as using a JSpinner or JComboBox that limits the user's selections to allowed numbers, or by using try/catch blocks to catch invalid input and then prompt the user for more correct input.
You can initialize them as instance variables so they can be used by various other methods, like so:
public class BlindDrawing extends JPanel {
private int emptyRectW1;
private int emptyRectH1;
public static void main (String[] args) {
new BlindDrawing().run();
}
private void run() {
Scanner kboard = new Scanner(System.in);
System.out.println("Welcome to the Blind Drawing Game!");
System.out.println("In this game, you will be asked questions about how to construct an image using rectangles and ovals. You will be asked the shape's dimensions and position. The origin (0,0) is the top left corner.");
System.out.println("First you're making an empty rectangle, how wide do you want it to be?");
emptyRectW1 = kboard.nextInt();
System.out.println("What about the height?");
emptyRectH1 = kboard.nextInt();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, emptyRectW1, emptyRectH1);
}
}
Actually, a variable declared inside a method is a local variable.
Please extend the scope of the the two variables just before your main method. See code below.
static int emptyRectW1, emptyRectH1;
public static void main (String[] args) {
Then manipulate the latter code to avoid duplicate variable declaration as shown below.
emptyRectW1 = kboard.nextInt();
System.out.println("What about the height?");
emptyRectH1 = kboard.nextInt();
I hope this helps.

Create and connect locations for a game

I want to make a text adventure game as a school project and I was wondering how it would be possible to create and connect game locations in which the story takes place.
I thought of making a super class Location with variables like name and a two-dimensional array like
int[][] locnow = new int[20][20];
for the location position itself (north, west, east, south point).
My main questions are
Is it a good way to realise something like this in this way, or is something different better?
How can I load locations like "Button Click -> go east" and the location one to the east is loaded?
Thank you for your help.
What about:
public class Location {
private int x, y;
private String name;
// getters and setters here
}
Combined with
public class Game {
private GameTile[][] field;
// getters and setters here
}
public class GameTile {
// some tile-specific information goes here
}
Thay way, you store the game-field specific information (in GameTile, if needed). If you don't need the GameTile class, you can just leave out the array in the Game class, and just store the maximum dimensions.
How does this answer your question:
Going east would just be x += 1,
west x -= 1,
etc...

java reset game method, number of games played not incrementing

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.

Swing based Java game

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.

Categories

Resources