Java 连连看 小游戏实现:
连连看小游戏曾经在我们的童年给我们带来了很多乐趣。连连看这款游戏现在基本上没人玩了,甚至在新一代人的印象中都已毫无记忆了。。。但是,这款游戏可以在一定程度上锻炼自己的编程能力。
运行效果如图:
游戏面板实现:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements ActionListener ,MouseListener,KeyListener{
private Image[] pics;// 图片数组
private int n;// 行列数
private int[][] map;// 存储地图信息
private int leftX = 140,leftY = 80;//row,column 表示人物坐标; leftX,leftY 记载左上角图片位置
private boolean isClick = false;// 标记是否第一次选中图片
private int clickId,clickX,clickY;// 记录首次选中图片的 id, 以及数组下标
private int linkMethod;// 连接方式
private Node z1,z2;// 存储拐角点的信息
private Map mapUtil;// 地图工具类
public static int count = 0;// 存储消去图案的个数
public static final int LINKBYHORIZONTAL = 1,LINKBYVERTICAL = 2,LINKBYONECORNER = 3,LINKBYTWOCORNER = 4;
public static final int BLANK_STATE = -1;
public GamePanel(int count){
setSize(600, 600);
n = 10;
mapUtil = new Map(count, n);
map = mapUtil.getMap();// 获取初始时,图片种类为 count, 行列数为 n 的地图信息
this.setVisible(true);
this.addKeyListener(this);
this.addMouseListener(this);
this.setFocusable(true);
getPics();
repaint();
}
// 初始化图片数组
private void getPics() {
pics = new Image[10];
for(int i=0;i<=9;i++){
pics[i] = Toolkit.getDefaultToolkit ().getImage(".\\lianliankan\\src\\main\\java\\com\\llk\\util\\linkGame\\pic"+(i+1)+".png");
}
}
public void paint(Graphics g){
g.clearRect(0, 0, 800, 30);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(map[i][j]!=BLANK_STATE ){
g.drawImage(pics[map[i][j]],leftX+j*50,leftY+i*50,50,50,this);
}else{
g.clearRect(leftX+j*50,leftY+i*50,50,50);
}
}
}
}
// 判断是否可以水平相连
private boolean horizontalLink(int clickX1, int clickY1, int clickX2, int clickY2) {
if(clickY1>clickY2){// 保证 y1<y2
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(map[clickX1][i]!=BLANK_STATE ){// 如果两图片中间还有其他图片,说明不能直接水平相连
return false;
}
}
//System.out.println(" 我们俩水平相连,我的下标是( "+clickX1+","+clickY1+"), 它的坐标是 ("+clickX2+","+clickY2+")");
linkMethod = LINKBYHORIZONTAL ;
return true;
}
return false;
}
// 判断是否可以垂直连接
private boolean verticalLink(int clickX1, int clickY1, int clickX2, int clickY2) {
if(clickX1>clickX2){// 保证 x1<x2
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(map[i][clickY1]!=BLANK_STATE ){// 如果两图片中间还有其他图片,说明不能直接垂直相连
return false;
}
}
linkMethod = LINKBYVERTICAL ;
//System.out.println(" 我们俩垂直相连,我的下标是( "+clickX1+","+clickY1+"), 它的坐标是 ("+clickX2+","+clickY2+")");
return true;
}
return false;
}
// 判断是否可以通过一个拐点相连
private boolean oneCornerLink(int clickX1, int clickY1, int clickX2, int clickY2) {
if(clickY1>clickY2){// 保证 (x1,y1) 是矩形的左上角或者左下角
int temp1 = clickX1;
int temp2 = clickY1;
clickX1 = clickX2;
clickY1 = clickY2;
clickX2 = temp1;
clickY2 = temp2;
}
if(clickX1<clickX2){// 如果 (x1,y1) 位于矩形左上角
// 判断右上角是否为空并且可以直接与 (x1,y1) 和 (x2,y2) 相连接 ,(clickX1, clickY2) 是右上角拐点下标
if(map[clickX1][clickY2]==BLANK_STATE &&horizontalLink(clickX1, clickY1, clickX1, clickY2)&&verticalLink(clickX2,clickY2,clickX1,clickY2)){
linkMethod = LINKBYONECORNER ;
z1 = new Node(clickX1,clickY2);
return true;
}
// 判断左下角是否为空并且可以直接与 (x1,y1) 和 (x2,y2) 相连接 ,(clickX2, clickY1) 是左下角拐点下标
if(map[clickX2][clickY1]==BLANK_STATE &&horizontalLink(clickX2, clickY2, clickX2, clickY1)&&verticalLink(clickX1,clickY1,clickX2, clickY1)){
linkMethod = LINKBYONECORNER ;
z1 = new Node(clickX2,clickY1);
return true;
}
}else{// 如果 (x1,y1) 位于矩形左下角
// 判断左上角是否为空并且可以直接与 (x1,y1) 和 (x2,y2) 相连接 ,(clickX2, clickY1) 是左上角拐点下标
if(map[clickX2][clickY1]==BLANK_STATE &&horizontalLink(clickX2, clickY2, clickX2, clickY1)&&verticalLink(clickX1,clickY1,clickX2, clickY1)){
linkMethod = LINKBYONECORNER ;
z1 = new Node(clickX2,clickY1);
return true;
}
// 判断右下角是否为空并且可以直接与 (x1,y1) 和 (x2,y2) 相连接 ,(clickX1, clickY2) 是右下角拐点下标
if(map[clickX1][clickY2]==BLANK_STATE &&horizontalLink(clickX1, clickY1, clickX1, clickY2)&&verticalLink(clickX2,clickY2,clickX1, clickY2)){
linkMethod = LINKBYONECORNER ;
z1 = new Node(clickX1,clickY2);
return true;
}
}
return false;
}
// 判断是否可以通过两个拐点相连
private boolean twoCornerLink(int clickX1, int clickY1, int clickX2, int clickY2) {
// 向上查找
for(int i=clickX1-1;i>=-1;i--){
// 两个拐点在选中图案的上侧,并且两个拐点在地图区域之外
if(i==-1&&throughVerticalLink(clickX2, clickY2, true)){
z1 = new Node(-1,clickY1);
z2 = new Node(-1,clickY2);
linkMethod = LINKBYTWOCORNER ;
return true;
}
if(i>=0&&map[i][clickY1]==BLANK_STATE ){
if(oneCornerLink(i, clickY1, clickX2, clickY2)){
linkMethod = LINKBYTWOCORNER ;
z1 = new Node(i,clickY1);
z2 = new Node(i,clickY2);
return true;
}
}else{
break;
}
}
// 向下查找
for(int i=clickX1+1;i<=n;i++){
// 两个拐点在选中图案的下侧,并且两个拐点在地图区域之外
if(i==n&&throughVerticalLink(clickX2, clickY2, false)){
z1 = new Node(n,clickY1);
z2 = new Node(n,clickY2);
linkMethod = LINKBYTWOCORNER ;
return true;
}
if(i!=n&&map[i][clickY1]==BLANK_STATE ){
if(oneCornerLink(i, clickY1, clickX2, clickY2)){
linkMethod = LINKBYTWOCORNER ;
z1 = new Node(i,clickY1);
z2 = new Node(i,clickY2);
return true;
}
}else{
break;
}
}
// 向左查找
for(int i=clickY1-1;i>=-1;i--){
// 两个拐点在选中图案的左侧,并且两个拐点在地图区域之外
if(i==-1&&throughHorizontalLink(clickX2, clickY2, true)){
linkMethod = LINKBYTWOCORNER ;
z1 = new Node(clickX1,-1);
z2 = new Node(clickX2,-1);
return true;
}
if(i!=-1&&map[clickX1][i]==BLANK_STATE ){
if(oneCornerLink(clickX1, i, clickX2, clickY2)){
linkMethod = LINKBYTWOCORNER ;
z1 = new Node(clickX1,i);
z2 = new Node(clickX2,i);
return true;
}
}else{
break;
}
}
// 向右查找
for(int i=clickY1+1;i<=n;i++){
// 两个拐点在选中图案的右侧,并且两个拐点在地图区域之外
if(i==n&&throughHorizontalLink(clickX2, clickY2, false)){
z1 = new Node(clickX1,n);
z2 = new Node(clickX2,n);
linkMethod = LINKBYTWOCORNER ;
return true;
}
if(i!=n&&map[clickX1][i]==BLANK_STATE ){
if(oneCornerLink(clickX1, i, clickX2, clickY2)){
linkMethod = LINKBYTWOCORNER ;
z1 = new Node(clickX1,i);
z2 = new Node(clickX2,i);
return true;
}
}else{
break;
}
}
return false;
}
// 根据 flag, 判断 (x1,y1) 左右两侧中的一侧是否还有其他图片,如果没有,可以相连
private boolean throughHorizontalLink(int clickX, int clickY,boolean flag){
if(flag){// 向左查找
for(int i=clickY-1;i>=0;i--){
if(map[clickX][i]!=BLANK_STATE ){
return false;
}
}
}else{// 向右查找
for(int i=clickY+1;i<n;i++){
if(map[clickX][i]!=BLANK_STATE ){
return false;
}
}
}
return true;
}
// 根据 flag, 判断 (x1,y1) 上下两侧中的一侧是否还有其他图片,如果没有,可以相连
private boolean throughVerticalLink(int clickX,int clickY,boolean flag){
if(flag){// 向上查找
for(int i=clickX-1;i>=0;i--){
if(map[i][clickY]!=BLANK_STATE ){
return false;
}
}
}else{// 向下查找
for(int i=clickX+1;i<n;i++){
if(map[i][clickY]!=BLANK_STATE ){
return false;
}
}
}
return true;
}
// 画选中框
private void drawSelectedBlock(int x, int y, Graphics g) {
Graphics2D g2 = (Graphics2D) g;// 生成 Graphics 对象
BasicStroke s = new BasicStroke(1);// 宽度为 1 的画笔
g2.setStroke(s);
g2.setColor(Color.RED );
g.drawRect(x+1, y+1, 48, 48);
}
// 画线,此处的 x1,y1,x2,y2 二维数组下标
@SuppressWarnings("static-access")
private void drawLink(int x1, int y1, int x2, int y2) {
Graphics g = this.getGraphics();
Point p1 = new Point(y1*50+leftX+25,x1*50+leftY+25);
Point p2 = new Point(y2*50+leftX+25,x2*50+leftY+25);
if(linkMethod == LINKBYHORIZONTAL || linkMethod == LINKBYVERTICAL ){
g.drawLine(p1.x, p1.y,p2.x, p2.y);
System.out .println("无拐点画线");
}else if(linkMethod ==LINKBYONECORNER ){
Point point_z1 = new Point(z1.y*50+leftX+25,z1.x*50+leftY+25);// 将拐点转换成像素坐标
g.drawLine(p1.x, p1.y,point_z1.x, point_z1.y);
g.drawLine(p2.x, p2.y,point_z1.x, point_z1.y);
System.out .println("单拐点画线");
}else{
Point point_z1 = new Point(z1.y*50+leftX+25,z1.x*50+leftY+25);
Point point_z2 = new Point(z2.y*50+leftX+25,z2.x*50+leftY+25);
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);
System.out .println("双拐点画线");
}
count +=2;// 消去的方块数目 +2
GameClient.textField .setText(count +"");
try {
Thread.currentThread ().sleep (500);// 延时 500ms
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
repaint();
map[x1][y1] = BLANK_STATE ;
map[x2][y2] = BLANK_STATE ;
isWin();// 判断游戏是否结束
}
public void clearSelectBlock(int i,int j,Graphics g){
g.clearRect(j*50+leftX, i*50+leftY, 50, 50);
g.drawImage(pics[map[i][j]],leftX+j*50,leftY+i*50,50,50,this);
// System.out.println(" 清空选定 "+i+","+j);
}
// 提示,如果有可以连接的方块就消去并且返回 true
private boolean find2Block() {
// boolean isFound = false;
if(isClick){// 如果之前玩家选中了一个方块,清空该选中框
clearSelectBlock(clickX, clickY, this.getGraphics());
isClick = false;
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(map[i][j]==BLANK_STATE ){
continue;
}
for(int p=i;p<n;p++){
for(int q=0;q<n;q++){
if(map[p][q]!=map[i][j]||(p==i&&q==j)){// 如果图案不相等
continue;
}
if(verticalLink(p,q,i,j)||horizontalLink(p,q,i,j)
||oneCornerLink(p,q,i,j)||twoCornerLink(p,q,i,j)){
drawSelectedBlock(j*50+leftX, i*50+leftY, this.getGraphics());
drawSelectedBlock(q*50+leftX, p*50+leftY, this.getGraphics());
drawLink(p, q, i, j);
repaint();
return true;
}
}
}
}
}
isWin();
return false;
}
private void isWin() {
if(count ==n*n){
String msg = "恭喜您通关成功,是否开始新局?";
int type = JOptionPane.YES_NO_OPTION ;
String title = "过关";
int choice = 0;
choice = JOptionPane.showConfirmDialog (null, msg,title,type);
if(choice==1){
System.exit (0);
}else if(choice == 0){
startNewGame();
}
}
}
public void startNewGame() {
// TODO Auto-generated method stub
count = 0;
mapUtil = new Map(10,n);
map = mapUtil.getMap();
isClick = false;
clickId = -1;
clickX = -1;
clickY = -1;
linkMethod = -1;
GameClient.textField .setText(count +"");
repaint();
}
public class Node{
int x;
int y;
public Node(int x,int y){
this.x = x;
this.y = y;
}
}
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if(e.getKeyCode() == KeyEvent.VK_A ){// 打乱地图
map = mapUtil.getResetMap();
repaint();
}
if(e.getKeyCode() == KeyEvent.VK_D ){// 智能提示
if(!find2Block()){
JOptionPane.showMessageDialog (this, "没有可以连通的方块了");
}
isWin();// 判断是否游戏结束
}
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
Graphics g = this.getGraphics();
int x = e.getX()-leftX;// 点击位置 x- 偏移量 x
int y = e.getY()-leftY;// 点击位置 y- 偏移量 y
int i = y/50;// 对应数组行数 , 根据像素坐标转换成数组下标坐标
int j = x/50;// 对应数组列数
if(x<0||y<0)// 超出地图范围
return ;
if(isClick){// 第二次点击
if(map[i][j]!=BLANK_STATE ){
if(map[i][j]==clickId){// 点击的是相同图片 Id, 但不是重复点击同一图片
if(i==clickX&&j==clickY)
return ;
if(verticalLink(clickX,clickY,i,j)||horizontalLink(clickX,clickY,i,j)||oneCornerLink(clickX,clickY,i,j)||twoCornerLink(clickX,clickY,i,j)){// 如果可以连通,画线连接,然后消去选中图片并重置第一次选中标识
drawSelectedBlock(j*50+leftX,i*50+leftY,g);
drawLink(clickX,clickY,i,j);// 画线连接
isClick = false;
}else{
clickId = map[i][j];// 重新选中图片并画框
clearSelectBlock(clickX,clickY,g);
clickX = i;
clickY = j;
drawSelectedBlock(j*50+leftX,i*50+leftY,g);
}
}else{
clickId = map[i][j];// 重新选中图片并画框
clearSelectBlock(clickX,clickY,g);
clickX = i;
clickY = j;
drawSelectedBlock(j*50+leftX,i*50+leftY,g);
}
}
}else{// 第一次点击
if(map[i][j]!=BLANK_STATE ){
// 选中图片并画框
clickId = map[i][j];
isClick = true;
clickX = i;
clickY = j;
drawSelectedBlock(j*50+leftX,i*50+leftY,g);
}
}
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
此篇文章仅为部分代码!
完整素材及全部代码
代码已上传csdn,0积分下载,觉得这片博文有用请留下你的点赞。