I wrongly worded my last question so I'm going to retry this. I am making a card game in java, and currently I have the code to print 4 random cards in an arraylist for x number of players. I am using slick 2d and currently have a menu and a play state. I currently have 2 variables connected to each card, a ranging from 0-3, and b ranging from 0-12.
How can I display an image in the play state that will relate back properly to these 2 variables? (ex. instead of displaying ace of spades, it displays a picture of the ace of spades)
Code:
Deck ()
{
cards = new ArrayList < > ();
for (int a = 0 ; a <= 3 ; a++)
{
for (int b = 0 ; b <= 12 ; b++)
{
cards.add (new Card (a, b));
}
}
}
This is the function to draw a card from a deck
public Card PlayerCardDraw ()
{
Random generator = new Random ();
int index = generator.nextInt (cards.size ());
return cards.remove (index);
}
and this is the function that uses the above function to add a card to player 1's hand. I made this to separate each player's hand of cards.
public ArrayList <Card> p1Hand;
public ArrayList <Card> P1CardDraw ()
{
p1Hand = new ArrayList < > ();
p1Hand.add (PlayerCardDraw ());
return p1Hand;
}
I mentioned I'm using slick 2d, so I assume I won't have to post any of that code.
If I were you, I would rewrite/append the Card class to attach an image on initialisation. Create an image in a common directory, and encode it a-bb.* for an example, and create a public image constant for that particular card. then it would be as simple as calling a simple getter to display the image.
Related
I'm creating a solitaire game using java swing gui. I'm trying to make this whole program very object-oriented. I've just learned java, but since it's my first language, I wasn't taught OOP and how to implement it into my code design (although I'm trying to learn this myself, as java is an object-oriented language).
I've created a 3d array within the constructor (but I'm not sure if I should put this in a separate method that is designated for the initial game state (which is alike for how the game has to be successfully completed)) for the card suit, colour, and value.
I want to either associate a value to a
each card in the deck between the image and the array, or be able to have an image be directly associated with an array so it's possible for the program to know the correct and legal sequencing in the gameplay.
all the cards require a back and front facing card so either is displayed depending on position & game state.
(unrelated, but I'm also making a layered pane for the depth of each card which will be important for game state)
i've previously learned how to display images in java with swing using imageIcon and attaching them to buttons or labels. I'm not sure if using imageIO would be better. Maybe a 3d array isn't the right choice? Any guidance/help is greatly appreciated. Thank you :)
the 3d array looks like this
String [][][] deck = new String[13][2][2]; //only 2 elements for suits in each colour, out of 4 suits
String[] numbers = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};
String[] colors = {"Red", "Black"}; //z
String[] suits = {"Spade", "Club", "Heart", "Diamond"}; //y
}
for (int n = 0; n < 13; n++) { //start with value -> colour -> suit
for (int c = 0; c < 2; c++) {
for (int s = 0; s < 2; s++) {
if (c == 0) { //if c==0 then suit != 1 or 2
deck[n][c][s] = colors[c] + " " + numbers[n] + " of " + suits[s + 2];
//bc adding 2 makes y be [2] or [4] bc those suits are red //combines array to form y#x in each z
} else {
deck[n][c][s] = colors[c] + " " + numbers[n] + " of " + suits[s];
// black card ==1 and it c==1, you wont add 2 to the value of [s], so black can only be [0] or [1] (spade and club)
}
}
}
}
little bit of info about some of my ideas for how the game will be organized:
the game will roughly look like this.
The circle "1" is where the unshuffled deck/array will start (initial gamestate), and this is also what it will look like when the player successfully solves the game (initial gamestate==final gamestate) so each suit has a designated start and finish position.
the array (the deck) will be shuffled by using Donald Knuth's shuffling algorithm.
after multiple iterations of shuffling, I'll divide the cards (elements in the array) into 2 piles: the hand pile (24 cards not yet played), the tableau pile (where the player plays to place the cards in sequential order of high-low and black/red or red/black)
this part is important-
when the player taps a button or label of a cards image, a MouseListener is used to get the position where it was clicked, the program searches for which card value & colour occupies that position, and then the program will look for legal moves that are available for the player.
If you want to make it object oriented you should probably make a class called Card with fields number, color and suit. Don't forget to have separation of concerns. Separate the presentation layer from the business layer. If you end up writing code for which you can't even tell what's front end code and what's back end code then that's bad. Your front end can have a CardDisplayer class, which is an adapter class to the Card class. CardDisplayer takes in a Card and it draws it on the screen.
Your front end sends messages to the back end when the player makes a move. Your back end should not make any changes to the data that front end has. Your back end should message back the front end with legal moves or with the new state of the game.
You also need a game loop. When the game finishes the player should go back to some sort of a start menu.
I'm developing a card game. From some of my previous questions (Assign int value to image fro compare and Assign random class object image to imageview I'm finally stuck on the main part - compare logic.
I have two classes - Card and EnemyCard.
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;
}
EnemyCard class is the same, only it's name is different.
In MainActivity I have objects, arrays, and random dealing.
//Creating objects
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);
...
//Creating array of my the cards
cards = new ArrayList<>();
cards.add(ash);
cards.add(atlas);
cards.add(banshee);
...
final Random random2 = new Random();
//Generate random indexes for my cards
int RandomCard5 = random2.nextInt(cards.size());
int RandomCard6 = random2.nextInt(cards.size());
int RandomCard7 = random2.nextInt(cards.size());
int RandomCard8 = random2.nextInt(cards.size());
//Generate my cards from RandomCard
Card drawableCard5 = cards.get(RandomCard5);
Card drawableCard6 = cards.get(RandomCard6);
Card drawableCard7 = cards.get(RandomCard7);
Card drawableCard8 = cards.get(RandomCard8);
Again it's the same for the EnemyCard class, only with some slight differences in the cards' names.
Then I assign the cards to IV.
//Deal my cards
card1.setImageResource(drawableCard5.getCardImage());
card2.setImageResource(drawableCard6.getCardImage());
card3.setImageResource(drawableCard7.getCardImage());
card4.setImageResource(drawableCard8.getCardImage());
Again the same for enemy cards. After this comes my clumsy design.
When you click on the IV (f.e. card1), the card is "transferred to other IV called expanded_card (this simulates larger view of the card), and a confirm button appears. If you confirm the card, it's transferred to the last IV called fight_card (this is the clumsy part).
After this is also chosen random enemy card. I did this creating array of those four enemy cards and then using switch-case and Collections.shuffle() to assign one random enemy card to an IV called fight_card2 (yeah, this is totally clumsy)
//Enemy fight cards
enemy_deck_cards = new ArrayList<>();
enemy_deck_cards.add(10);
enemy_deck_cards.add(11);
enemy_deck_cards.add(12);
enemy_deck_cards.add(13);
//Logic for enemy card for fight
public void assignImage(int card, ImageView image){
switch (card){
case 10:
image.setImageDrawable(enemy_card1.getDrawable());
enemy_card1.setVisibility(View.INVISIBLE);
enemy_card2.setVisibility(View.VISIBLE);
enemy_card3.setVisibility(View.VISIBLE);
enemy_card4.setVisibility(View.VISIBLE);
break;
case 11:
image.setImageDrawable(enemy_card2.getDrawable());
enemy_card2.setVisibility(View.INVISIBLE);
enemy_card1.setVisibility(View.VISIBLE);
enemy_card3.setVisibility(View.VISIBLE);
enemy_card4.setVisibility(View.VISIBLE);
break;
case 12:
image.setImageDrawable(enemy_card3.getDrawable());
enemy_card3.setVisibility(View.INVISIBLE);
enemy_card1.setVisibility(View.VISIBLE);
enemy_card2.setVisibility(View.VISIBLE);
enemy_card4.setVisibility(View.VISIBLE);
break;
case 13:
image.setImageDrawable(enemy_card4.getDrawable());
enemy_card4.setVisibility(View.INVISIBLE);
enemy_card1.setVisibility(View.VISIBLE);
enemy_card2.setVisibility(View.VISIBLE);
enemy_card3.setVisibility(View.VISIBLE);
break;
}
}
Setting visibility is for simulating that a card is chosen from the deck.
Lastly, there is the confirm button, where are the main parts (and some other, not so important stuff).
//Assign cards to fight
assignImage(enemy_deck_cards.get(0),fight_card2);
fight_card.setImageDrawable(expanded_card.getDrawable());
If you made it this far and haven't fainted from this horror code, I admire you. Now comes the logic and I'm stuck here.
How to achieve that the chosen cards in IVs (fight_card and fight_card2) are compared?
I tried something like this:
public void fightLogic(Card fightCard, EnemyCard fightCard2, TextView message){
if (fightCard.getCardValue() > fightCard2.getCardValue()){
message.findViewById(R.id.message);
message.setText(R.string.YOUWIN);
} else
if (fightCard.getCardValue() < fightCard2.getCardValue()){
message.findViewById(R.id.message);
message.setText(R.string.YOULOST);
} else
if (fightCard.getCardValue() == fightCard2.getCardValue()){
message.findViewById(R.id.message);
message.setText(R.string.DRAW);
}
}
But this obviously won't work. I don't see any way how to do this, if it's even possible with my horror code. If anybody has any piece of advice (and critique for sure) regarding the logic or even design, I'd be truly grateful.
Thanks.
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.
I am programming a small space-themed dungeon crawler game with a GUI made with Swing in Java. I am using the MVC programming paradigm. The game is represented as a grid on which buttons can be clicked to move the player over the board or attack enemies.
In the model/logic of the game I generate an abstract representation of the game environment using a 2D array by randomly assigning objects to x (column) and y (row) coordinates using the following method:
//methods
public void setGalaxy() {
galaxyArray = new GalacticObject[this.row][this.col];
//construct the array
Random rand = new Random();
int random;
for (int i = 0; i < this.row; i++) {
for (int j = 0; j < this.col; j++) {
GalacticObject obj = new GalacticObject(i,j);
random = rand.nextInt(100);
if (random < 5) {
//asteroid (5 percent chance)
obj.makeAsteroid();
} else if (random < 9) {
//blackhole (4 percent chance)
obj.makeBlackHole();
} else {
//rest is open (= empty)
obj.makeOpen();
}
galaxyArray[i][j] = obj;
}
}
}
Now I want to draw the actual GUI game board backed by this 2D array of objects in a JPanel container using a grid of JButtons. I want to basically call all the objects in the galaxyArray and draw a JButton with an corresponding image overlay at the corresponding coordinates in a ButtonGrid. What would be the best way to achieve this using Swing?
Currently, I also have written the following draft for a method that draws a JButtonGrid but I still fail to see what is the best strategy of having it backed by a 2D array of objects.
Furthermore, adding the icon for the buttons is not working for reasons unclear to me. (I commented that part out.)
public JPanel makeGameBoard() {
/** This method makes a first version of the game board when the object is first called */
//create a new JPanel
JPanel boardPanel = new JPanel();
// create a gridButton of JButtons defined by the width and length
JButton[][] gridButton = new JButton[this.boardWidth][this.boardLength];
// set layout
boardPanel.setLayout(new GridLayout(this.boardWidth,this.boardLength));
//for-loops to place buttons in gridButton
for(int y = 0; y < this.boardLength; y++) {
for(int x = 0; x < this.boardWidth; x++){
// creates new button (with coordinates as string); gridButton[x][y] needs to be reused as coordinate system
gridButton[x][y]=new JButton(x+":"+y);
gridButton[x][y].setActionCommand(x+":"+y);
gridButton[x][y].setText("");
gridButton[x][y].addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
String com = e.getActionCommand();
System.out.println(com);
}
});
// add icon to every button
// try {
// Image img = ImageIO.read(getClass().getResource("resources/invisible.png"));
// gridButton[x][y].setIcon(new ImageIcon(img));
// }
// catch (IOException ex) {
// System.out.println("Image file for gridButton not found!");
// }
// add the gridButton to the panel
boardPanel.add(gridButton[x][y]);
}
}
//return boardPanel
return boardPanel;
}
Essentially I am wondering what is the best strategy to access the objects stored in the galaxyArray from my makeGameBoard method so that the variables of the objects in the array can be used to draw an image on the button with corresponding coordinates in the grid.
/*EDIT Thanks to the suggestion and linked tutorials from the friendly people below, I have made it work! Here is the code for the board View for anyone having similar questions:
public void updateGameBoard(Galaxy board) {
/** This method initializes the board when the galaxy is first created in the game logic and updates it throughout the game */
Galaxy galaxyArray = board;
for (int r = 0; r < this.boardWidth; r++) {
for (int c = 0; c < this.boardLength; c++) {
//make galactic object and extract info from Galaxy
GalacticObject temporary = new GalacticObject(r,c);
temporary = galaxyArray.getGalacticObject(r,c);
//check the object and set the corresponding tile image
if (temporary.isAsteroid()) {
gridButton[r][c].setText("A");
} else if (temporary.isAsteroidField()) {
gridButton[r][c].setText("AF");
} else if (temporary.isBlackHole()) {
gridButton[r][c].setText("BH");
} else if (temporary.isOpen()) {
gridButton[r][c].setText("");
}
}
}
}
The exact details depend on how you implement the observer pattern. Following this outline, the example game cited here simply lets the main view, RCView, keep a private reference to the array named board, which is maintained by the game model, RCModel. Because RCView implements the Observer interface, the view's update() implementation simply iterates through the board and updates its array of tiles in response. Note that the update() method signature includes a reference to the Observable requesting the update. In your example,
public void update(Observable model, Object arg) {
GalacticObject galaxyArray = ((GameModel) model).getGalaxyArray();
//loop though model, updating view components
this.repaint();
}
Im learning Java and Im creating a memory type game where you have to find two equal cards.
I have created a Window etc etc but my problem is adding multiple JButtons to it. (my cards are JButtons with icons). I have commented my code where my problem is.
//Get the images.
private File bildmapp = new File("bildmapp");
private File[] bilder = bildmapp.listFiles();
//My own class extending JButton
Kort[] k = new Kort[bilder.length];
for(int i = 0; i < bilder.length; i++){
k[i] = new Kort(new ImageIcon(bilder[i].getPath()));
}
//Later in my code:
int sum = rows * columns;
Kort[] temp = new Kort[sum];
//My function to randomize.
Verktyg.slumpOrdning(k);
//***********************//
//Trying to fill a array from K (which contains all cards) so my temp contains SUM cards and SUM/2 pairs
for(int i = 0; i < sum/2; i++){
temp[i] = k[i];
temp[i+sum/2] = k[i];
}
//Problem is that i only get SUM/2 (half of the cards) cards, not the 16 (8 pairs) i would like to add in this case
//SYNLIGT = VISIBLE.
for(int i = 0; i < sum; i++){
temp[i].setStatus(Kort.Status.SYNLIGT);
j.add(temp[i]);
}
Your code ends up adding each Kort object to the container twice, since the array temp contains two references to each Kort. When you add a Kort a second time, it moves to the second location. A Component can only appear in one place at a time.
You may not add the same widget twice. You need two separate buttons (but you may use the same icon on both).
You have to create sum JButton objects not sum/2; otherwise 2 buttons are the same and therefore only displayed once.