• 游戏功能需求说明
  • 代码编写
    • 1 框架搭建
    • 2 主要技术难点
      • 21 图片面板对应的图片索引获取
      • 22 图片面板
    • 3 完整代码
  • 游戏截图
    • 1启动后界面
    • 2开始游戏界面
    • 3游戏结束界面

1 游戏功能需求说明

  该游戏主要模拟常见的翻牌游戏,即找到所有两两相同的牌认为游戏成功,主要需求包含:

  • 初始化面板后显示所有图片网格,图片默认显示为背景色;
  • 点击图片后显示图片,再次点击后显示背景;
  • 点击另一张图片,如果与前一张图片相同,则两张图片一直显示,再次点击不会再显示为背景,表示配对成功;如果与前一张图片不同,则两张图片显示50ms后显示为背景;
  • 重复上面两步,直到图片网格全部显示为图片,即所有图片配对成功;
  • 游戏开始后显示游戏用时,并在全部配对成功后提示游戏用时。

2 代码编写

2.1 框架搭建

  主面板当然是JFrame了,显示图片使用的是JLabel,考虑到点击事件的处理以及能够显示出图片的轮廓来,将JLabel放到了一个自己写的一个JPanel子类PicPanel中。

  实现过程中主要的问题就是PicPanel的实现问题,主要是为该类增加了一个MouseListener,需要处理好鼠标点击的事件。因为需要跟主面板进行交互,因此需要将主面板作为构造参数传入到该类中。同时该类是用于显示图片的,自然少不了传入的图片路径了。

2.2 主要技术难点

  当然了这里的技术难点是针对个人来讲的,就是比较耗时的功能点,对于大神来讲就不是什么难点了。

2.2.1 图片面板对应的图片索引获取

  因为需要在构造每个图片面板的时候传入每个面板对应的图片路径,因此首先需要初始化每个图片面板对应的图片路径,这里假设所有图片都存放在本地一个固定目录下,根据游戏设计,图片面板个数作为已知量使用(本程序使用了两个全局静态变量ROWS和COLUMNS表示图片面板网格的行数和列数,自然两者的乘积必须为偶数了),而初始化的图片索引指的是图片路径下所有图片按文件名从小到大排序后,随机生成的一个由int组成的数组,该数组必须满足以下条件:

  • 数组长度与图片面板个数相同;
  • 数组中每个值表示图片路径下的图片顺序;
  • 数组中的值介于0-picNums之间,不包含picNums(图片总数量);
  • 数组中的每个值出现的次数必须为偶数;
  • 数组中每个值所在的位置是随机的;
  • 图片总数小于图片网格个数一半时必须使用所有图片。

      这里针对图片数量和图片面板个数之间的关系使用了两种方法:

  • 图片数量大于等于图片面板个数一半时,因为图片数量多,因此只要随机从图片中选取不重复的图片索引即可,使用的是List;
  • 图片数量小于图片面板个数一半时,因为图片数量少,需要保证所有的图片都要使用上,因此Map来进行下标存储,并记录每个下标出现的次数;

2.2.2 图片面板

  由于需要将图片显示在面板上,这里采用了传统的图片显示方案,即使用JLabel对象,并使用其setIcon()方法为其设置背景图片,为保证图片能够完全铺满整个面板,因此对获取的图像进行了拉伸(有变形的可能)。
  

