用java实现贪吃蛇游戏(源码+详细注释)
(素材图片在文末)
一、文件结构
二、实现代码
- StartGame
在这里插入代package com.nanguadeng.eatsnakes;
import javax.swing.*;
import java.awt.*;
public class StartGame {
public static void main(String[] args) {
//创建一个窗体:
JFrame jf = new JFrame();
//给窗体设计标题:
jf.setTitle("贪吃蛇小游戏");
//获得屏幕宽和高
int width = Toolkit.getDefaultToolkit().getScreenSize().width;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
//设置窗体弹出对应坐标及对应窗体宽和高
jf.setBounds((width-800)/2,(height-800)/2,800,800);
//设置窗体大小不可调节
jf.setResizable(false);
//关闭窗口时程序就关闭:
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//创建面版:
GamePanel gp = new GamePanel();
//将面板放入窗体中:
jf.add(gp);
//默认情况下窗体是隐藏的,所以必须将窗体进行显现:
jf.setVisible(true);//显现方法最好放最后,因为中间有一些设置
}
}码片
- Images
在这里插入代package com.nanguadeng.eatsnakes;
import javax.swing.*;
import java.awt.*;
public class StartGame {
public static void main(String[] args) {
//创建一个窗体:
JFrame jf = new JFrame();
//给窗体设计标题:
jf.setTitle("贪吃蛇小游戏");
//获得屏幕宽和高
int width = Toolkit.getDefaultToolkit().getScreenSize().width;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
//设置窗体弹出对应坐标及对应窗体宽和高
jf.setBounds((width-800)/2,(height-800)/2,800,800);
//设置窗体大小不可调节
jf.setResizable(false);
//关闭窗口时程序就关闭:
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//创建面版:
GamePanel gp = new GamePanpackage com.nanguadeng.eatsnakes;
import java.net.URL;
import javax.swing.*;
//Image类专门用来获取游戏中所涉及的图片
public class Images {
/*因为是面向对象的语言
所以要将图片封装为一个对象
这样在程序中才可以通过操纵这个对象来操纵图片 */
//将图片路径封装为一个对象:
public static URL bodyURL = Images.class.getResource("/images/body.png");
//那一个斜杠表示的是相对路径,比如现在的路径file:/D:/java成品/组件及事件处理/eatsnakes/out/production/eatsnakes/
//将图片封装为一个对象:
public static ImageIcon bodyImg = new ImageIcon(bodyURL);
public static URL downURL = Images.class.getResource("/images/down.png");
public static ImageIcon downImg = new ImageIcon(downURL);
public static URL foodURL = Images.class.getResource("/images/food.png");
public static ImageIcon foodImg = new ImageIcon(foodURL);
public static URL headerURL = Images.class.getResource("/images/header.png");
public static ImageIcon headerImg = new ImageIcon(headerURL);
public static URL leftURL = Images.class.getResource("/images/left.png");
public static ImageIcon leftImg = new ImageIcon(leftURL);
public static URL upURL = Images.class.getResource("/images/up.png");
public static ImageIcon upImg = new ImageIcon(upURL);
public static URL rightURL = Images.class.getResource("/images/right.png");
public static ImageIcon rightImg = new ImageIcon(rightURL);
}
- GamePanel
在这里插入代码片package com.nanguadeng.eatsnakes;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
//继承了JPanel就是面板了
public class GamePanel extends JPanel {
//蛇的长度:
int length;
//定义两个数组
//一个专门存储X轴坐标
int[] snakeX = new int[200];
//一个专门存储Y轴坐标
int [] snakeY = new int[200];
//游戏只有两个状态,开始,暂停:
boolean isStart = false;//默认暂停
//加入一个定时器:
Timer timer;
//定义蛇的行走方向:
String direction;
//定义食物XY坐标
int foodX;
int foodY;
//定义一个积分:
int score;
//加入一个变量,判断小蛇死亡状态:
boolean isDie = false;
public void init(){
//初始化蛇的长度:
length = 3;
//初始化蛇头坐标:
snakeX[0] = 175;
snakeY[0] = 275;
//初始化第一节身子坐标:
snakeX[1] = 150;
snakeY[1] = 275;
//初始化第二节身子坐标:
snakeX[2] = 125;
snakeY[2] = 275;
//初始化蛇头方向
direction = "R";//之后将用U D R L表示方向
//初始化食物坐标:
foodX = 300;
foodY = 200;
}
public GamePanel(){
init ();
//将焦点定位在当前操做面板上:
this.setFocusable(true);
//加入监听:
this.addKeyListener(new KeyAdapter() {//监听按下操做
public void keyPressed(KeyEvent e) {//监听键盘按键的按下操作
super.keyPressed(e);
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_SPACE){//监听格键
if(isDie){
//全部恢复到初始态
init();
isDie = false;
}else {
isStart = !isStart;//监听到按下空格后,开始状态变暂停状态,暂停状态变开始状态
repaint();//重绘动作
}
}
//监听向上箭头:
if(keyCode == KeyEvent.VK_UP){
direction = "U";//改变方向
}
//监听向下箭头:
if(keyCode == KeyEvent.VK_DOWN){
direction = "D";//改变方向
}
//监听向左箭头:
if(keyCode == KeyEvent.VK_LEFT){
direction = "L";//改变方向
}
//监听向右箭头:
if(keyCode == KeyEvent.VK_RIGHT){
direction = "R";//改变方向
}
}
});
//对定时器进行初始化动作:
timer = new Timer(100, new ActionListener() {
/*
ActionListener是 事件监听
相当于每100毫秒监听一下是否发生了一个动作
具体动作放入ActionPerforemed
*/
public void actionPerformed(ActionEvent e) {
if(isStart && isDie == false){//游戏是开始状态并且不是死亡状态才会动
//后一节身子到前一节身子的位置上
for(int i = length - 1;i > 0;i--){
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
//动头:
if("R".equals(direction)){
snakeX[0] += 25;
}
if("L".equals(direction)){
snakeX[0] -= 25;
}
if("U".equals(direction)){
snakeY[0] -= 25;
}
if("D".equals(direction)){
snakeY[0] += 25;
}
//防止蛇飞出边界:
//向右边界:
if(snakeX[0] > 750){
snakeX[0] = 25;
}
//向上边界:
if(snakeY[0] < 75 ){
snakeY[0] = 725;
}
//向左边界:
if(snakeX[0] < 25){
snakeX[0] = 750;
}
//向下边界:
if(snakeY[0] > 725){
snakeY[0] = 75;
}
//检测碰撞的动作:(食物和蛇头坐标相同)
if (snakeX[0] == foodX && snakeY[0] ==foodY) {
//蛇长加一
length++;
//食物坐标改变:(随机生成坐标,且必须是25的倍数,不能超过矩形):
/*要一个[1,30]的随机数用来乘25
Math.random() --> [0.0,1.0)
Math.random() * 30 --> [0.0,30.0)
(int)(Math.random() * 30) --> [0,29]
(int)(Math.random() * 30) + 1 --> [1,30]
*/
foodX = ((int)(Math.random() * 30) + 1) * 25;//[25,750]
/*要一个[3,29]的随机数乘25
[3,29] --> [0,26] + 3
要[0,26]的随机数
new Random().nextInt(27) --> [0,27) --> [0,26]
*/
foodY = (new Random().nextInt(27) + 3) * 25;//[75,725]
//吃上食物后加10分:
score += 10;
}
//死亡判定:
for (int i = 1;i < length;i++){
if(snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]){
//将死亡状态改为true
isDie = true;
}
}
repaint();//刷新,重绘
}
}
});
//定时器要启动
timer.start();
}
//paintComponent这个方法比较特殊,这个方法属于图形版的main方法,虚拟机自己调用
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//填充背景颜色
this.setBackground(new Color(2, 76, 76, 67));
//画头部图片(当前窗口,G画笔工具,在-60,0处画)
Images.headerImg.paintIcon(this,g,-60,0);
//调节画笔颜色:
g.setColor(new Color(205, 205, 205));
//画一个矩形:
g.fillRect(9,70,770,685);
//画小蛇:
//画蛇头
if("R".equals(direction)){
Images.rightImg.paintIcon(this,g,snakeX[0],snakeY[0]);
}
if("L".equals(direction)){
Images.leftImg.paintIcon(this,g,snakeX[0],snakeY[0]);
}
if("U".equals(direction)){
Images.upImg.paintIcon(this,g,snakeX[0],snakeY[0]);
}
if("D".equals(direction)){
Images.downImg.paintIcon(this,g,snakeX[0],snakeY[0]);
}
//循环画蛇身:
for(int i = 1;i<length;i++){
Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
}
//如果游戏暂停,界面中间就应该有提示语:
if(isStart == false){
//调颜色
g.setColor(new Color(172, 113, 222));
//三个参数:字体,加粗,字号
g.setFont(new Font("楷体",Font.BOLD,40));
//画一文字:内容,X轴坐标,Y轴坐标
g.drawString("点击空格开始游戏",250,330);
}
//画食物:
Images.foodImg.paintIcon(this,g,foodX,foodY);
//画积分:
g.setColor(new Color(0, 47, 78));
g.setFont(new Font("微软雅黑",Font.BOLD,20));
g.drawString("积分:" + score,620,40);
//画入死亡状态:
if(isDie){
g.setColor(new Color(199, 64, 80));
g.setFont(new Font("微软雅黑",Font.BOLD,40));
g.drawString("你的蛇死了,按下空格重生",175,330);
}
}
}
三、效果实现
四、素材获得
https://pan.baidu.com/s/1YdUlQ2TFsx_Xwb_OEbcZkA
提取码:y5td