连连看课程设计

发布时间:


第一章 引言
1.背景
游戏连连看顾名思义就是找出相关联的东西,这个连连看在网上基本是用在小游戏中,就是找出相同的两样东西,在一定的规则之内可以做为相关联处理。连连看的发展经历了从桌面游戏、在线游戏、社交游戏三个过程。
游戏连连看是源自台湾的桌面小游戏,自从流入大陆以来风靡一时,也吸引众多程序员开发出多种版本的连连看。这其中,顾方编写的阿达连连看其精良的制作广受好评,这也成为顾方阿达系列软件的核心产品。并于2004年,取得了国家版权局的计算机软件著作权登记证书。
随着Flash应用的流行,网上出现了多种在线Flash版本连连看。如水晶连连看果蔬连连看等,流行的水晶连连看以华丽界面吸引了一大批的女性玩家。
2008年,随着社交网络的普及和开放平台的兴起,连连看被引入了社交网络。连连看与个人空间相结合,被快速的传播,成为一款热门的社交游戏,其中以开发者JoneveyManyou开放平台上推出的宠物连连看最为流行。
网络小游戏、网页游戏越来越受网民欢迎,除了玩的方法简单外(不像其他游戏还需要注册下载繁琐过程),很多游戏不乏经典。连连看游戏就是典型。
不管走到哪个网页游戏网站,连连看游戏总是排在受玩家欢迎排名的前5位,休闲、趣味、益智是连连看玩不厌的精华,且不分男女老少、工薪白领,是一款适合大众的经典网络、单机休闲小游戏。
游戏《连连看》,只要将相同的两张牌用三根以内的直线连在一起就可以消除,规则简单容易上手。游戏速度节奏快,画面清晰可爱,适合细心的玩家。丰富的道具和公共模式的加入,增强游戏的竞争性。多样式的地图,使玩家在各个游戏水平都可以寻找到挑战的目标,长期地保持游戏的新鲜感。
该游戏由30张不同的图片组成,游戏开始将会出现30张随机组合的图片,在规则下点击两张相同的图片后图片将会消失。图片全部消完为游戏成功。游戏还将设置退出,再来一局的按钮,并实现该功能,方便用户进行操作。
1.1课程设计内容
1)游戏计分功能
当消去两个相同的图片后分数将增加100分。
1



2)退出功能
该功能有一个“退出”按钮,当按下“退出”按钮后,将直接退出游戏。 3)成功完成任务时显示的
该功能有,恭喜成功,一个“再来一局”的按钮,当按下“再来一局”按钮后,图片将会重新排列,重新开始游戏。 4)游戏倒计时功能
在游戏界面的上方有一个倒计时的进度条,增加游戏的难度,激发玩家的挑战兴趣。



2

第二章 系统介绍
1.连连看游戏规则
1.1游戏基本规则
用鼠标左键点击方块,2个图案相同的方块用连线连接起来,连接线不多3根直线,连接后方块就会消失。在规定的时间内将30张图片全部消除。
1.2操作规则
选择一个图片用鼠标左键点击,图片会变色,然后点击另一个同样图片,果能够连线就成功消失,如果不能连线,第一次选择的图片就会失效,然后将继续寻找符合规则的图片。

1.3胜利和失败
把所有的图片成功消除完毕,则认为是本次游戏成功。
选择图片时间是有限的,在规定的时间内,若未能将图片全部消除,则失败,提醒是否再来一局。
2.游戏流程图分析
流程图分析如下图2.1所示:

3



开始
鼠标点击位置的确定
判断是否点击在图片方块

判断是否已选定一个方块

选定第一个方块 选定第二个方块
判断是否可以抵消方块

抵消方块
消除选定方块的记录
结束

2.1游戏流程图
此次设计所使用的语言为Java。主要应用到Swing组件,Java小程序,事4


件及接口等。这些接口为游戏的制作提供了便捷的条件,本系统的主要特点就是运用Swing组件和事件处理技术,进行界面的绘制,鼠标的操作,以及积分的显示等功能。
这次通过连连看的设计开发将对理解Swing组件技术以及事件处理技术在游戏方面的应用起到很大的帮助作用,同时为掌握Java编程技术及二维休闲游戏设计的一般方法打下坚实的基础。
游戏程序设计一般都采用面向对象的设计模式,提供了一个简单的图像显示接口,利用多文档视图结构的面向对象设计模式。