2.3 完整代码

  这里没有进行详细的拆分,所有代码都写到了一个类中,代码使用的图片放到了D:\pics文件夹下,使用的图片是从网上下载的三个车标,在后面的截图中可以看到,理论上将代码拷贝走,并在D:\pics文件夹下放入图片即可运行。
  

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.CompoundBorder;
import javax.swing.border.LineBorder;/*** @author jqs 主要实现记忆翻牌功能*/
public class RememberCard extends JFrame {/*** 初始化游戏的行列数,行列数成绩必须为偶数*/private static final int ROWS = 3;private static final int COLUMNS = 4;private static final long serialVersionUID = -8908268719780973221L;private JTextField txt_Time;private boolean isRunning = false;/*** 存放图片的目录,简单起见,存放图片的目录中图片个数为初始化的行列数乘积的一半*/private String picDir = "D:\\pics";private String[] picture;protected boolean isStart;private PicPanel preOne = null;/*** 用于标示已找到的对数*/private int count;private JPanel panel_Pic;public RememberCard() {setTitle("\u5BFB\u627E\u76F8\u540C\u5361\u724C");JPanel panel_Time = new JPanel();getContentPane().add(panel_Time, BorderLayout.NORTH);JLabel lbl_Time = new JLabel("\u7528\u65F6\uFF1A");panel_Time.add(lbl_Time);txt_Time = new JTextField();txt_Time.setEditable(false);panel_Time.add(txt_Time);txt_Time.setColumns(10);JLabel lbl_Unit = new JLabel("\u79D2");panel_Time.add(lbl_Unit);JButton btn_Start = new JButton("\u5F00\u59CB");panel_Time.add(btn_Start);panel_Pic = new JPanel();getContentPane().add(panel_Pic, BorderLayout.CENTER);btn_Start.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if (isRunning) {return;}setRunning(true);startGame();}});initPicPanels();}/*** 初始化图片面板*/private void initPicPanels() {panel_Pic.setLayout(new GridLayout(ROWS, COLUMNS, 5, 5));initPictureIndex();for (int i = 0; i < ROWS * COLUMNS; i++) {PicPanel panel_1 = new PicPanel(this, picture[i]);panel_Pic.add(panel_1);}}/*** 开始游戏*/protected void startGame() {new Thread() {@Overridepublic void run() {long startTime = System.currentTimeMillis();while (count < ROWS * COLUMNS / 2) {txt_Time.setText(((System.currentTimeMillis() - startTime) / 1000)+ "");}JOptionPane.showMessageDialog(null,"成功!共耗时" + txt_Time.getText() + "秒。");// 结束后重新初始化一下面板以便于下一次的运行count = 0;panel_Pic.removeAll();initPicPanels();txt_Time.setText(null);panel_Pic.validate();isRunning = false;}}.start();}/*** 初始化图片的索引并赋值每个图片的路径*/private void initPictureIndex() {picture = new String[ROWS * COLUMNS];// 这里没有检测图片目录中文件的有效性,需要保证都是图片类型。File file = new File(picDir);File[] pics = file.listFiles();// 初始化一个ROWS*COLUMNS的int数组,里面存放每个图片的索引int[] indexs = getIndexs(picture.length, pics.length);for (int i = 0; i < indexs.length; i++) {picture[i] = pics[indexs[i]].getAbsolutePath();}}/*** 根据提供的图片总数目(假设图片都是互不相同的)得到一个长度为sum的数组用来表示每个图片的索引* * @param sum*            游戏的行列数乘积* @param picNums*            给定目录下图片的总数目* @return*/private int[] getIndexs(int sum, int picNums) {int half = sum / 2;if (picNums < half) {return getIndexsByMap(sum, picNums);}int[] tmpResult = new int[sum];Random random = new Random(System.currentTimeMillis());int temp = 0;LinkedList<Integer> list = new LinkedList<Integer>();while (list.size() != half) {temp = random.nextInt(picNums);if (!list.contains(temp)) {list.add(temp);} else if (picNums < half) {list.add(temp);}}for (int i = 0; i < tmpResult.length; i++) {tmpResult[i] = list.get(i >= half ? i % half : i);}// 将顺序打乱,否则会出现前半部分和后半部分是完全分开的情况LinkedList<Integer> _result = new LinkedList<Integer>();while (_result.size() != sum) {temp = random.nextInt(sum);if (!_result.contains(temp)) {_result.add(temp);}}int[] result = new int[sum];for (int i = 0; i < result.length; i++) {result[i] = tmpResult[_result.get(i)];}return result;}/*** 当图片数量小于总格子数一半时需要使用下面的方法获取,保证所有的图片都能使用上* * @param sum* @param picNums* @return*/private int[] getIndexsByMap(int sum, int picNums) {int half = sum / 2;int[] tmpResult = new int[sum];Random random = new Random(System.currentTimeMillis());int temp = 0;HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();// 因为图片的数量小于sum的一半,因此先按顺序将图片索引都添加到map中以保证得到的结果中每个图片都被使用到for (int i = 0; i < picNums; i++) {map.put(i, 1);}int size = picNums;while (size != half) {temp = random.nextInt(picNums);if (!map.containsKey(temp)) {map.put(temp, 1);} else {map.put(temp, map.get(temp) + 1);}size++;}List<Integer> list = mapKeyToList(map);for (int i = 0; i < tmpResult.length; i++) {tmpResult[i] = list.get(i >= half ? i % half : i);}// 将顺序打乱,否则会出现前半部分和后半部分是完全分开的情况LinkedList<Integer> _result = new LinkedList<Integer>();while (_result.size() != sum) {temp = random.nextInt(sum);if (!_result.contains(temp)) {_result.add(temp);}}int[] result = new int[sum];for (int i = 0; i < result.length; i++) {result[i] = tmpResult[_result.get(i)];}return result;}/*** 将map中的key转换成一个list,其中每个key的value表示该key出现的次数,转换中如果次数多于1需要重复添加key到list中* * @param map* @return*/private List<Integer> mapKeyToList(HashMap<Integer, Integer> map) {List<Integer> list = new ArrayList<Integer>();Iterator<Integer> keyIt = map.keySet().iterator();Integer key = 0;while (keyIt.hasNext()) {key = keyIt.next();if (map.get(key) == 1) {list.add(key);} else {for (int i = 0; i < map.get(key); i++) {list.add(key);}}}return list;}public static void main(String[] args) {SwingUtilities.invokeLater(new Runnable() {@Overridepublic void run() {RememberCard remCard = new RememberCard();remCard.setSize(400, 300);remCard.setLocationRelativeTo(null);remCard.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);remCard.setVisible(true);}});}public PicPanel getPreOne() {return preOne;}public void setPreOne(PicPanel preOne) {this.preOne = preOne;}public void addCount() {count++;}public boolean isRunning() {return isRunning;}public void setRunning(boolean isRunning) {this.isRunning = isRunning;}
}/*** @author jqs* *         图片面板,主要实现了图片的显示与图片相同判断*/
class PicPanel extends JPanel {private static final long serialVersionUID = 2172162568449349737L;private String picPath;private JLabel lbl_Pic = new JLabel();private ImageIcon bgIcon = null;private boolean isShow = false;private RememberCard parent;private boolean finished = false;public PicPanel(RememberCard rememberCard, String picPath) {this.picPath = picPath;this.parent = rememberCard;this.setBorder(new CompoundBorder(null, new LineBorder(new Color(0, 0,0), 2)));this.setLayout(new BorderLayout());this.add(lbl_Pic, BorderLayout.CENTER);this.addMouseListener(mouseAdapter);}public String getPicPath() {return picPath;}public void setPicPath(String picPath) {this.picPath = picPath;}/*** 图片面板的鼠标事件监听,配对过程在此完成*/private MouseAdapter mouseAdapter = new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {new Thread() {public void run() {if (!parent.isRunning() || finished) {return;}isShow = !isShow;if (isShow) {if (bgIcon == null) {initLabelImage();}PicPanel curOne = (PicPanel) lbl_Pic.getParent();PicPanel preOne = parent.getPreOne();if (preOne == null) {parent.setPreOne(curOne);} else {boolean right = checkRight(curOne, preOne);if (right) {parent.setPreOne(null);curOne.setFinished(true);preOne.setFinished(true);parent.addCount();} else {lbl_Pic.setIcon(bgIcon);repaint();try {Thread.sleep(50);} catch (InterruptedException e1) {e1.printStackTrace();}lbl_Pic.setIcon(null);isShow = !isShow;repaint();preOne.getMouseListeners()[0].mouseClicked(null);parent.setPreOne(null);return;}}lbl_Pic.setIcon(bgIcon);} else {lbl_Pic.setIcon(null);}repaint();};}.start();}/*** 检查两个面板显示的图片是否一致,根据图片的路径来判断,同时要保证两个面板不是同一个面板* * @param curOne* @param preOne* @return*/private boolean checkRight(PicPanel curOne, PicPanel preOne) {return curOne.getPicPath().equals(preOne.getPicPath())&& !curOne.equals(preOne);}};/*** 初始化Label对象的image*/private void initLabelImage() {try {Image image = ImageIO.read(new File(picPath));if (image != null) {int lblWidth = this.getWidth();int lblHeight = this.getHeight();bgIcon = new ImageIcon(image.getScaledInstance(lblWidth,lblHeight, Image.SCALE_DEFAULT));}} catch (IOException e) {e.printStackTrace();}}/*** 当找到配对的图片面板后设置完成状态为true,此时点击图片面板已经无效了。* * @param b*/protected void setFinished(boolean b) {finished = b;}
}

3 游戏截图

3.1启动后界面

3.2开始游戏界面

3.3游戏结束界面

JAVA记忆翻牌游戏制作相关推荐

