java版实现2048游戏功能

本文实例为大家分享了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。条件成立则调用相应算法实现。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java编写迷宫小游戏

    缘起: 去年(大三上学期)比较喜欢写小游戏,于是想试着写个迷宫试一下. 程序效果: 按下空格显示路径: 思考过程: 迷宫由一个一个格子组成,要求从入口到出口只有一条路径. 想了一下各种数据结构,似乎树是比较合适的,从根节点到每一个子节点都只有一条路径.假设入口是根节点,出口是树中某个子节点,那么,从根节点到该子节点的路径肯定是唯一的. 所以如果能构造一棵树把所有的格子都覆盖到,也就能够做出一个迷宫了. 另外还要求树的父节点和子节点必须是界面上相邻的格子. 在界面显示时,父节点和子节点之间共用的边

  • Java制作智能拼图游戏原理及代码

    今天突发奇想,想做一个智能拼图游戏来给哄女友. 需要实现这些功能 第一图片自定义 第二宫格自定义,当然我一开始就想的是3*3 4*4 5*5,没有使用3*5这样的宫格. 第三要实现自动拼图的功能,相信大家知道女人耍游戏都不是很厉害,所以这个自动拼图功能得有. 其他什么暂停.排行就不写了! 现在重点问题出来了 要实现自动拼图功能似乎要求有点高哦!计算机有可不能像人一样只能: 先追究下本质 拼图游戏其实就是排列问题: 排列有这么一个定义:在一个1,2,...,n的排列中,如果一对数的前后位置与大小顺

  • java实现五子棋小游戏

    java实现五子棋小游戏 package Gomoku; import java.awt.Toolkit; import javax.swing.JFrame; public class GomokuFrame extends JFrame { //定义一个操作面板 OperatorPane op=null; public GomokuFrame() { //设置名称 this.setTitle("五子棋"); //设置窗口大小 this.setSize(510,510); //设置窗

  • Java编写掷骰子游戏

    废话不多说了,直接奔主题. **多线程&&观察者模式 题目要求:<掷骰子>窗体小游戏,在该游戏中,玩家初始拥有1000的金钱,每次输入押大还是押小,以及下注金额,随机3个骰子的点数,如果3个骰子的总点数小于等于9,则开小,否则开大,然后判断玩家是否押对,如果未押对则扣除下注金额,如果押对则奖励和玩家下注金额相同的金钱. 分析:这个题目要求灵活运用多线程的相关知识,达到点击开始按钮时,有3个线程启动,分别控制3颗骰子的转动,在3颗骰子全部转完以后,回到主线程计算游戏结果. //个

  • java编写贪吃蛇小游戏

    废话不多说,直接奉上代码: Frame.java package snake; import java.awt.Graphics; import java.awt.Menu; import java.awt.MenuBar; import java.awt.MenuItem; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import

  • Java完美实现2048小游戏

    完美地模仿了2048游戏,是根据网友的一个2048改的. Block.java import javax.swing.*; import java.awt.*; public class Block extends JLabel { private int value; public Block() { value = 0;//初始化值为0 setFont(new Font("font", Font.PLAIN, 40));//设定字体 setBackground(Color.gray

  • java使用OGEngine开发2048

    最近有一款2048的游戏非常火,本文将来介绍一下使用OGEngine游戏引擎开发游戏2048. OGEngine引擎是开源的,我们很容易找到,搭建起来也很方便,我们只需在Android工程下添加OGEngine的jar包或者直接引用源码就可以了. 源码下载:http://www.ogengine.com/download/resources.jsp private void initView() { // 游戏背景 AnimatedSprite game_bg = new AnimatedSpr

  • java实现的简单猜数字游戏代码

    本文实例讲述了java实现的简单猜数字游戏代码.分享给大家供大家参考. 具体代码如下: 复制代码 代码如下: import java.util.InputMismatchException; import java.util.Scanner; public class Main {         public static void main(String[] args) {                 // 产生一个随机数                 int number = (in

  • Java基于swing实现的弹球游戏代码

    本文实例讲述了Java基于swing实现的弹球游戏代码.分享给大家供大家参考. 主要功能代码如下: 复制代码 代码如下: package Game; import java.awt.Graphics; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Random;

  • java基于swing实现的五子棋游戏代码

    本文实例讲述了java基于swing实现的五子棋游戏代码.分享给大家供大家参考. 主要功能代码如下: 复制代码 代码如下: import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Main extends JFrame implements ActionListener{         private static final long serialVersionUID = 1L;      

随机推荐