软件工程第二次作业

软件工程第二次作业

2048游戏

 

一、题目内容

题目内容:2048游戏

要求:实现2048游戏

实现方式:windows界面,主要利用Swing技术和事件处理机制编程。

做法:

1、利用Swing技术绘制2048界面。

2、定义Block类,设置数据块的背景颜色及数字的字体,还有不同数据块的颜色。

3、分别编写用户向上、向下、向右、向左滑动式的函数及其中的算法。

4、利用事件处理机制编写用户对键盘操作(上、下、左、右)时2048对应的实现。

二、背景及相关技术

(一)相关背景

2048是比较流行的一款数字游戏。原版2048首先在github上发布,原作者是Gabriele Cirulli。它是基于《1024》和《小3传奇》的玩法开发而成的新型数字游戏。

随后2048便出现各种版本,走各大平台。由Ketchapp公司移植到IOS的版本最为火热,现在约有1000万下载,其名字跟原版一模一样。衍生版中最出名的是《2048六边形》版本,先后在全球81个国家中的board game中排进了前200。安卓版非常火爆的有《挑战2048》,其2.0.0版以后还加入了双人对战。其次比较特别的有2048中国朝代版。更有2048自定义版,可以自己定义文字和图片。《2048~》是IOS中流行的一款。

(二)相关技术

利用Swing技术和事件监听机制来实现2048游戏的编程,用到的数据结构包括数组,类等,用户向上、向下、向左、向右滑动时的算法包括:数组元素赋值,数组元素之间的值相加,以及if条件语句和for循环语句。

三、概要设计

(一)2048游戏实现步骤

1.新建项目javatestà新建包my2048à新建类My2048主类和Block类。

引入程序中可能会用到的包(java.awt.*; java.awt.event.* ; javax.swing.*;)

My2048主类需要继承JFrame类并且实现KeyListener接口以及接口的所有方法。Block类:这个类的主要功能是设置2048界面中值为0的数据块的背景颜色,数字的字体,以及值不为0的数字块的背景颜色。主要用到setBackground()方法和 if---else if--。。。。---else语句。

2.在主类中声明需要的Swing组件以及变量。创建主类的构造函数,在构造函数中定义已经声明的组件和变量,设置窗口的标题、大小、位置和程序关闭操作。

3.给窗口加一个监听器,并把显示窗口的函数值设为true。

4.定义成员方法addBlock,用for语句初始化每个block[i],设置图标和文本的水平对齐方式,设置控件不透明。

5.定义成员方法appearBlock,用while语句实现系统随机给出的数字方块2或者4,while语句判断是否还能继续生成随机数字,其中要用到取随机数的方法Math.random()。在while语句中用双层if条件语句设置在数字块block[index]为空(即其值为0时)时,当Math.random()<0.5时, block[index]=2,否则block[index]=4。

6.定义成员方法judgeAppear,记录2048界面中已经出现的数字块的个数,当个数等于16时,停止随机生成数字。

7. 定义成员方法upBlock,即用户向上滑动时程序对应的操作。用双层for语句循环和if条件语句实现数字块的上移和垂直方向上的相邻数字块上移相加。

8.分别用类似upBlock()的定义方法定义downBlock(),rightBlock()和leftBlock()方法,实现用户向下,向右,向左滑动时程序对应的操作。

9.定义成员方法over(),当数字块在各个方向上都不能移动时在2048界面中出现CAMEOVER。

10.定义成员方法win(),当用户在这16个数字块中凑出2048时在界面中出现YOUWIN。

11.实现接口KeyListener的keyPressed(KeyEvent e)方法,用switch-----case语句分别实现用户对键盘的上、下、左、右触发时程序对应的操作。

对于KeyListener接口的其他方法要在程序中定义,可以没有方法体。

12.在主函数实例化My2048。

(二)逻辑图

 

 

四、系统实现

(一)My2048类

这个类的功能是利用Swing技术绘制2048图形界面,实例化每个随机生成的数据块,利用事件监听机制分别实现用户上移,下移,左移,右移时对应的2048界面的操作,游戏运行时出现2048或者不能移动时,利用对某些数据块赋值,实现游戏结束时可能会出现的结果(GAMEOVER或YOU WIN)。大致完成2048游戏的主要功能。

 
package my2048;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.*;

@SuppressWarnings("serial")
public class My2048 extends JFrame implements KeyListener {

	Block[] block;
	JPanel panel;
	boolean numFlag;
	int moveFlag;

