IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java实现2048小游戏,我竟然一盘都没赢,你们说我到底行不行? -> 正文阅读

[Java知识库]Java实现2048小游戏,我竟然一盘都没赢,你们说我到底行不行?

作者简介

作者名:编程界明世隐
简介:CSDN博客专家,从事软件开发多年,精通Java、JavaScript,博主也是从零开始一步步把学习成长、深知学习和积累的重要性,喜欢跟广大ADC一起打野升级,欢迎您关注,期待与您一起学习、成长、起飞!

系列目录

1. Java俄罗斯方块
2. Java五子棋小游戏
3. 老Java程序员花一天时间写了个飞机大战
4. Java植物大战僵尸
5. 老Java程序员花2天写了个连连看
6. Java消消乐(天天爱消除)
7. Java贪吃蛇小游戏
8. Java扫雷小游戏
9. Java坦克大战
10. Java迷宫小游戏

Java 2048小游戏

引言:

前几天偶尔看到了这个数字游戏,感觉还蛮有意思,就玩了一下,竟然赢不了,怎么玩都是输,真是邪门了,这不作为程序员员,我玩不赢我就自己写一个,行不行?我自己写的,我想赢就赢,条件我自己设定,就是玩!!

效果图

在这里插入图片描述

实现思路

  1. 绘制窗口。
  2. 创建菜单。
  3. 创建所有空白卡片。
  4. 随机创建一个卡片(2或者4)。
  5. 键盘事件监听(上、下、左、右键监听)。
  6. 根据键盘的方向,处理数字的移动合并。
  7. 加入成功、失败判定。
  8. 处理其他收尾工作。

代码实现

创建窗口

首先创建一个游戏窗体类GameFrame,继承至JFrame,用来显示在屏幕上(window的对象),每个游戏都有一个窗口,设置好窗口标题、尺寸、布局等就可以。

package main;

import java.awt.Color;
import javax.swing.JFrame;
/**
 *窗体类
 */
public class GameFrame extends JFrame {
	//构造方法
	public GameFrame(){
		setTitle("2048");//设置标题
		setSize(370, 420);//设置窗体大小
		getContentPane().setBackground(new Color(66,136,83));//加上背景
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭后进程退出
		setLocationRelativeTo(null);//居中
		setResizable(false);//不允许变大
	}
}

创建面板容器GamePanel继承至JPanel

package main;

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

/*
 * 画布类
 */
public class GamePanel extends JPanel{
	private JFrame mainFrame=null;
	private GamePanel panel = null;
	//构造里面初始化相关参数
	public GamePanel(JFrame frame){
		this.setLayout(null);
		this.setOpaque(false);
		this.mainFrame=frame;
		this.panel =this;
	}
}

再创建一个Main类,来启动这个窗口,用来启动。

package main;

//Main类
public class Main {

	public static void main(String[] args) {
		GameFrame frame = new GameFrame();
		GamePanel panel = new GamePanel(frame);
		frame.add(panel);
		frame.setVisible(true);
	}
}

右键执行这个Main类,窗口建出来了
在这里插入图片描述

创建菜单

private Font createFont(){
		return new Font("思源宋体",Font.BOLD,18);
	}
	//创建菜单
	private void createMenu() {
		//创建JMenuBar
		JMenuBar jmb = new JMenuBar();
		//取得字体
		Font tFont = createFont(); 
		//创建游戏选项
		JMenu jMenu1 = new JMenu("游戏");
		jMenu1.setFont(tFont);
		//创建帮助选项
		JMenu jMenu2 = new JMenu("帮助");
		jMenu2.setFont(tFont);
		
		JMenuItem jmi1 = new JMenuItem("新游戏");
		jmi1.setFont(tFont);
		JMenuItem jmi2 = new JMenuItem("退出");
		jmi2.setFont(tFont);
		//jmi1 jmi2添加到菜单项“游戏”中
		jMenu1.add(jmi1);
		jMenu1.add(jmi2);
		
		JMenuItem jmi3 = new JMenuItem("操作帮助");
		jmi3.setFont(tFont);
		JMenuItem jmi4 = new JMenuItem("胜利条件");
		jmi4.setFont(tFont);
		//jmi13 jmi4添加到菜单项“游戏”中
		jMenu2.add(jmi3);
		jMenu2.add(jmi4);
		
		jmb.add(jMenu1);
		jmb.add(jMenu2);
		
		mainFrame.setJMenuBar(jmb);
		
		//添加监听
		jmi1.addActionListener(this);
		jmi2.addActionListener(this);
		jmi3.addActionListener(this);
		jmi4.addActionListener(this);
		//设置指令
		jmi1.setActionCommand("restart");
		jmi2.setActionCommand("exit");
		jmi3.setActionCommand("help");
		jmi4.setActionCommand("win");
	}

