简体   繁体   English

Java代码-纸牌

[英]Java Code - Solitaire

I've created a solitaire game in Java. 我用Java创建了一个纸牌游戏。

My question is: How can I fill objects (hearts, spades, diamonds, club) on every card with black or red color? 我的问题是:如何用黑色或红色填充每张卡上的物体(心,黑桃,钻石,球棍)?

Here is the code I have now: 这是我现在拥有的代码:

// 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);
      }
  }
}

I took your snippet, and made a snippet of my own. 我摘下了您的摘录,并制作了自己的摘录。 The snippet only does a fill of the heart suit, using Graphics.fillPolygon . 该代码段仅使用Graphics.fillPolygon填充心脏西装。 I've commented out the old drawing of lines in the snippet, so you can compare with what you did. 我已经注释掉了代码段中的旧线条,因此您可以将其与所做的进行比较。 The other cards I'll leave up to you. 其他的卡我留给你。

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);
            }
        });
    }
}

Result: 结果:

在此处输入图片说明

Some of my suggestions from an answer deleted from your recent question : 您最近的问题中删除的答案中的一些建议:

  • First of all, there is no such thing as "static constructors", static initializer blocks, yes, but these don't begin with the class name as a constructor would and so don't look like constructors and more importantly, they don't behave as constructors -- they don't create an instance of the class. 首先,没有“静态构造函数”,静态初始化程序块之类的东西,是的,但是它们没有像构造函数那样以类名开头,因此看起来不像构造函数,更重要的是,它们不像牛逼表现为构造-他们不创建类的实例。 Rather they are used for class-specific (not instance-specific) code that is called on class loading. 而是将它们用于在类加载时调用的特定于类(而不是特定于实例)的代码。
  • Myself, I'd create my card specific instance on GUI-card creation, thus I think that this code should go in a constructor wherever you create your GUI representation of a card. 我本人会在创建GUI卡时创建我的卡特定实例,因此我认为无论您在创建卡的GUI表示形式时,此代码都应放入构造函数中。 Note that this may be (and should be) separate from your creation of logical cards, although I don't do this in the example below. 请注意,这可能与(并且应该)与您创建逻辑卡分开,尽管在下面的示例中我没有这样做。
  • Since the card backing image is class-specific and not Card instance-specific, I'd create my card backing image either in a static initializer block, or as a singleton instance . 由于卡片背景图像是特定于类的,而不是卡片实例特定的,因此我将在静态初始化程序块或单例实例中创建卡片背景图像。 This way it should be created once and once only. 这样,应该只创建一次。 In the example below, I use the singleton pattern (some say "anti"-pattern). 在下面的示例中,我使用单例模式(有人说“反”模式)。 It should be safe to use this in a Swing GUI, since Swing is single threaded, and so it should only be called in one thread. 由于Swing是单线程的,因此在Swing GUI中使用它应该是安全的,因此只能在一个线程中调用它。
  • As per my comment in your original question, the slowest thing that your code currently does is to read in image files repeatedly, and you want to avoid doing that by storing your images in variables and then using them as needed, as the example below shows. 根据我对原始问题的评论,您的代码当前最慢的操作是重复读取图像文件,并且您希望通过将图像存储在变量中然后根据需要使用它们来避免这样做,如下例所示。
  • A side recommendation (not related to your original question): consider using RenderingHints to smooth out any drawing of text or graphics that you might be doing. 附带建议(与您的原始问题无关):考虑使用RenderingHints平滑您可能正在做的任何文本或图形绘制。 For example see code below. 例如,请参见下面的代码。
  • Also use enums for your card Ranks and Suits. 还可以对您的卡片等级和西服使用枚举。 This is the canonical example used when discussing the subject of enums, and as you'll see below, they lend themselves so well to use of enums. 这是讨论枚举主题时使用的规范示例,正如您将在下面看到的那样,它们非常适合使用枚举。
  • Your code uses a lot of "magic" numbers, in other words, lots of unexplained number literals such as g.drawString(club, x + 12, y + 45); 您的代码使用了很多“魔术”数字,换句话说,就是许多无法解释的数字文字,例如g.drawString(club, x + 12, y + 45); . So someone just glancing at your code is going to wonder, what do 12 and 45 represent? 因此,仅浏览您的代码的人就会想知道,12和45代表什么? Better to avoid this by using variables or constants with logical names to make your code more self-commenting. 最好通过使用带有逻辑名称的变量或常量来避免这种情况,以使您的代码更具自我注释性。 For example, something like: g2.drawString(s.getSymbol(), SYMBOL_X, SYMBOL_Y); 例如,类似: g2.drawString(s.getSymbol(), SYMBOL_X, SYMBOL_Y); where you can guess that SYMBOL_X is the x location of the symbol. 您可以在其中猜测SYMBOL_X是符号的x位置。

For example, please check out this code which can be copied into a single file and run: 例如,请检查以下代码,该代码可以复制到单个文件中并运行:

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;
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM