前言

2014年Gabriele Cirulli利用周末的时间写2048这个游戏的程序,仅仅只是好玩而已。他想用一种不同的视觉展现效果和更快速的动画来创造属于自己的游戏版本。

游戏是用java语言实现,采用了swing技术进行了界面化处理,设计思路用了面向对象思想。

主要需求

每次控制所有方块向同一个方向运动,两个相同数字的方块撞在一起之后合并成为他们的和,每次操作之后会在空白的方格处随机生成一个2或者4,最终得到一个“2048”的方块就算胜利了。如果16个格子全部填满并且相邻的格子都不相同也就是无法移动的话,那么游戏就会结束。

主要设计

1、游戏面板生成显示

2、方块设计

3、键盘监听,方向键控制数字移动

4、数字移动逻辑算法处理

5、数字累加到2048,游戏胜利

功能截图

游戏开始

移动效果

代码实现

界面布局类


public class Game2048View implements ActionListener{Block[] blocks;     //方块JPanel myJPanel;    //主面板JPanel jp1,jp2;        //子面板
//  int moveFlag;               // 用于累计移动的次数boolean numFlag;        // 用于判断是否还能加入新的数字JLabel scroeValue;     //显示分数public Game2048View(JFrame myJFrame){blocks=new Block[16];
//      moveFlag=0;numFlag=true;this.myJPanel=(JPanel)myJFrame.getContentPane();///获取内容面板setJp1();myJPanel.add(jp1,BorderLayout.NORTH);setJp2();myJPanel.add(jp2, BorderLayout.CENTER);myJFrame.addKeyListener(new Game2048Logic(this,myJFrame,blocks,numFlag,scroeValue));}public void addc(JPanel jp1,Component component, GridBagConstraints gbc,int gridwidth,int gridheight, int weightx,int weighty,int gridx,int gridy) {//此方法用来添加控件到容器中gbc.gridwidth=gridwidth;     //该方法是设置组件水平所占用的格子数,如果为0,就说明该组件是该行的最后一个gbc.gridheight=gridheight;        //该方法是设置组件垂直所占用的格子数gbc.weightx=weightx;                //该方法设置组件水平的拉伸幅度,如果为0就说明不拉伸,不为0就随着窗口增大进行拉伸,0到1之间gbc.weighty=weighty;              //该方法设置组件垂直的拉伸幅度,如果为0就说明不拉伸,不为0就随着窗口增大进行拉伸,0到1之间gbc.gridx=gridx;gbc.gridy=gridy;gbc.fill=GridBagConstraints.BOTH;jp1.add(component,gbc);}public void setJp1() {GridBagLayout gbLayout=new GridBagLayout();jp1=new JPanel(gbLayout);JPanel Jtitle=new JPanel();       JLabel title=new JLabel("2048");title.setFont(new Font("font", Font.PLAIN, 45));//类型、风格、大小title.setHorizontalAlignment(JLabel.LEFT);//jLabel的文本左右对齐属性设置方法,对齐方式Jtitle.add(title);jp1.add(Jtitle);JPanel Jscroe=new JPanel(new GridLayout(2, 1));//new GridLayout(2, 1)为网格布局样式。其中的参数“2”“1”分别为网格的“行数”和“列数”。JLabel scroe=new JLabel("Scroe");scroe.setFont(new Font("font", Font.PLAIN, 16));scroe.setHorizontalAlignment(JLabel.CENTER);scroeValue=new JLabel("0");scroeValue.setFont(new Font("font", Font.PLAIN, 16));scroeValue.setHorizontalAlignment(JLabel.CENTER);Jscroe.add(scroe);Jscroe.add(scroeValue);jp1.add(Jscroe);JPanel Jnoite=new JPanel();JLabel noite=new JLabel("方向键移动数字累加至2048");noite.setFont(new Font("font", Font.PLAIN, 14));noite.setHorizontalAlignment(JLabel.LEFT);Jnoite.add(noite);jp1.add(Jnoite);JPanel JnewGame=new JPanel();JButton newGame=new JButton("New Game");newGame.setHorizontalAlignment(JButton.CENTER);newGame.addActionListener(this);JnewGame.add(newGame);jp1.add(JnewGame);GridBagConstraints gbc=new GridBagConstraints();     addc(jp1, Jtitle, gbc, 3, 2, 60, 60, 0, 0);addc(jp1, Jscroe, gbc, 0, 2, 40, 60, 3, 0);addc(jp1, Jnoite, gbc, 3, 1, 60, 40, 0, 2);addc(jp1, JnewGame, gbc, 0, 1, 40, 40, 3, 2);}public void setJp2() {addBlock();initBlock();initBlock();}/*** 添加方块*/public void addBlock(){jp2=new JPanel();/** setLayout是对当前组件设置为流式布局.组件在窗体中从左到右依次排列 如果排到行的末尾 换行排列 * GridLayout(int rows, int cols, int hgap, int vgap)创建具有指定行数和列数的网格布局。rows - 该 rows 具有表示任意行数的值cols - 该 cols 具有表示任意列数的值hgap - 水平间距vgap - 垂直间距*/jp2.setLayout(new GridLayout(4, 4, 5, 5));for (int i = 0; i < blocks.length; i++) {blocks[i]=new Block();blocks[i].setHorizontalAlignment(JLabel.CENTER);// 不透明的标签blocks[i].setOpaque(true);// 设置控件不透明jp2.add(blocks[i]);}}/*** 初始化方块*/public void initBlock(){while (numFlag) {int index=(int) (Math.random()*16);if (blocks[index].getText().trim().equals("")) {blocks[index].setValue("2");break;} else {continue;}   }}/*** 获得第一个子面板的高度*/public int getMyJPanelHeidth() {return jp1.getSize().height;}@Overridepublic void actionPerformed(ActionEvent e) {// TODO 自动生成的方法存根newGame();}/*** 重新开始游戏*/    public void newGame() {for (int i = 0; i < blocks.length; i++) {          blocks[i].setValue("");           }numFlag=true;scroeValue.setText("0");initBlock();initBlock();}
}

