界面与基本的逻辑功能的设计
本次实训分为以下几部分:
JAVA实训-连连看(一)基本的逻辑功能以及框架
JAVA实训-连连看(二)扩展一些基本功能:退出、重列、新开一局 (no ending)
JAVA实训-连连看(三)高级编程:数据库连接登陆、网络商城 (no start...)
我们非常不建议将容易发生改变的常量直接写入函数中
以下代码注释了学习过程的一些笔记 由于时间有限就不分开叙说了
代码中注释部分是一开始用的方法 随着学习地推进发现了更多地方法因此不再采用:
其实很多知识点结合代码来看 会变得更加好了解,粗暴点说 满口胡话 不如直接上~代码
不过通过这一次我了解到了两个方法:
1.i++与++i 书写上的选择问题(QAQ 原来我一直没有注意到)
2.循环取余,重复取模(下面我们适用于在定位这部分)
package com.lyd.LinkGame.view; import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; import com.lyd.LinkGame.data.GameData; public class MainFrame extends JFrame { //我们将常量采用重构抽取出来 private static final int heigh = 800; private static final int width = 700; public MainFrame() { //创建gameData对象方便调用里面地方法以及成员 GameData gameData=new GameData(); //设置大小,代替reSize this.setSize(width, heigh); //由于分辨率不断变化则通过下列可以捕获分别率 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); //定义位置的时候我们不建议直接采用数值 this.setLocation((screenSize.width - width) / 2, ((screenSize.height - heigh) / 2)); this.setTitle("连连看"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); /*以下我们采用了两种方式设置布局,如果采用第一部分的话我们需要考虑具体的位置,使用 //下面被我被我们注释的setBounds() // this.getContentPane().setLayout(null); 循环取余,重复取模 // button.setBounds(i % 4 * 100, (i / 4) * 100, 100, 100); //网格布局可以是最好的*/ this.getContentPane().setLayout(new GridLayout(gameData.rows, gameData.cols)); Random ran1 = new Random(16); for (int i = 0; i < 16; ++i) { /*注意 实际上编译器++i和i++是一样的 但是我们不许清楚, * i++多了一个存储当前为变化 我们不提倡在同样作用情况下 使用i++*/ JButton button = new JButton(); //int imgName = ran1.nextInt(16); 测试随机数 // button.setText(""+imgName); //有两种方式,一种是打代码 一种直接复制下来编译器会将其看作是一个包 String path = this.getClass().getResource("/image").getPath(); // button.setIcon(new ImageIcon("src/pic/fruit_"+imgName+".png")); //以下交给数据程去处理 button.setIcon(new ImageIcon(path + "/fruit_" + gameData.data[i] + ".png")); //我们通常采用ActionListener监听器 本道题并不适用mouseClick button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // button.setVisible(false); JButton button = (JButton) e.getSource(); button.setVisible(false); } }); this.getContentPane().add(button); } } }
处理数据层:
com.lyd.LinkGame.data
其中的一个GameData类:
package com.lyd.LinkGame.data; public class GameData { public static final int cols = 4; public static final int rows = 4; public int[] data=new int[cols*rows];//我们不该将数量直接放入 public GameData() { //成对生成数据,存入data中 init(); //打乱data数组中的数据 shuff(); } private void shuff() { // TODO 自动生成的方法存根 //打乱data数组中的数据 for(int i=0;i<rows*cols/2;++i) { int index1=(int)(Math.random()*(cols*rows));//注意括号的问题 int index2=(int)(Math.random()*(cols*rows)); //交换 int temp = data[index1]; data[index1] = data[index2]; data[index2] = temp; } System.out.print("ok"); } private void init() { // TODO 自动生成的方法存根 //成对生成数据,存入data中 for(int i=0;i<data.length;++i) { //i/2按照偶数的方式,进行了划分因为没有0图片所以加1 data[i]=i/2+1; } } }
运行效果:
以上是上周的一些笔记,周末整理了以下 把一些基本的功能给完善了,期间遇到了一些小小郁闷的地方
难点的话感觉有两个:
1.逻辑代码的实现
第二天的主要任务是双消以及做相同判断的消除
1.1.相比第一天MainFrame类
//我们将常量采用重构抽取出来 private static final int heigh = 800; private static final int width = 700; int buttonMes1=0; int buttonMes2=0; JButton button1=null; JButton button2=null;
我们的监听事件发生了变化
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // button.setVisible(false); JButton button = (JButton) e.getSource(); if(button1 == null){ //以前没点击过 button1=button; System.out.print("START"); }else{ button2=button; int index1=button1.getY()/button1.getHeight()*gameData.cols+button1.getX()/button1.getWidth(); int index2=button2.getY()/button2.getHeight()*gameData.rows+button2.getX()/button2.getWidth(); if(GameRule.isConnext(gameData.data, index1, index2)) { button2=button; button1.setVisible(false); button2.setVisible(false); } button1=null; button2=null; } }
- 求index1,和index2
- 其实我们主要是通过按钮的位置来算的
- 由于按钮可能不在第二行所以我们算的时候需要考虑乘以一个行数或者列数
1.2.书写方便
同时
为了后面的书写我们将this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
后的部分抽取 为initButton(gameData);
注:这里我们
- final GameData gameData=new GameData();
- 是因为下面的监听器我们是使用了匿名类, 匿名类如果需要访问外部常量需要定义成final
我们这里涉及到了相同相处的数据处理,新定义一个
GameRule类
package com.icss.linkgame.data; public class GameRule { /** 判断数组DATA中 制定的两位置之间的图形能否消除 * @param data 数据 * @param index1 第一个位置的数值 * @param index2 第二个位置的数值 * @return */ public static boolean isConnext(int data[],int index1,int index2) { if(index1 == index2) { System.out.print("1"); return false; } if(data[index1] == data[index2]) { return true; } System.out.print("1"); return false; } }
1.3逻辑部分就不再意义叙述了 代码注释也写的很清楚,基本思路:
1.3.1直连 .。。就是最基本的后面都是在这个基础上 其中 sum=0 横和竖 但是咬住 位置的大小问题
1.3.2 拐一次弯:关键是拐弯点的特性(比如:与起点同行 与终点同列 注意:判断转弯点是否为空)
1.3.3 拐两次弯:关键是拐弯点(绿色的怎么搞,其实很好搞。。。 就是for循环 这种时候关键这个新的坐标,我们用for循环对其做出尝试,但是依然有特点:(row1,col1)-(rowX,col1) && (rowX,col1)-(rowX,col2) && (rowX,col2)-(row2,col2))
1.3.4 外部拐弯:我们将使用data[-1]这种形式考虑到不做数组 为0不会报错。。。因为编译器自动弄成0
2.第二个难点是:
事件类的处理 因为采用内部类的话是没问题,因为我做的实验的时候用了父类,这时候如果如果用外部类投递参数的时候会出现类型转换错误:
这个感觉问题很大。。。暂时没能很好的解决。。。
感受:
也不是第一次写窗体程序了 但是却写的有点郁闷,前期听老师的 用了一维数组 ,前期的确代码很少 但是代码不直观啊 而且感觉后期扩展不方便转换的地方太多,容易写错,建议没事的时候不要使用一维数组代替二维(QAQ)
no ending
基本框架已经搭好了 基本思想如上 有需要完整代码的同学 欢迎留言 。。。 CSDN 上传后也要积分才能下载。。。GIThub没玩熟练。。。