I am making a simple card game and I'm trying to use my file paths to .jpg files for card images. I am getting a NullPointerException, but I am new to Java and struggling to understand what exactly this means and what to look for.
This is my output:
Tie.
error in nextCard
Computer wins!
error in nextCard
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at War.getPlayerCard(War.java:160)
at WarGUI$PlayCardListener.actionPerformed(WarGUI.java:98)
I have traced it thus far:
War class:
public String getPlayerCard()
{
return playerWarCard.getFilepath(); // Error
}
called from WarGUI:
playerCard = new ImageIcon(game.getPlayerCard()); // Error
I have a feeling the problem is my getFilepath method in my Card class (marked at the bottom), but I'm unsure and so would appreciate if someone could confirm.
Card Class:
public class Card
{
// Suits
private int suit;
public final static int SPADES = 1;
public final static int HEARTS = 2;
public final static int DIAMONDS = 3;
public final static int CLUBS = 4;
// Ranks
private int rank;
public final static int JACK = 11;
public final static int QUEEN = 12;
public final static int KING = 13;
public final static int ACE = 14;
String cardFilepath;
/**
The constructor initializes the card's rank and suit.
@param rank
@param suit
*/
public Card(int rank, int suit)
{
this.rank = rank;
this.suit = suit;
cardFilepath = "cardpics/" + suit + rank + ".jpg";
}
/**
The other constructor initializes the card's rank and suit.
@param otherCard to be copied
*/
public Card(Card otherCard)
{
this.rank = otherCard.rank;
this.suit = otherCard.suit;
}
/**
The getRank method returns the int that represents the card's rank.
@return card's rank
*/
public int getSuit()
{
return suit;
}
/**
The getRank method returns the int that represents the card's rank.
@return card's rank
*/
public int getRank()
{
return rank;
}
/**
* Returns a description of this card.
* @return the name of the card.
*/
public String toString()
{
return getRankAsString() + " of " + getSuitAsString();
}
/**
The equals method compares the rank of the card to the rank of
another card. If they are the same, the method returns true.
@return boolean
*/
public boolean equals(Card otherCard )
{
return rank == otherCard.rank;
}
/**
The getSuitString method returns the card's suit as a string.
@return suitString
*/
public String getSuitAsString()
{
switch (suit)
{
case SPADES: return "Spades";
case HEARTS: return "Hearts";
case DIAMONDS: return "Diamonds";
case CLUBS: return "Clubs";
default: return "Invalid";
}
}
/**
The getRankString method returns the card's rank.
@return rank
*/
public String getRankAsString()
{
switch (rank)
{
case 2: return "2";
case 3: return "3";
case 4: return "4";
case 5: return "5";
case 6: return "6";
case 7: return "7";
case 8: return "8";
case 9: return "9";
case 10: return "10";
case 11: return "Jack";
case 12: return "Queen";
case 13: return "King";
case 14: return "Ace";
default: return "??";
}
}
/**
Returns the .jpg image of card
@return path to image
*/
public String getFilepath() // Error?
{
return cardFilepath;
}
}
Attached for reference is my War class:
import java.util.ArrayList;
import javax.swing.*;
public class War
{
static Cardpile warPile;
static Cardpile player1 = new Cardpile();
static Cardpile player2 = new Cardpile();
static Card unseenPlayerCard;
static Card unseenComputerCard;
static Card playerWarCard;
static Card computerWarCard;
static String war = "false";
/**
Constructor prepares, shuffles deck then deals to players.
*/
public void War()
{
Deck deck = new Deck();
deck.shuffle();
while(deck.getSize() > 0)
{
player1.collectCard(deck.deal());
player2.collectCard(deck.deal());
}
}
/**
The compareCards method compares rank of card to determine winner
@param playersCard, computersCard
@return outcome
*/
public static int compareCards(Card playersCard, Card computersCard)
{
if (playersCard.getRank() > computersCard.getRank())
{
player1.collectCard(playersCard);
player1.collectCard(computersCard);
System.out.println("Player's card: " + playersCard.toString() + "\nComputer's card: " +
computersCard.toString() + "\nYou win!");
return 1;
}
else if (playersCard.getRank() < computersCard.getRank())
{
player2.collectCard(playersCard);
player2.collectCard(computersCard);
System.out.println("Your card: " + playersCard.toString() + "\nComputer's card: " +
computersCard.toString() + "\nYou lose.");
return 2;
}
// If cards are equal, war
else
{
war = "true";
System.out.println("Your card: " + playersCard.toString());
System.out.println("Computer's card: " + computersCard.toString());
JOptionPane.showMessageDialog(null, "War!");
beginWar(playersCard, computersCard);
return 3;
}
}
/**
The beginWar method draws war cards, then compares to determine
the winner of the war.
@param playersCard, computersCard
*/
public static void beginWar(Card playersCard, Card computersCard)
{
// Prize cards
unseenPlayerCard = player1.playCard();
unseenComputerCard = player2.playCard();
// Add cards to winning pile
warPile.collectCard(playersCard);
warPile.collectCard(computersCard);
warPile.collectCard(unseenPlayerCard);
warPile.collectCard(unseenComputerCard);
// Determine winner
playerWarCard = player1.playCard();
computerWarCard = player2.playCard();
int outcome = compareCards(playerWarCard, computerWarCard);
if (outcome == '1')
{
System.out.println("You win the war!");
}
if (outcome == '2')
{
System.out.println("You lose the war.");
}
}
/**
The computerCardsLeft method returns the number of cards in
the computer's hand.
@return computer hand size
*/
public int computerCardsLeft()
{
return player2.getSize();
}
/**
The playerCardsLeft method returns the number of cards in
the players's hand.
@return player hand size
*/
public int playerCardsLeft()
{
return player1.getSize();
}
/**
The getComputerCard method returns the image path of
the computer's card for the GUI.
@return filepath
*/
public String getComputerCard()
{
return computerWarCard.getFilepath();
}
/**
The getPlayerCard method returns the image path of
the computer's card for the GUI.
@return filepath
*/
public String getPlayerCard()
{
return playerWarCard.getFilepath(); // Error
}
/**
The playerDraw method draws the next card in the player's pile.
@return card
*/
public Card playerDraw()
{
if (player1.getSize() < 1)
{
endGame();
}
return player1.nextCard();
}
/**
The computerDraw method draws the next card in the computer's pile.
*/
public Card computerDraw()
{
if (player2.getSize() < 1)
{
endGame();
}
return player2.playCard();
}
/**
The endGame method displays the results.
*/
public void endGame()
{
if (player1.getSize() > player2.getSize())
System.out.println("Player wins!");
else if (player2.getSize() > player1.getSize())
System.out.println("Computer wins!");
else
System.out.println("Tie.");
}
/**
The enoughCards method determins whether or not a player meets a minimum
card requirement.
*/
public static boolean enoughCards(int n)
{
if (player1.getSize() < n || player2.getSize() < n)
{
return false;
}
return true;
}
}
...and my WarGUI
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class WarGUI extends JFrame
{
private WarGUI guiGame;
private War game;
private JPanel rightPlayerPanel; // Player
private JPanel leftPlayerPanel; // Computer
private JPanel buttonPanel; // Holds buttons
private JPanel gamePanel; // Main deck area
private JButton playButton;
private static JLabel backLabelLeft;
private static JLabel playerCardLabel;
private static JLabel computerCardLabel;
private ImageIcon back; // Icon for backside of card
private ImageIcon blank; // Place holder
private static ImageIcon playerCard; // Player 1's current card
private static ImageIcon computerCard; // Player 2's current card
private JTextField playerCardsLeft;
private JTextField computerCardsLeft;
// static Hand player1;
// static Hand player2;
private Card playersCard;
Card computersCard;
private String war = "false";
String imagePath = "cardPics/back.jpg";
/**
This constructor builds & adds panels to contentpane.
*/
public WarGUI()
{
// Set contentPane
setLayout(new BorderLayout());
setTitle("Game of War");
setSize(1100, 550);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
// Build & add deck panel
assembleGamePanel();
add(gamePanel, BorderLayout.CENTER);
// Build & add player panels
assembleDecksPanel();
add(leftPlayerPanel, BorderLayout.WEST);
add(rightPlayerPanel, BorderLayout.EAST);
// Build & add button panel
assembleButtonPanel();
add(buttonPanel, BorderLayout.SOUTH);
setVisible(true);
// Prepare deck & Player hands
game = new War();
// //Welcome message
// JOptionPane.showMessageDialog(null, "Welcome!");
}
/**
The PlayCardListener tracks clicks on Play Card button. Cards are drawn, war status is checked, scores and images are adjusted.
*/
private class PlayCardListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
// Regular gameplay
if (war.equals("false"))
{
Card playersCard = game.playerDraw();
Card computersCard = game.computerDraw();
// Update card images
playerCard = new ImageIcon(game.getPlayerCard()); // Error
playerCardLabel.setIcon(playerCard);
computerCard = new ImageIcon(computersCard.getFilepath());
computerCardLabel.setIcon(computerCard);
// Compare
game.compareCards(playersCard, computersCard);
// // Otherwise, update score
// //if (!war.equals("true"))
// else
// {
// // playerCardsLeft.setText("Player's Cards: " + (player1.getSize() - 1));
// // computerCardsLeft.setText("Computer's Cards: " + (player2.getSize() - 1));
//
// }
playerCardsLeft.setText("Player's Cards: " + (game.playerCardsLeft() - 1));
computerCardsLeft.setText("Computer's Cards: " + (game.computerCardsLeft() - 1));
}
// War deckplay
// Second click - face down card
else if (war.equals("true"))
{
// Set icons to card backside
playerCardLabel.setIcon(back);
computerCardLabel.setIcon(back);
war = "last";
}
// Third click
else if (war.equals("last"))
{
// Identify cards involved in the war, update icons
computerCard = new ImageIcon(game.getComputerCard());
computerCardLabel.setIcon(computerCard);
playerCard = new ImageIcon(game.getPlayerCard());
playerCardLabel.setIcon(playerCard);
war = "final";
}
// War final
else if (war.equals("final"))
{
war = "false";
// Update scores
playerCardsLeft.setText("Player's Cards: " + (game.playerCardsLeft()));
computerCardsLeft.setText("Computer's Cards: " + (game.computerCardsLeft()));
}
else
System.out.println("ERROR");
}
}
/**
The assembleGamePanel builds the cardPanel - the main deck area, where cards are displayed.
*/
private void assembleGamePanel()
{
// Place holder for cards
blank = new ImageIcon();
playerCardLabel = new JLabel(blank);
computerCardLabel = new JLabel(blank);
// Add labels to cardPanel
gamePanel = new JPanel();
gamePanel.add(playerCardLabel);
gamePanel.add(computerCardLabel);
gamePanel.setPreferredSize(new Dimension(545, 540));
gamePanel.setBackground(new Color(0, 64, 0));
}
/**
The assembleDecksPanel method builds the panel that displays the players' cardpiles.
*/
private void assembleDecksPanel()
{
// Icons of card backside
back = new ImageIcon(imagePath);
// Add icons
backLabelLeft = new JLabel();
backLabelLeft.setIcon(back);
JLabel backLabelRight = new JLabel();
backLabelRight.setIcon(back);
// Add labels to panels
// Right
rightPlayerPanel = new JPanel();
rightPlayerPanel.setPreferredSize(new Dimension(150,220));
rightPlayerPanel.add(backLabelRight);
rightPlayerPanel.setBackground(new Color(0, 64, 0));
playerCardsLeft = new JTextField("Player's Cards: 26", 13);
playerCardsLeft.setEditable(false);
rightPlayerPanel.add(playerCardsLeft);
// Left
leftPlayerPanel = new JPanel();
leftPlayerPanel.setPreferredSize(new Dimension(150,220));
leftPlayerPanel.add(backLabelLeft);
leftPlayerPanel.setBackground(new Color(0, 64, 0));
computerCardsLeft = new JTextField("Computer's Cards: 26", 13);
computerCardsLeft.setEditable(false);
leftPlayerPanel.add(computerCardsLeft);
}
/**
The assembleButtonPanel method adds buttons to button panel.
*/
private void assembleButtonPanel()
{
// Create & add button
JButton playCardButton = new JButton("Play!");
playCardButton.setPreferredSize(new Dimension(150,80));
buttonPanel = new JPanel();
buttonPanel.add(playCardButton);
buttonPanel.setBackground(new Color(0, 64, 0));
// Add event listeners for the buttons.
playCardButton.addActionListener(new PlayCardListener());
}
/**
The main method begins the GUI deck.
*/
public static void main(String[] args)
{
WarGUI guiGame = new WarGUI();
}
}
Edit: I now understand there is a problem somewhere else. as such, I will post my other classes...
Cardpile
public class Cardpile
{
// Create an array to hold the player's pile, and parameters for that array.
private Card[] cardPile;
private int front;
private int end;
/**
Constructor creates an empty pile capable of holding 52 cards.
*/
public Cardpile()
{
cardPile = new Card[52];
front = 0;
end = 0;
}
/**
The nextCard method returns the card at the front of the pile.
@return c
*/
public Card nextCard()
{
if (front == end)
{
System.out.println("error in nextCard");
}
Card c = cardPile[front];
front++;
return c;
}
/**
The collectCard method adds a card to the pile.
*/
public void collectCard(Card c)
{
cardPile[end] = c;
end++;
}
public Card playCard()
{
return nextCard();
}
/**
The getSize method returns the size of the pile.
@return size
*/
public int getSize()
{
int size = end - front;
return size;
}
/**
The clear method clears the pile of all cards.
*/
public void clear()
{
front = 0;
end = 0;
}
}
Deck:
import java.util.*;
public class Deck
{
private Card[] deck;
private int numCards;
/**
The constructor creates a deck of 52 cards
*/
public Deck()
{
deck = new Card[52];
fillDeck();
}
/**
The fillDeck method fills the deck with cards.
*/
public void fillDeck()
{
int index = 0;
for (int q = 1; q <= 13; q++)
{
for (int n = 1; n <= 4; n++)
{
deck[index] = new Card(q, n);
index++;
}
}
}
/**
The shuffle method shuffles the deck.
*/
public void shuffle()
{
for (int sh = 0; sh < numCards - 1; sh++)
{
int r = myRandom(sh, numCards - 1);
Card shuffleCard = deck[sh];
deck[sh] = deck[r];
deck[r] = shuffleCard;
}
}
/**
The deal method deals to the players.
@return updated deck
*/
public Card deal()
{
if(numCards == 0)
{
return null;
}
numCards--;
return deck[numCards];
}
/**
The getSize method returns the size of the deck
@return numCards in deck
*/
public int getSize()
{
return numCards;
}
/**
The myRandom method returns a random number.
@return random number
*/
private static int myRandom(int low, int high)
{
int random = (int)((high + 1 - low) * Math.random() + low);
return random;
}
}