[size=medium] 一,需求分析:
1>首先要满足图片的个数是偶数,而且每张图片出现的个数是偶数。
2>消除图片的时候,消除图片的路径中不能再有其他的图片。
3>有三种路径方法选择:第一种是在同一行或同一列,第二种是可以有一个转折点,最后一种是可以有两个转折点。
4>只有当两者图片相同时才能消除
5>在消除图片的过程中把选中的图片给标记出来,并且画出消除相同图片所选择的路径。
满足了以上需求就可以做一个简单的连连看了
二,实现方法
1>满足第一个需求:首先我们需要写一个JFrame,在定义一个二维数组(int[rows][cols])(这里需要注意的是:我们必须保证rows*cols是一个偶数,这样才能保证我们的图片个数是偶数。) 用来存放连连看中的图片对象,将图片的宽度和高度设置成一个常量,使每个图片的宽度和高度都相同,这样可以方便之后计算图片的坐标。然后在JFrame中初始化这个二维数组 即往这个二维数组中放入图片,在往二维数组中放入图片的时候,我们需要另一一个容器作为一个中介在利用一个循环,循环rows*cols/2次每次往容器中加入2张一样的图片对象,接着在用两个for循环将容器中的图片取出再放入这个二维数组就完成了我们的第一个需求了。代码实现:
package LLK01;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MyFrame extends JFrame implements Constant {
Random ran=new Random();
List<ImageIcon> imagList=new ArrayList<ImageIcon>();
public void initUI() {
this.setTitle("连连看01");
this.setSize(600, 350);
putImage();
this.setResizable(false);
JPanel panel = new MyPanel();
panel.setBackground(Color.black);
this.add(panel);
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
this.setVisible(true);
MyListener listener = new MyListener();
panel.addMouseListener(listener);
}
public static void main(String[] args) {
new MyFrame().initUI();
}
public void putImage(){
for(int i=0;i<ROWS*COLS/2;i++){
int num=ran.nextInt(4);
String url="src/LLK01/imgs/"+num+".gif";
ImageIcon img=new ImageIcon(url);
// ImageIcon img2=new ImageIcon(url);
imagList.add(img);
imagList.add(img);
}
System.out.println(imagList.size());
for(int i=0;i<ROWS;i++){
for(int j=0;j<COLS;j++){
int index=ran.nextInt(imagList.size());
imgs[i][j]=imagList.remov(index);
}
}
}
class MyPanel extends JPanel {
@Override
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
ImageIcon img = imgs[i][j];
if (img != null)g.drawImage(img.getImage(), X0 + SIZE * j, Y0 + SIZE* i, null);
// System.out.println("huhu");
}
}
}
}
}
2>满足2.3.4.5需求:这里我们需要定义一个鼠标监听器 MouseAdapter,通过 mouseReleased(MouseEvent e) 事件来获得每次点击的图片对象。我们需要一个计数器int count=0 来记录我们点击的次数,每点击一次count++,当第二次点击的时候我们再把count=0;这样就可以保证我们每点两张图片就进行判断。判断图片是否相同,我们只需判断图片的路径是否一样。同时我们也需要获得每次点击的图片的下标,这对后面消除时路径的判断非常重要。当他们 下标相同时代表他们是同一张图片,这样是不能消除的。代码:package LLK01;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import com.sun.org.apache.bcel.internal.generic.GETSTATIC;
public class MyListener extends MouseAdapter implements Constant{
int count=0;
private ImageIcon icon1;
private ImageIcon icon2;
int i1,j1,i2,j2;
private JPanel panel;
private int sum=0;
private ArrayList<Point> plist;
@Override
public void mouseReleased(MouseEvent e) {
panel=(JPanel)e.getSource();
Graphics g=panel.getGraphics();
g.setColor(Color.red);
//获得鼠标点击的坐标
int x=e.getX();
int y=e.getY();
if(count==0){
sum=0;
//根据鼠标点击的坐标得到第一次点击的图片对象
icon1=getIcon(x, y);
//得到第一次点击的图片对象的下标
i1=(x-X0)/SIZE;//y
j1=(y-Y0)/SIZE;//x
System.out.println("huqian1");
//框住选中的图片对象
g.draw3DRect(X0+i1*SIZE, Y0+j1*SIZE, SIZE, SIZE, true);
count++;
sum++;
System.out.println("sum:"+sum+"第一次");
}else{
System.out.println(count);
plist=new ArrayList<Point>();
System.out.println("plist:"+plist.size());
//得到第二次点击时的图片对象
icon2=getIcon(x, y);
//得到第二次点击时的图片对象的下标
i2=(x-X0)/SIZE;
j2=(y-Y0)/SIZE;
//框住选中的图片对象
g.draw3DRect(X0+i2*SIZE, Y0+j2*SIZE, SIZE, SIZE, true);
System.out.println("huqian2");
sum++;
System.out.println("sum:"+sum);
count=0;
//
new MyThread(icon1,icon2,plist).start();
}
}
//或得鼠标点击处的的图片对象
public static ImageIcon getIcon(int x,int y){
for(int i=0;i<ROWS;i++){
for(int j=0;j<COLS;j++){
ImageIcon icon=imgs[i][j];
if((x-(X0+SIZE*j))<SIZE&&(y-(Y0+SIZE*i))<SIZE){
// System.out.println("huhu");
return icon;
}
}
}
return null;
}
class MyThread extends Thread{
ImageIcon icon1;
ImageIcon icon2;
List<Point> plist=new ArrayList<Point>();
private SunFa02 sunfa;
public MyThread(ImageIcon icon1,ImageIcon icon2,List<Point> plist){
this.icon1=icon1;
this.icon2=icon2;
this.plist=plist;
sunfa=new SunFa02(plist);
}
public void run(){
// while(islive){
if(sum==2){
//判断图片的路径是否一样,判断他们的下标是否一样
if(icon1!=null&&icon2!=null&&icon1.toString().equals(icon2.toString())&&(i1!=i2 || j1!=j2)){
//判断路径
if(sunfa.checkRow(j1, i1, j2, i2)|| sunfa.checkCol(j1, i1, j2, i2)|| sunfa.cheakTR(j1, i1, j2, i2)|| sunfa.cheakTR2(j1, i1, j2, i2) || sunfa.checkH(j1, i1, j2, i2) || sunfa.checkV(j1, i1, j2, i2)
){
//绘制图片消除时的路径
for(int i=0;i<plist.size();i+=2){
Point p1=plist.get(i);
Point p2=plist.get(i+1);
int p1x=X0+SIZE*p1.y+SIZE/2;
int p1y=Y0+SIZE*p1.x+SIZE/2;
int p2x=X0+SIZE*p2.y+SIZE/2;
int p2y=Y0+SIZE*p2.x+SIZE/2;
Graphics2D g2= (Graphics2D) panel.getGraphics();
g2.setColor(Color.red);
g2.setStroke(new BasicStroke(5));
g2.drawLine(p1x, p1y, p2x, p2y);
}
imgs[j1][i1]=null;
imgs[j2][i2]=null;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//刷新面板
if(panel!=null)
panel.repaint();
}else{
if(panel!=null)
panel.repaint();
}
}else{
//刷新面板
if(panel!=null)
panel.repaint();
}
}
}
}
}
//==================================================================================================================//
package LLK01;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
public class SunFa02 implements Constant{
List<Point> plist=new ArrayList<Point>();
public SunFa02(List<Point> plist){
this.plist=plist;
}
//判断同一行是否可以消除
public boolean checkRow(int r1,int c1,int r2,int c2){
if(r1==r2){
int maxcol=Math.max(c1,c2);
int mincol=Math.min(c1,c2);
for(int i=mincol+1;i<maxcol;i++){
//判断在同一行中选中的两张图片的中间是否还有其他的图片
if(!(imgs[r1][i]==null)){
return false;
}
}
//保存可以消除的两张图片的下标
plist.add(new Point(r1,c1));
plist.add(new Point(r2,c2));
return true;
}
return false;
}
//判断同一列是否可以消除
public boolean checkCol(int r1,int c1,int r2,int c2){
if(c1==c2){
int maxrow=Math.max(r1,r2);
int minrow=Math.min(r1,r2);
for(int i=minrow+1;i<maxrow;i++){
//判断在同一列中选中的两张图片的中间是否还有其他的图片
if(!(imgs[i][c1]==null)){
return false;
}
}
//保存可以消除的两张图片的下标
plist.add(new Point(r1,c1));
plist.add(new Point(r2,c2));
return true;
}
return false;
}
//判断有一个转折点的情况
public boolean cheakTR(int r1,int c1,int r2,int c2){
//判断转折点处是否有图片
if(!(imgs[r2][c1]==null)){
plist.clear();
return false;
}else{
if(checkCol(r1,c1,r2,c1) && checkRow(r2,c2,r2,c1)){
return true;
}
}
plist.clear();
return false;
}
//判断有一个转折点的情况
public boolean cheakTR2(int r1,int c1,int r2,int c2){
//判断转折点处是否有图片
if(!(imgs[r1][c2]==null)){
plist.clear();
return false;
}else{
if(checkCol(r2,c2,r1,c2) && checkRow(r1,c1,r1,c2)){
return true;
}
}
plist.clear();
return false;
}
//判断两个转折点的情况
public boolean checkH(int r1,int c1,int r2,int c2){
for(int i=0;i<ROWS;i++){
//判断两个转折点处是否有图片
if(imgs[i][c1]==null && imgs[i][c2]==null){
if(checkRow(i,c1,i,c2) && checkCol(r1,c1,i,c1)&& checkCol(r2,c2,i,c2))
{
return true;
}
}
}
plist.clear();
return false;
}
//判断两个转折点的情况
public boolean checkV(int r1,int c1,int r2,int c2){
for(int i=0;i<COLS;i++){
//判断两个转折点处是否有图片
if(imgs[r1][i]==null && imgs[r2][i]==null){
f(checkCol(r1,i,r2,i) && checkRow(r1,c1,r1,i)&& checkRow(r2,c2,r2,i)){
return true;
}
}
}
plist.clear();
return false;
}
}
在绘制图片消除路径的时候,会出现这样一种情况就是:在一个转折点或两个转折点路径的判断中它虽然没有满足所有的条件,但是却满足了其中的部分条件,这时plist中任然会将满足部分条件的那两张图片的下标给保存,下次绘制图片消除路径的时候就会造成出现其它多余的线。因此我们需要在sufa02 中return false的时候都清空plist。
在连连看中还有一点容易弄混的地方就是图片的下标与坐标的计算,在保证每张图片的高度和宽度都相同以及知道第一张图片的坐标的情况下,我们只需要知道图片的X轴坐标与图片在第几列有关,图片的Y轴坐标与图片在第几行有关。 同时知道了图片的下标或坐标我们就可以根据坐标算下标,根据下标[size=medium][/size][size=medium][/size]算坐标。
[/size]
1>首先要满足图片的个数是偶数,而且每张图片出现的个数是偶数。
2>消除图片的时候,消除图片的路径中不能再有其他的图片。
3>有三种路径方法选择:第一种是在同一行或同一列,第二种是可以有一个转折点,最后一种是可以有两个转折点。
4>只有当两者图片相同时才能消除
5>在消除图片的过程中把选中的图片给标记出来,并且画出消除相同图片所选择的路径。
满足了以上需求就可以做一个简单的连连看了
二,实现方法
1>满足第一个需求:首先我们需要写一个JFrame,在定义一个二维数组(int[rows][cols])(这里需要注意的是:我们必须保证rows*cols是一个偶数,这样才能保证我们的图片个数是偶数。) 用来存放连连看中的图片对象,将图片的宽度和高度设置成一个常量,使每个图片的宽度和高度都相同,这样可以方便之后计算图片的坐标。然后在JFrame中初始化这个二维数组 即往这个二维数组中放入图片,在往二维数组中放入图片的时候,我们需要另一一个容器作为一个中介在利用一个循环,循环rows*cols/2次每次往容器中加入2张一样的图片对象,接着在用两个for循环将容器中的图片取出再放入这个二维数组就完成了我们的第一个需求了。代码实现:
package LLK01;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MyFrame extends JFrame implements Constant {
Random ran=new Random();
List<ImageIcon> imagList=new ArrayList<ImageIcon>();
public void initUI() {
this.setTitle("连连看01");
this.setSize(600, 350);
putImage();
this.setResizable(false);
JPanel panel = new MyPanel();
panel.setBackground(Color.black);
this.add(panel);
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
this.setVisible(true);
MyListener listener = new MyListener();
panel.addMouseListener(listener);
}
public static void main(String[] args) {
new MyFrame().initUI();
}
public void putImage(){
for(int i=0;i<ROWS*COLS/2;i++){
int num=ran.nextInt(4);
String url="src/LLK01/imgs/"+num+".gif";
ImageIcon img=new ImageIcon(url);
// ImageIcon img2=new ImageIcon(url);
imagList.add(img);
imagList.add(img);
}
System.out.println(imagList.size());
for(int i=0;i<ROWS;i++){
for(int j=0;j<COLS;j++){
int index=ran.nextInt(imagList.size());
imgs[i][j]=imagList.remov(index);
}
}
}
class MyPanel extends JPanel {
@Override
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
ImageIcon img = imgs[i][j];
if (img != null)g.drawImage(img.getImage(), X0 + SIZE * j, Y0 + SIZE* i, null);
// System.out.println("huhu");
}
}
}
}
}
2>满足2.3.4.5需求:这里我们需要定义一个鼠标监听器 MouseAdapter,通过 mouseReleased(MouseEvent e) 事件来获得每次点击的图片对象。我们需要一个计数器int count=0 来记录我们点击的次数,每点击一次count++,当第二次点击的时候我们再把count=0;这样就可以保证我们每点两张图片就进行判断。判断图片是否相同,我们只需判断图片的路径是否一样。同时我们也需要获得每次点击的图片的下标,这对后面消除时路径的判断非常重要。当他们 下标相同时代表他们是同一张图片,这样是不能消除的。代码:package LLK01;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import com.sun.org.apache.bcel.internal.generic.GETSTATIC;
public class MyListener extends MouseAdapter implements Constant{
int count=0;
private ImageIcon icon1;
private ImageIcon icon2;
int i1,j1,i2,j2;
private JPanel panel;
private int sum=0;
private ArrayList<Point> plist;
@Override
public void mouseReleased(MouseEvent e) {
panel=(JPanel)e.getSource();
Graphics g=panel.getGraphics();
g.setColor(Color.red);
//获得鼠标点击的坐标
int x=e.getX();
int y=e.getY();
if(count==0){
sum=0;
//根据鼠标点击的坐标得到第一次点击的图片对象
icon1=getIcon(x, y);
//得到第一次点击的图片对象的下标
i1=(x-X0)/SIZE;//y
j1=(y-Y0)/SIZE;//x
System.out.println("huqian1");
//框住选中的图片对象
g.draw3DRect(X0+i1*SIZE, Y0+j1*SIZE, SIZE, SIZE, true);
count++;
sum++;
System.out.println("sum:"+sum+"第一次");
}else{
System.out.println(count);
plist=new ArrayList<Point>();
System.out.println("plist:"+plist.size());
//得到第二次点击时的图片对象
icon2=getIcon(x, y);
//得到第二次点击时的图片对象的下标
i2=(x-X0)/SIZE;
j2=(y-Y0)/SIZE;
//框住选中的图片对象
g.draw3DRect(X0+i2*SIZE, Y0+j2*SIZE, SIZE, SIZE, true);
System.out.println("huqian2");
sum++;
System.out.println("sum:"+sum);
count=0;
//
new MyThread(icon1,icon2,plist).start();
}
}
//或得鼠标点击处的的图片对象
public static ImageIcon getIcon(int x,int y){
for(int i=0;i<ROWS;i++){
for(int j=0;j<COLS;j++){
ImageIcon icon=imgs[i][j];
if((x-(X0+SIZE*j))<SIZE&&(y-(Y0+SIZE*i))<SIZE){
// System.out.println("huhu");
return icon;
}
}
}
return null;
}
class MyThread extends Thread{
ImageIcon icon1;
ImageIcon icon2;
List<Point> plist=new ArrayList<Point>();
private SunFa02 sunfa;
public MyThread(ImageIcon icon1,ImageIcon icon2,List<Point> plist){
this.icon1=icon1;
this.icon2=icon2;
this.plist=plist;
sunfa=new SunFa02(plist);
}
public void run(){
// while(islive){
if(sum==2){
//判断图片的路径是否一样,判断他们的下标是否一样
if(icon1!=null&&icon2!=null&&icon1.toString().equals(icon2.toString())&&(i1!=i2 || j1!=j2)){
//判断路径
if(sunfa.checkRow(j1, i1, j2, i2)|| sunfa.checkCol(j1, i1, j2, i2)|| sunfa.cheakTR(j1, i1, j2, i2)|| sunfa.cheakTR2(j1, i1, j2, i2) || sunfa.checkH(j1, i1, j2, i2) || sunfa.checkV(j1, i1, j2, i2)
){
//绘制图片消除时的路径
for(int i=0;i<plist.size();i+=2){
Point p1=plist.get(i);
Point p2=plist.get(i+1);
int p1x=X0+SIZE*p1.y+SIZE/2;
int p1y=Y0+SIZE*p1.x+SIZE/2;
int p2x=X0+SIZE*p2.y+SIZE/2;
int p2y=Y0+SIZE*p2.x+SIZE/2;
Graphics2D g2= (Graphics2D) panel.getGraphics();
g2.setColor(Color.red);
g2.setStroke(new BasicStroke(5));
g2.drawLine(p1x, p1y, p2x, p2y);
}
imgs[j1][i1]=null;
imgs[j2][i2]=null;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//刷新面板
if(panel!=null)
panel.repaint();
}else{
if(panel!=null)
panel.repaint();
}
}else{
//刷新面板
if(panel!=null)
panel.repaint();
}
}
}
}
}
//==================================================================================================================//
package LLK01;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
public class SunFa02 implements Constant{
List<Point> plist=new ArrayList<Point>();
public SunFa02(List<Point> plist){
this.plist=plist;
}
//判断同一行是否可以消除
public boolean checkRow(int r1,int c1,int r2,int c2){
if(r1==r2){
int maxcol=Math.max(c1,c2);
int mincol=Math.min(c1,c2);
for(int i=mincol+1;i<maxcol;i++){
//判断在同一行中选中的两张图片的中间是否还有其他的图片
if(!(imgs[r1][i]==null)){
return false;
}
}
//保存可以消除的两张图片的下标
plist.add(new Point(r1,c1));
plist.add(new Point(r2,c2));
return true;
}
return false;
}
//判断同一列是否可以消除
public boolean checkCol(int r1,int c1,int r2,int c2){
if(c1==c2){
int maxrow=Math.max(r1,r2);
int minrow=Math.min(r1,r2);
for(int i=minrow+1;i<maxrow;i++){
//判断在同一列中选中的两张图片的中间是否还有其他的图片
if(!(imgs[i][c1]==null)){
return false;
}
}
//保存可以消除的两张图片的下标
plist.add(new Point(r1,c1));
plist.add(new Point(r2,c2));
return true;
}
return false;
}
//判断有一个转折点的情况
public boolean cheakTR(int r1,int c1,int r2,int c2){
//判断转折点处是否有图片
if(!(imgs[r2][c1]==null)){
plist.clear();
return false;
}else{
if(checkCol(r1,c1,r2,c1) && checkRow(r2,c2,r2,c1)){
return true;
}
}
plist.clear();
return false;
}
//判断有一个转折点的情况
public boolean cheakTR2(int r1,int c1,int r2,int c2){
//判断转折点处是否有图片
if(!(imgs[r1][c2]==null)){
plist.clear();
return false;
}else{
if(checkCol(r2,c2,r1,c2) && checkRow(r1,c1,r1,c2)){
return true;
}
}
plist.clear();
return false;
}
//判断两个转折点的情况
public boolean checkH(int r1,int c1,int r2,int c2){
for(int i=0;i<ROWS;i++){
//判断两个转折点处是否有图片
if(imgs[i][c1]==null && imgs[i][c2]==null){
if(checkRow(i,c1,i,c2) && checkCol(r1,c1,i,c1)&& checkCol(r2,c2,i,c2))
{
return true;
}
}
}
plist.clear();
return false;
}
//判断两个转折点的情况
public boolean checkV(int r1,int c1,int r2,int c2){
for(int i=0;i<COLS;i++){
//判断两个转折点处是否有图片
if(imgs[r1][i]==null && imgs[r2][i]==null){
f(checkCol(r1,i,r2,i) && checkRow(r1,c1,r1,i)&& checkRow(r2,c2,r2,i)){
return true;
}
}
}
plist.clear();
return false;
}
}
在绘制图片消除路径的时候,会出现这样一种情况就是:在一个转折点或两个转折点路径的判断中它虽然没有满足所有的条件,但是却满足了其中的部分条件,这时plist中任然会将满足部分条件的那两张图片的下标给保存,下次绘制图片消除路径的时候就会造成出现其它多余的线。因此我们需要在sufa02 中return false的时候都清空plist。
在连连看中还有一点容易弄混的地方就是图片的下标与坐标的计算,在保证每张图片的高度和宽度都相同以及知道第一张图片的坐标的情况下,我们只需要知道图片的X轴坐标与图片在第几列有关,图片的Y轴坐标与图片在第几行有关。 同时知道了图片的下标或坐标我们就可以根据坐标算下标,根据下标[size=medium][/size][size=medium][/size]算坐标。
[/size]