	public My2048() {

		numFlag = true;
		moveFlag = 0;
		block = new Block[16];
		setTitle("2048");
		setSize(400, 400);
		setLocation(500, 200);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		panel = (JPanel) getContentPane();
		panel.setLayout(new GridLayout(4, 4, 5, 5));
		addBlock();
		for (int i = 0; i < 2; i++)
			appearBlock();
		this.addKeyListener(this);

		this.setVisible(true);
	}

	public void addBlock() {
		for (int i = 0; i < 16; i++) {
			block[i] = new Block();
			block[i].setHorizontalAlignment(JLabel.CENTER);
			// 不透明
			block[i].setOpaque(true);
			panel.add(block[i]);
		}
	}

	public void appearBlock() {
	while(numFlag) {
			int index = (int) (Math.random() * 16);
			if (block[index].getValue() == 0) {
				if (Math.random() < 0.5)
					block[index].setValue(2);
				else
					block[index].setValue(4);
				break;
			}
		}

	}

	public void judgeAppear() {
		int sum = 0;
		for (int i = 0; i < 16; i++) {
			if (block[i].getValue() != 0)
				sum++;
		}
		if (sum == 16)
			numFlag = false;

	}

	public void upBlock() {

		for (int i = 12; i < 16; i++) {
			int index = i;
			for (int j = i - 4; j >= i - 12; j -= 4) {
				int valueI = block[index].getValue(), valueJ = block[j]
						.getValue();
				if (valueJ == 0) {
					block[index].setValue(0);
					block[j].setValue(valueI);
				} else {
					if (valueI == valueJ) {
						block[index].setValue(0);
						block[j].setValue(valueI + valueJ);
						if (valueI + valueJ == 4096)
							win();
						numFlag = true;
						moveFlag = 0;
					} else if (numFlag == false)
						moveFlag += 1;
				}
				index = j;
			}
		}

	}

	public void downBlock() {

		for (int i = 0; i < 4; i++) {
			int index = i;
			for (int j = i + 4; j <= i + 12; j += 4) {
				int valueI = block[index].getValue(), valueJ = block[j]
						.getValue();
				if (valueJ == 0) {
					block[index].setValue(0);
					block[j].setValue(valueI);
				} else {
					if (valueI == valueJ) {
						block[index].setValue(0);
						block[j].setValue(valueI + valueJ);
						if (valueI + valueJ == 4096)
							win();
						numFlag = true;
						moveFlag = 0;
					} else if (numFlag == false)
						moveFlag += 1;
				}
				index = j;
			}
		}

	}

	public void rightBlock() {

		for (int i = 0; i <= 12; i += 4) {
			int index = i;
			for (int j = i + 1; j <= i + 3; j++) {
				int valueI = block[index].getValue(), valueJ = block[j]
						.getValue();
				if (valueJ == 0) {
					block[index].setValue(0);
					block[j].setValue(valueI);
				} else {
					if (valueI == valueJ) {
						block[index].setValue(0);
						block[j].setValue(valueI + valueJ);
						if (valueI + valueJ == 4096)
							win();
						numFlag = true;
						moveFlag = 0;
					} else if (numFlag == false)
						moveFlag += 1;
				}
				index = j;
			}
		}

	}

	public void leftBlock() {

		for (int i = 3; i <= 15; i += 4) {
			int index = i;
			for (int j = i - 1; j >= i - 3; j--) {
				int valueI = block[index].getValue(), valueJ = block[j]
						.getValue();
				if (valueJ == 0) {
					block[index].setValue(0);
					block[j].setValue(valueI);
				} else {
					if (valueI == valueJ) {
						block[index].setValue(0);
						block[j].setValue(valueI + valueJ);
						if (valueI + valueJ == 4096)
							win();
						numFlag = true;
						moveFlag = 0;
					} else if (numFlag == false)
						moveFlag += 1;
				}
				index = j;
			}
		}

	}