此时直接把这个代码加入到GamePanel中,发现是会报错的,需要实现ActionListener,并重写actionPerformed 方法。
在这里插入图片描述
此时GamePanel的代码如下:

package main;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.plaf.FontUIResource;

/*
 * 画布类
 */
public class GamePanel extends JPanel implements ActionListener{
	private JFrame mainFrame=null;
	private GamePanel panel = null;
	//构造里面初始化相关参数
	public GamePanel(JFrame frame){
		this.setLayout(null);
		this.setOpaque(false);
		this.mainFrame=frame;
		this.panel =this;
		
		//创建菜单
		createMenu();
	}
	
	private Font createFont(){
		return new Font("思源宋体",Font.BOLD,18);
	}
	//创建菜单
	private void createMenu() {
		//创建JMenuBar
		JMenuBar jmb = new JMenuBar();
		//取得字体
		Font tFont = createFont(); 
		//创建游戏选项
		JMenu jMenu1 = new JMenu("游戏");
		jMenu1.setFont(tFont);
		//创建帮助选项
		JMenu jMenu2 = new JMenu("帮助");
		jMenu2.setFont(tFont);
		
		JMenuItem jmi1 = new JMenuItem("新游戏");
		jmi1.setFont(tFont);
		JMenuItem jmi2 = new JMenuItem("退出");
		jmi2.setFont(tFont);
		//jmi1 jmi2添加到菜单项“游戏”中
		jMenu1.add(jmi1);
		jMenu1.add(jmi2);
		
		JMenuItem jmi3 = new JMenuItem("操作帮助");
		jmi3.setFont(tFont);
		JMenuItem jmi4 = new JMenuItem("胜利条件");
		jmi4.setFont(tFont);
		//jmi13 jmi4添加到菜单项“游戏”中
		jMenu2.add(jmi3);
		jMenu2.add(jmi4);
		
		jmb.add(jMenu1);
		jmb.add(jMenu2);
		
		mainFrame.setJMenuBar(jmb);
		
		//添加监听
		jmi1.addActionListener(this);
		jmi2.addActionListener(this);
		jmi3.addActionListener(this);
		jmi4.addActionListener(this);
		//设置指令
		jmi1.setActionCommand("restart");
		jmi2.setActionCommand("exit");
		jmi3.setActionCommand("help");
		jmi4.setActionCommand("win");
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		String command = e.getActionCommand();
		UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("思源宋体", Font.ITALIC, 18)));
		UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("思源宋体", Font.ITALIC, 18)));
		if ("exit".equals(command)) {
			Object[] options = { "确定", "取消" };
			int response = JOptionPane.showOptionDialog(this, "您确认要退出吗", "",
					JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null,
					options, options[0]);
			if (response == 0) {
				System.exit(0);
			} 
		}else if("restart".equals(command)){
		}else if("help".equals(command)){
			JOptionPane.showMessageDialog(null, "通过键盘的上下左右来移动,相同数字会合并!",
					"提示!", JOptionPane.INFORMATION_MESSAGE);
		}else if("win".equals(command)){
			JOptionPane.showMessageDialog(null, "得到数字2048获得胜利,当没有空卡片则失败!",
					"提示!", JOptionPane.INFORMATION_MESSAGE);
		}
	}
}

在这里插入图片描述

创建Card

建立Card类

package main;

import java.awt.Graphics;

