ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

10款Java基础小游戏实战项目,零基础轻松掌握Swing与核心语法

10款Java基础小游戏实战项目,零基础轻松掌握Swing与核心语法 很多刚开始学 Java 的人卡住的往往不是语法本身而是不知道写完 for、if、数组之后该拿什么练手。我这些年带过不少零基础的新同事和实习生试过让他们直接做图书管理系统、学生成绩管理这类项目效果普遍不好反而是那些看起来不起眼的小游戏项目能把人留下来还能把 Java 基础打得非常扎实。所以我把平时带人常用的一套“10 款 Java 基础小游戏实战项目”整理出来从控制台猜数字开始一路做到 Swing 的贪吃蛇、扫雷、打砖块和飞机大战。所有项目都不依赖第三方框架只用一个 JDK 和一个 IDEA 社区版就能跑。适合完全零基础、刚学完 Java 语法但没做过完整项目的人也适合准备 Java 面试但感觉基础题答不出细节的人。这篇不会把完整源码贴满让你照着敲而是告诉你每个项目该练什么、流程怎么拆、容易踩哪些坑。你按顺序做下来基本就把循环、数组、集合、面向对象、事件监听、线程、碰撞检测这些内容全部过了一遍。后面说到单个项目时我会给出核心代码片段和可执行的步骤你可以直接拿来“抄作业”。1. 为什么我用“小游戏”当 Java 入门练手项目1.1 管理系统类项目为什么不适合新手很多教程喜欢一上来就搞“学生管理系统”“图书管理系统”听着正规其实对零基础非常不友好。这类项目的大部分代码都是在做增删改查还没学会走就想让新手跑 JDBC、MySQL、Maven最后挫败感极强代码报错都不知道该从哪查。小游戏项目最大的优势是反馈快。你写一个while循环程序立刻告诉你猜大了还是猜小了你写一个if画面上的小球马上改变方向。这种即时反馈能让新手把注意力集中在 Java 语言本身上而不是被框架和配置淹没。等 Java 基础稳定了再回去做管理系统你会发现数据库和框架其实好理解得多。1.2 十个项目背后是一条完整的学习路径这十个项目不是随便凑的我按难度分成了四个阶段阶段项目核心知识点控制台热身猜数字、猜拳、井字棋变量、循环、分支、数组、方法拆分Swing 入门简易计算器、记忆翻牌JFrame、布局、事件监听、状态管理经典复刻贪吃蛇、扫雷、俄罗斯方块集合、二维数组、递归、键盘控制动作游戏打砖块、飞机大战游戏循环、线程、碰撞检测、对象管理每个项目都解决上一阶段遗留的问题同时给下一阶段埋下伏笔。比如控制台阶段练熟了条件判断到 Swing 阶段才能理解“事件就是另一套 if/else”数组和二维数组练熟了扫雷和俄罗斯方块才不会写到一半崩溃。1.3 开发环境怎么选JDK 17 IDEA 就够了先统一环境避免后面各种版本问题。建议直接装 JDK 17 LTS不要用 JDK 8 也不要追最新版。JDK 17 是目前大多数公司实际在用的版本语法上有switch增强、record这些新特性但又不至于像 JDK 21 那样太新网上资料和面试题都覆盖得到。IDE 用 IntelliJ IDEA Community Edition 就好免费且功能足够。Swing 是 JDK 自带的图形界面库不需要额外装任何东西。个别教程会让你用 JavaFX但 JavaFX 在较新 JDK 里已经不是默认组件配置过程就能劝退一批新手。我们的目标是练 Java 核心语法不是折腾环境。如果不想装 IDE用记事本加命令行也能跑javac GuessNumber.java java GuessNumber不过我建议还是装 IDEA后面做图形界面项目时调试按钮和断点功能能省大量时间。2. 热身期先把逻辑写对再做界面2.1 项目一猜数字猜数字是所有项目里最简单的一个规则不用多说程序随机生成 1 到 100 的整数玩家输入数字程序提示“大了”或“小了”直到猜中。这个项目练的是三件事Random随机数、while循环、if分支。很多新手会犯一个毛病把逻辑写在main方法里一长串长辈谁看了都摇头。所以从第一个项目开始我建议养成“方法拆分”的习惯。核心结构大概是这样Random random new Random(); Scanner scanner new Scanner(System.in); int target random.nextInt(100) 1; int count 0; while (true) { System.out.print(请输入 1-100 之间的整数); int guess scanner.nextInt(); count; if (guess target) { System.out.println(大了); } else if (guess target) { System.out.println(小了); } else { System.out.println(猜中了共猜了 count 次); break; } }这里有一个很多初学者不知道的小知识点random.nextInt(100)生成的是 0 到 99想要 1 到 100 就要加 1。同理如果你要生成 50 到 100公式是random.nextInt(51) 50。把这个规律想明白后面打砖块、飞机大战里生成随机位置就都不会错。做进阶扩展也很简单限制最多猜 7 次或者把难度分成“简单 1-50”“中等 1-100”“困难 1-1000”本质上就是改一个随机范围加一个条件判断。实话说这个项目做十五分钟就够了但它是你第一次体验“完整的小项目闭环”。2.2 项目二猜拳猜拳比猜数字多了一层逻辑判断的复杂度。最简单的做法是用数字 1 表示石头、2 表示剪刀、3 表示布玩家输入数字电脑随机出然后判断胜负。判断胜负的代码写得好不好最能看出一个人有没有编程感觉。新手通常会写一堆 ifif (user 1 computer 2) { System.out.println(你赢了); } if (user 2 computer 3) { System.out.println(你赢了); }这能跑但很蠢。更好的做法是先把胜负关系抽象出来。在“剪刀石头布”里胜负可以看作一种循环关系石头赢剪刀剪刀赢布布赢石头。如果你用 0 表示石头1 表示剪刀2 表示布那么(user - computer 3) % 3的结果一出来就能判断方向。我更喜欢用枚举虽然零基础阶段会稍微多写几行但可读性直接上一个档次enum Move { ROCK, SCISSORS, PAPER } public static Result judge(Move user, Move computer) { if (user computer) return Result.DRAW; if (user ROCK computer SCISSORS) return Result.WIN; if (user SCISSORS computer PAPER) return Result.WIN; if (user PAPER computer ROCK) return Result.WIN; return Result.LOSE; }注意一个细节猜拳项目里要加入“是否再来一局”的循环否则每次都要重新启动程序体验很差。很多新手会把主流程写乱我的方法是把“单局逻辑”拆成一个方法主循环里只负责调用它和询问是否继续。这个项目的额外价值是让你体会“代码重构”的快乐先用一堆 if 跑通然后再改成枚举或switch看看哪种写法更不容易出错。如果你能做到这一步说明你已经从“会写代码”过渡到“会写可维护的代码”了。2.3 项目三井字棋井字棋是第一个涉及二维数组的项目强烈建议在这个阶段就做控制台版本而不是急着做界面。棋盘是 3×3 的char数组玩家 A 和玩家 B 轮流输入行列坐标落子后判断胜负。结构上我们可以拆成四个方法printBoard(char[][] board); boolean isValidMove(char[][] board, int row, int col); boolean checkWin(char[][] board, char player); boolean isBoardFull(char[][] board);主流程大概是while (true) { printBoard(board); // 读入 row col // 判断合法性不合法就重新输入 board[row][col] currentPlayer; // 判断胜负 // 切换玩家 }这里的重点不是写出来而是判断胜负的逻辑。井字棋只有 8 种赢法3 行、3 列、2 条对角线。新手最容易出现的问题是把 8 种情况全部手动if出来又长又容易漏。我的建议是行、列各写一个循环两条对角线单独处理。虽然这个项目规模不大但你已经接触到“算法思维”了同样的问题怎么用更少的代码、更不容易错的方式解决。从井字棋开始你要慢慢接受一个事实程序卡住不是电脑的问题多半是逻辑有漏洞比如没检查坐标越界、没检查格子已经被占、下完棋没切换玩家。这些 bug 找起来的过程其实就是在训练你的逻辑严谨度。3. 图形界面热身从“能跑”到“能看”3.1 项目四简易计算器严格说计算器不算游戏但我强烈建议把它放在这一阶段因为它是上手 Swing 的最小可行项目。界面就一个文本框加一排按钮做完你就会用JFrame、JButton、GridLayout和ActionListener了。先搭一个最小的窗口JFrame frame new JFrame(简易计算器); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 400); frame.setVisible(true);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)是必须的否则关掉窗口后 Java 进程不会结束IDEA 控制台一直显示正在运行这个细节很多人栽过。按钮布局用GridLayout(4, 4)排成四行四列数字和运算符统一用一个监听器处理。一个常用的技巧是给每个按钮设置setActionCommand(1)或setActionCommand()把所有按钮绑定到同一个ActionListener然后根据actionCommand判断按的是哪个。private void onButtonClick(String command) { if (0123456789.contains(command)) { display.setText(display.getText() command); } else if (command.equals()) { // 保存当前数字和运算符 } else if (command.equals()) { // 执行计算 } }Swing 的界面布局、监听器模式到这里就算入门了。等你会写计算器之后再做任何带按钮的游戏逻辑都是相通的。3.2 项目五记忆翻牌记忆翻牌是我非常推荐的一个 Swing 入门项目。棋盘是 4×4 共 16 张牌8 对图案打乱排列玩家每次翻开两张相同则保留不同则盖回去直到全部配对。这个项目比计算器难一截因为它需要你分清“数据”和“界面”。数据部分是一维数组或二维数组里面存的是牌面。界面部分是 16 个JButton。点按钮时你先更新数据状态再根据数据决定按钮显示什么。这块思想其实就是以后做任何正式项目都要用到的“模型视图分离”虽然现在听起来很抽象但做完这个项目你会自然有感觉。建议按下面的步骤拆用一个整数数组存牌面比如{1, 1, 2, 2, 3, 3, ...}然后打乱。创建 4×4 的按钮数组给每个按钮注册MouseListener或ActionListener。维护“当前翻开的第一张牌”和“第二张牌”的状态。两张牌翻完后用Timer延迟 1 秒再判断否则玩家根本看不清第二张是什么。这里有一个难点用Thread.sleep会导致整个窗口卡死因为 Swing 界面刷新必须在事件分发线程EDT上执行你一旦在主线程上sleep界面就冻结了。正确做法是用javax.swing.Timer做延时操作。这个知识点会在后面的贪吃蛇和打砖块里反复出现提前在这里遇到是好事。3.3 Swing 项目的通病布局和刷新做完这两个 Swing 项目你大概率会碰到几个经典问题。第一个是按钮位置不受控制。新手喜欢用setBounds自己画坐标然后发现窗口大小一变界面就乱了。正确的思路是用布局管理器比如GridLayout、BorderLayout、FlowLayout。虽然刚开始不习惯但你只需要知道布局管理器会自动帮你计算位置你能少掉一大半头发。第二个是界面修改后不生效。改完按钮文字、颜色、启用状态之后如果界面没变化一般需要调用revalidate()和repaint()。前者告诉布局管理器重新计算后者触发重绘。第三个是监听器不响应。常见原因是忘记addActionListener或者按钮被其他覆盖。用 IDEA 的调试模式在监听器里打一个断点点击按钮看断点是否进入这是最直接的排查手段。4. 经典复刻贪吃蛇、扫雷、俄罗斯方块4.1 项目六贪吃蛇贪吃蛇几乎是每个 Java 初学者的“成人礼”。它看起来简单但涉及的数据结构和逻辑比前面所有项目都多。蛇身可以用DequePoint或LinkedListPoint表示头在队首尾在队尾。每走一步把头按当前方向插入队首如果吃到食物就不动尾巴否则把尾巴移除。这个思路想明白整个游戏的逻辑基本就通了。// 玩家按上下左右定时器每隔 200ms 走一步 nextHead.x snake.getFirst().x direction.dx; nextHead.y snake.getFirst().y direction.dy; snake.addFirst(nextHead); if (nextHead.equals(food)) { score; generateNewFood(); } else { snake.removeLast(); }移动之后要做三种碰撞检测撞墙、撞自己、吃食物。撞墙和撞自己都直接结束游戏这个判断放在移动之后最合适因为移动前的蛇身和移动后的蛇身都在数据里。画界面我建议用JPanel的paintComponent把蛇身画成一格一格的正方形。核心代码就两行g.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);这里有个容易犯的错坐标轴方向。屏幕的 y 轴往下是正方向也就是说“向下移动”是y 1”而不是y - 1。很多新手第一次做贪吃蛇时蛇会反向移动多半就是这个原因。方向控制用键盘监听。需要注意两个细节一是不能让贪吃蛇直接掉头比如当前方向是右你按左应该被忽略二是KeyListener需要窗口获得焦点才有效所以JFrame上要setFocusable(true)如果你后面发现按方向键没反应不要怀疑键坏了先检查焦点。4.2 项目七扫雷扫雷是这几个经典项目里“算法浓度”最高的一款。二维数组、随机布雷、数字统计、递归展开一个项目全占齐了。数据模型建议准备三个二维数组int[][] mine; // -1 表示地雷0-8 表示周围地雷数 boolean[][] revealed; // 是否已翻开 boolean[][] flagged; // 是否被标记旗帜第一步随机布雷。经典做法是在所有格子中随机选 N 个位置设为地雷。注意要用Random生成不重复的坐标不能同一点放两个雷。第二步计算每个格子周围的雷数。新手最容易在这里写错。一个安全的方法是对每个非雷格子遍历周围 3×3 的九个位置统计其中有多少个雷。写一个inBoard方法判断是否越界可以避免大量数组越界异常。第三步处理点击事件。左键翻开右键标记旗帜。翻开时如果踩雷则游戏结束如果周围雷数为 0则递归展开相邻格子直到遇到数字为止。递归代码并不复杂private void reveal(int row, int col) { if (!inBoard(row, col)) return; if (revealed[row][col]) return; revealed[row][col] true; if (mine[row][col] 0) { for (int dr -1; dr 1; dr) { for (int dc -1; dc 1; dc) { reveal(row dr, col dc); } } } }这里必须注意递归的退出条件少一个if都会栈溢出。当你点一个空格子刷啦啦展开一片格子时那种成就感真的是其他项目给不了的。扫雷还有一个隐藏问题第一次点击不应该踩雷。最简单的方案是等玩家第一次点击后才开始布雷或者布雷后检查第一次点击的位置及其周围是否安全。作为进阶题很值得自己试一试。4.3 项目八俄罗斯方块俄罗斯方块是 10 款项目里体量最大的一个做完它你的 Java 基础基本就过关了。核心数据是一个 10×20 的boolean[][]或颜色数组表示已经落定堆叠的方块。当前正在下落的方块则由“当前形状”“当前所在行”和“当前所在列”三部分组成。形状可以用三维数组定义比如int[][][] SHAPES { // I 形方块 {{1,1,1,1}}, // L 形方块 {{1,0},{1,0},{1,1}} // ... };旋转的逻辑比较麻烦。最直接的方案是提前把每个形状的所有旋转方向都存进去例如 I 形存横和竖两种状态L 形存四种状态。下落时如果旋转后会和已有方块重叠或越界就放弃旋转。这样的代码虽然冗余但对初学者来说最不容易出错。每次下落之前都要检测“当前方块如果能下落会不会和底部或已有方块重叠”。检测方法大同小异把当前方块的每个格子坐标计算出来判断是否越界、是否与背景方块重叠。这个判断是俄罗斯方块的命门所有 bug 基本都出在这。消行逻辑相对简单逐行检查是否满行满行就删除该行上面的行整体下移一格。注意要从下往上检查否则删多行时会乱。做这个项目的心态建议是先让方块能缓缓下落再处理左右移动再一次次修碰撞和旋转。相信我你至少会删掉重来一遍这很正常我第一次写也重构了两次。5. 动作游戏进阶线程、碰撞和游戏循环5.1 项目九打砖块打砖块核心就三件事挡板跟随鼠标移动、小球撞击挡板和砖块反弹、砖块清空就算胜利。整个游戏的驱动方式是用javax.swing.Timer作为“心跳”。每 16ms 或 33ms 执行一次更新移动球、检测碰撞、重绘界面。这里不要用while(true)加Thread.sleep因为在 Swing 里直接操作组件有线程安全问题界面会撕裂或卡死。球的移动用速度分量表示ball.x ball.speedX; ball.y ball.speedY;碰到左右墙就把speedX取反碰到上墙把speedY取反碰到挡板或砖块也要反转速度。砖块碰撞可以用矩形相交判断砖块存储为矩形列表球的移动距离作为一个矩形调用Rectangle.intersects就可以知道撞上了谁。这里有个细节球的速度不要设置成固定值后永远不改。随着关卡进行球速应该逐渐加快否则游戏没有节奏感。最简单的做法是每打掉 5 个砖块让速度乘一个 1.05。打砖块里还隐藏着一个常见问题球卡进砖块或挡板里反复反弹。解决思路是每次移动前先计算并判断下一步会不会撞到如果会就直接修改位置到碰撞点附近再反转方向而不是等已经重叠了才处理。这个“先计算再移动”的思路也是飞机大战里敌人子弹逻辑的雏形。5.2 项目十飞机大战飞机大战可以做得非常复杂但作为练手项目我建议做最经典的纵版射击玩家控制飞机左右上下移动自动发射子弹敌方飞机从上方不断下落撞到敌机或子弹击中敌机都产生效果。这个项目的核心不再是具体某个算法而是对象管理。玩家是一个对象每颗子弹是一个对象每架敌机也是一个对象。它们都在同一个游戏循环里移动、绘制、碰撞、销毁。子弹集合用ArrayListBullet管理。因为游戏中会不停地添加和删除子弹这里一定会遇到ConcurrentModificationException所以遍历删除时一定要用IteratorIteratorBullet it bullets.iterator(); while (it.hasNext()) { Bullet bullet it.next(); bullet.move(); if (bullet.y 0 || bullet.isHit) { it.remove(); } }用 for-each 遍历集合时直接list.remove程序会立刻抛异常。这个知识在面试里也常被问到很多工作两年的人也说不清楚为什么你在项目里亲身体会一次就永远不会忘。动作类游戏需要一个简单的状态管理菜单界面、游戏中、暂停、游戏结束。用枚举GameState表示每次循环先判断状态再执行不同的逻辑。这既是项目结构问题也是以后做任何复杂程序的常见分层思路。我建议做完打砖块再开始飞机大战因为两者的碰撞、循环逻辑很像但飞机大战多了一层“对象多、生命周期短”的复杂度很适合用来补集合的知识。5.3 动作游戏的通用设计更新与绘制分离做打砖块和飞机大战时最好一开始就养成“更新逻辑”和“绘制界面”分开的习惯。更新逻辑只改数据比如x speedX绘制只负责根据数据画东西比如g.fillRect(x, y, w, h)。两者不要混在一起否则后期加暂停、加难度、加特效时会非常痛苦。还有一个容易被忽略的问题是速度单位。如果你用int表示坐标每帧移动 3 个像素在高速显示器上看起来就会一格一格地跳。建议用double保存位置绘制时才转成int这样不同刷新率下运动才能平滑。6. 常见问题速查每天都会踩的坑都在这做这十个项目的过程中大概率会遇到下面这些高频问题。我直接整理成了一张表卡住时先来查。问题现象可能原因解决办法Scanner输入后下一行输入被跳过nextInt()后残留了回车换行字符用nextLine()读取整行再Integer.parseInt或在两次读取间加一次nextLine()Swing 按钮点击没反应按钮没有注册监听器或监听器逻辑绑错对象加断点点击按钮看断点是否进入方向键控制无效JFrame没有焦点KeyListener没收到事件在窗口上调用setFocusable(true)并在点击窗口后重新请求焦点界面卡死、白屏在事件分发线程里执行Thread.sleep或耗时操作使用javax.swing.Timer或SwingWorkerArrayList遍历时删除报错for-each中直接remove触发快速失败机制用Iterator的remove()俄罗斯方块旋转后穿墙或重叠旋转前没有做越界和重叠检测先计算旋转后的格子坐标全部合法后才应用旋转扫雷点空格子导致栈溢出递归展开缺少revealed判断或越界判断检查递归出口先判断越界再判断是否已翻开小球频繁穿过砖块每帧移动步长太大跨越了砖块矩形将球速控制在单个砖块尺寸内采用先检测碰撞再移动的方式窗口关闭后程序还在运行setDefaultCloseOperation设置不对设为JFrame.EXIT_ON_CLOSE确保进程随窗口退出这张表不用背做过两个项目后你自然会记住。对了一定要学会用 IDEA 的 Debug 模式尤其是“断点暂停 变量查看”这两个功能。很多问题在代码里瞪眼看半天都发现不了一调试立刻现形。7. 做完项目之后别急着下一个先重建一次这十个项目做完你的代码量大概在三千行上下。这时你可能会想继续做下一个更炫的项目但我个人的建议是挑一个你最满意的游戏推翻重写一遍。不是照抄而是不再看之前的代码重新设计。比如把贪吃蛇的“蛇身、食物、游戏规则”分别拆成独立类把各个常量集中管理把重复代码提炼成私有方法。第一次写是“让它跑起来”第二次写是“让结构好看”。你会发现第二次写的代码量可能只有原来的一半而且更容易扩展。这个过程比多做十个新项目还值。从面试角度来说这些小游戏项目也可以作为 Java 基础面试的谈资。面试官问你“谈谈你做过的项目”你完全可以说一个俄罗斯方块但要讲清楚里面的数据结构、碰撞处理、线程模型和踩过的并发坑。相比背一堆八股文这种真实项目的经验回答起来更自然也更难被问倒。最后分享一个我自己的习惯每完成一个项目我会在项目根目录写一个README.md简单记录“这个项目做了什么”“核心类有哪些”“运行方式是什么”。这个习惯一开始看起来很麻烦但三个月后你再回来打开这个项目你会感谢自己写了这几行说明。做完这十个项目后你到 GitHub 上一看已经有十个小项目在仓库里躺着那种积累的实感比任何课程打卡都更能让你坚持下去。
返回列表