`

JAVA模拟2048

    博客分类:
  • Java
阅读更多

非常感谢c87094279的提醒 ,之前在键盘监听器中忘记将是否可以生成新的元素的标记置0了,所以在用键盘操作的时候,没有可移动的方块时会冒出新的方块。现在已经改进了,只需在keyReleased方法中加上count=0;

 

 

 

最近学习了文件的保存,所以做了个小游戏,来实现简单的数据保存.

2048最近很火,所以选择了它.

 

先放运行效果图(界面没做什么美化)


 

 


 

 

重点来了:

简介:

1.四个方向键可使那一排(列)数字靠在同一个方向,遇到相同的自动相加.

 

2.计算步数以及分数,每一步获得的分数为两个方块合并时候生成的数字

3.随着数字改变颜色

4.当所有元素都在同一个方向时,按该方向按钮不会冒出新的元素

5.拼出2048后弹出提示

6.加入撤销功能

7.结束游戏又立即开始新游戏

 

8.可以保存进度,可以继续游戏

9.增加键盘功能

 

10.每次退出游戏自动保存数据,修复每次游戏自动读取上次保存的数据

 

实现方法:

1.用4*4的JButton数组(方便重置数字与背景颜色),用4*4int数组保存数组并btn.setText();

2.首先生成6个随机数,4个作为两个方块的xy轴,2个作为初始数字.

3.每点击一下方向则将相邻的相同数字相加,并将非0方块靠至该方向(写了很多判断)

 

4.每次点击按钮都判断是否能继续下一步,不能下一步则弹出结束游戏对话.

5.遍历数字时顺便设置颜色

6.当发生数字合并或者方块移动时,令count=1;否则count=0;只有count=1时才能生成新的数字

7.用S保存当前最大的数字,一旦达到2048,弹出提示.

8.用一个中间数组保存(将这些数据,包括数组,分数,最大数字变成对象,用一个动态数组保存对象.撤销一步则移除一个.)

9.用fileinputstream和fileoutputstream保存最后一次记录 ,ObjectOutputStream保存操作步骤

10.键盘监听器需要窗体上没有焦点,所有的JButton 都必须设置为不可成为焦点.setFocusable(false);

11.复合键设置了几个中间变量存储当前该键的状态,程序中实现了ctrl+z撤销 ctrl+s 保存.主要是要解决ctrl+s 与s 不能冲突.

12.每次自动保存进度到planAuto.dat,手动保存的保存到plan.dat.这样就避免了程序设计的缺陷(之前每次进入游戏都会自动回到上次保存的进度)

 

13.为减少数据保存的空间占用,只保存最近5个每一步的操作记录,所以恢复记录后只能撤消之前的步骤最多5次.

 

 

遇到的问题:

 


程序用到的知识都很基础,在这里只谈一下心得:

1.创建了4*4的JButton,用来显示数字和背景颜色.(JLabel也有setBackGround的方法,不过试了一下看不到效果,所以就改用JButton了.)然后创建了四个方向键来控制游戏.用JLabel显示得分score,步数status,最大数字S等信息,生成6个随机数,4个作为两个方块的xy轴,2个作为初始数字.

2.在ActionListener监听器类里面,我需要确定按下了哪一个方向键,进行判断之后进行相应操作,先调用setX方法(X表示任意方向),把相邻的相同加起来并且遇到0就自动填充过去.并刷新4*4Jbutton的显示.然后生成下一个随机位置和随机数.

3.在监听器增加判断,如果已经不能游戏了,就不能再生成随机数了,并弹出提示,如果最大数字S达到2048也要弹出提示

4.为了更好的心情舒畅的玩这个游戏,撤销功能是必须的,万一不小心按错了可能就输掉了,所以我考虑加入撤销功能.原打算用int[n][4][4]来保存,后来决定先把每一次int[4][4]变成对象再加入到ArrayList里面.点击撤销之后,先删除最新加进去的对象,再取出上一次加进去的对象.并将对象undo.data数组赋值给Game.data.(S,score也是一样)

             在这里就遇到了一个问题,我加进arraylist里面的时候直接用undo.data=Game.data.再add(undo);

             结果取出来之后每次都是最后一次加进去的data数组.这里卡住了很久,后来才想通.a=b;等于是把b的              地址赋值给了a;所以b指向的是a,而不是a的值.所以用两个for循环来进行赋值.

                Undo undo = new Undo();
		for(int i=0;i<4;i++){
			for(int j=0;j<4;j++){
				undo.data[i][j]=Game.data[i][j];
			}
		}
		MyListener.undoAl.add(undo);
if(source.equals("撤销")){
			if(undoAl.size()>1){
				
				undoAl.remove(undoAl.size()-1);
				status--;
				if(score1.size()>1){
					score1.remove(score1.size()-1);
					score=score1.get(score1.size()-1);
					System.out.println(score1.size());
					if(S1.size()>0){
						S=S1.remove(S1.size()-1);
						System.out.println(S1.size());
//这里又有疑问了,S1的size方法返回的数字是不重复的数据的个数,如果我加了很多个16进去,他不断的remove16,但是S1.size()确只有一次改变
					}
					
				}
				
				temp=(Undo)undoAl.get(undoAl.size()-1);


				for(int i=0;i<4;i++){
					for(int j=0;j<4;j++){
						Game.data[i][j]=temp.data

[i][j];
					}
				}

				show();
			}
		}

 

 

 5这个是这次的重点

是为了巩固知识才写了这个小游戏,巩固文件保存的知识,因为游戏本身的逻辑是很简单的.

一开始用FileoutputStream保存S,score,status,和data[4][4]中的每一个元素,读取的时候也按顺序读进来.但是这样子读进来的数据会影响到撤销功能,读了数据之后是没办法撤销的(读进来的时候必须先清空ArrayList,又要把读进来的数据加到ArrayList.之前的记录没了).又考虑到S,score都用了单独的ArrayList,后来就直接把data,S,score都写成undo的属性,以对象形式保存在文件里面,最多保存6个,这样就可以实现最多5次撤销.要是用FileOutputStream太麻烦.直接用ObjectOutputStream将ArrayList的最后6项写出去.

 

6.最后,加入了键盘功能.ctrl+s 可以保存,ctrl+z可以撤销 wasd 小键盘2468以及 方向键均可控制方向.,加了WindowListener 在关闭窗口时自动保存数据,下次进入游戏就可以自动继续了.

 

统计了一下保存的数据占用的空间,最多占用844字节

 

 /*

  * 步数 字节数

* 0 76+128=204

* 1 332

* 2 460

* 3 588

* 4 716

* >=5 844

*/

 

 

Config类是便于打包成jar后图片资源能正常显示

Game为主类,程序的入口,初始化窗口和游戏数据

MyListener为监听器类,实现了动作,键盘,窗口监听器

planSave为保存文件的类

Undo为保存需要撤销的数据的类


 

  • 大小: 11.4 KB
  • 大小: 11.9 KB
  • 2048.zip (113.9 KB)
  • 描述: 源代码参考
  • 下载次数: 132
17
3
分享到:
评论
5 楼 肆无忌惮_ 2014-06-07  
c87094279 写道
正常情况下,按方向键没有可以移动的方块时,不会出现的新的方块。

谢谢提醒,已经修改了一下。
4 楼 c87094279 2014-06-06  
正常情况下,按方向键没有可以移动的方块时,不会出现的新的方块。
3 楼 suixing_001 2014-06-06  
目测会火啊     
2 楼 人生难得糊涂 2014-06-05  
牛逼牛逼!
1 楼 金R在奋斗着 2014-06-05  
    目测是会火的   先占个沙发 哈哈哈哈 ~~~~~~  顶一个

相关推荐

Global site tag (gtag.js) - Google Analytics