public class Card {
	private int x = 0;// x坐标
	private int y = 0;// y坐标
	private int w = 80;// 宽
	private int h = 80;// 高
	private int i = 0;//下标i
	private int j = 0;//下标j
	private int start=10;//偏移量(固定值)
	private int num=0;//显示数字
	private boolean merge=false;//当前是否被合并过,如果合并了,则不能继续合并,针对当前轮
	
	public Card(int i,int j){
		this.i=i;
		this.j=j;
	}
	//根据i j计算x y坐标
	private void cal(){
		this.x = start + j*w + (j+1)*5;
		this.y = start + i*h + (i+1)*5;
	}
	//绘制方法
	public void draw(Graphics g) {
		cal();
		g.fillRoundRect(x, y, w, h, 4, 4);
	}
	
	
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public boolean isMerge() {
		return merge;
	}
	public void setMerge(boolean merge) {
		this.merge = merge;
	}
}

在GamePanel中加入相关参数

private final int COLS=4;//列
private final int ROWS=4;//行
private Card cards[][] = new Card[ROWS][COLS];
private String gameFlag = "start";//游戏状态

实例化Card对象

//初始化
private void init() {
	Card card;
	for (int i = 0; i < ROWS; i++) {
		for (int j = 0; j < COLS; j++) {
			card = new Card(i,j);
			cards[i][j]=card;
		}
	}
}

在构造方法中调用

//构造里面初始化相关参数
public GamePanel(JFrame frame){
	this.setLayout(null);
	this.setOpaque(false);
	this.mainFrame=frame;
	this.panel =this;
	
	//创建菜单
	createMenu();
	
	//初始化
	init();
}

在GamePanel中重写paint方法,并在此方法中绘制这些卡片。

@Override
public void paint(Graphics g) {
	super.paint(g);
	//绘制卡片
	drawCard(g);
}
//绘制卡片
private void drawCard(Graphics g) {
	Card card;
	for (int i = 0; i < ROWS; i++) {
		for (int j = 0; j < COLS; j++) {
			card = cards[i][j];
			card.draw(g);
		}
	}		
}

运行
在这里插入图片描述
这个黑色不是我们想要的,要根据不同的数字来设置不同的颜色,于是我们在Card修改一下。

//获取color
private Color getColor(){
	Color color=null;
	//根据num设定颜色
	switch (num) {
	case 2:
		color = new Color(238,244,234);
		break;
	case 4:
		color = new Color(222,236,200);
		break;
	case 8:
		color = new Color(174,213,130);
		break;
	case 16:
		color = new Color(142,201,75);
		break;
	case 32:
		color = new Color(111,148,48);
		break;
	case 64:
		color = new Color(76,174,124);
		break;
	case 128:
		color = new Color(60,180,144);
		break;
	case 256:
		color = new Color(45,130,120);
		break;
	case 512:
		color = new Color(9,97,26);
		break;
	case 1024:
		color = new Color(242,177,121);
		break;
	case 2048:
		color = new Color(223,185,0);
		break;

	default://默认颜色
		color = new Color(92,151,117);
		break;
	}
	
	return color;
}

加入数字的显示和颜色的修改代码,修改draw方法。

//绘制方法
public void draw(Graphics g) {
	cal();
	//获取旧的颜色
	Color oColor = g.getColor();
	//获取要用的颜色
	Color color = getColor();
	//设置画笔颜色
	g.setColor(color);
	g.fillRoundRect(x, y, w, h, 4, 4);
	
	if(num!=0){
		//设置字的颜色
		g.setColor(new Color(125,78,51));
		Font font = new Font("思源宋体", Font.BOLD, 35);
		g.setFont(font);
		//转换成String
		String text = num+"";
		//计算该字体文本的长度
        int wordWidth = getWordWidth(font, text);
        //计算出字体居中位置的X坐标
        int sx = x+(w-wordWidth)/2;
        //绘制
		g.drawString(text, sx , y+50);
	}
	
	//恢复画笔颜色
	g.setColor(oColor);
}

//得到该字体字符串的长度  
public static int getWordWidth(Font font, String content) {
    FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
    int width = 0;
    for (int i = 0; i < content.length(); i++) {
        width += metrics.charWidth(content.charAt(i));
    }
    return width;
}