5



第三章 系统游戏设计
1.系统分析
1.1游戏系统需求分析
主要设计目标:
使用GUI设计连连看,载入图片信息,进行正确分析系统的功能,总载入30张图片,且图片信息成对出现,且可以偶数项删除,并具有计时等功能游戏中将有“退出”功能,选择退出命令后程序将终止执行,关闭窗口。
还将有“再来一局”功能,选择再来一局命令后程序将对图片重新排列,重新开始游戏。该游戏还有一个时间倒计时的进度条,提醒玩家剩余的时间,增加游戏的难度。在界面的顶部有计分功能,当玩家消去图片后就会赢得相应的分数。
1.2系统开发及运行环境
硬件平台:
本游戏对硬件要求较低,基本都可以正常运行。 软件平台:
操作系统:Windows系列。 开发工具包:JDK Version1.6.2
1.3系统功能主要要求
1.系统采用图片连连看方式.界面美观,用户使用灵活,方便快捷. 2.计分自动完成,提高工作效率。 3.用进度条进行游戏界面的计时功能。
4.可方便快捷地进行下一盘游戏,并且两盘的分数在规定的时间内会叠加起来。

5.操作员可以随时退出游戏。
6.对用户输入的信息,系统进行严格的信息检验,尽可能排除人为的错误。 7.系统最大限度地实现了易维护性和易操作性。 8.系统运行稳定、安全可靠。
6



2.系统总体结构
连连看是基于java基本知识设置的一个小游戏,最中间有连连看的主体构成——连连看图片,上面有计分、时间条,下面有退出、再来一局按键。一个标准的连连看系统应该包括以下几大功结构:
1、鼠标操作模块; 2、图像处理模块; 3、菜单模块; 4、显示模块。
3. 系统各模块功能介绍
系统各功能模块实现的功能为
鼠标操作模块:玩家在玩游戏时需要运用鼠标与游戏系统进行交互,这个模块的实现 是运用鼠标事件触发的,在连连看的游戏场景中运用鼠标进行交互的事件主要有两个,一个 是用户点击游戏场景中的图片时触发的事件。另外一种是用户点击菜单栏上的菜单按钮时说 触发的鼠标事件。
当用户点击游戏场景中的图像块时就会响应鼠标的OnLButtonDown事件,然后进行相应的逻辑判断。
当用户点击菜单栏上的菜单命令时就会触发相应的菜单命令对应的相应的事件。
图像处理模块: 程序运行后,用户通过游戏菜单的开始命令进入游戏,在这个模块里要把资源文件中的图片进行处理然后加载到游戏场景中这在程序中是通过DrawMap(方法实现的。其中用到的API函数主要是是BitBlt,他的主要功能是将某一内存块的数据传送到另一内存块,前一内存块被称为"",后一内存块被称为"目标"图象程序开发者使用Blit的函数在内存中将某页面上的一幅位图经过一定的变换转移到另一个页面上。
菜单模块: 玩家在游戏游戏过程中随时可以通过选择不同的菜单命令来进行相应的操作,菜单的制作是通过MFC框架中多文档程序的菜单栏来添加的,菜单包含一下几个部分:(1游戏菜单中的开始、放弃和退出命令。
界面显示模块: 游戏场景中界面的显示包括以下部分:游戏计分,剩余时间、游戏主场景,游戏完成提示界面。这些显示信息会随着游戏的进行而动态改变。 在连连看游戏中。
整个连连看游戏的系统是在VC++6.0开发环境中进行开发的,开发过程中大量的使用了微软提供的API接口方法,减少了程序代码的编写量、提高了编程效率。
7



第四章 系统的具体实现
1.系统主要运行界面
1.1运行界面
运行界面如下图4.1所示:

4.1运行界面

1.2执行界面,进入游戏正常运行
执行界面如下图4.2所示:
8




4.2执行界面
1.3时间到界面
时间到界面如下图4.3所示:
9




4.3时间到界面
1.4赢家界面
游戏运行成功界面如下图4.4所示:

4.4游戏运行成功界面

10



1.5进度条界面
程序运行进度条如下图4.5所示:

4.5程序运行进度条
2.游戏实现代码
2.1主面板内所需要的组件的声明
主面板内所需要的组件的声明代码如下图4.6所示:

4.6组件声明
2.2填充一个矩形框,进行显示时间
填充一个矩形框,进行显示时间代码如下图4.7所示:
4.7填充矩形框显示时间
11



2.3主面板及各组件初始化
主面板及各组件初始化如下图4.8所示:
4.8主面板及各组件初始化
2.4创建时间对象,每隔100毫秒刷新一次
创建时间对象,每隔100毫秒刷新一次代码如下图4.9所示:

4.9创建时间对象
2.5分数代码。
每消除一对图片,则分数加上100。代码如下图4.10所示:
12




4.10 分数代码
3.消除图片具体情况
当点击两个按钮的图片一样时,运用消去算法来判断是否可消去,具体情况如下:
3.1两次点击相同图片相邻
当两次点击的相同图片相邻时,如下图4.11所示,则消去。

4.11 点击图片相邻
3.2水平方向消去算法
当两次点击的相同图片如下图4.12所示,则在水平方向用循环算法for (j = 0; j < 7; j++判断,设第一次选中按钮坐标为x0 , y0,第二次选中按钮坐标为x , y则先找到gridx0,j)为0j,再判断x水平方向xj是否gridx,j)都为0若是则判断x0水平方向x0j是否gridx0,j)都为0,若是,则再判断xx0,若相等消去,若不等判断在j竖直方向上是否gridn,jnxx0之间的数)都为0,若是则消去。
13




