资源描述
《JAVA语言程序设计》
课程设计汇报
2048智力小游戏设计
专业班级: 计算机科学和技术嵌入13-1
学生姓名: 卓海有
学生学号:
小组组员: 单建飞 堵文斐 李栋承 梅孔伟
指导老师姓名: 宋 强
目录
1.序言 1
2.游戏需求分析 1
2.1 需求分析 1
2.2 可行性分析 2
3.概要设计 3
4.具体设计 4
4.1步骤图 4
4.2界面整体布局 4
4.3方法模块分析 5
5.测试 8
6.总结 10
6.参考文件 10
7.部分源代码: 10
一、序言
最近以来,移动手游越来越成为当下游戏产业中关键一环,市场也在加大对这一产业投入,涌现出了愤怒小鸟,水果忍者,flappy bird,2048等很多优异手游,然而任何一款手游能够风靡,关键还是依靠其简单操作性,所以此次java课设我选择其中经典2048PC版作为此次课设课题。
2048游戏规则很简单,玩家每次能够选择上下左右其中一个方向去移动,每移动一次,全部数字方块全部会往移动方向靠拢外,系统也会在空白地方随机出现一个数字方块,相同数字方块在靠拢、相撞时会相加。系统给数字方块不是2就是4,玩家要想措施在这小小16格范围中凑出“2048”这个数字方块。
二、游戏需求分析
2.1需求分析
现代社会对休闲小游戏需求是:提升游戏操作可行性,降低游戏操作难度,降低游戏上手难度,降低游戏竞争需求,对使用设备要求趋于简单化和多样化,游戏界面愈加人性化,功效愈加贴合使用。
(1)界面
一款好游戏其界面必需友好,简练已经成为当今UI设计主流,简单易上手才能得到玩家青睐。
(2)功效需求
能够显示游戏目前得得分,并统计游戏最高分并显示,当在次打开游戏时,能够显示最高分;在游戏进行过程中循环播放音乐,并能够关闭音乐或打开音乐;游戏主界面上,相同数字要显示相同颜色。游戏结束要有对应提醒。游戏关键目标是经过上下左右移动来将相邻相同数字相加,经过不停地累加最终加到2048。
(3)操作性需求
游戏体验是衡量一款游戏关键,本游戏可经过键盘w,s,a,d和方向键来控制方块移动,还能够经过在游戏主面板中向上下左右拖动鼠标来控制方块移动,左右手全部能够操作,充足考虑便捷性。 不一样人有不一样习惯,经过多个方法来操作游戏,能够多种习惯人需求。
2.2可行性分析
(1)面向对象程序设计方法
Java面向对象程序设计基础思想是经过结构和组织对象来求解问题。对象是很好了解,任何一个物体全部能够被认为是对象,比如,汽车就是一个对象。对象含有两个最基础属性:含有一定物质基础和一定功效,这两种基础属性在Java语言中表现为拥有一定存放单元并含有一定功效。了解了Java这种面向对象程序设计基础思想以后,在以后编程过程中,就应该个结构大家轻易了解更靠近于真实物理世界物体对象。
Java面向对象程序设计过程很简单。这里介绍一个自顶向下程序设计方法,首先结构一个类来处理需要处理问题,然后依据已经拥有类(比如以前求解其它问题时实现类),分析和结构新类,设法将问题分解下去,而最开始结构类经过组织这些新结构类、已经有类及由她们生成实例来求解指定问题。这个过程能够继续递归下去,用在新结构类上,直到最终处理了指定问题,比如Java应用程序和小应用程序全部必需有一个类作为入口求解问题。
在计算机语言中,面向对象类通常含有三个基础特征:封装性、继承性和多态性,这三种特征深入简化了Java求解模型,提升了程序复用性,节省了程序代码量,从而提升了软件生产率。
(2)java技术分析
图形用户界面不仅能够提供多种数据基础图形直观表示形式,而且能够建立友好交互方法,从而使计算机软件能够设计得十分简单易用。从Java语言诞生到现在,Java语言已经提供了两代图形用户界面。第一代图形用户界面AWT提供了基础图形用户界面,它强烈地依靠于具体计算机操作系统,而且缺乏基础剪贴板和打印支持功效。现在第二代图形用户界面Swing对AWT进行了扩展,Swing不仅在功效上比AWT强大,而且在很大程度上克服了AWT上述缺点,它所设计图形用户界面和具体计算机操作相关性很小,而且能够定制指定操作系统风格图形用户界面。
GUI(图形用户界面)组件组成了图形用户界面基础。在Java程序设计中,要求根据一定布局方法将组件安排在容器中,然后经过事件处理方法实现人机交互,而容器本身也是组件,这么在容器中也能够含有容器,从而能够经过这种嵌套方法方便地组合多种组件。
事件处理模型是Java语言提供一个人机交互模型,它使得用户能够经过鼠标、键盘或其它输入设备来控制程序实施步骤,从而达成人机交互目标。对鼠标、键盘或其它输入设备多种操作通常也称为事件。Java语言对这些事件处理模型是采取面向对象方法,即经过对象形式把多种事件进行封装和处理。这种事件处理模型三个基础要素是事件源、事件对象和事件监听器。事件源是多种组件,是接收多种事件对象。在多种事件源上利用鼠标、键盘或其它输入设备进行多种操作,就会有事件发生。每种操作通常全部对应着事件,Java语言经过事件对象来包装这些事件。对事件进行处理是经过事件监听器实现。
因为鼠标事件也是一个事件,所以对鼠标事件进行处理要遵照事件处理模型。鼠标事件处理也是建立在事件源基础之上,以事件对象本身,最终经过事件监听器进行处理。
类java.awt.event.MouseEvent包装常见鼠标事件,比如,按下鼠标键和放开鼠标键等。类MouseEvent实例对象统计了鼠标目前位置和状态发生改变鼠标键等。对鼠标事件进行处理最关键是实现事件监听器接口。这些相关接口包含MouseListener,MouseMotionListener,MouseWheelListener,MouseInputListener。前面三个是包java.awt.event中接口,最终一个接口MouseInputlistener来自包javax.swing.event。
接口Java.awt.event.MouseListener关键用来处理按下鼠标键、放开鼠标键、单击鼠标键、鼠标进入组件内和鼠标离开组件区域等事件。
对鼠标事件进行处理,就是要设计类,实现上面鼠标事件监听器接口,然后在事件源中注册处理鼠标事件监听器对象,方便对鼠标事件进行处理。
三、 概要设计
四、 具体设计
(1) 步骤图
(2) 界面整体布局
分别构建mainPane,scoresPane两大模块放入游戏窗体,其中scoresPane包含2048字样提醒,目前得分和最高分,当得分超出最高分时,将得分存入工程文件夹下myRecording.txt,覆盖最高分,同时在最高分显示最新myRecording.txt内容。
经过Create方法随机产生2号方块或4号方块,经过setColor方法设置每个数字代表方块颜色。
(3) 方法模块分析
方法1:设置标签颜色,每次随机产生2或4和数字合并以后就要调用该方法来设置标签颜色
public void setColor(int i, int j, String str) {
if ("".equals(str)) {
texts[i][j].setBackground(new Color(120,221,247));
return;
}
int result = Integer.parseInt(str);
switch (result) {
case 2: texts[i][j].setBackground(new Color(240,240,0)); break;
case 4: texts[i][j].setBackground(Color.pink); break;
case 8: texts[i][j].setBackground(new Color(240,150,10)); break;
case 16: texts[i][j].setBackground(Color.green); break;
case 32: texts[i][j].setBackground(Color.magenta); break;
case 64: texts[i][j].setBackground(new Color(155,10,190));break;
case 128: texts[i][j].setBackground(Color.blue); break;
case 256: texts[i][j].setBackground(Color.gray); break;
case 512: texts[i][j].setBackground(Color.cyan); break;
case 1024: texts[i][j].setBackground(Color.DARK_GRAY); break;
case 2048: texts[i][j].setBackground(Color.red); break;
case 4096: texts[i][j].setBackground(Color.white); break;
default: break;
}
}
方法2:在随机位置产生一个2号或4号方块方法,同时该方法也用于判定游戏是否结束。
public void Create() {
int i, j;//用于统计产生二维方阵下标值
boolean r = true;
String str;
if (times > 0 && biaoji == 1) {
while (r) {
i = random.nextInt(4);
j = random.nextInt(4);
str = texts[i][j].getText();
if ((pareTo("") == 0)) {
int ima = 2 * (int) (1 + Math.random() * 2);// 随机产生2或4
String imass = String.valueOf(ima);
texts[i][j].setText(imass);
setColor(i, j, imass);
times--;
r = false;
p1 = p2 = p3 = p4 = 0;
}
}
//统计目前状态
for(int p = 0; p < 4; ++p){
for(int q = 0; q < 4; ++q){
temp1[p][q] = temp2[p][q];
if( "".equals(texts[p][q].getText()) )temp2[p][q] = 0;
else temp2[p][q] = Integer.parseInt(texts[p][q].getText());
}
}
temp1scores = temp2scores;
temp2scores = scores;
}
else if (p1 > 0 && p2 > 0 && p3 > 0 && p4 > 0)
{
// l1到l4同时被键盘赋值为1说明任何方向键全部不能产生新数字,说明游戏失败
tips.setText(" 游 戏 结 束 !");
currentScores.setText("<html>SCORE<br>"+String.valueOf(scores)+"</html>");
JOptionPane.showMessageDialog(null,"游戏结束!");
System.exit(0);;
}
}
方法3:经过鼠标左键按下和释放来判定向那个方向拖动,拖动实现关键是经过统计按下鼠标左键时鼠标指针位置,然后在统计鼠标左键释放时指针位置坐标,经过对两次坐标值计算处理,能够得到鼠标指针移动方向,在将取得方向值传到do_label_keyPressed(int)函数中,从而达成移动目标。
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
//鼠标按下
//若鼠标位置在灰色区域内则统计鼠标左键按下时坐标
if(e.getX()>=20&&e.getX()<=480&&e.getY()>=180&&e.getY()<=640)
{
this.x1=e.getX();
this.y1=e.getY();
//调试程序输出鼠标坐标位置
System.out.println("X="+e.getX()+" "+"Y="+e.getY());
}
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
//鼠标释放
//若鼠标位置在灰色区域内而且按下鼠标位置不为0,则进行对应处理
if(e.getX()>=20&&e.getX()<=480&&e.getY()>=180&&e.getY()<=640&&this.x1!=0&&this.y1!=0)
{
this.x2=e.getX();
this.y2=e.getY();
if((x1>x2)&&((x1-x2)>Math.abs(y2-y1)))
{
option=1;//移动方向向左
System.out.println("向左方向移动");
}
if((x1<x2)&&((x2-x1)>Math.abs(y2-y1)))
{
option=2;//移动方向向右
System.out.println("向右方向移动");
}
if((y1>y2)&&((y1-y2)>Math.abs(x1-x2)))
{
option=3;//移动方向向上
System.out.println("向上方向移动");
}
if((y1<y2)&&((y2-y1)>Math.abs(x1-x2)))
{
option=4;//移动方向向下
System.out.println("向下方向移动");
}
//将上一次鼠标位置清零
this.x1=0;
this.y1=0;
this.x2=0;
this.y2=0;
do_label_keyPressed(option);
}
}
方法4:从文件中读取,统计。从文件中读取统计,同时也要将新数据保留到文件中。读取文件需要处理问题是,当程序首次运行时候,文件不存在,这时不仅不能从文件中读数据,还要创建对应文件。创建文件以后,接下来在运行程序就能读取到数据。文件读取结束要将文件关闭。
public static void getRecording()
{
boolean flag=false;//用于判定文件是否是新创建
try {
File f=new File("src/myRecording.txt");
if(f.exists())
{
fr=new FileReader(f);
br=new BufferedReader(fr);
String n=br.readLine();
maxscores_2048=Integer.parseInt(n);
}
else
{
flag=f.createNewFile();
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
finally
{
try {
//关闭文件流次序,先开后关闭
if(!flag)
{
br.close();
fr.close();
}
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
}
五、 测试
(1)首次运行程序(在工程文件中建立保留最高分文件)和再次运行程序
(2)游戏结束
六、总结
在这次课程设计中不仅检验了我所学习知识,也培养了我实践能力,让我知道碰到一个问题,怎样去寻求思绪,怎样去处理问题,最终完成整个事情。课程设计是我们专业课程知识综合应用实践训练,是我们迈向社会,从事职业工作前一个必不少过程。这次课程设计不仅是对这学期所学知识一个综合检验,而且也是对自己动手能力一个提升,增强了自己实践能力。经过这次课程设计使我明白了自己知识还比较欠缺,只是学习书本知识还是远远不够,自己不会东西还有太多,学习需要自己长久积累,在以后学习、工作中全部应该不停学习,将书本理论知识和生活中实践知识相结合,不停提升自己文化知识和实践能力。因为此次试验很多知识全部是现学现用,以致很多地方代码显得累赘繁琐。但总体上关键功效是实现了,而且美化了一下主界面,使得界面愈加简练。
最终也感谢老师给耐心指导和帮助。
总而言之,此次课程设计让我获益匪浅,我将会继续把它完善做好
参考文件
[1] java语言程序设计基础篇[M].机械工业出版社..3.
[2] 黄晓东.Java课程设计案例精编[M].北京:中国水利水电出版社,.5.
[3] 求是科技. Java信息管理系统开发实例导航[M].北京:人民邮电出版社..4.
源代码清单
package my2048game;
import javax.sound.sampled.*;
import javax.swing.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class My2048Game extends JFrame{
//定义自己面板
MyPanel mp=null;
public static void main(String[] args) {
// TODO Auto-generated method stub
My2048Game m2048=new My2048Game();
m2048.setFocusable(true);//(设置)该对象焦点,不能用请求焦点 对象名.requestFocus();
}
//结构函数
public My2048Game()
{
mp=new MyPanel();
this.add(mp);
//注册鼠标监听
this.addMouseListener(mp);
//注册键盘监听
this.addKeyListener(mp);
this.setTitle("2048游戏");
this.setLocation(400, 30);
this.setSize(500, 800);
this.setResizable(false);//严禁调整窗口大小
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
}
class MyPanel extends JPanel implements MouseListener,KeyListener,ActionListener//动作监听器 通常见于监听按钮或菜单点击事件
{
private int x1=0,y1=0;//按下鼠标左键位置坐标
private int x2=0,y2=0;//释放鼠标左键位置坐标
private int option=0;//统计鼠标移动方向
//定义组件
private JButton jb1;//声音图标按钮
private static boolean jb1_flag=true;//用于控制声音开关一个标志
private boolean jb1_flag2=true;//
public static boolean isJb1_flag() {
return jb1_flag;
}
public static void setJb1_flag(boolean jb1_flag) {
MyPanel.jb1_flag = jb1_flag;
}
private JPanel scoresPane; // 分数面板
private JPanel mainPane; // 游戏主面板
private JLabel labelMaxScores; // "最高分"标签
private JLabel m2048;//显示2048
private JLabel labelScores; // 目前"得分"标签
private JLabel tips;// 提醒操作标签
private JLabel currentScores;
private JLabel textScores;
private JLabel[][] texts; // 创建文本框二维数组
private int[][] temp1 = new int [4][4]; //统计上一步状态
private int[][] temp2 = new int [4][4]; //统计目前状态
private int times = 16;// 统计剩下空方块数目
private int scores = 0;// 统计分数
private int maxscores=0;//最高分
private int temp1scores = 0;
private int temp2scores = 0;
private int p1, p2, p3, p4;// 用于判定游戏是否失败
private int biaoji = 1; //标识能否移动
Font font = new Font("", Font.BOLD, 14); // 设置字体类型和大小(标签字体设置)
Font font2 = new Font("", Font.BOLD, 30); // 主面板数字字体设置
Random random = new Random();
//结构函数
public MyPanel()
{
super();//调用父类结构方法
//在结构函数中创建组件
this.setLayout(null);// 设置空布局
this.setBackground(new Color(2,150,220));//设置该MyPanel类背景颜色
scoresPane=new JPanel();//创建分数显示面板
scoresPane.setBackground(new Color(5,150,220));//设置分数面板背景颜色
scoresPane.setBounds(0,0,482,100);//设置该面板显示位置和长宽
//scoresPane.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.yellow));//设置该面板边框
this.add(scoresPane);//将分数面板加载到MyPanel面板上
scoresPane.setLayout(null);//设置得分面板布局为空
m2048=new JLabel("2048");//创建标签
//m2048.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.yellow));
m2048.setFont(new Font("宋体", Font.BOLD, 45));//设置字体类型和大小
m2048.setBounds(0,0,120,100);
scoresPane.add(m2048);
currentScores = new JLabel();// 目前得分标签
currentScores.setText("<html>SCORE<br>"+String.valueOf(scores)+"</html>");
currentScores.setFont(new Font("宋体", Font.BOLD, 30));// 设置字体类型和大小
//currentScores.setBorder(BorderFactory.createMatteBorder(0,0, 0, 1, Color.yellow));
currentScores.setBounds(240,0, 140, 100);// 设置最高分标签位置尺寸
scoresPane.add(currentScores);// 将最高分标签添加到得分容器中
//从文件取得最高分数据
Recorder.getRecording();
maxscores=Recorder.getMaxscores_2048();
labelMaxScores = new JLabel("<html>BEST<br>"+String.valueOf(maxscores)+"</html>");// 最高得分标签
labelMaxScores.setFont(new Font("宋体", Font.BOLD, 30));// 设置字体类型和大小
//labelMaxScores.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.yellow));
labelMaxScores.setBounds(380, 0, 120, 100);
scoresPane.add(labelMaxScores);// 将得分标签添加到分数面板中
jb1=new JButton(new ImageIcon("src/声音图标.jpg"));
jb1.setBounds(433,120,45,30);
this.add(jb1);
//注册按钮监听
jb1.setActionCommand("shengyin");
jb1.addActionListener(this);
mainPane = new JPanel();// 创建游戏主面板
mainPane.setBounds(18, 150, 460, 460);// 设置主面板位置尺寸
mainPane.setBackground(new Color(40,190,240));
//mainPane.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.yellow));
this.add(mainPane);
mainPane.setLayout(null);// 设置空布局
texts = new JLabel[4][4];// 创建文本框二维数组
for (int i = 0; i < 4; i++) {// 遍历数组
for (int j = 0; j < 4; j++) {
texts[i][j] = new JLabel();// 创建标签
texts[i][j].setFont(font2);
texts[i][j].setHorizontalAlignment(SwingConstants.CENTER); // 设置标签内容沿X轴对齐方法;某区域中心位置
texts[i][j].setText("");
texts[i][j].setBounds(110 * j+15, 110 * i+15, 100, 100);// 设置方块大小位置
setColor(i, j, "");
texts[i][j].setOpaque(true); // 设置控件不透明
//texts[i][j].setBorder(BorderFactory.createMatteBorder(2, 2, 2,
// 2, Color.green));// 设置方块边框颜色
mainPane.add(texts[i][j]);// 将创建文本框放在主面板中
}
}
tips = new JLabel("<html>小提醒:在灰色区域内按下鼠标左键并向上下左右 方向拖动 <br>&NBSP &NBSP &NBSP &NBSP &NBSP &NBSP &NBSP 也能够经过键盘方向键来上下左右移动"
+ "<br>&NBSP &NBSP &NBSP &NBSP &NBSP &NBSP &NBSP Z 键返回上一步<html>");
tips.setFont(font);
tips.setForeground(Color.black);
tips.setBounds(0, 640, 500, 60);
this.add(tips);
//定义音频
AePlayWave apw=new AePlayWave("src/后弦 - 有你就很幸福_new.wav");
apw.start();
Create(); // 初始时在随机位置产生一个2号或4号方块
Create();
//统计一下目前状态
for(int i = 0; i < 4; ++i){
for(int j = 0; j < 4; ++j){
if( "".equals(texts[i][j].getText()) ) temp1[i][j] = temp2[i][j] = 0;
else temp1 [i][j] = temp2[i][j] = Integer.parseInt(texts[i][j].getText());
}
}
}
// 设置标签颜色
public void setColor(int i, int j, String str) {
if ("".equals(str)) {
texts[i][j].setBackground(new Color(120,221,247));
return;
}
int result = Integer.parseInt(str);
switch (result) {
case 2: texts[i][j].setBackground(new Color(240,240,0)); break;
case 4: texts[i][j].setBackground(Color.pink); break;
case 8: texts[i][j].setBackground(new Color(240,150,10)); break;
case 16: texts[i][j].setBackground(Color.green); break;
case 32: texts[i][j].setBackground(Color.magenta); break;
case 64: texts[i][j].setBackground(new Color(155,10,190)); break;
case 128: texts[i][j].setBackground(Color.blue); break;
case 256: texts[i][j].setBackground(Color.gray); break;
case 512: texts[i][j].setBackground(Color.cyan); break;
case 1024: texts[i][j].setBackground(Color.DARK_GRAY); break;
case 2048: texts[i][j].setBackground(Color.red); break;
case 4096: texts[i][j].setBackground(Color.white); break;
default: break;
}
}
// 按键输入事件处理方法
protected void do_label_keyPressed(final KeyEvent e) {
int code = e.getKeyCode();// 获取按键代码
int a; // a引入是为了预防连加情况出现
String str;
String str1;
int num;
switch (code) {
case KeyEvent.VK_LEFT:
case KeyEvent.VK_A: // 假如按键代码是左方向键或A键
biaoji = 0; // 标识左边能不能合并
for (int i = 0; i < 4; i++) {
a = 5;
for (int k = 0; k < 3; k++) { // 让左边每2个能合并全合并了
for (int j = 1; j < 4; j++) {// 遍历16个方块
str = texts[i][j].getText();// 获取目前方块标签文本字符
str1 = texts[i][j - 1].get
展开阅读全文