2016-02-06 43 views
2

我用Java創建了一個單人紙牌遊戲。Java代碼 - Solitaire

我的問題是:我怎麼能每卡黑色或紅色的填充物(紅心,黑桃,鑽石,俱樂部)?

這裏是我現在的代碼:

// draw the card 
    public void draw (Graphics g, int x, int y) { 
    // clear rectangle, draw border 
    g.clearRect(x, y, width, height); 
    g.setColor(Color.black); 
    g.drawRect(x, y, width, height); 

    // draw body of card 
    if (faceUp()) 
     { 
    if (color() == red) 
     g.setColor(Color.red); 
     else 
     g.setColor(Color.black); 

    g.drawString(names[rank()], x+3, y+15); 

    if (suit() == heart) 
     { 
     g.drawLine(x+25, y+30, x+35, y+20); 
     g.drawLine(x+35, y+20, x+45, y+30); 
     g.drawLine(x+45, y+30, x+25, y+60); 
     g.drawLine(x+25, y+60, x+5, y+30); 
     g.drawLine(x+5, y+30, x+15, y+20); 
     g.drawLine(x+15, y+20, x+25, y+30); 
     // g.fill(Color.red); 
     } 
    else if (suit() == spade) 
     { 
     g.drawLine(x+25, y+20, x+40, y+50); 
     g.drawLine(x+40, y+50, x+10, y+50); 
     g.drawLine(x+10, y+50, x+25, y+20); 
     g.drawLine(x+23, y+45, x+20, y+60); 
     g.drawLine(x+20, y+60, x+30, y+60); 
     g.drawLine(x+30, y+60, x+27, y+45); 
     } 
    else if (suit() == diamond) 
     { 
     g.drawLine(x+25, y+20, x+40, y+40); 
     g.drawLine(x+40, y+40, x+25, y+60); 
     g.drawLine(x+25, y+60, x+10, y+40); 
     g.drawLine(x+10, y+40, x+25, y+20); 
     } 
    else if (suit() == club) 
     { 
     g.drawOval(x+20, y+25, 10, 10); 
     g.drawOval(x+25, y+35, 10, 10); 
     g.drawOval(x+15, y+35, 10, 10); 
     g.drawLine(x+23, y+45, x+20, y+55); 
     g.drawLine(x+20, y+55, x+30, y+55); 
     g.drawLine(x+30, y+55, x+27, y+45); 
     } 
     } 
    else // face down 
     { 
    g.setColor(Color.black); 
    g.drawLine(x+15, y+5, x+15, y+65); 
    g.drawLine(x+35, y+5, x+35, y+65); 
    g.drawLine(x+5, y+20, x+45, y+20); 
    g.drawLine(x+5, y+35, x+45, y+35); 
    g.drawLine(x+5, y+50, x+45, y+50); 
     } 
    } 
} 
+0

你有什麼具體的問題? – nolexa

+0

我可以推薦加載四張圖片來代表西裝嗎?它不僅更高效,更易讀,更容易。它也解決了你的問題! – Emz

+0

您可能還想知道每個卡片符號都有ASCII碼。 –

回答

3

我把你的片段,並做了我自己的一個片段。該片段僅使用Graphics.fillPolygon填充心臟套裝。我已經評論了片段中的舊線條,因此您可以將其與您所做的相比較。其他卡我會留給你。

import java.awt.*; 
import javax.swing.*; 

