“羊了个羊”Java版本实现

目录

一、效果图

二、 代码实现

1、布局规划

2、卡片生成

3、卡片属性

4、操作面板

5、游戏窗口


一、效果图

这里使用数字卡片来代替图片,纯Java代码实现, 使用Swing来绘图。

二、 代码实现

这里主要用来练手,尤其是对于新手来说,可以更深刻的理解多线程、异步操作、对象引用、简单算法、数据结构等。

1、布局规划

真个布局分为以上6个区域,其中较为复杂的为1和6。

1区域当前采用塔型结构进行堆叠演示(堆叠规则可以任意调整),技术点在于如果点击的卡片的上方有其它卡片,则该卡片不能移动。

技术点:

1、图中每个卡片最多可被四个卡片同时覆盖,其中四个角、边缘、中间区域的卡片覆盖个数都有差别,设计算法校验时需要考虑全面。

2、各个层级的图片之间没有使用遮照进行处理,主要个人喜好。

6区域看起来就是消除三个相同数字的卡片。

技术分析:

1、1~5区域的卡片要能移动到6,最大个数为6

2、对卡片进行排序,由小到大

3、卡片消除处理。

2~4区域的卡片相对简单,只需要注意点击的是最后一张图片即可。

2、卡片生成

每次运行游戏,都会随机生成所有卡片,是否通关完全靠运气,没有对死局进行处理。

通过Swing来练手,对新手来说,了解Java面向对象的设计理念很有帮助。

卡片数字范围1~9,卡片个数93张,其中1区域55张,2、3各10张,4、5各9张。

代码实现:

/**
 * @ClassName: NumCardsUtil
 * @Description 工具类
 * @author 月夜烛峰
 * @date 2022/9/27 20:18
 */
public class NumCardsUtil {

    /**随机卡片数组*/
    public static int[] cardsCount = new int[9];
    /**所有卡片数字存储*/
    public static List<Integer> cardsList = new ArrayList<>();
    /**卡片name存储*/
    public static List<String> centerCardData = new ArrayList<>();

    /**中间卡片*/
    public static List<CardNode> centerCards = new ArrayList<>();
    /**左边卡片*/
    public static List<CardNode> leftCards1 = new ArrayList<>();
    public static List<CardNode> leftCards2 = new ArrayList<>();
    /**右边卡片*/
    public static List<CardNode> rightCards1 = new ArrayList<>();
    public static List<CardNode> rightCards2 = new ArrayList<>();

    /**
     * 初始化卡片数字
     */
    public static void initCards() {
        clearCards();

        //初始化数字卡片
        Random r = new Random();
        int num;
        for (int i = 0; i < 93; i++) {
            num = r.nextInt(8) + 1;
            cardsCount[num]++;
            cardsList.add(num);
        }

        initCardList(centerCards, 55);
        initCardList(leftCards1, 9);
        initCardList(leftCards2, 10);
        initCardList(rightCards1, 9);
        initCardList(rightCards2, 10);
    }

    /**
     * 初始化卡片对象
     * @param list
     * @param cardCount
     */
    public static void initCardList(List<CardNode> list, int cardCount) {
        Random r = new Random();
        int index;
        CardNode numLabel;
        for (int i = 0; i < cardCount; i++) {
            index = r.nextInt(cardsList.size());
            numLabel = new CardNode(String.valueOf(cardsList.get(index)), JLabel.CENTER);
            list.add(numLabel);
            cardsList.remove(index);
        }
    }

    /**
     * 根据层级个数生成图片,固定为5,可拓展
     * @param level
     */
    public static void initcenterCardData(int level) {

        for (int n = 1; n < level; n++) {
            for (int i = 0, x = 0, y = -1; i < n * n; i++) {
                if (i % n == 0) {
                    x = 0;
                    y++;
                }
                centerCardData.add("center-" + n + "-" + x + "-" + y);
                x++;
            }
        }
    }

    /**
     * 清空数据
     */
    public static void clearCards() {
        centerCardData.clear();
        centerCards.clear();
        leftCards1.clear();
        leftCards2.clear();
        rightCards1.clear();
        rightCards2.clear();
    }
}

3、卡片属性

主要定义卡片的存放位置、展示位置、区域类型等

/**
 * @ClassName: CardNode
 * @Description 卡片属性
 * @author 月夜烛峰
 * @date 2022/9/27 20:13
 */
public class CardNode extends JLabel {

