目录

一、效果图

二、 代码实现

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.leftCardscreateNumLabel("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.leftCardscreateNumLabel("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() {@Overridepublic void run() {while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.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]);}}@Overridepublic void mouseClicked(MouseEvent e) {}@Overridepublic void mousePressed(MouseEvent e) {}@Overridepublic 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);}}}@Overridepublic void mouseEntered(MouseEvent e) {}@Overridepublic 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) {// 显示应用 GUISwingUtilities.invokeLater(new Runnable() {@Overridepublic void run() {new GameFrame();}});}
}

“羊了个羊”Java版本实现相关推荐

  1. 5小时复刻《羊了个羊》,Java代码已开源,还有108套皮肤

    简介 羊了个羊游戏爆火,就是太难玩了,我玩了几十次,玩不过去,很纠结,作为技术人员的我,忍不了,就抽了5个小时用Java实现了一个桌面版本,效果如下: 测试现场 羊了个羊开发现场 实现思路+代码实现 ...

  2. 来了超火爆的Java游戏羊了个羊_java开发游戏项目

    <羊了个羊>是一款网络上的卡通背景消除闯关游戏,游戏利用各种道具和提示来消除每一个关卡当中的障碍和陷阱. 游戏规则 羊了个羊在游戏下方共有7个槽位,玩家只要把3个相同方块点到槽位中就会消除 ...

  3. 【尚学堂】超火爆的Java游戏羊了个羊_java开发游戏项目

    <羊了个羊>是一款网络上的卡通背景消除闯关游戏,游戏利用各种道具和提示来消除每一个关卡当中的障碍和陷阱. 游戏规则 羊了个羊在游戏下方共有7个槽位,玩家只要把3个相同方块点到槽位中就会消除 ...

  4. 实现用java做一个简易版《羊了个羊》小游戏(附源代码)

    该项目是跟着这个b站视频一步一步写出来的,初学java有些地方我看不是很明白,但是讲解很仔细,大家可以看原视频,我没有添加背景音乐和背景图片,做出来的效果也勉勉强强. 代码已经上传到github上了, ...

  5. 效果最接近《羊了个羊》(卡牌堆叠游戏)的开源代码 微信小程序开源了

    ⭐零.教程概述 效果最接近<羊了个羊>(卡牌堆叠游戏)的开源代码,有数据库和关卡. 我写的程序是指 卡牌堆叠游戏 ,效果与羊了个羊一致.本教程有已有两个版本. 本来是想着Fork多一点的时 ...

  6. 关于羊了个羊,我真的是娘了个娘。

    最近,游戏"羊了个羊"风靡各平台及社交圈,那么应广大博友和官方强烈要求呢,我们来讨论一下娘了个娘的一些趣事.: 个人意见,请勿网B 1."羊了个羊"背后有哪些技 ...

  7. 《羊了个羊》还在火!创始人被制成展牌,竟成母校招生“活广告”?

    自从<羊了个羊>爆火之后,身边似乎总能看见各种"打脸"现场: 今天:"以后再玩<羊了个羊>熬夜到一两点我就是狗!" 明天:"什 ...

  8. 羊le个羊 小游戏 简单源码开源 思路分析

    被最近很火的小游戏 吸引了,去玩了两把 发现那个开发者老坏了,全是随机的 仔细思考了一下,发现仿造一个并不难,就着手开始敲代码,下面是成果,分享给大家 对于这个游戏呢,其实就是简单的元素块移动,然后判 ...

  9. 互联网晚报 | 9月25日 | 辉瑞公司CEO新冠检测再次呈阳性;​央视揭秘“羊了个羊”通关诈骗陷阱;特斯拉变相降价8000元?...

    辉瑞公司CEO新冠病毒检测结果再次呈阳性 据路透社报道,辉瑞公司CEO艾伯乐(Albert Boura)周六表示,他的新冠病毒检测呈阳性,并称自己感觉很好,没有任何症状.艾伯乐曾于今年8月份称自己新冠 ...

  10. 由爆火的“羊了个羊”浅谈小游戏开发

    自9月初突然爆火以来,小程序游戏"羊了个羊"一路高歌猛进,日活跃用户数量最高曾一度破亿:仅两天时间,就在微博上就斩获18个关联热搜. <羊了个羊>的爆火,除了玩法很有传 ...

最新文章

  1. Android offsetTopAndBottom 和 setTranslationY 的作用 和区别
  2. 底部固定菜单_【悬浮菜单】安卓悬浮amp;手势助手
  3. Python02 标准输入输出、数据类型、变量、随记数的生成、turtle模块详解
  4. python打印所有花数_Python中使用while循环实现花式打印乘法表
  5. sed 删除某一行_Linux常用命令三剑客之sed,您真的会用吗?
  6. django缓存优化(二)
  7. 背景图片铺不满全屏时处理
  8. 查找丢包故障点的一个好命令:pathping
  9. java比较两个对象_Java比较两个对象
  10. 华为手机计算机小游戏,华为手机怎么玩自带小游戏 | 手游网游页游攻略大全
  11. vscode使用教程-开始学习前端开发啦~
  12. 路由与交换技术(复习知识点-全)
  13. java ssh超市进销存管理系统(源码+文档)【源码分享】
  14. HTML之基本布局设计之三栏式、两栏式设计
  15. 六级阅读翻译——2017.11.13
  16. Oracle 常用 语句
  17. WIN10插上耳机还是声音外放
  18. 实现企业邮箱登录验证功能
  19. [Android UI界面] Android UI 设计准则
  20. w10计算机无法打印,win10电脑无法打印文件怎么办?

热门文章

  1. 湖北二师计算机学院学生会,我校会与湖北第二师范学院学生会联谊活动取得圆满成功...
  2. 年底了,带你看看韩国IT公司团建怎么玩?
  3. vue H5页面实现海报功能demo
  4. 华为eNSP综合实验
  5. MapReduce之倒排索引
  6. 【st表/猫树】【堆+贪心】超级钢琴
  7. 7-2 判断素数 (10分)
  8. 高中会考计算机时间,2018年北京高中会考时间安排表
  9. Cassandra数据分布之4机架感应(snitch)
  10. AD域服务器的搭建(1)--AD域介绍