java实现2048小游戏

本文实例为大家分享了java实现2048小游戏的具体代码,供大家参考,具体内容如下

一、实现效果

二、实现代码

Check表示格子,GameView实现游戏视图界面及功能,是核心。

Check.java

import java.awt.Color;
import java.awt.Font;

// 方格类
public class Check {
 public int value;

 Font font1 = new Font("宋体", Font.BOLD, 46);
 Font font2 = new Font("宋体", Font.BOLD, 40);
 Font font3 = new Font("宋体", Font.BOLD, 34);
 Font font4 = new Font("宋体", Font.BOLD, 28);
 Font font5 = new Font("宋体", Font.BOLD, 22);

 public Check() {
 value = 0; //value为方格中数字
 }
 //字体颜色
 public Color getForeground() {
 switch (value) {
 case 0:
 return new Color(0xcdc1b4);//0的颜色与背景色一致,相当于没有数字
 case 2:
 case 4:
 return Color.BLACK;
 default:
 return Color.WHITE;
 }
 }

 //字体背景颜色,即方格颜色
 public Color getBackground() {
 switch (value) {
 case 0:
 return new Color(0xcdc1b4);
 case 2:
 return new Color(0xeee4da);
 case 4:
 return new Color(0xede0c8);
 case 8:
 return new Color(0xf2b179);
 case 16:
 return new Color(0xf59563);
 case 32:
 return new Color(0xf67c5f);
 case 64:
 return new Color(0xf65e3b);
 case 128:
 return new Color(0xedcf72);
 case 256:
 return new Color(0xedcc61);
 case 512:
 return new Color(0xedc850);
 case 1024:
 return new Color(0xedc53f);
 case 2048:
 return new Color(0xedc22e);
 case 4096:
 return new Color(0x65da92);
 case 8192:
 return new Color(0x5abc65);
 case 16384:
 return new Color(0x248c51);
 default:
 return new Color(0x248c51);
 }
 }

 public Font getCheckFont() {
 if (value < 10) {
 return font1;
 }
 if (value < 100) {
 return font2;
 }
 if (value < 1000) {
 return font3;
 }
 if (value < 10000) {
 return font4;
 }

 return font5;
 }

}

