Java开发-一小时学会贪吃蛇游戏

1.窗口搭建

首先创建一个MySnake类,用来当做主类,搭建出框架

效果如图:

2.引入JPanel组件(用来添加各种模块)

首先创建一个MyPanel类,同时继承JPanel类(重写其中的paintComponent方法来绘制出各种组件)(paintComponent方法其实属于Panel的超类JComponent,不过因为添加到框架时要用到JPanel,故这里也可以理解为重写),同时在MySnake类中,创建一个MyPanel类的对象,添加到f中

然后构造类,将panel背景设置成白色

最后重写paintComponent类(目的是实现自定义的组件绘制逻辑。这对于创建具有特定外观和行为的自定义组件非常有用。)

3.paintComponent方法的具体重写

首先导入贪吃蛇游戏的标题图像、蛇头图像(四个,因为有四个方向)、蛇身体图像、食物图像

注意:导入的图像放到与src同级的目录下,否则读取不到(还可以直接读取图像地址,不过比较麻烦)

导入之后分别创建这7个图像的ImageIcon对象(可以直接复制这几个图片)

3-1添加贪吃蛇标题

(调用 super.paintComponent(g) 是一种常见的做法,主要用于执行一些基本的图形绘制处理,如清除旧的画面内容,确保组件的其他部分正确渲染,以及处理一些继承的绘图逻辑。不调用super.paintComponent(g) 可能导致前一次的绘制内容没有被清除,从而在新的绘制上留下旧的图像。这通常会导致画面出现拖影或重叠现象。

运行主类,结果如下:

3-2添加蛇的活动区域

在paintComponent方法中调用Graphics的fillRect方法(25,75意思是左上角坐标为25,75),实现蛇的活动区域

实现效果如图

3-3初始化一条蛇到画布中

首先,确定蛇的初始长度,再定义两个整型数组来存放蛇的x,y坐标(都在MyPanel类中完成)

之后创建一个initSnake方法,用来初始化蛇的头坐标以及两个身体坐标

最后,在paintComponent方法中画出蛇头以及两个身体

效果如图

3-4设置“开始”的提示字

继续在paintComponent方法中实现,利用Graphics的drawString方法在画布中添加字符串。

为了区分活动区域和字体,利用setColor方法改变字体颜色,setFont方法是用来设置字符串样式的

4.设置键盘监听

以上都是对静态画面的绘制,键盘操作是不会有任何反应的,接下来处理动态的事件

在贪吃蛇游戏中,交互由键盘进行,故需要设置键盘监听

1.对“开始”字样的监听

首先设置布尔变量isStarted,并初始化为false,在paintComponent方法中加入条件判断,从而区分开始页面和游戏进行页面

让MyPanel类实现KeyListener接口,这样MyPanel类自身可以处理键盘事件。(换句话说,当前对象将成为键盘事件的监听器,并负责处理该组件上的键盘事件)

继承后需要重写三个方法keyTyped keyPressed keyReleased(键入字符时适用第一个,键入特殊键如方向键,空格键适用后面两个)

这里我们重写keyPressed方法,此方法在每次特殊键被按下时会被自动调用

最后在构造器中进行前提设置,就完成了对空格键的监听

2.对蛇运动方向的监听

创建一个字符hdirect表示蛇的运动方向,初始化为向右

在keyPressed方法中实现对四个方向键的监听,并转换成对应字符

画出对应方向的蛇头

5.让蛇动起来

首先创建一个Timer对象,作为计时器(每次计时结束时自动调用listener对象),这里将listener作为自己,此时程序会要求实现ActionListener接口并重写actionPerformed方法

在构造器中加入timer.start,这样程序会在构建对象后自动执行

timer在每一次倒计时(前面设为了100毫秒)结束后会自动调用actionPerformed方法,也就是说每一步毫秒后程序会自动执行actionPerformed方法,由于我们要画出运动的蛇,这里就可以理解为动画以100ms/1帧刷新。

当isStarted==true时,游戏才可以运行,因此要在actionPerformed中加入条件判断

上述代码理解:当游戏启动后,将蛇的各个部分的坐标重新赋值,同时注意蛇头越界后会从另一端出现(后续也可以实现碰壁游戏结束)

赋完坐标值之后,对画面进行重绘(注意这也是在actionPerformed方法中),接着调用启动器,实现循环调用actionPerformed方法

效果如下:

6.添加食物

创建整型变量foodx,foody来表示食物的坐标,用Random类生成随机值

在initSnake方法中进行初始化,然后在paintComponent方法中画出来

画完之后,要建立食物和蛇的互动,当蛇头坐标等于食物时,蛇的长度增加,由于长度增加这一事件属于活动,我们自然想到在actionPerformed方法中进行

注意这里将最后的新增body坐标设为了倒数第二个的,这是因为在接下来repaint后最后的body在默认情况下会被设置为(0,0)坐标,那么左上角会跳一帧,虽然问题不大,但是影响观感

(这个if语句也在isStarted的判断中)

实现效果如图:

7.添加结束标语

当蛇头碰到身体或墙壁时,认为游戏结束

首先创建两个个布尔变量isFailed和wining

当结束时,打印字样(在paintComponent方法中):

当胜利时,打印字样(在paintComponent方法中):

实现失败和成功的动画(在actionPerformed方法中),这里蛇的活动被限制在启动后,未失败,未开始的状态

当蛇头与身体,蛇头与墙壁碰撞时,游戏失败(同时这里我们要清除上面的蛇可以越过墙壁的代码)

至于胜利标志,我们首先设置一个积分,当积分达到一定时游戏胜利

当蛇头每次和食物接触时,积分增加

这样,当游戏失败或者成功时,都会弹出字样提示,同时我们还需要有对应的措施重新开始游戏,

在initSnake方法中,我们进行如下初始化

在键盘监听方法中,按下空格来使游戏重新开始

8.设置积分字样

为了在游戏中看到实时的积分画面,我们需要在paintComponent方法中画出积分

效果如图

9.结束

到此,游戏基本已经结束,我们还有可以进行扩展。

1.当蛇的长度增加时,可以增加蛇的移动速度(可以通过剪短计时周期)

2.添加背景音乐

3.设置不同的食物,有的具有增益效果,有的具有负面效果,从而增加趣味性

  • 41
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是一个简单的贪吃蛇游戏JAVA代码,供您参考: ```java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class SnakeGame extends JPanel implements ActionListener { private final int WIDTH = 300; private final int HEIGHT = 300; private final int DOT_SIZE = 10; private final int ALL_DOTS = 900; private final int RAND_POS = 29; private final int DELAY = 140; private int[] x = new int[ALL_DOTS]; private int[] y = new int[ALL_DOTS]; private int dots; private int apple_x; private int apple_y; private boolean leftDirection = false; private boolean rightDirection = true; private boolean upDirection = false; private boolean downDirection = false; private boolean inGame = true; private Timer timer; private Image ball; private Image apple; private Image head; public SnakeGame() { addKeyListener(new TAdapter()); setBackground(Color.black); setPreferredSize(new Dimension(WIDTH, HEIGHT)); ImageIcon iid = new ImageIcon(this.getClass().getResource("dot.png")); ball = iid.getImage(); ImageIcon iia = new ImageIcon(this.getClass().getResource("apple.png")); apple = iia.getImage(); ImageIcon iih = new ImageIcon(this.getClass().getResource("head.png")); head = iih.getImage(); initGame(); } public void initGame() { dots = 3; for (int z = 0; z < dots; z++) { x[z] = 50 - z * 10; y[z] = 50; } locateApple(); timer = new Timer(DELAY, this); timer.start(); } public void paintComponent(Graphics g) { super.paintComponent(g); doDrawing(g); } public void doDrawing(Graphics g) { if (inGame) { g.drawImage(apple, apple_x, apple_y, this); for (int z = 0; z < dots; z++) { if (z == 0) { g.drawImage(head, x[z], y[z], this); } else { g.drawImage(ball, x[z], y[z], this); } } Toolkit.getDefaultToolkit().sync(); } else { gameOver(g); } } public void gameOver(Graphics g) { String msg = "Game Over"; Font small = new Font("Helvetica", Font.BOLD, 14); FontMetrics metr = getFontMetrics(small); g.setColor(Color.white); g.setFont(small); g.drawString(msg, (WIDTH - metr.stringWidth(msg)) / 2, HEIGHT / 2); } public void checkApple() { if ((x[0] == apple_x) && (y[0] == apple_y)) { dots++; locateApple(); } } public void move() { for (int z = dots; z > 0; z--) { x[z] = x[(z - 1)]; y[z] = y[(z - 1)]; } if (leftDirection) { x[0] -= DOT_SIZE; } if (rightDirection) { x[0] += DOT_SIZE; } if (upDirection) { y[0] -= DOT_SIZE; } if (downDirection) { y[0] += DOT_SIZE; } } public void checkCollision() { for (int z = dots; z > 0; z--) { if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) { inGame = false; } } if (y[0] >= HEIGHT) { inGame = false; } if (y[0] < 0) { inGame = false; } if (x[0] >= WIDTH) { inGame = false; } if (x[0] < 0) { inGame = false; } if(!inGame) { timer.stop(); } } public void locateApple() { int r = (int) (Math.random() * RAND_POS); apple_x = ((r * DOT_SIZE)); r = (int) (Math.random() * RAND_POS); apple_y = ((r * DOT_SIZE)); } public void actionPerformed(ActionEvent e) { if (inGame) { checkApple(); checkCollision(); move(); } repaint(); } private class TAdapter extends KeyAdapter { public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) { leftDirection = true; upDirection = false; downDirection = false; } if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) { rightDirection = true; upDirection = false; downDirection = false; } if ((key == KeyEvent.VK_UP) && (!downDirection)) { upDirection = true; rightDirection = false; leftDirection = false; } if ((key == KeyEvent.VK_DOWN) && (!upDirection)) { downDirection = true; rightDirection = false; leftDirection = false; } } } } ``` 这是一个简单的贪吃蛇游戏的实现,你可以在这个代码的基础上进行修改和完善,让游戏更加好玩。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值