老Java程序员花2天写了个连连看,我竟连不过我女儿,我了个去!
Posted 编程界明世隐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了老Java程序员花2天写了个连连看,我竟连不过我女儿,我了个去!相关的知识,希望对你有一定的参考价值。
老Java程序员花2天时间做了个连连看
引言:
最近做小游戏有点上瘾,这一不小心翻到了个连连看,二话不说找到素材,就撸了起来。
期间在我加入背景音乐的时候,被女儿听到了,她多次到我身边说:
“爸爸,我很会玩这个游戏,你给我玩,不然就捣乱”。
然后就在我旁边转来转去,动我鼠标摸我键盘,竟然不让我写代码。
讲实话我写代码正投入的时候,如果换做我老婆,我肯定一把推开。
没办法是我女儿,只好继续当好我慈祥老父亲的角色,我跟她说做完给你玩,如果连的过爸爸,就给你玩多几盘,但是现在不能,等我做完我们来比赛,她这才答应不捣乱。
打断我写代码的思路,我要抓狂的,不知各位亲在你全身心投入写代码的时候,女票、媳妇捣乱你会怎么做呢?欢迎就此话题留言,让我好生学习一波你们的精彩操作!
代码实现
创建窗口
首先创建一个游戏窗体类GameFrame,继承至JFrame,用来显示在屏幕上(window的对象),每个游戏都有一个窗口,设置好窗口标题、尺寸、布局等就可以。
/*
* 游戏窗体类
*/
public class GameFrame extends JFrame {
public GameFrame() {
setTitle("连连看");//设置标题
setSize(786, 510);//设定尺寸
setLayout(new BorderLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//点击关闭按钮是关闭程序
setLocationRelativeTo(null); //设置居中
setResizable(false); //不允许修改界面大小
}
}
创建面板容器GamePanel继承至JPanel
package main;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
/*
* 画布类
*/
public class GamePanel extends JPanel{
GamePanel gamePanel=this;
private JFrame mainFrame=null;
//构造里面初始化相关参数
public GamePanel(JFrame frame){
this.setLayout(null);
mainFrame = frame;
mainFrame.setVisible(true);
}
@Override
public void paint(Graphics g) {
}
}
再创建一个Main类,来启动这个窗口,用来启动。
package main;
public class Main {
//主类
public static void main(String[] args) {
GameFrame frame = new GameFrame();
GamePanel panel = new GamePanel(frame);
frame.add(panel);
frame.setVisible(true);//设定显示
}
}
右键执行这个Main类,窗口建出来了
创建菜单及菜单选项
创建菜单
private void initMenu(){
// 创建菜单及菜单选项
jmb = new JMenuBar();
JMenu jm1 = new JMenu("游戏");
jm1.setFont(new Font("微软雅黑", Font.BOLD, 15));// 设置菜单显示的字体
JMenu jm2 = new JMenu("帮助");
jm2.setFont(new Font("微软雅黑", Font.BOLD, 15));// 设置菜单显示的字体
JMenuItem jmi1 = new JMenuItem("开始新游戏");
JMenuItem jmi2 = new JMenuItem("退出");
jmi1.setFont(new Font("微软雅黑", Font.BOLD, 15));
jmi2.setFont(new Font("微软雅黑", Font.BOLD, 15));
JMenuItem jmi3 = new JMenuItem("操作说明");
jmi3.setFont(new Font("微软雅黑", Font.BOLD, 15));
JMenuItem jmi4 = new JMenuItem("胜利条件");
jmi4.setFont(new Font("微软雅黑", Font.BOLD, 15));
jm1.add(jmi1);
jm1.add(jmi2);
jm2.add(jmi3);
jm2.add(jmi4);
jmb.add(jm1);
jmb.add(jm2);
mainFrame.setJMenuBar(jmb);// 菜单Bar放到JFrame上
jmi1.addActionListener(this);
jmi1.setActionCommand("Restart");
jmi2.addActionListener(this);
jmi2.setActionCommand("Exit");
jmi3.addActionListener(this);
jmi3.setActionCommand("help");
jmi4.addActionListener(this);
jmi4.setActionCommand("win");
}
实现ActionListener并重写方法actionPerformed
actionPerformed方法的实现
//各种事件的触发方法
@Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("宋体", Font.ITALIC, 18)));
UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("宋体", Font.ITALIC, 18)));
if ("Exit".equals(command)) {
Object[] options = { "确定", "取消" };
int response = JOptionPane.showOptionDialog(this, "您确认要退出吗", "",
JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null,
options, options[0]);
if (response == 0) {
System.exit(0);
}
}else if("Restart".equals(command)){
if(startFlag){
Object[] options = { "确定", "取消" };
int response = JOptionPane.showOptionDialog(this, "游戏中,您确认要重新开始吗", "",
JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null,
options, options[0]);
if (response == 0) {
//需要先结束游戏
realGameEnd(1);
restart();
}
}else{
restart();
}
}else if("help".equals(command)){
JOptionPane.showMessageDialog(null, "鼠标点击相同的且没有阻挡的消除!",
"提示!", JOptionPane.INFORMATION_MESSAGE);
}else if("win".equals(command)){
JOptionPane.showMessageDialog(null, "全部连对完成即获得胜利!时间超过200秒则失败!",
"提示!", JOptionPane.INFORMATION_MESSAGE);
}
}
初始化图片
将所有要用到的图片初始化,方便待会使用
public class ImageValue {
//小卡片
public static List<BufferedImage> itemImageList = new ArrayList<BufferedImage>();
//被点击后小卡片
public static List<BufferedImage> itemOverImageList = new ArrayList<BufferedImage>();
//胜利图片
public static BufferedImage winImage = null;
//失败图片
public static BufferedImage loseImage = null;
//准备图片
public static BufferedImage readyImage = null;
//图片路径
public static String ImagePath = "/images/";
//将图片初始化
public static void init(){
String path = "";
//玛丽奥图片初始化
for(int i=1;i<=36;i++){
try {
path = ImagePath + i+".gif";
itemImageList.add(ImageIO.read(ImageValue.class.getResource(path)));
path = ImagePath + i+"_over.gif";
itemOverImageList.add(ImageIO.read(ImageValue.class.getResource(path)));
} catch (IOException e) {
e.printStackTrace();
}
}
try {
path = ImagePath +"win.png";
winImage = ImageIO.read(ImageValue.class.getResource(path));
path = ImagePath +"lost.png";
loseImage = ImageIO.read(ImageValue.class.getResource(path));
path = ImagePath +"ready.png";
readyImage = ImageIO.read(ImageValue.class.getResource(path));
} catch (IOException e) {
e.printStackTrace();
}
}
}
根据难度系数选取图片
本例共有36张图片,并设置为8行、18列,总共144个卡片位置,难度系数有三种,分别是12、24、36
难度系数的数字越大意味中难度越大
比如难度系数12,则系统从36组图片中选出12组,组成144个卡片,意味着重复的卡片较多,而如果是难度系数36,则重复的卡片数量较少,所以难度比较大。
作为老程序员,我果断选择了12,别为我为什么?那我走?
图片列表如下
从36张图片中获取12张图片,怎么做?
从1-36中随机取一个数字并存到一个集合中,如果集合中存在则跳过继续随机,直到集合中的元素达到12个,则跳出。
//初始化下标值
private void initIndexs() {
Random random = new Random();
int n ;
while(true){//
n = random.nextInt(36)+1;//随机从36张图片下标中选取
if(!indexs.contains(n)){//重复的则过滤
indexs.add(n);
}
if(indexs.size()==difficulty){//根据difficulty 来确定要多少对
break;
}
}
}
执行并打印indexs(每次都不一样,这是我截图的其中一次)
凑齐144张图片
多次循环上述indexs 集合添加数据,其实刚好循环12次
//凑齐144张图片
private void initImage144() {
while(true){
for(int i=0;i<indexs.size();i++){
cardIndexs.add(indexs.get(i));
}
if(cardIndexs.size()==144){
break;
}
}
}
打乱顺序
因为144 是根据indexs重复循环得来的,所以顺序很固定
采用 Collections的shuffle方法
//随机排序
private void sortImage() {
Collections.shuffle(cardIndexs);
}
再打印看看
创建卡片类
卡片类,属性有坐标x、y,宽高、图片、选择后图片、类型、对应行、对应列等;方法主要有绘制、判断鼠标点击是否在范围内等。
package main;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import common.ImageValue;
public class Card {
private int x = 0;//x坐标
private int y = 0;//y坐标
private int width = 0;//宽
private int height = 0;//高
private int i = 0;//行
private int j = 0;//列
private int index = 0;//对应图片下标值
private int type = 0;//0 原始图片 1 over图片 2 空图片
private BufferedImage image = null;//图片对象
private BufferedImage overImage = null;//点击后图片对象
private GamePanel panel=null;
public Card(int x,int y,int index,int i,int j,GamePanel panel){
this.x=x;
this.y=y;
this.panel=panel;
this.index=index;
this.i=i;
this.j=j;
this.image = ImageValue.itemImageList.get(index);
this.overImage = ImageValue.itemOverImageList.get(index);
this.width=this.image.getWidth();
this.height=this.image.getHeight();
}
//绘制
public void draw(Graphics g) {
if(type==0){
g.drawImage(image, x, y, width,height, null);
}else if(type==1){
g.drawImage(overImage, x, y, width,height, null);
}else if(type==2){//不绘制
}
}
//判断鼠标是否卡片范围内
boolean isPoint(int x,int y){
//大于左上角,小于右下角的坐标则肯定在范围内
if(x>this.x && y >this.y
&& x<this.x+this.width && y <this.y+this.height){
return true;
}
return false;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public int getJ() {
return j;
}
public void setJ(int j) {
this.j = j;
}
public int getIndex() {
return index;
}
public void 女朋友想减肥,程序员花了3天写了个卡路里计数器