	@Override
	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_UP:
			upBlock();
			judgeAppear();
			appearBlock();
			over();
			break;
		case KeyEvent.VK_DOWN:
			downBlock();
			judgeAppear();
			appearBlock();
			over();
			break;
		case KeyEvent.VK_LEFT:
			leftBlock();
			judgeAppear();
			appearBlock();
			over();
			break;
		case KeyEvent.VK_RIGHT:
			rightBlock();
			judgeAppear();
			appearBlock();
			over();
			break;
		}

	}

	public void over() {
		if (!numFlag && moveFlag >= 36) {
			block[4].setText("G");
			block[5].setText("A");
			block[6].setText("M");
			block[7].setText("E");
			block[8].setText("O");
			block[9].setText("V");
			block[10].setText("E");
			block[11].setText("R");
			
			block[11].addMouseListener(new MouseAdapter() {
				@Override
				public void mousePressed(MouseEvent e) {
					reStart();
				}
			});
		}
	}
    
	public void win() {
		
		block[0].setText("Y");
		block[1].setText("O");
		block[2].setText("U");
		block[13].setText("W");
		block[14].setText("I");
		block[15].setText("N");
		
		block[15].addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {
				reStart();
			}
		});

	}
    public void reStart(){
    	numFlag=true;
		moveFlag=0;
		for(int i=0;i<16;i++)
			block[i].setValue(0);
    	for (int i = 0; i < 2; i++)
			appearBlock();
    }
	@Override
	public void keyTyped(KeyEvent e) {

	}

	@Override
	public void keyReleased(KeyEvent e) {

	}

	public static void main(String args[]) {
		try {
			UIManager
					.setLookAndFeel("org.jvnet.substance.skin.SubstanceRavenGraphiteLookAndFeel");
		} catch (ClassNotFoundException | InstantiationException
				| IllegalAccessException | UnsupportedLookAndFeelException e) {
			
			e.printStackTrace();
		}
		JFrame.setDefaultLookAndFeelDecorated(true);
		new My2048();
	}

}

 

(二)Block类

    这个类的主要功能是设置2048界面中值为0的数据块的背景颜色,数字的字体,以及值不为0的数字块的背景颜色。主要用到setBackground()方法和if—else if。。。else条件语句。

package my2048;

import javax.swing.*;
import java.awt.*;

@SuppressWarnings("serial")
public class Block extends JLabel {
	private int value;

	public Block() {
		value = 0;
		setFont(new Font("font", Font.PLAIN, 40));
		setBackground(Color.gray);

	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
		String text = String.valueOf(value);
		if (value != 0)
			setText(text);
		else
			setText("");
		setColor();
	}

	public void setColor() {
		if (this.value == 0)
			setBackground(Color.gray);
		else if (this.value == 2)
			setBackground(new Color(238, 228, 218));
		else if (this.value == 4)
			setBackground(new Color(238, 224, 198));
		else if (this.value == 8)
			setBackground(new Color(243, 177, 116));
		else if (this.value == 16)
			setBackground(new Color(243, 177, 116));
		else if (this.value == 32)
			setBackground(new Color(248, 149, 90));
		else if (this.value == 64)
			setBackground(new Color(249, 94, 50));
		else if (this.value == 128)
			setBackground(new Color(239, 207, 108));
		else if (this.value == 256)
			setBackground(new Color(239, 207, 99));
		else if (this.value == 512)
			setBackground(new Color(239, 203, 82));
		else if (this.value == 1024)
			setBackground(new Color(239, 199, 57));
		else if (this.value == 2048)
			setBackground(new Color(239, 195, 41));
		else if (this.value == 4096)
			setBackground(new Color(255, 60, 57));
	}
}


五、结果测试

(一)运行环境

运行环境:windows7。

开发工具:Eclipse

(二)运行结果



 

六、性能分析

性能测试工具 :JDK自带的 Visualvm插件

(一)CPU


(二)堆


(三)类


(四)线程


    七、心得体会

    经过对程序反复调试以及不断完善,基本能实现2048游戏的功能,例如,用户每次可以选择上、下、左、右其中一个方向去滑动,每滑动一次,大部分的数字方块都会往滑动的方向靠拢,同时在空白的地方随机出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。随机出现的数字方块不是2就是4,当用户凑出2048是就胜利,并且会出现YOU WIN 字样,当各个方向都不能滑动时,游戏失败,界面会出现GAMEOVER字样。2048的界面,一开始整体16个方格有14个都是灰色的(即是说有14个空的数据块),当用户滑动出现数字之后就会改变颜色。程序的不足之处是,每滑动一次,并不是所有的数字方块都会往滑动的方向靠拢。这点以后在程序中的上下左右滑动方法中加以改进。

    通过对该游戏的设计,我对Java程序设计知识有了更进一步的认识;并且通过上机实践提高了我的动手能力。加深了我对Swing技术的理解,以及对事件监听机制的掌握。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值