public class CardFrame { 
    enum CardColor{red,black}; 
    enum CardSuit{heart,diamond,spade,club} 
    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       JPanel cardDisplay = new JPanel() { 
        @Override 
        public Dimension getPreferredSize() { 
         return new Dimension(50,100); 
        } 
        @Override 
        protected void paintComponent(Graphics g) { 
         super.paintComponent(g); 
         draw(g,0,0); 
        } 

        private int width = 50; 
        private int height = 80; 

        private boolean faceUp() { 
         return true; 
        } 
        private CardColor color() { 
         return CardColor.red; 
        } 
        private CardSuit suit() { 
         return CardSuit.heart; 
        } 
        private int rank() { 
         return 0; 
        } 
        private String[] names = {"1","2","3","4","5","6","7","8","9","10","J","Q","K","A"}; 
        private void draw(Graphics g, int x, int y) { 
         // clear rectangle, draw border 
         g.clearRect(x, y, width, height); 
         g.setColor(Color.black); 
         g.drawRect(x, y, width, height); 

         // draw body of card 
         if (faceUp()) { 
          if (color() == CardColor.red) 
           g.setColor(Color.red); 
          else 
           g.setColor(Color.black); 

          g.drawString(names[rank()], x + 3, y + 15); 

          if (suit() == CardSuit.heart) { 
//        g.drawLine(x + 25, y + 30, x + 35, y + 20); 
//        g.drawLine(x + 35, y + 20, x + 45, y + 30); 
//        g.drawLine(x + 45, y + 30, x + 25, y + 60); 
//        g.drawLine(x + 25, y + 60, x + 5, y + 30); 
//        g.drawLine(x + 5, y + 30, x + 15, y + 20); 
//        g.drawLine(x + 15, y + 20, x + 25, y + 30); 
           int[] xPoints = new int[]{x + 5,x + 15,x + 25,x + 35,x + 45,x + 25}; 
           int[] yPoints = new int[]{y + 30,y + 20,y + 30,y + 20,y + 30,y + 60}; 
           g.fillPolygon(xPoints, yPoints, 6); 
          } else if (suit() == CardSuit.spade) { 
           // ... 
          } else if (suit() == CardSuit.diamond) { 
           // ... 
          } else if (suit() == CardSuit.club) { 
           // 
          } 
         } else // face down 
         { 
          // ... 
         } 
        } 
       }; 

       JFrame frm = new JFrame(); 
       frm.setContentPane(cardDisplay); 
       frm.pack(); 
       frm.setVisible(true); 
      } 
     }); 
    } 
} 

結果:

enter image description here

+0

非常感謝! –

+0

@BorisP不客氣=) –

+0

frm.setSize(50,150);應覆蓋JPanel中的getPreferredSize – mKorbel

0

your recent question刪除回答我的一些建議:

所有的
  • 首先,是爲 「靜態構造函數」 沒有這樣的事,靜態初始化塊,是的,但是這些並不是以類的名字作爲構造函數開始的,所以看起來不像構造函數,更重要的是,它們不是表現爲作爲構造函數 - 它們不創建類的實例。相反,它們用於在類加載時調用的特定於類的(不是特定於實例的)代碼。
  • 我自己,我會在GUI卡創建創建我的卡特定的實例,因此,我認爲這個代碼應該在構造函數中去,無論你創建一個卡你的GUI表示。請注意,這可能(也應該)與您創建邏輯卡分開,但我不在下面的示例中執行此操作。
  • 由於卡後盾圖像類特定的,而不是特定的卡實例,我創造我的卡的支持圖像無論是在靜態初始化塊,或作爲singleton instance。這樣它應該只被創建一次。在下面的例子中,我使用了單例模式(有人說「反」模式)。在Swing GUI中使用它應該是安全的,因爲Swing是單線程的,所以它只能在一個線程中調用。
  • 按我在你原來的問題的評論,你的代碼目前做的最慢的就是反覆讀取圖像文件,並且要避免這樣做,在變量存儲您的圖像,然後使用它們可以根據需要,爲下面的例子顯示。
  • A面的建議(不涉及到你原來的問題):考慮使用RenderingHints的理順,你可能會做文字或圖形的任何繪圖。例如,請參閱下面的代碼。
  • 也可以使用枚舉排序和套裝。這是討論枚舉主題時使用的典型示例,正如您將在下面看到的,它們適合使用枚舉。
  • 你的代碼使用了很多「神奇」的數字,換言之,很多不明原因的數量文字如g.drawString(club, x + 12, y + 45);的。所以有人只是看了你的代碼就會想知道12和45代表什麼?通過使用具有邏輯名稱的變量或常量來更好地避免這種情況,從而使您的代碼更加自我評論。例如,如:g2.drawString(s.getSymbol(), SYMBOL_X, SYMBOL_Y);,您可以猜測SYMBOL_X是符號的x位置。

例如,請看看這個代碼可以被複制到一個單一的文件並運行:

