《Java程序设计》课程设计报告
题 目: 2048 小游戏
学 院:计算机科学与工程学院
专 业: 软件工程
学生姓名:
学 号:
指导教师:
20##年7月4日
目 录
1. 前言.................................................................................. 1
2. 需求分析.......................................................................... 1
3. 概要设计.......................................................................... 1
4. 详细设计.......................................................................... 1
5. 测试.................................................................................. 1
6. 总结.................................................................................. 1
参考文献.............................................................................. 2
附录....................................................................................... 2
一、前言
最近以来,移动手游越来越成为当下游戏产业中重要的一环,市场也在加大对这一产业的投入,涌现出了愤怒的小鸟,水果忍者,flappy bird,2048等诸多优秀的手游,然而任何一款手游能够风靡,主要还是依靠其简单的操作性,因此本次java课设我选择其中的典型2048PC版作为本次课设的课题。
二、需求分析
1、界面
一款的好的游戏其界面必须友好,简洁已经成为当今UI设计的主流,简单易上手才能得到玩家的青睐。
这是本次游戏的界面,界面上方是游戏分数面板,中间是游戏主面板,靠下是一颗重置按钮,当游戏失败时可通过本按钮重置游戏。最下方是本次游戏的提示,2048刚出来时没有提示,很多玩家云里雾里,通过提示可以一目了然地知道本游戏玩法。界面的设计体现了简洁性。
2、操作性
游戏的体验是衡量一款游戏的关键,本游戏通过键盘w,s,a,d以及方向键来控制方块的移动,左右手都可以操作~充分考虑便捷性。
三、概要设计
// 按键输入事件的处理方法
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键
for(int i = 0; i < 4; i++){
a = 5;
for(int k = 0; k < 3; k++){
for(int j = 1; j < 4; j++){ //遍历16个方块
str = texts[i][j].getText(); //获取当前方块标签文本字符
str1 = texts[i][j-1].getText(); //获取当前左1方块标签文本字符
if(str1.compareTo("") == 0){ //如果左1方块文本为空字符
texts[i][j-1].setText(str); //字符左移
setColor(i, j-1,str);
texts[i][j].setText(""); //当前方块字符置空
setColor(i, j, "");
}elseif((str.compareTo(str1) == 0) && (j !=a) && (j != a-1)){ //如果当前方块和左1方块文本字符相等
num = Integer.parseInt(str);
scores += num;
times ++;
str = String.valueOf(2 * num);
texts[i][j-1].setText(str); //左1方块文本字符变为两方块之和
setColor(i, j-1, str);
texts[i][j].setText(""); //当前方块字符置空
setColor(i, j, "");
a = j;
}
}
}
}
//通过按键事件的处理,监视滑块的移动
四、详细设计
分别构建mainPane,scoresPane两大模块放入游戏窗体getContentPane(),其中scoresPane包含得分以及最高分,当得分超过最高分时,将得分存入工程文件夹下的score.txt,覆盖最高分,同时在最高分显示最新score.txt的内容。
通过Create2方法随机显示2号方块,通过setColor方法设置每个数字代表的方块颜色,通过initMap遍历数组(方块是用二维数组存贮的)
RESET按钮是通过设计的图片覆盖,同时消掉按钮的边框达到的,保持了游戏的美观性。
五、测试
当方块都无法移动,即l1,l2,l3,l4都为1时,弹出Game Over!
点击RESET按钮后,得分清零,游戏面板回归初始状态。
六、总结
通过此次课程设计我学会了很多知识,将Java课上遗漏的知识又进一步补上。实践过程中遇到了很多困难,比如在按钮中导入图片,设置方块随机出现的方法,如何将最高分显示出来。由于本次试验的很多知识都是现学现用,以致很多地方的代码显得累赘繁琐。但总体上主要功能是实现了的,并且美化了一下主界面,使得界面更加简洁。
总之,此次课程设计让我获益匪浅,我将会继续把它完善做好
七、源代码清单
package howwer;
import java.awt.Color;
importjava.awt.Container;
import java.awt.EventQueue;
importjava.awt.BorderLayout;
importjava.awt.FlowLayout;
import java.awt.Font;
importjava.awt.Image;
importjava.awt.Insets;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
importjava.util.ArrayList;
importjava.util.List;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
importjavax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
importjavax.swing.JSplitPane;
import javax.swing.SwingConstants;
importjavax.swing.border.*;
import javax.swing.JTextField;
publicclassCopy2048extends JFrame implements initMap{
private JButton Button1;
private JPanel scoresPane;
private JPanel mainPane;
private JLabel labelMaxScores ;
private JLabel labelScores;
private JLabel tips; //提示操作标签
private JLabel tips2;
private ImageIcon img;
private JTextField textMaxScores;
private JLabel textScores;
private JLabel texts[][]=new JLabel[4][4];
private Icon icon2;
privateint times = 16; //记录剩余空方块数目
privatestaticintscores = 0; //记录分数
privateint l1,l2,l3,l4,l5; //用于判断游戏是否失败
Font font = new Font("", Font.BOLD,14); //设置字体类型和大小
Font font2 = new Font("", Font.BOLD,25);
Font font3=new Font("",Font.CENTER_BASELINE,12);
Random random = new Random();
publicvoid writeBest(){
File f=new File("score.txt");
BufferedReader br;;
if(f.exists()){
try {
br=new BufferedReader(new FileReader(f));
textMaxScores.setText(br.readLine().trim());
br.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
BufferedWriter bw;
if(scores>Integer.parseInt(textMaxScores.getText().toString())){
try {
bw = new BufferedWriter(new FileWriter(f));
bw.write(scores+"");
textMaxScores.setText(scores+"");
bw.flush();
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
publicvoid initMap(){
for(int i = 0; i < 4; i++){ //遍历数组
for(int j = 0; j < 4; j++){
//创建标签
texts[i][j].setText("");
texts[i][j].setOpaque(true);
setColor(i, j, "");
}
}
times=16;
Create2();
Create2();
}
publicstaticvoid main(String[] args){
EventQueue.invokeLater(new Runnable(){
publicvoid run(){
try{
Copy2048 frame = new Copy2048();
frame.setVisible(true);
// Thread thread = new Thread(frame);
// thread.start();
}
catch(Exception e1){
e1.printStackTrace();
}
}
});
}
/**
* 构造方法
*/
public Copy2048(){
super();
setResizable(false); //禁止调整窗体大小
getContentPane().setLayout(null); //设置空布局
setBounds(500, 50, 295, 440);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("2048 by502陆彬"); //设置窗体标题
scoresPane = new JPanel(); //创建最高分数显示面板
scoresPane.setBackground(Color.red); //设置分数显示面板的背景色
scoresPane.setBounds(20, 10, 250, 40);
scoresPane.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.white)); //设置得分面板的边框
getContentPane().add(scoresPane); //将得分面板添加到窗体
scoresPane.setLayout(null); //设置面板空布局
labelMaxScores = new JLabel("最高分:"); //最高分标签
labelMaxScores.setFont(font); //设置字体类型和大小
labelMaxScores.setBounds(10, 5, 50, 30); //设置最高分标签的位置尺寸
scoresPane.add(labelMaxScores); //将最高分标签添加到得分容器中
textMaxScores = new JTextField("0"); //得分标签
textMaxScores.setBounds(60, 5, 90, 30);
textMaxScores.setFont(font);
textMaxScores.setEditable(false);
scoresPane.add(textMaxScores); //将得分标签添加到分数面板中
labelScores = new JLabel("得 分:");
labelScores.setFont(font); //设置字体类型和大小
labelScores.setBounds(150, 5, 50, 30);
scoresPane.add(labelScores);
textScores = new JLabel(String.valueOf(scores));
textScores.setFont(font);
textScores.setBounds(195, 5, 150, 30);
scoresPane.add(textScores);
mainPane = new JPanel(); //创建游戏主面板
mainPane.setBounds(20, 70, 345,380 ); //设置主面板位置尺寸
this.getContentPane().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);
texts[i][j].setText("");
texts[i][j].setBounds(62 * j, 62 * i, 60, 60); //设置方块的大小位置
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]); //将创建的文本框放在
}
}//创建文本框二维数组
writeBest();
tips= new JLabel("Tips:使用上、下、左、右键或者W、S");
tips2=new JLabel("A、D键控制方块移动,直至出现最大值2048");
tips.setFont(font3);
tips.setForeground(Color.red);
tips2.setFont(font3);
tips2.setForeground(Color.red);
tips.setBounds(10,290,400,20);
tips2.setBounds(5, 310, 400, 20);
mainPane.add(tips2);
mainPane.add(tips);
ImageIcon buttonIcon1 = new ImageIcon("image\\简洁按钮.png");
Button1=new JButton(buttonIcon1);
Button1.setBounds(78, 249, 89, 40);
Button1.setBorderPainted(false);
mainPane.add(Button1);
Button1.addActionListener(new ActionListener() {
@Override
publicvoid actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
scores=0;
initMap();
textMaxScores.requestFocus();
textScores.setText("0");
}
});
textMaxScores.addKeyListener(new KeyAdapter(){ //为最高分标签添加按键监听器
publicvoid keyPressed( KeyEvent e){
do_label_keyPressed(e); //调用时间处理方法
}
});
Create2();
Create2();
}
// 按键输入事件的处理方法
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键
for(int i = 0; i < 4; i++){
a = 5;
for(int k = 0; k < 3; k++){
for(int j = 1; j < 4; j++){ //遍历16个方块
str = texts[i][j].getText(); //获取当前方块标签文本字符
str1 = texts[i][j-1].getText(); //获取当前左1方块标签文本字符
if(str1.compareTo("") == 0){ //如果左1方块文本为空字符
texts[i][j-1].setText(str); //字符左移
setColor(i, j-1,str);
texts[i][j].setText(""); //当前方块字符置空
setColor(i, j, "");
}elseif((str.compareTo(str1) == 0) && (j !=a) && (j != a-1)){ //如果当前方块和左1方块文本字符相等
num = Integer.parseInt(str);
scores += num;
times ++;
str = String.valueOf(2 * num);
texts[i][j-1].setText(str); //左1方块文本字符变为两方块之和
setColor(i, j-1, str);
texts[i][j].setText(""); //当前方块字符置空
setColor(i, j, "");
a = j;
}
}
}
}
l1 = 1; //用于判断游戏是否失败
Create2();
break;
case KeyEvent.VK_RIGHT:
case KeyEvent.VK_D:
for(int i = 0; i < 4; i ++){
a = 5;
for(int k = 0; k < 3; k++){
for(int j = 2; j >= 0; j--){
str = texts[i][j].getText();
str1 = texts[i][j + 1].getText();
if(str1.compareTo("") == 0){
texts[i][j + 1].setText(str);
setColor(i, j+1, str);
texts[i][j].setText("");
setColor(i, j, "");
}
elseif(str.compareTo(str1) == 0 && j !=a && j != a+ 1){
num = Integer.parseInt(str);
scores += num ;
times ++;
str = String.valueOf(2 * num);
texts[i][j + 1].setText(str);
setColor(i, j+1, str);
texts[i][j].setText("");
setColor(i, j, "");
a = j;
}
}
}
}
l2 = 1;
Create2();
break;
case KeyEvent.VK_UP:
case KeyEvent.VK_W:
for(int j = 0; j < 4; j++){
a = 5;
for(int k = 0; k < 3; k++){
for(int i = 1; i < 4; i++){
str = texts[i][j].getText();
str1 = texts[i - 1][j].getText();
if(str1.compareTo("") == 0){
texts[i - 1][j].setText(str);
setColor(i-1, j, str);
texts[i][j].setText("");
setColor(i, j, "");
}
elseif(str.compareTo(str1) == 0 && i != a && i != a -1){
num = Integer.parseInt(str);
scores += num ;
times ++;
str = String.valueOf(2 * num);
texts[i - 1][j].setText(str);
setColor(i-1, j, str);
texts[i][j].setText("");
setColor(i, j, "");
a = i;
}
}
}
}
l3 =1;
Create2();
break;
case KeyEvent.VK_DOWN:
case KeyEvent.VK_S:
for(int j = 0; j < 4; j ++){
a = 5;
for(int k = 0; k < 5; k++){
for(int i = 2; i >= 0; i--){
str = texts[i][j].getText();
str1 = texts[i + 1][j].getText();
if(str1.compareTo("") == 0){
texts[i + 1][j].setText(str);
setColor(i+1, j, str);
texts[i][j].setText("");
setColor(i, j, "");
}
elseif(str.compareTo(str1) == 0 && i != a && i != a + 1){
num = Integer.parseInt(str);
scores += num ;
times ++;
str = String.valueOf(2 * num);
texts[i + 1][j].setText(str );
setColor(i+1, j, str);
texts[i][j].setText("");
setColor(i, j, "");
a = i;
}
}
}
}
l4 = 1;
Create2();
break;
default:
break;
}
textScores.setText(String.valueOf(scores));
writeBest();
}
//随机产生新的2号方块方法
publicvoid Create2(){
int i ,j;
boolean r = false;
String str;
if(times > 0){
while(!r){
i = random.nextInt(4);
j = random.nextInt(4);
str = texts[i][j].getText();
if((str.compareTo("") == 0)){
texts[i][j].setIcon(icon2);
texts[i][j].setText("2");
setColor(i, j, "2");
times --;
r = true;
l1 = l2 = l3 = l4 = 0;
}
}
}
elseif(l1 >0 && l2 >0 && l3 > 0 && l4 > 0){ //l1到l4同时被键盘赋值为1说明任何方向键都不能产生新的数字2,说明游戏失败,弹出Game Over对话框
JOptionPane.showMessageDialog(null, " Game Over !");
}
}
//设置标签方块颜色
publicvoid setColor(int i, int j, String str){
switch(str){
case "2":
texts[i][j].setBackground(new Color(200,160,50));
break;
case "4":
texts[i][j].setBackground(Color.red);
break;
case "8":
texts[i][j].setBackground(Color.yellow);
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(Color.LIGHT_GRAY);
break;
case "128":
texts[i][j].setBackground(Color.pink);
break;
case "256":
texts[i][j].setBackground(Color.gray);
break;
case "512":
texts[i][j].setBackground(Color.DARK_GRAY);
break;
case "1024":
texts[i][j].setBackground(Color.cyan);
break;
case "20##":
texts[i][j].setBackground(Color.blue);
break;
case "":
case "4096":
texts[i][j].setBackground(Color.white);
break;
default:
break;
}
}
}