    /**区域类型*/
    private int type;
    /**堆放级别*/
    private int level;
    /**横坐标索引*/
    private int xIndex;
    /**纵坐标索引*/
    private int yIndex;

    public CardNode(String text, int horizontalAlignment) {
        super(text, horizontalAlignment);
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public int getxIndex() {
        return xIndex;
    }

    public void setxIndex(int xIndex) {
        this.xIndex = xIndex;
    }

    public int getyIndex() {
        return yIndex;
    }

    public void setyIndex(int yIndex) {
        this.yIndex = yIndex;
    }
}

4、操作面板

关于操作面板中内容操作的代码实现:

/**
 * @ClassName: PlayGamePanel
 * @Description 游戏面板
 * @author 月夜烛峰
 * @date 2022/9/27 20:00
 */
public class PlayGamePanel extends JPanel implements MouseListener {

    private int[] nodeCount = new int[9];
    private int[][] bottomPoints = new int[6][2];
    private List<CardNode> bottomNodeList = new ArrayList<>();

    private JPanel bottomPanel = new JPanel();

    private JLabel tips = new JLabel("游戏进行中...", JLabel.CENTER);

    public PlayGamePanel() {
        this.setLayout(null);
        bottomPanel.setLayout(null);
        bottomPanel.setBounds(150, 480, 500, 80);
        bottomPanel.setBackground(Color.LIGHT_GRAY);

        tips.setFont(new Font("Dialog", Font.PLAIN, 20));
        tips.setBounds(150, 370, 500, 80);
        add(tips);

        initCardLabel();
        //初始化底部卡槽背景
        for (int i = 6; i > 0; i--) {
            JLabel emptyLabel = new JLabel();
            emptyLabel.setOpaque(true);
            emptyLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
            emptyLabel.setBackground(Color.GRAY);
            emptyLabel.setBounds(70 * i - 20, 15, 50, 50);
            bottomPanel.add(emptyLabel);
        }
        //初始化底部6个卡槽坐标
        for (int x = 0; x < 6; x++) {
            bottomPoints[x][0] = 200 + x * 70;
            bottomPoints[x][1] = 495;
        }

        add(bottomPanel);
    }

    public void initCardLabel() {
        NumCardsUtil.initCards();
        NumCardsUtil.initcenterCardData(5);

        int curIndex = 0;
        int curLineNum = 0;
        int nextLineNum = 0;


        for (int n = 1; n <= 5; n++) {
            for (int i = 0; i < n * n; i++) {
                if (i % n == 0) {
                    nextLineNum++;
                    curLineNum = 0;
                }
                CardNode node = createNumLabel("center-" + n + "-" + curLineNum + "-" + (nextLineNum - 1), NumCardsUtil.centerCards.get(curIndex++), 0, 395 - n * 25 + 50 * curLineNum, 125 - 25 * n + 50 * nextLineNum);
                node.setxIndex(curLineNum);
                node.setyIndex(nextLineNum - 1);
                node.setLevel(n);

                curLineNum++;
            }
            curLineNum = 0;
            nextLineNum = 0;
        }

        //底部卡片列表
        for (int i = 8; i > 0; i--) {
            //NumCardsUtil.leftCards
            createNumLabel("left1-" + i, NumCardsUtil.leftCards1.get(i), 1, 20 + 15 * i, 400);
            createNumLabel("right1-" + i, NumCardsUtil.rightCards1.get(i), 2, 730 - 15 * i, 400);
        }

        //中部卡片列表
        for (int i = 9; i > 0; i--) {
            //NumCardsUtil.leftCards
            createNumLabel("left2-" + i, NumCardsUtil.leftCards2.get(i), 3, 150, 180 + 15 * i);
            createNumLabel("right2-" + i, NumCardsUtil.rightCards2.get(i), 4, 600, 180 + 15 * i);
        }
    }

    /**
     * 数字卡片
     * @param numLabel
     * @param x
     * @param y
     */
    public CardNode createNumLabel(String name, CardNode numLabel, int type, int x, int y) {
        numLabel.setName(name);
        numLabel.setFont(new Font("Dialog", Font.PLAIN, 18));
        numLabel.setOpaque(true);
        numLabel.setType(type);

        numLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        numLabel.setBackground(Color.GRAY);
        numLabel.setBounds(x, y, 50, 50);
        numLabel.setPreferredSize(new Dimension(50, 50));
        numLabel.setVerticalTextPosition(JLabel.BOTTOM);
        numLabel.setHorizontalTextPosition(JLabel.CENTER);
        numLabel.addMouseListener(this);

        add(numLabel);
        return numLabel;
    }

