Java版2048
功能要求:2048的基本界面,能够实现2048的游戏功能。
总思路:两个类:Game和GameListener。
Game负责界面的实现和paint方法的重写
GameListener负责实现键盘和鼠标事件的处理。移动方法,相加方法,输赢判断和随机数的出现都要在键盘监听的方法中实现。
实现分析:要实现2048游戏,首先需要考虑2048都有些什么?
界面实现:
2048的游戏界面很简单,就是一些方格和数字。要实现这样的界面,我们可以考虑一下使用Java的绘图功能。具体来说就是使用JFrame类提供的Graphics对象进行绘图。2048界面由一个大的矩形背景和包含数字的许多小方块组成。Graphics对象的绘制矩形的方法就能实现背景和小方格的绘制。小方格内的数字则可以使用graphics的drawString方法来绘制。只需要在绘制的时候注意一下颜色就好。界面实现要拥到的类主要是JFrame类。
基本界面实现代码,不过是一些按钮之类的,没什么好说的。
private void initUI() {
setTitle("2048");
setDefaultCloseOperation(3);
setSize(600, 700);
setLocationRelativeTo(null);
this.setLayout(null);
//添加分数
jl2 = new JLabel("分数:0");
jl2.setFont(new Font("黑体", Font.BOLD, 30));
jl2.setBounds(20, 30, 200, 50);
this.add(jl2);
//添加开始按钮
ImageIcon start=new ImageIcon("res/start.png");//开始游戏图标,随意替换就好
startJB=new JButton(start);
startJB.setBounds(280, 40, 120, 30);
startJB.setFocusable(false);
startJB.setBorderPainted(false);//设置按钮的边框为空
startJB.setFocusPainted(false);
startJB.setContentAreaFilled(false);//设置按钮的边框内填充颜色 //添加退一步按钮
ImageIcon back=new ImageIcon("res/backicon.png");//游戏结束图标,随意替换就好
backJB=new JButton(back);
backJB.setBounds(430, 40, 120, 30);
backJB.setFocusable(false);
backJB.setBorderPainted(false);
backJB.setFocusPainted(false);
backJB.setContentAreaFilled(false); this.add(startJB);
this.add(backJB);
setVisible(true);
GameListener gl = new GameListener(this, arry, jl2,startJB,backJB);
addKeyListener(gl);
startJB.addActionListener(gl);
backJB.addActionListener(gl);
}
方格和数字的绘制:
方格和数字的绘制同样是使用JFrame的画布对象的绘制矩形的方法实现。
public void buffPaint(Graphics g) {
Image image = createImage(600, 600);
Graphics g2 = image.getGraphics();
g2.setColor(Color.LIGHT_GRAY);
Graphics2D g2d = (Graphics2D) g2;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.fillRoundRect(0, 0, Draw2048.RD, Draw2048.RD, 20, 20);
g2.setColor(Color.GRAY);
for (int r = 0; r < arry.length; r++) {
for (int c = 0; c < arry[r].length; c++) {
g2.fillRect(20 + c * (Draw2048.D + Draw2048.space), 20 + r
* (Draw2048.D + Draw2048.space), Draw2048.D, Draw2048.D);
}
}
for (int r = 0; r < arry.length; r++) {
for (int c = 0; c < arry[r].length; c++) {
if (arry[r][c] != 0) {
g2.setColor(255, 250, 240);
g2.fillRect(20 + c * (Draw2048.D + Draw2048.space), 20 + r
* (Draw2048.D + Draw2048.space), Draw2048.D,
Draw2048.D);
g2.setColor(new Color(0, 191, 255));
g2.setFont(new Font("楷体", Font.BOLD, Draw2048.FSIZE));
g2.drawString(arry[r][c] + "", 50 + c
* (Draw2048.D + Draw2048.space), 90 + r
* (Draw2048.D + Draw2048.space));
}
}
}
g.drawImage(image, 50, 150, this);
}
Draw2048是一个接口,里面定义了关于方格绘制的相关常量,D方格边长,space方格间间隔。RD背景大矩形的边长。使用接口的好处就是使得界面的更改(如改成5*5的格子)可以更加方便的实现,提高程序的扩展性。另外界面需要不断的更新,所以要调用paint方法不断的重绘。如果直接把这里的绘制写在paint方法中,不断的重绘会使得界面一直在闪烁。这里的解决方案就是使用图片缓冲,先在图片中绘制好,在把图片一次性绘制出来,这样就不会出现界面的闪烁问题了。
移动实现:
要想让方格移动起来,可以考虑的方法就是使用画板的重绘。方格内的数字则使用一个二维数组来保存。每次移动就让数组的值发生变化就行,然后根据数组的值把数据绘制到界面上。当然玩游戏时总不能靠意念操控,我们需要有输入设备,也就是键盘。所以需要给界面加上键盘监听。当用户按下不同的键则实现不同的移动算法。值得注意的是,在监听类中编写相应的移动算法的时候要理清循环的使用和结束(尤其是break语句的使用),否则会出现各种各样的bug。移动实现是需要用到keyListener类。
下面是向上移动的实现,其他方向的移动都差不多,自己琢磨一下就好:
//向上移动的算法
for (int r = 0; r < arry.length; r++)
for (int c = 0; c < arry[r].length; c++) {
if (arry[r][c] > max)//找出数组最大值,用于判断玩家的方块是否达到2048
max = arry[r][c];
if (arry[r][c] == 0) {
for (int r1 = r + 1; r1 < arry[c].length; r1++)
if (arry[r1][c] != 0) {
arry[r][c] = arry[r1][c];
arry[r1][c] = 0;
count++;//判断是否发生移动,并且作为输赢判断的标准之一
break;
}
}
}
通过双层循环,循环每一个值,如果它为0,则可以往上移动。遍历该值所在列,找到第一个不为0的值,移动这个值(即交换两个数的值)。移动后退出内层循环,继续遍历下一个值。
数字的相加:
使用独立的算法遍历数组,在移动方向上的相邻数两个相加,然后一个置为0。这里的算法实现和移动的算法十分相像,需要注意的地方同样也是break和循环的使用。还有一个要注意的就是:数字的相加要放在数字移动之前来完成,否则会出现移动后的数字空格。
//向左的相加算法
for (int r = 0; r < arry.length; r++)
for (int c = 0; c < arry[r].length; c++)
if (arry[r][c] != 0)
for (int c1 = c + 1; c1 < arry[r].length; c1++)
if (arry[r][c] == arry[r][c1]) {
arry[r][c] *= 2;
score += arry[r][c];
arry[r][c1] = 0;
count++;//判断是否发生相加,并作为输赢判断条件之一。
break;
} else if (arry[r][c1] != 0) {
break;
}
同样是遍历数组的每一个值,如果这个值不为0,则找所在行的相邻的相同的值相加,结束最内层循环。如果相邻的两个值不同,也结束最内层循环。两个break语句的使用,避免了数字之间的跳跃相加。
输赢的判断:
2048的赢的规则是,相加数字出现2048,所以只需要判断数组中是否有一个数字等于2048就行,如果有,就输出相应的获胜信息。
2048的输的规则是,界面已经满(数组已满,且无可移动,相加的数字)。个人的判断方法是全局变量count加上判断数组是否已满。count如果等于0,则表示无法移动和相加,配合数组已满的条件就能判断玩家已经输了。
随机数字的出现:
随机数字出现的条件是发生移动或者相加,所以判断然让使用count。条件成立则调用相应算法实现。
Java版2048的更多相关文章
- 从零開始开发Android版2048 (一)初始化界面
自学Android一个月多了,一直在工作之余零零散散地看一些东西.感觉经常使用的东西都有些了解了,可是一開始写代码总会出各种奇葩的问题.感觉还是代码写得太少.这样继续杂乱地学习下去进度也太慢了,并且学 ...
- 从零開始开发Android版2048 (三)逻辑推断
近期工作比較忙,所以更新的慢了一点,今天的主要内容是关于Android版2048的逻辑推断,经过本篇的解说,基本上完毕了这个游戏的主体部分. 首先还是看一下,我在实现2048时用到的一些存储的数据结构 ...
- 从零開始开发Android版2048 (二)获取手势信息
今天是尝试開始Android版2048小游戏的第二天.在今天,我主要学习了怎样获取用户在屏幕滑动的手势,以及对布局进行了一些小小的完好. 获取用户操作的手势(比方向左滑.向右滑等)主要用到了Gestu ...
- JAVA版StarDict星际译王简单实现
由胡正开发的星际译王是Linux平台上很强大的一个开源的翻译软件(也有Windows版本的)支持多种词库.多种语言版本.尤其词库设计比较合理.之前看到一篇博文<星际译王词库应用-自制英汉词典&g ...
- jQuery实践-网页版2048小游戏
▓▓▓▓▓▓ 大致介绍 看了一个实现网页版2048小游戏的视频,觉得能做出自己以前喜欢玩的小游戏很有意思便自己动手试了试,真正的验证了这句话-不要以为你以为的就是你以为的,看视频时觉得看懂了,会写了, ...
- ArcGIS Server 10 Java 版的Rest服务手动配置方法
Java版的Manager中发布的服务默认只发布了该服务的SOAP接口,而REST接口需要用户在信息服务器,如Tomcat. Apache.WebLogic等中手工配置.由于在Java版的Server ...
- PetaPojo —— JAVA版的PetaPoco
背景 由于工作的一些原因,需要从C#转成JAVA.之前PetaPoco用得真是非常舒服,在学习JAVA的过程中熟悉了一下JAVA的数据组件: MyBatis 非常流行,代码生成也很成熟,性能也很好.但 ...
- 【转载】java版打字练习软件
网上找到一个java版的打字的游戏 import java.applet.Applet; import java.applet.AudioClip; import java.awt.Dimension ...
- 微博地址url(id)与mid的相互转换 Java版
原理: 新浪微博的URL都是如:http://weibo.com/2480531040/z8ElgBLeQ这样三部分. 第一部分(绿色部分)为新浪微博的域名,第二部分(红色部分)为博主Uid,第三部分 ...
随机推荐
- Log4net使用详细说明
1.概述 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.本文主要是介绍如何在Visual S ...
- LCA(最近公共祖先)之倍增算法
概述 对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. 如图,3和5的最近公共祖先是1,5和2的最近公共祖先是4 在本篇中我们先介 ...
- 2、jQuery的一些静态方法
上次粗略说了jQuery的整体结构,这次挑一些静态方法先说一下吧 一.noConflict函数 这个函数是个比较有意思的函数,基本上很少用到,之所以说他是因为这个函数在最下面,太显眼了,先把他解决掉. ...
- 【C++】bazel的使用
bazel的使用 bazel是google开源的构建工具,可以支持多种语言的构建.这里来尝试一下如何在C++项目中使用bazel构建. 安装就不介绍了,在官网很详细,输入bazel --help: U ...
- 使用document.execCommand复制内容至剪贴板
API https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand 兼容性 http://caniuse.com/#se ...
- Jmeter_打印当前时间戳&打印偏移时间戳
Jmeter中提供了一种函数,可以打印时间戳,如下图 年: yyyy 月:MM 日:dd 时: HH 分: mm 秒:ss 关于时间戳的格式,可以自由组合定义,这里我写成这样 yyyy-MM-dd H ...
- JAX-RS和Jersey
一:JAX-RS JAX-RS是JAVA EE6 引入的一个新技术. JAX-RS即Java API for RESTful Web Services,是一个Java 编程语言的应用程序接口,支持按照 ...
- CF341C. Iahub and Permutations [DP 排列]
http://codeforces.com/contest/341/problem/C 题意: 有一个长度为n的排列a,其中有一些位置被替换成了-1.你需要尝试恢复这个排列,将-1替换回数字.求有多少 ...
- [Python爬虫] Selenium爬取新浪微博客户端用户信息、热点话题及评论 (上)
转载自:http://blog.csdn.net/eastmount/article/details/51231852 一. 文章介绍 源码下载地址:http://download.csdn.net/ ...
- Selenium_WebDriver_控制浏览器
版权声明:本文为博主原创文章,转载请注明出处. 浏览器环境: ①GoogleChrome:60 ②chromedriver:2.30: 访问 操作 方法 示例 访问页面 void get(java. ...