先给大家看看效果图片
第一张游戏开始界面
第二战是游戏进入界面
第三张是游戏结束界面
连连看实现难点:
1.因为连连看每次要点击两张图片进行删除,所以随机生成的图片是要成双的出现在界面
实现代码如下
public void suiji() {
int x1;
int x2;
int y1;
int y2;
for (int i = 0; i < shuzu.length; i++) {
for (int j = 0; j < shuzu[i].length; j++) {
shuzu[i][j] = 0;
}
}
Random rand = new Random();
for (int i = 0; i < shuzu.length * shuzu[0].length / 2; i++) {
int type = rand.nextInt(10) + 1;// 值是1,2,...,10 数组1-10对应图片0-9
do {
x1 = (int) ((12 * Math.random()));// x1范围是0,1,2,。。。12
y1 = (int) ((10 * Math.random()));// y1范围是0,10
} while (shuzu[x1][y1] != 0);
shuzu[x1][y1] = type;
do {
x2 = (int) ((12 * Math.random()));
y2 = (int) ((10 * Math.random()));
} while (shuzu[x2][y2] != 0);
shuzu[x2][y2] = type;
}
}
2.对二维数组随机生成以后,二维数组中的每个数字代表一个图片。然后就可以将图片插入,实现每次打开界面都会是新的连连看界面。生成图片的代码要写进重绘里面,不然会导致图片无故刷新。随机数组的代码不能写进重绘,因为不能当把界面拉一下,就会让界面刷新。
因为是12x10的图片放置,所以本人首先画了一个13x11条线的棋盘辅助,后面实现功能后,将棋盘重绘代码注释,初学者可以借用棋盘辅助线。
重绘代码如下:
public void paint(Graphics g) {
super.paint(g);
ImageIcon image = new ImageIcon(getClass().getResource("A梦.png"));
int width = getWidth();// 获取图片组件宽
int height = getHeight();
g.drawImage(image.getImage(), 0, 0, width , height, this);
Font font = new Font("黑体", Font.BOLD, 135);// 创建体字
g.setFont(font);// 使用字体
g.setColor(Color.WHITE);// 使用白色
/*
* // 重绘棋盘 for (int i = 0; i < Cow; i++) { g.drawLine(leftX + SIZE * i, leftY,
* leftX + SIZE * i, leftY + SIZE * (Lum - 1));// 竖线 g.drawLine(leftX, leftY +
* SIZE * i, leftX + SIZE * (Cow - 1), leftY + SIZE * i);// 横线 }
*/
// int[][] shuzu = new int[12][10];//二维数组用来表示12*10地图
Image[] imagArr = new Image[10];
for (int i = 0; i < imagArr.length; i++) {
imagArr[i] = new ImageIcon("C:\\Users\\TANGNAN\\Desktop\\连连看\\ameng\\" + i + ".png").getImage();
}
System.out.println(shuzu[1][1] + "png");
for (int i = 0; i < shuzu.length; i++) {
for (int j = 0; j < shuzu[i].length; j++) {
if (0 < shuzu[i][j]) {
g.drawImage(imagArr[shuzu[i][j] - 1], leftX + i * 80, leftY + j * 80, 80, 80, this);
}
}
}
}
3.整个连连看界面实现后,就是实现连连看的规则。连连看里面最多只能设置两个拐角的线条才能消除方块。所以现在要写四个方法,分别实现连连看的水平连接,竖直连接,单拐点连接,双拐点连接,以及还有一个最边缘的两个相同方块的边缘连接。其中单拐点连接和双拐点连接较难,水平垂直边缘连接比较基础。
代码如下:
水平连接
水平连接代码,用的拼音还见谅
public boolean shuipingLink(int clickX1, int clickY1, int clickX2, int clickY2) {
//水平连接
if(clickX1>clickX2){//保证x2>x1
int temp1 = clickX1;
int temp2 = clickY1;
clickX1 = clickX2;
clickY1 = clickY2;
clickX2 = temp1;
clickY2 = temp2;
}
if(clickY1==clickY2){//如果两个选中图片的所在列数相同,说明可以水平相联
for(int i=clickX1+1;i<clickX2;i++){
if(shuzu[i][clickY1]!=0){//如果两图片中间还有其他图片,说明不能水平相连
return false;
}
}
linkMethod=shuipingLink;
return true;
}
return false;
}
垂直连接
public boolean chuizhiLink(int clickX1,int clickY1,int clickX2,int clickY2) {
//垂直连接
if(clickY1>clickY2) {//保证Y2>Y1
int temp1 = clickX1;
int temp2 = clickY1;
clickX1=clickX2;
clickY1=clickY2;
clickX2=temp1;
clickY2=temp2;
}
if(clickX1==clickX2) {//两个图片列数相同,可以垂直相连
for(int i=clickY1+1;i<clickY2;i++) {
if(shuzu[clickX1][i]!=0) {
return false;
}
}
linkMethod=chuizhiLink;
return true;
}
return false;
}
边缘连接实现
public boolean edgeLink(int clickX1,int clickY1,int clickX2,int clickY2) {
if(clickY1==0&&clickY2==0&&shuzu[clickX1][clickY1]==shuzu[clickX2][clickY2]) {//在最上边边缘查找
return true;
}else if(clickX1==0&&clickX2==0&&shuzu[clickX1][clickY1]==shuzu[clickX2][clickY2]) {//左边边缘查找
return true;
}
else if(clickY1==9&&clickY2==9&&shuzu[clickX1][clickY1]==shuzu[clickX2][clickY2]) {//最下边边缘查找
return true;
}else if(clickX1==11&&clickX2==11&&shuzu[clickX1][clickY1]==shuzu[clickX2][clickY2]) {//在右边查找
return true;
}
return false;
}
单拐点连接实现
public boolean oneLink(int clickX1,int clickY1,int clickX2,int clickY2) {
//有一个拐点的连接
if(clickY1>clickY2) {//保证Y2>Y1
int temp1 = clickX1;
int temp2 = clickY1;
clickX1=clickX2;
clickY1=clickY2;
clickX2=temp1;
clickY2=temp2;
}
if(clickX1<clickX2){
//判断左下角是否为空并且可以直接与(x1,y1)和(x2,y2)相连接,(clickX1, clickY2)是右上角拐点下标
if(shuzu[clickX1][clickY2]==0&&shuipingLink(clickX2, clickY2, clickX1, clickY2)&&chuizhiLink(clickX1,clickY1,clickX1,clickY2)){
linkMethod=oneLink;
z1=new Node(clickX1,clickY2);
return true;
}
if(shuzu[clickX2][clickY1]==0&&shuipingLink(clickX2, clickY1, clickX1, clickY1)&&chuizhiLink(clickX2,clickY2,clickX2, clickY1)){
linkMethod=oneLink;
z1=new Node(clickX2,clickY1);
return true;
}
}else{
if(shuzu[clickX2][clickY1]==0&&shuipingLink(clickX1, clickY1, clickX2, clickY1)&&chuizhiLink(clickX2,clickY2,clickX2, clickY1)){
linkMethod=oneLink;
z1=new Node(clickX2,clickY1);
return true;
}
if(shuzu[clickX1][clickY2]==0&&shuipingLink(clickX1, clickY2, clickX2, clickY2)&&chuizhiLink(clickX1,clickY2,clickX1, clickY1)){
linkMethod=oneLink;
z1=new Node(clickX1,clickY2);
return true;
}
}
return false;
}
双拐点连接实现
public boolean twoLink(int clickX1,int clickY1,int clickX2,int clickY2) {
//向上查找
for(int i=clickY1-1;i>=0;i--) {
//两个拐点在选中图案的上侧
if(i>=0&&shuzu[clickX1][i]==0) {
if(oneLink(clickX1,i,clickX2,clickY2)) {
z1=new Node(clickX1,i);
z2=new Node(clickX2,i);
linkMethod=twoLink;
return true;
}
}
else {
break;
}
}
//向下查找
for(int i=clickY1+1;i<=10;i++) {
//两个拐点在选中图案的下侧
if(i!=10&&shuzu[clickX1][i]==0) {
if(oneLink(clickX1,i,clickX2,clickY2)) {
z1=new Node(clickX1,i);
z2=new Node(clickX2,i);
linkMethod=twoLink;
return true;
}
}
else {
break;
}
}
//向左查找
for(int i=clickX1-1;i>=0;i--) {
//两个拐点在选中图片左侧
if(i!=-1&&shuzu[i][clickY1]==0) {
if(oneLink(i,clickY1,clickX2,clickY2)) {
z1=new Node(i,clickY1);
z2=new Node(i,clickY2);
linkMethod=twoLink;
return true;
}
}
else {
break;
}
}
//向右查找
for(int i=clickX1+1;i<=12;i++) {
//两个拐点在右边
if(i!=12&&shuzu[i][clickY1]==0) {
if(oneLink(i,clickY1,clickX1,clickY2)) {
z1=new Node(i,clickY1);
z2=new Node(i,clickY2);
linkMethod=twoLink;
return true;
}
}
else {
break;
}
}
return false;
}
对选中方块画线连接实现
在连连看里面每次,每次选中方块后,应该在方块画一个选中框,并且在第二个选中的方块之间,画一根线进行连接。其中画线条也是分为水平画线,垂直画线,单拐画线,双拐画线。边缘画线和水平画线难度一样简单,在代码里面没有进行赘述。
private void drawLink(int x1, int y1, int x2, int y2) {
//Graphics g = this.getGraphics();
Point p1 = new Point(x1*80+leftX+40,y1*80+leftY+40);
Point p2 = new Point(x2*80+leftX+40,y2*80+leftY+40);
if(linkMethod == shuipingLink || linkMethod == chuizhiLink){
g.drawLine(p1.x, p1.y,p2.x, p2.y);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("无拐点画线");
//System.out.println("g="+g);
}else if(linkMethod ==oneLink){
Point point_z1 = new Point(z1.x*80+leftX+40,z1.y*80+leftY+40);//将拐点转换成像素坐标
g.drawLine(p1.x, p1.y,point_z1.x, point_z1.y);
g.drawLine(p2.x, p2.y,point_z1.x, point_z1.y);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("单拐点画线");
//System.out.println("g="+g);
}else{
Point point_z1 = new Point(z1.x*80+leftX+40,z1.y*80+leftY+40);
Point point_z2 = new Point(z2.x*80+leftX+40,z2.y*80+leftY+40);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(p1.x!=point_z1.x&&p1.y!=point_z1.y){//保证(x1,y1)与拐点z1在同一列或者同一行
Point temp;
temp = point_z1;
point_z1 = point_z2;
point_z2 = temp;
}
g.drawLine(p1.x, p1.y, point_z1.x, point_z1.y);
g.drawLine(p2.x, p2.y, point_z2.x, point_z2.y);
g.drawLine(point_z1.x,point_z1.y, point_z2.x, point_z2.y);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("双拐点画线");
}
shuzu[x1][y1] = 0;
shuzu[x2][y2] = 0;
}
提示框功能
然后接下来是提示框功能,如果你已经实现了我前面提到的连接与画线,那么提示功能就十分简单,只要调用前面的方法了。博主在游戏中设置了每局只能提示一次。点击重新开始便可以刷新次数。点击刷新并不能够刷新提示次数。对整个数组进行遍历,查找还没有找到的可以进行连接的方块。
public void find2Block() {
for(int i=0;i<12;i++){
for(int j=0;j<10;j++){
if(shuzu[i][j]==0){
continue;
}
for(int p=i;p<12;p++){
for(int q=0;q<10;q++){
if(shuzu[p][q]!=shuzu[i][j]||(p==i&&q==j)){//如果图案不相等
continue;
}
if((chuizhiLink(p,q,i,j)||shuipingLink(p,q,i,j)||oneLink(p,q,i,j)||twoLink(p,q,i,j))&&tishi==1){
g.setColor(Color.green);
g.drawRect(i*80+leftX, j*80+leftY,80,80);
g.drawRect(p*80+leftX, q*80+leftY,80,80);
drawLink(p, q, i, j);
return;
// repaint();
}
}
}
}
}
}
移动方块功能
因为只有单个连连看的功能的话,玩法比较单调,博主给出了实现将全体方块实现移动一格(前提是将要移动的地方是空白格)的方法,和全体方块整体全部移动到最边缘的方法(不限格数)。在实现这两类移动方法后,便可以把连连看改为消消乐等玩法更高的游戏或者可以为连连看实现难度增加(比如每次消除方块后,剩下的方块就整体往左边移动等等),这样的话玩法就大大增加。因为我在移动方法中,进行两次for循环遍历数组进行查找要移动的方块,如果要实现自动移动,去掉遍历加在监听器即可。下面示例左移和全员左移的代码。其他的差不多照着这个写,博主就不贴了,特别注意,比如如果要实现右移,按照我的代码,需要从数组末尾,也就是右边开始进行循环,不然达不到预期效果。
public void leftMove(int[][] shuzu){
for (int i = 0; i < shuzu.length; i++) {
for (int j = 0; j < shuzu[i].length; j++) {
if(shuzu[i][j]!=0){
//向左边查找
for(int n=i-1;n>=0;n--) {
if(shuzu[n][j]==0) {
int temp;
temp=shuzu[n][j];
shuzu[n][j]=shuzu[i][j];
shuzu[i][j]=temp;
}
}
}
}
}
}
//全部左移
public void AllLeft(int[][] shuzu) {
int jishu=0;
for(int i =0;i<shuzu.length;i++) {
for(int j=0;j<shuzu[i].length;j++) {
if(shuzu[i][j]!=0){
//向左边查找
for(int n=i-1;n>=0;n--) {
if(shuzu[n][j]==0) {
jishu++;
}
}
int temp;
temp = shuzu[i][j];
shuzu[i][j]=shuzu[i-jishu][j];
shuzu[i-jishu][j]=temp;
jishu=0;
}
}
}
}
刷新功能
刷新功能就是对剩下的方块进行洗牌的过程。
代码如下:
public void refresh(int[][] shuzu){
for (int i = 0; i < shuzu.length; i++) {
for (int j = 0; j < shuzu[i].length; j++) {
if(shuzu[i][j]!=0){
//向左边查找
for(int n=i-1;n>=0;n--) {
do {
int temp;
temp=shuzu[n][j];
shuzu[n][j]=shuzu[i][j];
shuzu[i][j]=temp;
}while(shuzu[i][j]==0);
}
}
}
}
}
音乐
需要加音乐的话,需要把音乐设置为WAV格式,博主用的qq音乐(新版)实现mp3转WAV。大家可以自己百度一下,很多音乐软件自带转换格式功能。把转换好的WAV格式文件直接复制粘贴到连连看的项目工程文件下即可调用。
但是有时候玩着玩着会自动音乐停掉,我也找不到原因。但是刚刚进去的时候,音乐是有播放的,而且如果不进行操作的话,音乐也会一直唱,暂时没找到原因。
代码如下
import java.applet.AudioClip;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JApplet;
public class Playmusic {
public static AudioClip loadSound(String filename) {
URL url = null;
try {
url = new URL("file:" + filename);
}
catch (MalformedURLException e) {;}
return JApplet.newAudioClip(url);
}
public void play() {
AudioClip christmas = loadSound("llk.wav");
christmas.loop();
}
}
好了,到了这里,连连看的基本功能及加强功能就已经基本实现了。监听器部分的代码我就没有贴了。博主本人是底层一个JFrame,然后边框布局,中间一个JPanel放连连看界面,右边一个JPanel用流式布局放按钮。界面稍微有点丑,大嘎可以自己发挥创意。