    /**
     * 刷新面板
     */
    public void startRun() {
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    //刷新屏幕,自动调用paint()方法
                    repaint();
                }
            }
        }.start();
    }

    /**
     * 是否存在父级
     * @param level
     * @param x
     * @param y
     * @return
     */
    public boolean hasParentLabel(int level, int x, int y) {
        String[] ids = {level + "-" + x + "-" + y, level + "-" + (x - 1) + "-" + y, level + "-" + x + "-" + (y - 1), level + "-" + (x - 1) + "-" + (y - 1)};
        for (String id : ids) {
            if (NumCardsUtil.centerCardData.contains("center-" + id)) {
                return true;
            }
        }
        return false;
    }

    public void dealUnCenterCardList(List<CardNode> list, CardNode node) {
        CardNode lastNode = list.get(list.size() - 1);
        if (lastNode != node) {
            return;
        }
        list.remove(node);
        orderList(node);
    }

    /**
     * 重排序
     * @param node
     */
    private void orderList(CardNode node) {
        int curValue = Integer.parseInt(node.getText());
        nodeCount[curValue]++;
        if (bottomNodeList.size() == 0) {
            bottomNodeList.add(node);
            node.setLocation(bottomPoints[0][0], bottomPoints[0][1]);
            return;
        }
        int curIndex = 0;
        for (CardNode n : bottomNodeList) {
            int tempValue = Integer.parseInt(n.getText());
            if (curValue >= tempValue) {
                curIndex++;
            } else {
                break;
            }
        }
        bottomNodeList.add(curIndex, node);
        for (int j = 0; j < bottomNodeList.size(); j++) {
            bottomNodeList.get(j).setLocation(bottomPoints[j][0], bottomPoints[j][1]);
        }

        if (nodeCount[curValue] >= 3) {
            nodeCount[curValue] = 0;
            for (int i = 0; i < 3; i++) {
                bottomNodeList.get(curIndex).setVisible(false);
                bottomNodeList.remove(curIndex);
                if (curIndex > 0) {
                    curIndex--;
                }
            }
        }
        for (int j = 0; j < bottomNodeList.size(); j++) {
            bottomNodeList.get(j).setLocation(bottomPoints[j][0], bottomPoints[j][1]);
        }
    }

    @Override
    public void mouseClicked(MouseEvent e) {

    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

        Component com = e.getComponent();
        if (com instanceof CardNode) {
            CardNode node = (CardNode) com;
            switch (node.getType()) {
                case 0:
                    boolean flag = hasParentLabel(node.getLevel() - 1, node.getxIndex(), node.getyIndex());
                    if (!flag) {
                        NumCardsUtil.centerCardData.remove(node.getName());
                        orderList(node);
                    }
                    break;
                case 1:
                    dealUnCenterCardList(NumCardsUtil.leftCards1, node);
                    break;
                case 2:
                    dealUnCenterCardList(NumCardsUtil.rightCards1, node);
                    break;
                case 3:
                    dealUnCenterCardList(NumCardsUtil.leftCards2, node);
                    break;
                case 4:
                    dealUnCenterCardList(NumCardsUtil.rightCards2, node);
                    break;
                default:
                    break;
            }

            if (bottomNodeList.size() >= 6) {
                tips.setText("游戏结束!");
                tips.setForeground(Color.RED);

                this.setEnabled(false);
            }
        }
    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }
}

5、游戏窗口

/**
 * @ClassName: GameFrame
 * @Description 游戏窗口
 * @author 月夜烛峰
 * @date 2022/9/27 20:05
 */
public class GameFrame extends JFrame{

    public GameFrame() {
        init();
    }

    public void init() {
        this.setTitle("月夜烛峰");
        //添加面板
        this.setSize(800, 600);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.setVisible(true);
        PlayGamePanel play = new PlayGamePanel();
        add(play);
        play.startRun();

    }
}

运行游戏:

/**
 * @ClassName: StartGame
 * @Description 开始游戏
 * @author 月夜烛峰
 * @date 2022/9/27 19:04
 */
public class StartGame {
    public static void main(String[] args) {
        // 显示应用 GUI
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new GameFrame();
            }
        });
    }
}

  • 24
    点赞
  • 109
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月夜烛峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值