在这里插入图片描述
修改一下Card默认的数字,试试效果
在这里插入图片描述
在这里插入图片描述

随机创建一个数字,2或者4

  1. 先把Card类中 num 默认改成0
  2. 因为2跟4出现的比例是1:4,所以采用随机出1-5的数字,当是1的时候就表示,当得到2、3、4、5的时候就表示要出现数字2.
  3. 随机获取i,j 就可以得到卡片的位置,割接i,j取到card实例,如果卡片没有数字,就表示可以,否则就递归继续取,取到为止。
  4. 把刚才取到的数字,设置到card实例对象中就好了。

代码如下:

//在随机的空卡片创建数字2或者4
private void createRandomNumber() {
	int num = 0;
	Random random = new Random();
	int index = random.nextInt(5)+1;//这样取出来的就是1-5 之间的随机数
	//因为2和4出现的概率是1比4,所以如果index是1,则创建数字4,否则创建数字2(1被随机出来的概率就是1/5,而其他就是4/5 就是1:4的关系)
	
	if(index==1){
		num = 4;
	}else {
		num = 2;
	}
	//判断如果格子已经满了,则不再获取,退出
	if(cardFull()){
		return ;
	}
	//获取随机卡片,不为空的
	Card card = getRandomCard(random);
	//给card对象设置数字
	if(card!=null){
		card.setNum(num);
	}
}
//获取随机卡片,不为空的
private Card getRandomCard(Random random) {
	int i = random.nextInt(ROWS);
	int j = random.nextInt(COLS);
	Card card = cards[i][j];
	if(card.getNum()==0){//如果是空白的卡片,则找到了,直接返回
		return card;
	}
	//没找到空白的,就递归,继续寻找
	return getRandomCard(random);
}
//判断格子满了
private boolean cardFull() {
	Card card;
	for (int i = 0; i < ROWS; i++) {
		for (int j = 0; j < COLS; j++) {
			card = cards[i][j];
			if(card.getNum()==0){//有一个为空,则没满
				return false;
			}
		}
	}		
	return true;
}

构造中调用,表示打开游戏默认一个数字
在这里插入图片描述
在这里插入图片描述

加入键盘事件

记得在构造中调用这个方法哦。

//添加键盘监听
private void createKeyListener() {
	KeyAdapter l = new KeyAdapter() {
		//按下
		@Override
		public void keyPressed(KeyEvent e) {
			if(!"start".equals(gameFlag)) return ;
			int key = e.getKeyCode();
			switch (key) {
				//向上
				case KeyEvent.VK_UP:
				case KeyEvent.VK_W:
					moveCard(1);//向上
					break;
					
				//向右	
				case KeyEvent.VK_RIGHT:
				case KeyEvent.VK_D:
					moveCard(2);//向右
					break;
					
				//向下
				case KeyEvent.VK_DOWN:
				case KeyEvent.VK_S:
					moveCard(3);//向上下
					break;
					
				//向左
				case KeyEvent.VK_LEFT:
				case KeyEvent.VK_A:
					moveCard(4);//向左
					break;
			}
		
		}
		//松开
		@Override
		public void keyReleased(KeyEvent e) {
		}
		
	};
	//给主frame添加键盘监听
	mainFrame.addKeyListener(l);
}

加入鼠标移动逻辑处理代码

//卡片移动的方法
protected void moveCard(int dir) {
	//将卡片清理一遍,因为每轮移动会设定合并标记,需重置
	clearCard();
	
	if(dir==1){//向上移动
		moveCardTop(true);
	}
	//移动后要创建新的卡片
	createRandomNumber();
	//重绘
	repaint();
}

//将卡片清理一遍,因为每轮移动会设定合并标记,需重置
private void clearCard() {
	Card card;
	for (int i = 0; i < ROWS; i++) {//i从1开始,因为i=0不需要移动
		for (int j = 0; j < COLS; j++) {
			card = cards[i][j];
			card.setMerge(false);
		}
	}
}

