• “羊了个羊”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张。

    代码实现:

    1. /**
    2. * @ClassName: NumCardsUtil
    3. * @Description 工具类
    4. * @author 月夜烛峰
    5. * @date 2022/9/27 20:18
    6. */
    7. public class NumCardsUtil {
    8. /**随机卡片数组*/
    9. public static int[] cardsCount = new int[9];
    10. /**所有卡片数字存储*/
    11. public static List cardsList = new ArrayList<>();
    12. /**卡片name存储*/
    13. public static List centerCardData = new ArrayList<>();
    14. /**中间卡片*/
    15. public static List centerCards = new ArrayList<>();
    16. /**左边卡片*/
    17. public static List leftCards1 = new ArrayList<>();
    18. public static List leftCards2 = new ArrayList<>();
    19. /**右边卡片*/
    20. public static List rightCards1 = new ArrayList<>();
    21. public static List rightCards2 = new ArrayList<>();
    22. /**
    23. * 初始化卡片数字
    24. */
    25. public static void initCards() {
    26. clearCards();
    27. //初始化数字卡片
    28. Random r = new Random();
    29. int num;
    30. for (int i = 0; i < 93; i++) {
    31. num = r.nextInt(8) + 1;
    32. cardsCount[num]++;
    33. cardsList.add(num);
    34. }
    35. initCardList(centerCards, 55);
    36. initCardList(leftCards1, 9);
    37. initCardList(leftCards2, 10);
    38. initCardList(rightCards1, 9);
    39. initCardList(rightCards2, 10);
    40. }
    41. /**
    42. * 初始化卡片对象
    43. * @param list
    44. * @param cardCount
    45. */
    46. public static void initCardList(List list, int cardCount) {
    47. Random r = new Random();
    48. int index;
    49. CardNode numLabel;
    50. for (int i = 0; i < cardCount; i++) {
    51. index = r.nextInt(cardsList.size());
    52. numLabel = new CardNode(String.valueOf(cardsList.get(index)), JLabel.CENTER);
    53. list.add(numLabel);
    54. cardsList.remove(index);
    55. }
    56. }
    57. /**
    58. * 根据层级个数生成图片,固定为5,可拓展
    59. * @param level
    60. */
    61. public static void initcenterCardData(int level) {
    62. for (int n = 1; n < level; n++) {
    63. for (int i = 0, x = 0, y = -1; i < n * n; i++) {
    64. if (i % n == 0) {
    65. x = 0;
    66. y++;
    67. }
    68. centerCardData.add("center-" + n + "-" + x + "-" + y);
    69. x++;
    70. }
    71. }
    72. }
    73. /**
    74. * 清空数据
    75. */
    76. public static void clearCards() {
    77. centerCardData.clear();
    78. centerCards.clear();
    79. leftCards1.clear();
    80. leftCards2.clear();
    81. rightCards1.clear();
    82. rightCards2.clear();
    83. }
    84. }

    3、卡片属性

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

    1. /**
    2. * @ClassName: CardNode
    3. * @Description 卡片属性
    4. * @author 月夜烛峰
    5. * @date 2022/9/27 20:13
    6. */
    7. public class CardNode extends JLabel {
    8. /**区域类型*/
    9. private int type;
    10. /**堆放级别*/
    11. private int level;
    12. /**横坐标索引*/
    13. private int xIndex;
    14. /**纵坐标索引*/
    15. private int yIndex;
    16. public CardNode(String text, int horizontalAlignment) {
    17. super(text, horizontalAlignment);
    18. }
    19. public int getType() {
    20. return type;
    21. }
    22. public void setType(int type) {
    23. this.type = type;
    24. }
    25. public int getLevel() {
    26. return level;
    27. }
    28. public void setLevel(int level) {
    29. this.level = level;
    30. }
    31. public int getxIndex() {
    32. return xIndex;
    33. }
    34. public void setxIndex(int xIndex) {
    35. this.xIndex = xIndex;
    36. }
    37. public int getyIndex() {
    38. return yIndex;
    39. }
    40. public void setyIndex(int yIndex) {
    41. this.yIndex = yIndex;
    42. }
    43. }

    4、操作面板

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

    1. /**
    2. * @ClassName: PlayGamePanel
    3. * @Description 游戏面板
    4. * @author 月夜烛峰
    5. * @date 2022/9/27 20:00
    6. */
    7. public class PlayGamePanel extends JPanel implements MouseListener {
    8. private int[] nodeCount = new int[9];
    9. private int[][] bottomPoints = new int[6][2];
    10. private List bottomNodeList = new ArrayList<>();
    11. private JPanel bottomPanel = new JPanel();
    12. private JLabel tips = new JLabel("游戏进行中...", JLabel.CENTER);
    13. public PlayGamePanel() {
    14. this.setLayout(null);
    15. bottomPanel.setLayout(null);
    16. bottomPanel.setBounds(150, 480, 500, 80);
    17. bottomPanel.setBackground(Color.LIGHT_GRAY);
    18. tips.setFont(new Font("Dialog", Font.PLAIN, 20));
    19. tips.setBounds(150, 370, 500, 80);
    20. add(tips);
    21. initCardLabel();
    22. //初始化底部卡槽背景
    23. for (int i = 6; i > 0; i--) {
    24. JLabel emptyLabel = new JLabel();
    25. emptyLabel.setOpaque(true);
    26. emptyLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    27. emptyLabel.setBackground(Color.GRAY);
    28. emptyLabel.setBounds(70 * i - 20, 15, 50, 50);
    29. bottomPanel.add(emptyLabel);
    30. }
    31. //初始化底部6个卡槽坐标
    32. for (int x = 0; x < 6; x++) {
    33. bottomPoints[x][0] = 200 + x * 70;
    34. bottomPoints[x][1] = 495;
    35. }
    36. add(bottomPanel);
    37. }
    38. public void initCardLabel() {
    39. NumCardsUtil.initCards();
    40. NumCardsUtil.initcenterCardData(5);
    41. int curIndex = 0;
    42. int curLineNum = 0;
    43. int nextLineNum = 0;
    44. for (int n = 1; n <= 5; n++) {
    45. for (int i = 0; i < n * n; i++) {
    46. if (i % n == 0) {
    47. nextLineNum++;
    48. curLineNum = 0;
    49. }
    50. CardNode node = createNumLabel("center-" + n + "-" + curLineNum + "-" + (nextLineNum - 1), NumCardsUtil.centerCards.get(curIndex++), 0, 395 - n * 25 + 50 * curLineNum, 125 - 25 * n + 50 * nextLineNum);
    51. node.setxIndex(curLineNum);
    52. node.setyIndex(nextLineNum - 1);
    53. node.setLevel(n);
    54. curLineNum++;
    55. }
    56. curLineNum = 0;
    57. nextLineNum = 0;
    58. }
    59. //底部卡片列表
    60. for (int i = 8; i > 0; i--) {
    61. //NumCardsUtil.leftCards
    62. createNumLabel("left1-" + i, NumCardsUtil.leftCards1.get(i), 1, 20 + 15 * i, 400);
    63. createNumLabel("right1-" + i, NumCardsUtil.rightCards1.get(i), 2, 730 - 15 * i, 400);
    64. }
    65. //中部卡片列表
    66. for (int i = 9; i > 0; i--) {
    67. //NumCardsUtil.leftCards
    68. createNumLabel("left2-" + i, NumCardsUtil.leftCards2.get(i), 3, 150, 180 + 15 * i);
    69. createNumLabel("right2-" + i, NumCardsUtil.rightCards2.get(i), 4, 600, 180 + 15 * i);
    70. }
    71. }
    72. /**
    73. * 数字卡片
    74. * @param numLabel
    75. * @param x
    76. * @param y
    77. */
    78. public CardNode createNumLabel(String name, CardNode numLabel, int type, int x, int y) {
    79. numLabel.setName(name);
    80. numLabel.setFont(new Font("Dialog", Font.PLAIN, 18));
    81. numLabel.setOpaque(true);
    82. numLabel.setType(type);
    83. numLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    84. numLabel.setBackground(Color.GRAY);
    85. numLabel.setBounds(x, y, 50, 50);
    86. numLabel.setPreferredSize(new Dimension(50, 50));
    87. numLabel.setVerticalTextPosition(JLabel.BOTTOM);
    88. numLabel.setHorizontalTextPosition(JLabel.CENTER);
    89. numLabel.addMouseListener(this);
    90. add(numLabel);
    91. return numLabel;
    92. }
    93. /**
    94. * 刷新面板
    95. */
    96. public void startRun() {
    97. new Thread() {
    98. @Override
    99. public void run() {
    100. while (true) {
    101. try {
    102. Thread.sleep(100);
    103. } catch (InterruptedException e) {
    104. // TODO Auto-generated catch block
    105. e.printStackTrace();
    106. }
    107. //刷新屏幕,自动调用paint()方法
    108. repaint();
    109. }
    110. }
    111. }.start();
    112. }
    113. /**
    114. * 是否存在父级
    115. * @param level
    116. * @param x
    117. * @param y
    118. * @return
    119. */
    120. public boolean hasParentLabel(int level, int x, int y) {
    121. String[] ids = {level + "-" + x + "-" + y, level + "-" + (x - 1) + "-" + y, level + "-" + x + "-" + (y - 1), level + "-" + (x - 1) + "-" + (y - 1)};
    122. for (String id : ids) {
    123. if (NumCardsUtil.centerCardData.contains("center-" + id)) {
    124. return true;
    125. }
    126. }
    127. return false;
    128. }
    129. public void dealUnCenterCardList(List list, CardNode node) {
    130. CardNode lastNode = list.get(list.size() - 1);
    131. if (lastNode != node) {
    132. return;
    133. }
    134. list.remove(node);
    135. orderList(node);
    136. }
    137. /**
    138. * 重排序
    139. * @param node
    140. */
    141. private void orderList(CardNode node) {
    142. int curValue = Integer.parseInt(node.getText());
    143. nodeCount[curValue]++;
    144. if (bottomNodeList.size() == 0) {
    145. bottomNodeList.add(node);
    146. node.setLocation(bottomPoints[0][0], bottomPoints[0][1]);
    147. return;
    148. }
    149. int curIndex = 0;
    150. for (CardNode n : bottomNodeList) {
    151. int tempValue = Integer.parseInt(n.getText());
    152. if (curValue >= tempValue) {
    153. curIndex++;
    154. } else {
    155. break;
    156. }
    157. }
    158. bottomNodeList.add(curIndex, node);
    159. for (int j = 0; j < bottomNodeList.size(); j++) {
    160. bottomNodeList.get(j).setLocation(bottomPoints[j][0], bottomPoints[j][1]);
    161. }
    162. if (nodeCount[curValue] >= 3) {
    163. nodeCount[curValue] = 0;
    164. for (int i = 0; i < 3; i++) {
    165. bottomNodeList.get(curIndex).setVisible(false);
    166. bottomNodeList.remove(curIndex);
    167. if (curIndex > 0) {
    168. curIndex--;
    169. }
    170. }
    171. }
    172. for (int j = 0; j < bottomNodeList.size(); j++) {
    173. bottomNodeList.get(j).setLocation(bottomPoints[j][0], bottomPoints[j][1]);
    174. }
    175. }
    176. @Override
    177. public void mouseClicked(MouseEvent e) {
    178. }
    179. @Override
    180. public void mousePressed(MouseEvent e) {
    181. }
    182. @Override
    183. public void mouseReleased(MouseEvent e) {
    184. Component com = e.getComponent();
    185. if (com instanceof CardNode) {
    186. CardNode node = (CardNode) com;
    187. switch (node.getType()) {
    188. case 0:
    189. boolean flag = hasParentLabel(node.getLevel() - 1, node.getxIndex(), node.getyIndex());
    190. if (!flag) {
    191. NumCardsUtil.centerCardData.remove(node.getName());
    192. orderList(node);
    193. }
    194. break;
    195. case 1:
    196. dealUnCenterCardList(NumCardsUtil.leftCards1, node);
    197. break;
    198. case 2:
    199. dealUnCenterCardList(NumCardsUtil.rightCards1, node);
    200. break;
    201. case 3:
    202. dealUnCenterCardList(NumCardsUtil.leftCards2, node);
    203. break;
    204. case 4:
    205. dealUnCenterCardList(NumCardsUtil.rightCards2, node);
    206. break;
    207. default:
    208. break;
    209. }
    210. if (bottomNodeList.size() >= 6) {
    211. tips.setText("游戏结束!");
    212. tips.setForeground(Color.RED);
    213. this.setEnabled(false);
    214. }
    215. }
    216. }
    217. @Override
    218. public void mouseEntered(MouseEvent e) {
    219. }
    220. @Override
    221. public void mouseExited(MouseEvent e) {
    222. }
    223. }

    5、游戏窗口

    1. /**
    2. * @ClassName: GameFrame
    3. * @Description 游戏窗口
    4. * @author 月夜烛峰
    5. * @date 2022/9/27 20:05
    6. */
    7. public class GameFrame extends JFrame{
    8. public GameFrame() {
    9. init();
    10. }
    11. public void init() {
    12. this.setTitle("月夜烛峰");
    13. //添加面板
    14. this.setSize(800, 600);
    15. this.setLocationRelativeTo(null);
    16. this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    17. this.setResizable(false);
    18. this.setVisible(true);
    19. PlayGamePanel play = new PlayGamePanel();
    20. add(play);
    21. play.startRun();
    22. }
    23. }

    运行游戏:

    1. /**
    2. * @ClassName: StartGame
    3. * @Description 开始游戏
    4. * @author 月夜烛峰
    5. * @date 2022/9/27 19:04
    6. */
    7. public class StartGame {
    8. public static void main(String[] args) {
    9. // 显示应用 GUI
    10. SwingUtilities.invokeLater(new Runnable() {
    11. @Override
    12. public void run() {
    13. new GameFrame();
    14. }
    15. });
    16. }
    17. }

  • 相关阅读:
    从零开始深入了解MySQL的Buffer Pool
    Ribbon框架原理及解析
    在C++中加上using namespace std; 和不加上有什么区别
    HarmonyOS鸿蒙学习笔记(4)Tabs模仿安卓ViewPager+Fragment的效果
    PT_数字特征_矩协方差相关系数
    Revit SDK 介绍:RayTraceBounce 光线反弹
    webstorm 去掉编辑区右侧竖线
    分布式--Redis的安装与数据类型的使用
    表单的语法及属性(form)
    K8S简单学习
  • 原文地址:https://blog.csdn.net/yueyezhufeng/article/details/127100226