import java.awt.BasicStroke; 
import java.awt.Font; 
import java.awt.Graphics2D; 
import java.awt.GridLayout; 
import java.awt.RenderingHints; 
import java.awt.TexturePaint; 
import java.awt.event.*; 
import java.awt.geom.Rectangle2D; 
import java.awt.image.BufferedImage; 
import java.awt.Color; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 
import javax.swing.*; 

/** 
* 
* @author Hovercraftfullofeels 
* link: https://stackoverflow.com/a/35351199/522444 
* 
*/  
public class PlayingCardExample { 

    private static void createAndShowGui() { 
     PlayingCardPanel mainPanel = new PlayingCardPanel(); 

     JFrame frame = new JFrame("Playing Card Example"); 
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(() -> { 
      createAndShowGui(); 
     }); 
    } 
} 

@SuppressWarnings("serial") 
class PlayingCardPanel extends JPanel { 
    private static final Color BG = Color.GREEN.darker().darker(); 
    private static final int GAP = 15; 
    private MyDeck myDeck = new MyDeck(); 

    public PlayingCardPanel() { 
     setBackground(BG); 
     int rows = Suit.values().length; 
     int cols = Rank.values().length; 
     setLayout(new GridLayout(rows, cols, GAP, GAP)); 
     setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP)); 

     while (myDeck.size() > 0) { 
      Card myCard = myDeck.deal(); 
      final CardLabel cardLabel = new CardLabel(myCard); 
      add(cardLabel.getLabel()); 
      cardLabel.addMouseListener(new CardListener(cardLabel)); 
     } 
    } 
} 

// class to allow us to flip cards on mouse press 
class CardListener extends MouseAdapter { 
    private CardLabel cardLabel; 

    public CardListener(CardLabel cardLabel) { 
     this.cardLabel = cardLabel; 
    } 

    @Override 
    public void mousePressed(MouseEvent e) { 
     boolean faceDown = ! cardLabel.isFaceDown(); 
     cardLabel.setFaceDown(faceDown); 
    } 
} 

class CardLabel { 
    private JLabel label = new JLabel(); 
    private Card myCard; 
    private boolean faceDown = true; 

    public CardLabel(Card myCard) { 
     this.myCard = myCard; 
     setFaceDown(true); 
    } 

    public void addMouseListener(MouseListener listener) { 
     label.addMouseListener(listener); 
    } 

    public boolean isFaceDown() { 
     return faceDown; 
    } 

    public void setFaceDown(boolean faceDown) { 
     this.faceDown = faceDown; 
     // get my singleton icon: 
     Icon cardBackIcon = CardBack.getInstance().getIcon(); 
     Icon icon = faceDown ? cardBackIcon : myCard.getIcon(); 
     label.setIcon(icon); 
    } 

    public JLabel getLabel() { 
     return label; 
    } 

    public Card getMyCard() { 
     return myCard; 
    } 

} 

// singleton class to create the backing image shared by all cards 
class CardBack { 
    private static final Color BG = Color.WHITE; 
    private static final Color COLOR = Color.BLUE; 
    private static final int W = 10; 
    private static final float STROKE_WIDTH = 3f; 
    private static CardBack instance = null; 
    private BufferedImage image; 
    private Icon icon; 

    // singleton constructor is private and so is only called by this class itself 
    private CardBack() { 
     BufferedImage repeatImg = new BufferedImage(W, W, BufferedImage.TYPE_INT_ARGB); 
     Graphics2D g2 = repeatImg.createGraphics(); 
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
     g2.setBackground(BG); 
     g2.clearRect(0, 0, W, W); 
     g2.setStroke(new BasicStroke(STROKE_WIDTH)); 
     g2.setColor(COLOR); 
     g2.drawLine(0, 0, W, W); 
     g2.drawLine(0, W, W, 0); 
     g2.dispose(); 

     int width = Card.WIDTH; 
     int height = Card.HEIGHT; 
     int imageType = BufferedImage.TYPE_INT_ARGB; 
     image = new BufferedImage(width, height, imageType); 
     g2 = image.createGraphics(); 
     Rectangle2D anchor = new Rectangle2D.Double(0, 0, W, W); 
     TexturePaint texturePaint = new TexturePaint(repeatImg, anchor); 
     g2.setPaint(texturePaint); 
     g2.fillRect(0, 0, width, height); 
     g2.dispose(); 
     icon = new ImageIcon(image); 
    } 