  1. 记忆翻牌游戏代码html,原生JS实现记忆翻牌游戏

    本文实例为大家分享了JS实现记忆翻牌游戏的具体代码,供大家参考,具体内容如下 html代码 css代码 * { padding: 0; margin: 0; } #game { width: 600p ...

  2. Java飞机小游戏制作简单实现详细小结

    567881@ftJava小游戏开发 Java飞机小游戏制作简单实现小结 本人原来是个技术小白,寒假我跟着高淇老师的Java300集开始自学Java,跟着做了一个飞机大战小游戏,已经实现了飞机的自由移 ...

  3. html5 翻牌小游戏,html5记忆翻牌游戏实现思路及代码

    翻开的2张牌如果配对就会消除,否则2张牌都会返回背面. 需求分析 怎么绘制正的牌面和背的牌面及配对成功后怎么消除牌面 怎么生成牌组并且确定每张牌的位置和对应的图片 怎么洗牌 怎么记录牌组的配对信息 怎 ...

  4. 【unity3D】unity记忆翻牌小游戏教程(简单详细)

    游戏开发的学习记录⑨ 项目:记忆翻牌小游戏 unity版本:unity2020.3.30f1c1 目录 项目:记忆翻牌小游戏 unity版本:unity2020.3.30f1c1 一.游戏内容说明 二 ...