//向上移动
private boolean moveCardTop(boolean bool) {
	boolean res = false;
	Card card;
	for (int i = 1; i < ROWS; i++) {//i从1开始,因为i=0不需要移动
		for (int j = 0; j < COLS; j++) {
			card = cards[i][j];
			if(card.getNum()!=0){//只要卡片不为空,要移动
				if(card.moveTop(cards,bool)){//向上移动
					res = true;//有一个为移动或者合并了,则res为true
				}
			}
		}
	}
	return res;
}

在Card类中加入向上移动的处理逻辑

  1. 从第2行开始移动,因为第一行不需要移动。
  2. 只要卡片的数字不是0,就表示要移动。
  3. 根据 i-1 可以获取到上一个卡片,如果上一个卡片是空,则把当前卡片交换上去,并且递归,因为可能要继续往上移动。
  4. 如果当前卡片与上一个卡片是相同数字的,则要合并。
  5. 以上两种都不是,则不做操作。
//卡片向上移动
public boolean moveTop(Card[][] cards,boolean bool) {
	//设定退出条件
	if(i==0){//已经是最上面了
		return false;
	}
	//上面一个卡片
	Card prev = cards[i-1][j];
	if(prev.getNum()==0){//上一个卡片是空
		//移动,本质就是设置数字
		if(bool){//bool为true才执行,因为flase只是用来判断能否移动
			prev.num=this.num;
			this.num=0;
			//递归操作(注意这里是要 prev 来 move了)
			prev.moveTop(cards,bool);
		}
		return true;
	}else if(prev.getNum()==num && !prev.merge){//合并操作(如果已经合并了,则不运行再次合并,针对当然轮)
		if(bool){bool为true才执行
			prev.merge=true;
			prev.num=this.num*2;
			this.num=0;
		}
		return true;
	}else {//上一个的num与当前num不同,无法移动,并退出
		return false;
	}
}

看看效果
在这里插入图片描述

加入其他3个方向的代码,首先是在GamePanel中加入几个代码。

//向右移动
private boolean moveCardRight(boolean bool) {
	boolean res = false;
	Card card;
	for (int i = 0; i < ROWS; i++) {
		for (int j = COLS-1; j >=0 ; j--) {//j从COLS-1开始,从最右边开始移动递减
			card = cards[i][j];
			if(card.getNum()!=0){//只要卡片不为空,要移动
				if(card.moveRight(cards,bool)){//向右移动
					res = true;//有一个为移动或者合并了,则res为true
				}
			}
		}
	}
	return res;
}

//向下移动
private boolean moveCardBottom(boolean bool) {
	boolean res = false;
	Card card;
	for (int i = ROWS-1; i >=0; i--) {//i从ROWS-1开始,往下递减移动
		for (int j = 0; j < COLS; j++) {
			card = cards[i][j];
			if(card.getNum()!=0){//只要卡片不为空,要移动
				if(card.moveBottom(cards,bool)){//下移动
					res = true;//有一个为移动或者合并了,则res为true
				}
			}
		}
	}
	return res;
}

//向左移动
private boolean moveCardLeft(boolean bool) {
	boolean res = false;
	Card card;
	for (int i = 0; i < ROWS; i++) {
		for (int j = 1; j < COLS ; j++) {//j从1开始,从最左边开始移动
			card = cards[i][j];
			if(card.getNum()!=0){//只要卡片不为空,要移动
				if(card.moveLeft(cards,bool)){//向左移动
					res = true;//有一个为移动或者合并了,则res为true
				}
			}
		}
	}
	return res;
}

在Card加入其他几个方向的方法