业务逻辑类

public class Game2048Logic implements KeyListener{Block[] blocks;boolean numFlag;        // 用于判断是否还能加入新的数字JLabel scroeValue;     //显示分数int blocksarr[]=new int[4];      //保存一行/列方块中的数值JFrame myJFrame;int scroe=0;Game2048View game2048View;//初始化键盘事件public Game2048Logic(Game2048View game2048View, JFrame myJFrame, Block[] blocks,boolean numFlag,JLabel scroeValue) {// TODO 自动生成的构造函数存根this.blocks=blocks;this.numFlag=numFlag;this.scroeValue=scroeValue;this.myJFrame=myJFrame;this.game2048View=game2048View;}//初始化按钮事件public Game2048Logic() {// TODO 自动生成的构造函数存根}public boolean getnumFlag() {return numFlag;}@Overridepublic void keyPressed(KeyEvent e) {// TODO 自动生成的方法存根int[] blocksarr=getBlock();switch (e.getKeyCode()) {case KeyEvent.VK_UP:colBlock("up");hasEmptyBlock();if (Arrays.equals(blocksarr, getBlock())) {} else {refershBlock();}          isGameFail("up");break;case KeyEvent.VK_DOWN:colBlock("down");hasEmptyBlock();if (Arrays.equals(blocksarr, getBlock())) {} else {refershBlock();}   isGameFail("down");break;case KeyEvent.VK_LEFT:rowBlock("left");hasEmptyBlock();if (Arrays.equals(blocksarr, getBlock())) {} else {refershBlock();} isGameFail("left");break;case KeyEvent.VK_RIGHT:rowBlock("right");hasEmptyBlock();if (Arrays.equals(blocksarr, getBlock())) {} else {refershBlock();}   isGameFail("right");break;default:break;}scroeValue.setText(""+scroe);win();}/*** 垂直方向方块移动处理函数*/public void colBlock(String direction){int tmp1=0;int tmp2=0;int index=0;for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (blocks[tmp1].getText().trim().equals("")) {tmp1+=4;if (tmp1>=16) {break;} else {continue;}} else {blocksarr[index]=Integer.parseInt(blocks[tmp1].getText().trim());index+=1;tmp1+=4;if (tmp1>=16 || index>=4) {break;} else {continue;}}}switch (direction) {case "up":blocksarr=handleBlocksarr(blocksarr);break;case "down":blocksarr=reverseArr(handleBlocksarr(reverseArr(blocksarr)));break;default:break;}for (int n = 0; n < blocksarr.length; n++) {if (blocksarr[n]==0) {blocks[tmp2].setText("");blocks[tmp2].setBackground(Color.gray);} else {blocks[tmp2].setValue(blocksarr[n]+"");}tmp2+=4;}            index=0;tmp1=i+1;tmp2=i+1;//清空数组blockarrfor (int n = 0; n < blocksarr.length; n++) {blocksarr[n]=0;             }}}/*** 水平方向方块移动处理函数*/public void rowBlock(String direction) {int tmp1=0;int tmp2=0;int index=0;for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (blocks[tmp1].getText().trim().equals("")) {tmp1+=1;if (tmp1>=16) {break;} else {continue;}} else {blocksarr[index]=Integer.parseInt(blocks[tmp1].getText().trim());index+=1;tmp1+=1;if (tmp1>=16 || index>=4) {break;} else {continue;}}}switch (direction) {case "left":blocksarr=handleBlocksarr(blocksarr);break;case "right":blocksarr=reverseArr(handleBlocksarr(reverseArr(blocksarr)));break;default:break;}for (int n = 0; n < blocksarr.length; n++) {if (blocksarr[n]==0) {blocks[tmp2].setText("");blocks[tmp2].setBackground(Color.gray);} else {blocks[tmp2].setValue(blocksarr[n]+"");}tmp2+=1;}           index=0;//清空数组blockarrfor (int n = 0; n < blocksarr.length; n++) {blocksarr[n]=0;               }}      }/*** 处理并返回一个数组*/public int[] handleBlocksarr(int[] blocksarr) {int index=0;int[] result=new int[4];for (int i = 0; i < blocksarr.length; i++) {            //排序if (blocksarr[i]!=0) {result[index]=blocksarr[i];index++;} }if (index==0 || index==1) {for (int i = index; i < result.length; i++) {result[i]=0;}} else {for (int i = 0; i < blocksarr.length; i++) {blocksarr[i]=0;}switch (index) {case 2:if (result[0]==result[1]) {blocksarr[0]=result[0]+result[1];scroe+=result[0]*2;} else {blocksarr=result;}              break;case 3:if (result[0]==result[1]) {blocksarr[0]=result[0]+result[1];scroe+=result[0]*2;blocksarr[1]=result[2];} else {if (result[1]==result[2]) {blocksarr[0]=result[0];blocksarr[1]=result[1]+result[2];scroe+=result[1]*2;} else {blocksarr=result;}}break;case 4:if (result[0]==result[1]) {blocksarr[0]=result[0]+result[1];    scroe+=result[0]*2;if (result[2]==result[3]) {blocksarr[1]=result[2]+result[3];scroe+=result[2]*2;} else {blocksarr[1]=result[2];blocksarr[2]=result[3];}} else {if (result[1]==result[2]) {blocksarr[0]=result[0];blocksarr[1]=result[1]+result[2];scroe+=result[1]*2;blocksarr[2]=result[3];} else {blocksarr[0]=result[0];blocksarr[1]=result[1];if (result[2]==result[3]) {blocksarr[2]=result[2]+result[3];scroe+=result[2]*2;} else {blocksarr=result;}}}break;default:break;}result=blocksarr;}      return result;  }/*** 反转数组eg:45000 --> 00054*/public int[] reverseArr(int[] arr) {int[] tmp=new int[arr.length];int index=arr.length-1;for (int i = 0; i < arr.length; i++) {tmp[index]=arr[i];index--;}return tmp;}/*** 刷新方块,添加新出现的2或4*/public void refershBlock(){if (numFlag==false) {}while (numFlag) {int index=(int) (Math.random()*16);    if (blocks[index].getText().trim().equals("")) {if (Math.random()<0.8) {blocks[index].setValue("2");} else {blocks[index].setValue("4");}break;} else {continue;}  }}/*** 判断是否有空的方块*/public void hasEmptyBlock() {for (int i = 0; i < blocks.length; i++) {if (blocks[i].getText().trim().equals("")) {this.numFlag=true;break;} else {this.numFlag=false;}}}/*** 判断游戏是否失败*/public void isGameFail(String direction) {boolean result=true;  //true代表失败 false代表没有失败int tmp=0;if (numFlag == false) { // 表示没有空的方块switch (direction) {case "up":case "down":for (int i = 0; i < 4; i++) {tmp=i*4;for (int j = 0; j < 3; j++) {                     if (blocks[tmp].getText().trim().equals(blocks[tmp+1].getText().trim())) {result = false; //游戏未失败break;} else {tmp++;}}if (result==false) {break;}}break;case "left":case "right":for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {                      if (blocks[tmp].getText().trim().equals(blocks[tmp+4].getText().trim())) {result = false; //游戏未失败break;} else {tmp+=4;if (tmp>=16) {break;} else {continue;}}}tmp=i+1;if (result==false) {break;}}break;default:break;}} else {result=false;}if (result==true) {JOptionPane.showMessageDialog( null , "Game Over",null , JOptionPane.ERROR_MESSAGE) ;game2048View.newGame();} else {}}/*** 判断游戏是否成功,即成功累加至2048*/public void win() {for (int i = 0; i < blocks.length; i++) {if (blocks[i].getText().trim().equals("2048")) {JOptionPane.showMessageDialog( null , "YOU ARE WIN",null , JOptionPane.ERROR_MESSAGE) ;game2048View.newGame();break;} }      }/*** 获得全部方块内容,用于对比*/public int[] getBlock() {int[] blocksarr=new int[16];for (int i = 0; i < blocks.length; i++) {if (blocks[i].getText().trim().equals("")) {blocksarr[i]=0;} else {blocksarr[i]=Integer.parseInt(blocks[i].getText().trim());}         }return blocksarr;}@Overridepublic void keyReleased(KeyEvent e) {// TODO 自动生成的方法存根}@Overridepublic void keyTyped(KeyEvent e) {// TODO 自动生成的方法存根}}

总结

通过此次的《2048游戏》游戏实现,让我对swing的相关知识有了进一步的了解,对java这门语言也有了比以前更深刻的认识。

java的一些基本语法,比如数据类型、运算符、程序流程控制和数组等,理解更加透彻。java最核心的核心就是面向对象思想,对于这一个概念,终于悟到了一些。

源码获取

源码下载地址:传送门------->

点赞,关注博主后,私聊博主免费获取
需要技术指导,写项目程序,等更多服务请联系博主

今天是持续写作的第 14 / 100 天。
可以关注我,点赞我、评论我、收藏我啦。

JAVA 实现《2048游戏》游戏相关推荐