GameView.java

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class GameView{
 private static final int jframeWidth = 405;//窗口宽高
 private static final int jframeHeight = 530;
 private static int score = 0;

 Font topicFont = new Font("微软雅黑", Font.BOLD, 50);//主题字体
 Font scoreFont = new Font("微软雅黑", Font.BOLD, 28);//得分字体
 Font explainFont = new Font("宋体", Font.PLAIN,20);//提示字体

 private JFrame jframeMain;
 private JLabel jlblTitle;
 private JLabel jlblScoreName;
 private JLabel jlblScore;
 private JLabel jlblTip;
 private GameBoard gameBoard;

 public GameView() {
 init();
 }

 public void init() {
 //1、创建窗口
 jframeMain = new JFrame("2048小游戏");
 jframeMain.setSize(jframeWidth, jframeHeight);
 jframeMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 jframeMain.setLocationRelativeTo(null);//窗口显示位置居中
 jframeMain.setResizable(false);
 jframeMain.setLayout(null);//设置绝对布局,以便后面可以用setBounds设置位置

 jlblTitle = new JLabel("2048", JLabel.CENTER);
 jlblTitle.setFont(topicFont);
 jlblTitle.setForeground(Color.BLACK);
 jlblTitle.setBounds(50, 0, 150, 60);
 jframeMain.add(jlblTitle);

 //2、框架窗口搭建好,则需向里面开始添加内容
 //设置字体及其颜色、位置
 jlblScoreName = new JLabel("得 分", JLabel.CENTER);
 jlblScoreName.setFont(scoreFont);
 jlblScoreName.setForeground(Color.WHITE);
 jlblScoreName.setOpaque(true);
 jlblScoreName.setBackground(Color.GRAY);
 jlblScoreName.setBounds(250, 0, 120, 30);
 jframeMain.add(jlblScoreName);

 //3、得分区(得分名+分数)
 jlblScore = new JLabel("0", JLabel.CENTER);
 jlblScore.setFont(scoreFont);
 jlblScore.setForeground(Color.WHITE);
 jlblScore.setOpaque(true);
 jlblScore.setBackground(Color.GRAY);
 jlblScore.setBounds(250, 30, 120, 30);
 jframeMain.add(jlblScore);

 //4、提示说明区
 jlblTip = new JLabel("操作: ↑ ↓ ← →, 按esc键重新开始 ",
 JLabel.CENTER);
 jlblTip.setFont(explainFont);
 jlblTip.setForeground(Color.DARK_GRAY);
 jlblTip.setBounds(0, 60, 400, 40);
 jframeMain.add(jlblTip);

 //5、主游戏面板区
 gameBoard = new GameBoard();
 gameBoard.setBounds(0, 100, 400, 400);
 gameBoard.setBackground(Color.GRAY);
 gameBoard.setFocusable(true);//焦点即当前正在操作的组件,也就是移动的数字
 gameBoard.setLayout(new FlowLayout());
 jframeMain.add(gameBoard);
 }

 // 游戏面板
 class GameBoard extends JPanel implements KeyListener {
 private static final int CHECK_GAP = 10;//方格之间的间隙
 private static final int CHECK_SIZE = 85;//方格大小
 private static final int CHECK_ARC = 20;//方格弧度

 private Check[][] checks = new Check[4][4];
 private boolean isadd = true;

 public GameBoard() {
 initGame();
 addKeyListener(this);
 }

 private void initGame() {
 score = 0;
 for (int indexRow = 0; indexRow < 4; indexRow++) {
 for (int indexCol = 0; indexCol < 4; indexCol++) {
  checks[indexRow][indexCol] = new Check();
 }
 }
 // 最开始时生成两个数
 isadd = true;
 createCheck();
 isadd = true;
 createCheck();
 }

 @Override
 public void keyPressed(KeyEvent e) {
 switch (e.getKeyCode()) {
 case KeyEvent.VK_ESCAPE:
  initGame();//重新开始游戏(初始化游戏)
  break;
 case KeyEvent.VK_LEFT:
  moveLeft();
  createCheck();//调用一次方法创建一个方格数字
  judgeGameOver();//创建后判断是否GameOver,若所有格子均满即跳出GameOver
  break;
 case KeyEvent.VK_RIGHT:
  moveRight();
  createCheck();
  judgeGameOver();
  break;
 case KeyEvent.VK_UP:
  moveUp();
  createCheck();
  judgeGameOver();
  break;
 case KeyEvent.VK_DOWN:
  moveDown();
  createCheck();
  judgeGameOver();
  break;
 default:
  break;//按其他键没有反应
 }
 repaint();//刷新,会自动调用paint()方法,重新绘制移动后的图
 }

 private void createCheck() {
 List<Check> list = getEmptyChecks();

 if (!list.isEmpty() && isadd) {
 Random random = new Random();
 int index = random.nextInt(list.size());
 Check check = list.get(index);
 // 2, 4出现概率3:1
 int randomValue = random.nextInt(4);
 check.value = ( randomValue % 3 == 0 || randomValue % 3 == 1) ? 2 : 4;//只有[0,4)中的2才能生成4
 isadd = false;
 }
 }

 // 获取空白方格
 private List<Check> getEmptyChecks() {
 List<Check> checkList = new ArrayList<>();
 for (int i = 0; i < 4; i++) {
 for (int j = 0; j < 4; j++) {
  if (checks[i][j].value == 0) {
  checkList.add(checks[i][j]);
  }
 }
 }
 return checkList;
 }
 //是否全部格子占满,全部占满则GameOver
 private boolean judgeGameOver() {
 jlblScore.setText(score + "");

 if (!getEmptyChecks().isEmpty()) {
 return false;
 }

 for (int i = 0; i < 3; i++) {
 for (int j = 0; j < 3; j++) {
  //判断是否存在可合并的方格
  if (checks[i][j].value == checks[i][j + 1].value
  || checks[i][j].value == checks[i + 1][j].value) {
  return false;
  }
 }
 }

 return true;
 }

 private void moveLeft() {
 //找到一个非空格子后checks[i][j].value > 0,可分为三种情况处理
 for (int i = 0; i < 4; i++) {
 for (int j = 1, index = 0; j < 4; j++) {
  if (checks[i][j].value > 0) {
  //第一种情况:checks[i][j](非第1列)与checks[i][index]的数相等,则合并乘以2,且得分增加
  if (checks[i][j].value == checks[i][index].value) {
  score += checks[i][index].value *= 2;
  checks[i][j].value = 0;
  isadd = true;
  } else if (checks[i][index].value == 0) {
  //第二种:若checks[i][index]为空格子,checks[i][j]就直接移到最左边checks[i][index]
  checks[i][index].value = checks[i][j].value;
  checks[i][j].value = 0;
  isadd = true;
  } else if (checks[i][++index].value == 0) {
  //第三种:若checks[i][index]不为空格子,并且数字也不相等,若其旁边为空格子,则移到其旁边
  checks[i][index].value = checks[i][j].value;
  checks[i][j].value = 0;
  isadd = true;
  }
  }
 }
 }
 }

 private void moveRight() {
 for (int i = 0; i < 4; i++) {
 for (int j = 2, index = 3; j >= 0; j--) {
  if (checks[i][j].value > 0) {
  if (checks[i][j].value == checks[i][index].value) {
  score += checks[i][index].value *= 2;
  checks[i][j].value = 0;
  isadd = true;
  } else if (checks[i][index].value == 0) {
  checks[i][index].value = checks[i][j].value;
  checks[i][j].value = 0;
  isadd = true;
  } else if (checks[i][--index].value == 0) {
  checks[i][index].value = checks[i][j].value;
  checks[i][j].value = 0;
  isadd = true;
  }
  }
 }
 }
 }

 private void moveUp() {
 for (int i = 0; i < 4; i++) {
 for (int j = 1, index = 0; j < 4; j++) {
  if (checks[j][i].value > 0) {
  if (checks[j][i].value == checks[index][i].value) {
  score += checks[index][i].value *= 2;
  checks[j][i].value = 0;
  isadd = true;
  } else if (checks[index][i].value == 0) {
  checks[index][i].value = checks[j][i].value;
  checks[j][i].value = 0;
  isadd = true;
  } else if (checks[++index][i].value == 0){
  checks[index][i].value = checks[j][i].value;
  checks[j][i].value = 0;
  isadd = true;
  }
  }
 }
 }
 }

 private void moveDown() {
 for (int i = 0; i < 4; i++) {
 for (int j = 2, index = 3; j >= 0; j--) {
  if (checks[j][i].value > 0) {
  if (checks[j][i].value == checks[index][i].value) {
  score += checks[index][i].value *= 2;
  checks[j][i].value = 0;
  isadd = true;
  } else if (checks[index][i].value == 0) {
  checks[index][i].value = checks[j][i].value;
  checks[j][i].value = 0;
  isadd = true;
  } else if (checks[--index][i].value == 0) {
  checks[index][i].value = checks[j][i].value;
  checks[j][i].value = 0;
  isadd = true;
  }
  }
 }
 }
 }

 @Override
 public void paint(Graphics g) {
 super.paint(g);
 for (int i = 0; i < 4; i++) {
 for (int j = 0; j < 4; j++) {
  drawCheck(g, i, j);
 }
 }

 // GameOver
 if (judgeGameOver()) {
 g.setColor(new Color(64, 64, 64, 100));//RGBA最后一个A可以视为透明度
 g.fillRect(0, 0, getWidth(), getHeight());//填充矩形(游戏面板),将暗黑色填充上去
 g.setColor(Color.WHITE);
 g.setFont(topicFont);
 FontMetrics fms = getFontMetrics(topicFont);//FontMetrics字体测量,该类是Paint的内部类,通过getFontMetrics()方法可获取字体相关属性
 String value = "Game Over!";
 g.drawString(value, (getWidth()-fms.stringWidth(value)) / 2, getHeight() / 2);//字体居中显示
 }
 }

 // 绘制方格
 // Graphics2D 类是Graphics 子类,拥有强大的二维图形处理能力
 private void drawCheck(Graphics g, int i, int j) {
 Graphics2D gg = (Graphics2D) g;
 //下面两句是抗锯齿模式,计算和优化消除文字锯齿,字体更清晰顺滑
 gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
 gg.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
 //获取方格
 Check check = checks[i][j];
 //不同数字设置背景色
 gg.setColor(check.getBackground());
 // 绘制圆角
 gg.fillRoundRect(CHECK_GAP + (CHECK_GAP + CHECK_SIZE) * j,
  CHECK_GAP + (CHECK_GAP + CHECK_SIZE) * i,
  CHECK_SIZE, CHECK_SIZE, CHECK_ARC, CHECK_ARC);
 //绘制字体及其颜色
 gg.setColor(check.getForeground());
 gg.setFont(check.getCheckFont());

 // 文字测量,并对文字进行绘制
 FontMetrics fms = getFontMetrics(check.getCheckFont());
 String value = String.valueOf(check.value);
 //使用此图形上下文的当前颜色绘制由指定迭代器给定的文本。
 //getAscent()是FontMetrics中的一个方法,
 //getDescent() 为降部
 gg.drawString(value,
  CHECK_GAP + (CHECK_GAP + CHECK_SIZE) * j +
  (CHECK_SIZE - fms.stringWidth(value)) / 2,
  CHECK_GAP + (CHECK_GAP + CHECK_SIZE) * i +
  (CHECK_SIZE - fms.getAscent() - fms.getDescent()) / 2
  + fms.getAscent());//让数字居中显示
 }

 @Override
 public void keyReleased(KeyEvent e) {
 }

 @Override
 public void keyTyped(KeyEvent e) {
 }

 }

 public void showView() {
 jframeMain.setVisible(true);
 }

}