//向下移动
public boolean moveBottom(Card[][] cards,boolean bool) {
	//设定退出条件
	if(i==3){//已经是最下面了
		return false;
	}
	//上面一个卡片
	Card prev = cards[i+1][j];
	if(prev.getNum()==0){//上一个卡片是空
		//移动,本质就是设置数字
		if(bool){//bool为true才执行,因为flase只是用来判断能否移动
			prev.num=this.num;
			this.num=0;
			//递归操作(注意这里是要 prev 来 move了)
			prev.moveBottom(cards,bool);
		}
		return true;
	}else if(prev.getNum()==num && !prev.merge){//合并操作(如果已经合并了,则不运行再次合并,针对当然轮)
		if(bool){bool为true才执行
			prev.merge=true;
			prev.num=this.num*2;
			this.num=0;
		}
		return true;
	}else {//上一个的num与当前num不同,无法移动,并退出
		return false;
	}

	
}
//向右移动
public boolean moveRight(Card[][] cards,boolean bool) {
	//设定退出条件
	if(j==3){//已经是最右边了
		return false;
	}
	//上面一个卡片
	Card prev = cards[i][j+1];
	if(prev.getNum()==0){//上一个卡片是空
		//移动,本质就是设置数字
		if(bool){//bool为true才执行,因为flase只是用来判断能否移动
			prev.num=this.num;
			this.num=0;
			//递归操作(注意这里是要 prev 来 move了)
			prev.moveRight(cards,bool);
		}
		return true;
	}else if(prev.getNum()==num && !prev.merge){//合并操作(如果已经合并了,则不运行再次合并,针对当然轮)
		if(bool){bool为true才执行
			prev.merge=true;
			prev.num=this.num*2;
			this.num=0;
		}
		return true;
	}else {//上一个的num与当前num不同,无法移动,并退出
		return false;
	}
}
//向左移动
public boolean moveLeft(Card[][] cards,boolean bool) {
	//设定退出条件
	if(j==0){//已经是最左边了
		return false;
	}
	//上面一个卡片
	Card prev = cards[i][j-1];
	if(prev.getNum()==0){//上一个卡片是空
		//移动,本质就是设置数字
		if(bool){//bool为true才执行,因为flase只是用来判断能否移动
			prev.num=this.num;
			this.num=0;
			//递归操作(注意这里是要 prev 来 move了)
			prev.moveLeft(cards,bool);	
		}
		return true;
	}else if(prev.getNum()==num && !prev.merge){//合并操作(如果已经合并了,则不运行再次合并,针对当然轮)
		if(bool){bool为true才执行
			prev.merge=true;
			prev.num=this.num*2;
			this.num=0;
		}
		return true;
	}else {//上一个的num与当前num不同,无法移动,并退出
		return false;
	}
}

修改一下moveCard方法

//卡片移动的方法
protected void moveCard(int dir) {
	//将卡片清理一遍,因为每轮移动会设定合并标记,需重置
	clearCard();
	
	if(dir==1){//向上移动
		moveCardTop(true);
	}else if(dir==2){//向右移动
		moveCardRight(true);
	}else if(dir==3){//向下移动
		moveCardBottom(true);
	}else if(dir==4){//向左移动
		moveCardLeft(true);
	}
	//移动后要创建新的卡片
	createRandomNumber();
	//重绘
	repaint();
}

在这里插入图片描述

做到这里就基本完成了,加入其他一下辅助的东西就行了,比如重新开始、游戏胜利,游戏结束等,也就不多说了。

看到这里的大佬,动动发财的小手 点赞 + 回复 + 收藏,能【 关注 】一波就更好了。

代码获取方式

帮忙文章【点赞】 +【 收藏】+【关注】+【评论】 后,加我主页左边的微信 或者 私聊我,我发给你!

更多精彩

1. Java俄罗斯方块
2. Java五子棋小游戏
3. 老Java程序员花一天时间写了个飞机大战
4. Java植物大战僵尸
5. 老Java程序员花2天写了个连连看
6. Java消消乐(天天爱消除)
7. Java贪吃蛇小游戏
8. Java扫雷小游戏
9. Java坦克大战
10. Java迷宫小游戏

相关阅读

1. JavaWeb图书管理系统
2. JavaWeb学生宿舍管理系统
3. JavaWeb在线考试系统

另外

为了帮助更多小白从零进阶 Java 工程师,从CSDN官方那边搞来了一套 《Java 工程师学习成长知识图谱》,尺寸 870mm x 560mm,展开后有一张办公桌大小,也可以折叠成一本书的尺寸,原件129元现价 29 元先到先得,有兴趣的小伙伴可以了解一下

在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-10 23:55:15  更:2021-09-10 23:55:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:44:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码