  1. 一文教你用java实现儿时的超级玛丽游戏

    导读:近年来,Java作为一种新的编程语言,以其简单性.可移植性和平台无关性等优点,得到了广泛地应用.J2SE称为Java标准版或Java标准平台.J2SE提供了标准的SDK开发平台.利用该平台可以开 ...

  2. java实现儿时的超级玛丽游戏

    导读:近年来,Java作为一种新的编程语言,以其简单性.可移植性和平台无关性等优点,得到了广泛地应用.J2SE称为Java标准版或Java标准平台.J2SE提供了标准的SDK开发平台.利用该平台可以开 ...

  3. java简单通讯录的实现02person类_用java实现简单的小游戏(你一定玩过)

    用java实现简单的小游戏(你一定玩过) 对于java初学者来说,通过一些学习小游戏来对swing学习以及对java基础的学习是一个好的方法,同时也给学习带来了很多的乐趣,接下来就给大家分享一个jav ...

  4. java实现简单窗体小游戏----球球大作战

    java实现简单窗体小游戏----球球大作战 需求分析 1.分析小球的属性: ​ 坐标.大小.颜色.方向.速度 2.抽象类:Ball ​ 设计类:BallMain-创建窗体 ​ BallJPanel- ...

  5. main java game,playgame 一个JAVA编写的飞行小游戏,有基本完整的 框架,适合初学者参照学习 Other s 其他 238万源代码下载- www.pudn.com...