  5. 翻牌游戏如何打乱牌面java_家长专栏提高儿童记忆力的游戏训练

    记忆是人脑对过去经验的保持和再现.记忆过程包括三个基本环节,即识记.保持.再认或回忆.识记是识别和记住事物.保持是将已获得的知识或经验巩固与保留在大脑中.再认是指过去经历过的事物再度出现时,能将它指认 ...

  6. java入门-五子棋游戏的制作

    java入门-五子棋游戏的制作 想要开发一个简单的五子棋游戏,需要实现五子棋的棋盘.棋子.输赢判定.重新开始游戏.悔棋.认输.人机大战以及退出游戏等功能. 1.实现五子棋的棋盘功能 想要实现这个功能, ...

  7. Java版AVG游戏开发入门示例 3 ——脚本引擎的制作及应用

    源码下载地址:http://code.google.com/p/loon-simple/downloads/list 根据wikipedia的解释:脚本语言(Script language,scrip ...

  8. Java版AVG游戏开发入门示例[3]——脚本引擎的制作及应用

    源码下载地址:http://code.google.com/p/loon-simple/downloads/list 根据wikipedia的解释:脚本语言(Script language,scrip ...

  9. java游戏开发总结_java游戏制作总结——飞机大战

    用Java制作游戏之前,一定要做到方向明确,思路清晰.首先确定自己需要用到几个类,类里的内容大致是什么,用脑图进行表达展现. Java语言是一种跨平台.适合于分布式计算环境的面向对象编程语言,具有简单 ...

  10. 用c语言400行代码小游戏,程序员400行代码制作翻牌游戏解决无聊时间

    原标题:程序员400行代码制作翻牌游戏解决无聊时间 上班感觉累,很想放假,但是放假在家又感觉非常无聊,总是不知道干什么,又感觉还不如上班呢,反正无聊不如练练写小游戏吧,即练习了代码,做完后还能接着玩, ...

最新文章

  1. 在WinSCP中使用sudo进行sftp,不用输入密码,获得root权限
  2. 一样入职的应届生工资不一样_刘涛入职阿里:为什么阿里要招聘明星?明星入职和普通人一样吗...
  3. android,面向对象
  4. 《JavaScript高级程序设计(第四版)》红宝书学习笔记(第五章:基本引用类型,原始值包装类型,单例内置对象)
  5. 三个案例快速入门Nettty
  6. oracle日期与字符串的相互转化
  7. 演示Go语言多返回值功能
  8. gstat | 空间插值(二)——克里金插值之普通克里金
  9. 黑马博客——详细步骤(九)项目功能的实现之mongoDB数据库添加账号
  10. 检查Python列表项是否在另一个字符串中包含一个字符串
  11. 棋盘问题(深度搜索)
  12. js 前端导出报错 格式不正确_js-xlsx 实现前端 Excel 导出(支持多 sheet)
  13. 计算机系统感染了病毒怎么办,笔者教你电脑感染了病毒怎么解决
  14. 开源Jamendo在线音乐播放器源码(四)
  15. mysql choose when_mybatis 基础(二) 动态sql 关于where if / where choose when otherwise
  16. 哪家的云服务器便宜?
  17. win10镜像无法再此计算机上运行,Win10安装镜像提示运行此工具时出现问题如何解决...
  18. From little Cutie to Rockin Beauty(about Hilary Duff and someone concerned.)
  19. html防微信抢红包,如何实现仿微信抢红包
  20. C++ Builder-程序无法在其他机器上运行(显示找不到vcl60.bpl 或者BORLANDMM.DLL等)

热门文章

  1. php的seeder是什么,轻松学Laravel6数据填充之方式一Seeder填充
  2. CSS 常见样式 特殊用法 贯穿线徽章箭头
  3. [转载]Android学习网站
  4. 报错:UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0x93 in position 1721: illegal multibyte sequen
  5. pubg服务器维护6.23,pubg维护6月23日 | 手游网游页游攻略大全
  6. 【Matlab车牌识别】BP神经网络车牌识别【含GUI源码 669期】
  7. vue项目没有package.json文件
  8. Ubuntu Linux
  9. vue中使用图片裁切器
  10. 跨站点请求伪造攻击的原理及防御