4.12水平消去算法图片

3.3竖直方向消去算法
竖直方向消去算法。情况与水平方向基本相同,重点提一下图片4.13所示的情况,其余情况不再重复描述。出现下图情况则会消去,消去原理与水平方向消去算法相似。


4.13竖直消去算法图片



14



第五章 程序清单
package c02;
import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; import javax.swing.*; class MyPanel extends JPanel { int cnt = 0; public void paint(Graphics g { super.paint(g; g.setColor(Color.red; g.fillRect(this.getWidth( - cnt, 0, cnt, this.getHeight(; //填充一个矩形区域 } public boolean isEnd( { if (cnt++ > this.getWidth( return true; repaint(; return false; }
} public class LianLianKan implements ActionListener { JFrame mainFrame; // 主面板 MyPanel time; JPanel centerPanel, southPanel, northPanel; // 3个子面板
JButton diamondsButton[][] = new JButton[6][5];// 游戏按钮数组
JButton exitButton, newlyButton; // 退出,重新开始按钮
JLabel scoreLable; // 分数标签 JButton firstButton, secondButton; // 分别记录两次被选中的按钮
Timer timer; int grid[][] = new int[8][7];// 储存游戏按钮位置
static boolean pressInformation = false; // 判断是否有按钮被选中
int sum=0;
int x0 = 0, y0 = 0, x = 0, y = 0,

fristMsg = 0, secondMsg = 0; // 游戏按钮的位置坐标
int i, j, k, n;// 消除方法控制 // =============调用图片================// private static Icon icons[] = new ImageIcon[6 * 5]; //静态数组icons【】用于存放图片绝对地址
private static final String imgDir = "f:/meng"; static { try { File dir = new File(imgDir;


File[] imgFiles = dir.listFiles(new FilenameFilter( { //获取f:/meng文件中的图片
public boolean accept(File dir, String name { return name.toLowerCase(.endsWith(".jpg"; } }; for (int i = 0; i < 6 * 5; i++ { //获取f:/meng文件中的图片的绝对路径放在icons数组中
icons[i] = new ImageIcon(imgFiles[i].getAbsolutePath(; // System.out.println(i+"
"+icons[i]; } } catch (Exception e { e.printStackTrace(;// 常处理
} } public void init( { //初始化面板
mainFrame = new JFrame("JKJ连连看";// 设置主面板的名称为"JKJ连连15

" mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE;// 结束窗体所在的应用程序

mainFrame.setLayout(new BorderLayout(; // 设置为BorderLayout(布局
scoreLable= new JLabel("0"; centerPanel = new JPanel(;// 设置面板
southPanel = new JPanel(; northPanel = new JPanel(; northPanel.setLayout(new BorderLayout(; //设置时间分数面板布局为边界布局
mainFrame.add(centerPanel, "Center"; // 添加组件
mainFrame.add(southPanel, "South"; mainFrame.add(northPanel, "North";
centerPanel.setLayout(new GridLayout(6, 5;// 设置一个6*5的网格布
for (int cols = 0; cols < 6; cols++ { for (int rows = 0; rows < 5; rows++ { // ===========置图片=============// diamondsButton[cols][rows] = new JButton( icons[grid[cols + 1][rows + 1]];

diamondsButton[cols][rows].addActionListener(this; centerPanel.add(diamondsButton[cols][rows];
}


}
exitButton = new JButton("退";// 退出按钮

exitButton.addActionListener(this; newlyButton = new JButton("再来一局";// 再来一局按钮

newlyButton.addActionListener(this; southPanel.add(exitButton;// 添加退出按钮
southPanel.add(newlyButton;// 添加再来一局按钮
scoreLable.setText(String.valueOf(Integer.parseInt(scoreLable .getText(; time = new MyPanel(;
northPanel.add(time, BorderLayout.CENTER; //时间-分数面板上在CENTER位置添加时间
northPanel.add(scoreLable, BorderLayout.WEST; //时间-分数面板上WEST位置添加分数Lable mainFrame.setSize(500, 450; // 设置主面板的大小
mainFrame.setLocationRelativeTo(null; //设置窗口在屏幕中间显示
mainFrame.setVisible(true;//设置窗口可见
} public void startt({ timer = new Timer(10, this; //创建时间对象,每隔100毫秒计时一次。
init(; timer.start(; } public void randomBuild( //初始化存放游戏按钮位置的grid[][]数组(也就是icon【】下标+1
{ int randoms, cols, rows; // 量定义
16
for (int twins = 1; twins <= 15; twins++ {

randoms = (int (Math.random( *24; for (int alike = 1; alike <= 2; alike++ { cols = (int (Math.random( * 6 + 1; rows = (int (Math.random( * 5 + 1; while (grid[cols][rows] != 0 { cols = (int (Math.random( * 6 + 1; rows = (int (Math.random( * 5 + 1; } this.grid[cols][rows] = randoms;

} } } public void score(// 方法声明 { scoreLable.setText(String.valueOf(Integer.parseInt(scoreLable .getText( + 100; } public void reload(// 方法声明 { int save[] = new int[30]; // 建声明数组
int n = 0, cols, rows; // 变量定
int grid[][] = new int[8][7]; // 创建声明数组
for (int i = 0; i <= 6; i++ { for (int j = 0; j <= 5; j++ { if (this.grid[i][j] != 0 { save[n] = this.grid[i][j];

n++; } } } n = n - 1; this.grid = grid; // this出现在实例方法中,表示使用该方法的当前对象
while (n >= 0 // while循环 { cols = (int (Math.random( * 6 + 1; rows = (int (Math.random( * 5 + 1; while (grid[cols][rows] != 0// 循环嵌套
{ cols = (int (Math.random( * 6 + 1; rows = (int (Math.random( * 5 + 1; } this.grid[cols][rows] = save[n]; // this出现在实例方法中,表示使用该方法的当前对象
n--; } mainFrame.setVisible(false;// 窗口不可见
pressInformation = false; // 里一定要将按钮点击信息归为初始
init(; for (int i = 0; i < 6; i++// for
{ for (int j = 0; j < 5; j++// 循环嵌套
{ if (grid[i + 1][j + 1] == 0 diamondsButton[i][j].setVisible(false;// 窗口不可见
}
}
17
}
public void estimateEven(int placeX, int placeY, JButton bz // 点击按钮触发
{ if (pressInformation == false// 选择语句
{ x = placeX; y = placeY; secondMsg = grid[x][y]; secondButton = bz; pressInformation = true; } else { x0 = x; y0 = y; fristMsg = secondMsg; firstButton = secondButton; x = placeX; y = placeY; secondMsg = grid[x][y]; secondButton = bz;
if (fristMsg == secondMsg && secondButton != firstButton { // 相同的情况下能不能消去。
xiao(; } } } public void xiao( { if ((x0 == x && (y0 == y + 1 || y0 == y - 1 ||(y0 == y && ((x0 == x + 1 || x0 == x - 1 // 判断是否相邻
{ remove(; } else { for (j = 0; j < 7; j++ { if (grid[x0][j] == 0// 判断第一个按钮同行哪个按钮为空

{


if (y > j // 如果第二个按钮的Y坐标大于空按钮的Y坐标说明第一按钮在第二按钮左边
{ for (i = y - 1; i >= j; i--// 判断第二按钮左侧直到第一按钮中间有没有按钮
{ if (grid[x][i] != 0 { k = 0;
break; } else { k = 1; } // K=1说明通过了第一次验证
} if (k == 1 {
linePassOne(; } } if (y < j // 如果第二个按钮的Y坐标小于空按钮的Y坐标说明第一按钮在第二按钮右边
{ for (i = y + 1; i <= j; i++// 判断第二按钮左侧直到第一按钮中间有没有按钮
{ if (grid[x][i] != 0 { k = 0;
break; } else {
k
18
= 1;

}
}
if (k == 1
{
linePassOne(; } } if (y == j {
linePassOne(; } } if (k == 2 { if (x0 == x { remove(; } if (x0 < x { for (n = x0; n <= x - 1; n++ { if (grid[n][j] != 0 { k = 0;
break; } if (grid[n][j] == 0 && n == x - 1 {
remove(; } } } if (x0 > x { for (n = x0; n >= x + 1; n-- { if (grid[n][j] != 0 { k = 0;
break;


} if (grid[n][j] == 0 && n == x + 1 {
remove(; } } } } } for (i = 0; i < 8; i++// { if (grid[i][y0] == 0 { if (x > i { for (j = x - 1; j >= i; j-- { if (grid[j][y] != 0 { k = 0;
break; } else { k = 1; } } if (k == 1 {
rowPassOne(; } } if (x < i { for (j = x + 1; j <= i; j++ { if (grid[j][y] != 0 { k = 0;
break;
} else
19

{
k
break;
= 1; }
}





if (k == 1
{
rowPassOne(; } } if (x == i {
rowPassOne(; } } if (k == 2 { if (y0 == y { remove(; } if (y0 < y { for (n = y0; n <= y - 1; n++ { if (grid[i][n] != 0 { k = 0;
break; } if (grid[i][n] == 0 && n == y - 1 {
remove(; } } } if (y0 > y { for (n = y0; n >= y + 1; n-- { if (grid[i][n] != 0 { k = 0;
} if (grid[i][n] == 0 && n == y + 1 {
remove(; } } } } } } } public void linePassOne( { if (y0 > j// 第一按钮同行空按钮在左边
{ for (i = y0 - 1; i >= j; i--// 判断第一按钮同左侧空按钮之间有没按钮
{ if (grid[x0][i] != 0 { k = 0; break; } else { k = 2; } // K=2说明通过了第二次验证
} } if (y0 < j// 第一按钮同行空按钮在与第二按钮之间
{ for (i = y0 + 1; i <= j; i++ { if (grid[x0][i] != 0 { k = 0; break; } else { k = 2; } } }
}
20

public void rowPassOne( { if (x0 > i { for (j = x0 - 1; j >= i; j-- { if (grid[j][y0] != 0 { k = 0; break; } else { k = 2; } } } if (x0 < i {
for (j = x0 + 1; j <= i; j++ { if (grid[j][y0] != 0 { k = 0; break; } else { k = 2; } } } } public void remove( { //消除两个按钮
if(grid[x0][y0] !=0 && grid[x][y]!= 0 { firstButton.setVisible(false; // 不可见
secondButton.setVisible(false; score(; //分数加100 pressInformation = false; grid[x0][y0] = 0; grid[x][y] = 0; sum++; if(sum==15 { timer.stop(; if (JOptionPane.showConfirmDialog(mainFrame,

"恭喜你,你赢了! 想再来一局吗?", "胜利", JOptionPane.YES_NO_OPTION== JOptionPane.OK_OPTION { int grid[][] = new int[8][7]; this.grid = grid; randomBuild(; mainFrame.setVisible(false;//窗口不可

pressInformation = false;

init(; timer.start(;//启动线 sum=0; } else System.exit(0;
} } }
public void actionPerformed(ActionEvent e { //接口实现
if (e.getSource( == newlyButton {
int grid[][] = new int[8][7];//创建数组
this.grid = grid; randomBuild(; mainFrame.setVisible(false;//窗口不可 pressInformation = false; init(; timer.start(; sum=0; }
if (e.getSource( == exitButton
21

System.exit(0; if (e.getSource( == timer { if (time.isEnd( { timer.stop(;//时间到的提示

if (JOptionPane.showConfirmDialog(mainFrame, "时间到了,o(︶︿︶o \n要再来一局吗?", "提示", JOptionPane.YES_NO_OPTION== JOptionPane.OK_OPTION { int grid[][] = new int[8][7]; this.grid = grid; randomBuild(;

mainFrame.setVisible(false;//窗口不可
pressInformation = false;

init(;

timer.start(;//





动线程

sum=0; } else System.exit(0; } } for (int cols = 0; cols < 6; cols++ { for (int rows = 0; rows < 5; rows++ { if (e.getSource( == diamondsButton[cols][rows]{ estimateEven(cols + 1, rows + 1, diamondsButton[cols][rows]; } } }
} public static void main(String[] args {//主函数
LianLianKan llk = new LianLianKan(;//创建对象
llk.randomBuild(;//调用方法 llk.startt(; } } 22

第六章 结束语
本次java课程设计,通过一学期的学习知识,成功的设计出一个非常经典的连连看小游戏,参考网络上的知识,进行扩展知识面,本节只要了解了图形界面的概念,及其应用到实际界面中,深刻的了解了AWT得基本体系结构,SWING组件的功能,Swing组件从功能上分为三种类型:顶级组件,中间组件和基本组件。深刻的了解到它是用java纯代码来实现的,并且它在不同的平台上的运行效果相同,开发出的图形用户界面更加的美观。
同时总结了开发图形用户界面的一般步骤:首先要创建窗体,再而在窗体上添加相应中间组件和基本组件,并设置这些组件的相关属性,再设置布局管理的策略,指定添加的组件在窗体上的位置,最后再添加事件的处理。在一整套对连连看的设计中,实现了开发此游戏过程所用到的知识点。还有要注意的是,在创建完窗体流程后,要setVisibletrue)窗体可见。本节还用到了事件处理过程,鼠标点击的处理,以及设置监听器,此事件去响应。凡是要ActionEvent事件类都必须实现ActionListener接口,实现接口就必须重写接口中的actionPerformedActionEvent e)方法。在重写方法体中通常需要调用e.getSource()查明产生ActionEvent的事件源,然后采取相应的措施处理该事件。还掌握了布局管理器的使用方法,该游戏还将设置退出,再来一局按钮,并实现相应的功能。
此次课程设计的过程虽然辛苦,但也收获了不少东西。经过到图书馆以及网络上查阅资料,我们在对已学的Java知识有了进一步的掌握,例如Swing组件的使用,事件的处理等,另外,还了解了许多新的知识。经过小组成员的合作努力,我们对此游戏进行各种完善,从原来的数字图片改成了一些可爱复杂的图片,从没有计时功能到增加了计时功能,从没有登录界面到制作了一个登录界面,从一次次的完善中,我们收获了很多。当然该游戏并不是完美的,还有一些功能可以加强完善,这需要我们继续努力,进一步探究。



23



第七章 参考文献
[1] 刘宝林.Java程序设计与案例习题解答与实验指导[M]. [2] 王鹏 何云峰.Swing图形界面开发与案例分析[M].

[3](美)Karl Avedal , Danny Ayers, Timothy Briggs. JSP编程指南[M]. 电子工业出版社, 2004,47-125. [4](美)Mark Linsenbardt. JSP在数据库中的应用与开发[M]. 希望电子出版社,2005,210-236. [5] Dianne PhelanBuilding a simple web database application[C].IEEE International Professional Communication Conference, 2004, 79-86. [6](美)Karl Avedal,Danny Ayers,Timothy Briggs.JSP编程指南[M].电子工业出版社,2006,47-125. [7] Dianne PhelanBuilding a simple web database application[C].IEEE International Professional Communication Conference, 2005, 79-86. [8] Altendorf. Eric, Hohman. Moses, Zabicki. Roman. Using J2EE on a large, web-based project[J]. IEEE Software.2002,19(02:81-89.



24


连连看课程设计

相关推荐