    文件名称: playgame下载 收藏√  [ 5  4  3  2  1 ] 开发工具: Java 文件大小: 7050 KB 上传时间: 2013-06-06 下载次数: 3 提 供 者: Lyq ...

  6. 简易贪吃蛇小游戏java版_用GUI实现java版贪吃蛇小游戏

    本文实例为大家分享了java版贪吃蛇小游戏的具体代码,供大家参考,具体内容如下 项目结构 新建一个JFrame窗口,作为程序入口 public class GameStart{ public stat ...

  7. [Leedcode][JAVA][第45题][跳跃游戏 II][贪心算法]

    [问题描述][Leedcode][JAVA][第45题][跳跃游戏 II] 输入: [2,3,1,1,4] 输出: 2 解释: 跳到最后一个位置的最小跳跃数是 2.从下标为 0 跳到下标为 1 的位置 ...

  8. java演练 猜奇偶小游戏开发 DB游戏必输的设计

    java演练 猜奇偶小游戏开发 DB游戏必输的设计 阶段一,视频 https://www.ixigua.com/6870390946270446088?logTag=J_BVJOm_LIpQ-hWYY ...

  9. 递归走迷宫java,java递归实现的迷宫游戏

    java递归实现的迷宫游戏 public class Migong { private int gard[][]={  {1,1,1,1,0,1,1,1}, {0,0,0,1,1,1,1,1}, {1 ...

  10. 推箱子游戏的java设计思路_用JAVA实现一个推箱子游戏

    技术应用 TECHNOLOGY AND MARKET Vol. 26,No. 2,2019 用 JAVA 实现一个推箱子游戏 马寅璞1,孔阳坤2 ( 1. 南京信息工程大学计算机软件学院物联网工程 1 ...

最新文章

  1. 如何去除使用inline-block之后的间距(二)?
  2. python 嵌入键值数据库_PupDB 一个用Python编写基于文件的简单键值数据库
  3. 2020-11-30(为什么字符串可以赋值给字符指针变量)
  4. 用C语言编写的简历,一份用C语言写的简历
  5. 开发工具链(国内项目)(持续更)
  6. c语言猜拳游戏思考,这是一个猜拳游戏的程序 大家有更好的解决方法么?
  7. EF批量插入太慢?那是你的姿势不对
  8. Oracle的resetlogs机制浅析
  9. STC15W408读取HX711称重数据串口发送
  10. FD.io VPP利用iperf3进行UDP灌包测试-英特尔X520万兆网卡
  11. li:hover与a:hover的区别
  12. java wait() notify_Java的wait(), notify()和notifyAll()使用小结
  13. 如何压缩jpg图片的大小
  14. 视频教程-cURL实战教程-PHP
  15. excel表自动向下填充
  16. asp.net 下利用DirectoryEntry验证用户及获取域控制器下的用户结构信息
  17. 基于springboot的医院管理系统
  18. 全国哀悼日,我们也把博客灰一下吧
  19. 四象限法推导lm曲线_四象限法分析
  20. 网络安全-破解win10开机密码

热门文章

  1. python3 模块详细解释_详解Python3中的contextvars模块
  2. linux 0.01内核分析与操作系统设计 百度网盘,《Linux 0.01内核分析与操作系统设计——创造你自己的操作系统》...
  3. python修改html,Python爬虫精简步骤 HTML基础
  4. java统计单机次数_java流类,快速统计出字符次数+++
  5. Java虚拟机类加载机制--类加载器详解
  6. Spark2.1.0模型设计与基本架构(下)
  7. kvm初体验之八:调整vm的vcpu, memory, disk大小
  8. 【转】 Git 常用命令详解(二)----不错
  9. SQL中返回刚插入记录的ID
  10. 深入了解mysql 5.5分区功能增强_深入了解MySQL 5.5分区功能增强