    public BufferedImage getImage() { 
     return image; 
    } 

    public Icon getIcon() { 
     return icon; 
    } 

    public static CardBack getInstance() { 
     // create the instance in a lazy fashion -- only create it if it has not 
     // yet been created. Thus, it should only be created *once* 
     if (instance == null) { 
      instance = new CardBack(); 
     } 
     return instance; 
    } 
} 

class MyDeck { 
    List<Card> cards = new ArrayList<>(); 

    public MyDeck() { 
     initialize(); 
     shuffle(); 
    } 

    public final void initialize() { 
     cards.clear(); 
     for (Rank rank : Rank.values()) { 
      for (Suit suit : Suit.values()) { 
       cards.add(new Card(rank, suit)); 
      } 
     } 
    } 

    public int size() { 
     return cards.size(); 
    } 

    public Card deal() { 
     if (cards.size() > 0) { 
      return cards.remove(0); 
     } else { 
      // TODO: better to use exceptions here! 
      // String text = "cards size is " + cards.size(); 
      // throw new MyDeckException(text); 
      return null; 
     } 
    } 

    public void shuffle() { 
     Collections.shuffle(cards); 
    } 
} 

// Quick an dirty code below. If this were a "real" program, 
// I'd probably create a class without image or icon 
// and then use a wrapper or decorator class to add the image information 
// since this would be GUI library specific 
class Card { 
    public static final int WIDTH = 50; 
    public static final int HEIGHT = 70; 
    private static final Font TEXT_FONT = new Font(Font.DIALOG, Font.BOLD, 14); 
    private static final Font SYMBOL_FONT = TEXT_FONT.deriveFont(Font.PLAIN, 28f); 
    private static final int NAME_X = 3; 
    private static final int NAME_Y = 15; 
    private static final int SYMBOL_X = 12; 
    private static final int SYMBOL_Y = 45; 
    private Rank rank; 
    private Suit suit; 
    private BufferedImage image; 
    private Icon icon; 

    public Card(Rank rank, Suit suit) { 
     this.rank = rank; 
     this.suit = suit; 

     // create each card's image and icon once on Card creation 
     image = createImage(rank, suit); 
     icon = new ImageIcon(image); 
    } 

    private static BufferedImage createImage(Rank r, Suit s) { 
     BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB); 
     Graphics2D g2 = img.createGraphics(); 
     g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 
       RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 

     g2.setColor(java.awt.Color.WHITE); 
     g2.fillRect(0, 0, WIDTH, HEIGHT); 
     g2.setColor(java.awt.Color.BLACK); 
     g2.drawRect(0, 0, WIDTH - 1, HEIGHT - 1); 

     g2.setColor(s.getColor()); 
     g2.setFont(TEXT_FONT); 
     g2.drawString(r.getName(), NAME_X, NAME_Y); 

     g2.setFont(SYMBOL_FONT); 
     g2.drawString(s.getSymbol(), SYMBOL_X, SYMBOL_Y); 

     g2.dispose(); 
     return img; 
    } 

    public Rank getRank() { 
     return rank; 
    } 

    public Suit getSuit() { 
     return suit; 
    } 

    public BufferedImage getImage() { 
     return image; 
    } 

    public Icon getIcon() { 
     return icon; 
    } 
} 

enum Rank { 
    ACE("A"), TWO("2"), THREE("3"), FOUR("4"), FIVE("5"), SIX("6"), SEVEN("7"), EIGHT("8"), 
    NINE("9"), TEN("10"), JACK("J"), QUEEN("Q"), KING("K"); 
    private String name; 

    private Rank(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 

} 

// Suit enum will hold its own color and symbol 
enum Suit { 
    CLUB("Club", "\u2663", Color.BLACK), 
    DIAMOND("Diamond", "\u2666", Color.RED), 
    HEART("Heart", "\u2665", Color.RED), 
    SPADE("Spade", "\u2660", Color.BLACK); 

    private String name; 
    private String symbol; 
    private Color color; 

    private Suit(String name, String symbol, Color color) { 
     this.name = name; 
     this.symbol = symbol; 
     this.color = color; 
    } 

    public String getName() { 
     return name; 
    } 

    public String getSymbol() { 
     return symbol; 
    } 

    public Color getColor() { 
     return color; 
    } 

}