Main.java

public class Main {
 public static void main(String[] args) {
 new GameView().showView();
 }
}

三、重难点讲解

3.1 数字移动问题

数字移动是一难点,分三种情况,以moveLeft()为例

(1)按左键,若最左边是相同的,则合并

(2)若左边是空格,则直接移动到最左即可

(3)若最左边不为空格,且不相等,则看它右边是否是空格,是则移动到其旁边

3.2 绘图问题—抗锯齿

java提供的Graphics 2D,它是Graphics 子类

Graphics2D gg = (Graphics2D) g;
gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
gg.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,RenderingHints.VALUE_STROKE_NORMALIZE);

上面这两个语句实现的功能是消除文字锯齿,字体更清晰顺滑,可以看下图没有setRenderingHint和有setRenderingHint的区别

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

(0)

相关推荐

  • 200行java代码实现2048小游戏

    本文实例为大家分享了java实现2048小游戏的具体代码,供大家参考,具体内容如下 效果图: 游戏介绍: 1.2048是一款益智类小游戏,刚开始随机出现两个数字,可以上下左右控制数字的移动. 2.当选择一个方向移动后,所有数字都会沿该方向移动到表格尽头,并且空余表格会随机出现2或4,当碰到相同的两个数字时,该两个数字会合并相加成一个数字,直到最大的数字变成2048游戏成功 3.否则当数字填满表格且不能再移动时游戏失败. 游戏代码: import java.awt.*; import java.a

  • 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版实现2048游戏功能

    本文实例为大家分享了java实现2048游戏功能的具体代码,供大家参考,具体内容如下 功能要求:2048的基本界面,能够实现2048的游戏功能. 总思路:两个类:Game和GameListener. Game负责界面的实现和paint方法的重写 GameListener负责实现键盘和鼠标事件的处理.移动方法,相加方法,输赢判断和随机数的出现都要在键盘监听的方法中实现. 实现分析:要实现2048游戏,首先需要考虑2048都有些什么? 界面实现: 2048的游戏界面很简单,就是一些方格和数字.要实现

  • java实现2048游戏源代码

    本文实例为大家分享了java实现2048游戏源代码,供大家参考,具体内容如下 一.主要功能: 1.游戏初始化:新建游戏4×4的16宫格画布,随机格子上生成2或者4两个数字 2.格子的移动:先判断能否移动,移动后判断能否合并,合并后改变格子颜色和数字 3.新格子的生成:移动一次,就在剩余的空格子中随机生成一个2或者4 4.判赢:16宫格中合并出了"2048"则为游戏胜利 5.判输:16宫格中没有剩余空格子且不能再向任何方向移动则为游戏失败 二.项目的主要结构: 在项目2018游戏中,有4

  • java实现的2048游戏完整实例

    本文实例讲述了java实现的2048游戏.分享给大家供大家参考,具体如下: 先来看看运行效果: 具体代码如下: package awtDemo; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; @SuppressWarnings("serial") public class Game2048 extends JApplet{ @

  • 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实现2048小游戏

    本文实例为大家分享了java实现2048小游戏的具体代码,供大家参考,具体内容如下 一.实现效果 二.实现代码 Check表示格子,GameView实现游戏视图界面及功能,是核心. Check.java import java.awt.Color; import java.awt.Font; // 方格类 public class Check { public int value; Font font1 = new Font("宋体", Font.BOLD, 46); Font fon

  • Java实现2048小游戏(可直接运行)

    运行效果: 1.项目结构 2.代码 BaseData接口 package com.hsy.game; import java.awt.*; public interface BaseData { Font topicFont = new Font("微软雅黑", Font.BOLD, 50); Font scoreFont = new Font("微软雅黑", Font.BOLD, 28); Font normalFont = new Font("宋体&q

  • java实现2048小游戏(含注释)

    本文实例为大家分享了java实现2048小游戏的具体代码,供大家参考,具体内容如下 实现文件 APP.java import javax.swing.*; public class APP { public static void main(String[] args) { new MyFrame(); } } 类文件 import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionList

  • java实现2048小游戏(含注释)

    本文实例为大家分享了java实现2048小游戏的具体代码,供大家参考,具体内容如下 实现文件 APP.java import javax.swing.*; public class APP { public static void main(String[] args) { new MyFrame(); } } 类文件 import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionList

  • Android高仿2048小游戏实现代码

    刚开始进入Splash界面: 1.SplashActivity.Java(两秒后进入开始界面,Splash界面的布局只有一个图片,在博客后,会展示给大家看) public class SplashActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.a

  • 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); //设置窗

  • 使用Javascript写的2048小游戏

    最近心血来潮,项目结束了,使用javascript写个小游戏,练练收吧,写的不好还请各位大侠给出批评建议. HTML代码如下 <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8" /> <link rel="stylesheet" href="2048.css"/> <scri

  • 用Python写一个无界面的2048小游戏

    以前游戏2048火的时候,正好用其他的语言编写了一个,现在学习python,正好想起来,便决定用python写一个2048,由于没学过python里面的界面编程,所以写了一个极其简单的无界面2048.游戏2048的原理和实现都不难,正好可以拿来练手,要是不知道这游戏的话,可以去网上查一下,或者下载一个到手机来玩一下,我就不在说其原理.我知道不放图的话大家一点兴趣都没,下面首先放一张游戏成型图,然后我们在来讲如何一步步用最基础的知识来实现. 一.生成4*4的矩阵 游戏的第一步便是生成一个4*4的矩

随机推荐