JAVA小项目(四)—— 贪吃蛇【轻松入门,附源码】

本文详细介绍了如何使用Java编程实现一个简单的贪吃蛇游戏,包括加载图片资源、创建窗体、绘制面板、小蛇的动态绘制、监听键盘事件、控制蛇的移动以及食物和得分的处理。通过这个游戏的实现,读者可以了解Java图形界面的基本操作和游戏逻辑的构建。
摘要由CSDN通过智能技术生成

目录

(一)效果图

(二)代码实现

(1)将图片加载到程序中

(2)创建窗体

(3)创建面板

(4)绘制静态的小蛇

(5) 加入监听事件

 (6)让蛇动起来 

(7)绘制食物和吃食物

(8)把游戏打包

💴哈喽,大家好丫,你们的小郭子又来啦 ~

🌞今天我们用java来写一个简单的小项目——【贪吃蛇】,嘿嘿,是不是DNA动了呀🌞🌞

🌞话不多说,直接上干货,

  

(一)效果图

 

(二)代码实现

(1)将图片加载到程序中

现在本程序中创建一个Images包,包中保存需要使用的照片,如图所示

 

/**
 * Images这个类,专门用来获取游戏中所涉及的图片
 */
public class Images {
    /*
    现在是面向对象的语言,面向对象的思维--》将图片进行封装 ,封装为一个对象,这样在程序中才可以通过操纵这个对象来操纵图片。
     */
    //将图片的路径封装为一个对象:
    public static URL bodyURL = Images.class.getResource("/images/body.png");
    //将图片封装为程序中一个对象:
    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 rightURL = Images.class.getResource("/images/right.png");
    //将图片封装为程序中一个对象:
    public static ImageIcon rightImg = new ImageIcon(rightURL);
    //将图片的路径封装为一个对象:
    public static URL upURL = Images.class.getResource("/images/up.png");
    //将图片封装为程序中一个对象:
    public static ImageIcon upImg = new ImageIcon(upURL);
}
class TestURL {
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        URL url = Images.class.getResource("/");// /指代的就是相对路径,相对/D:/IDEA_workspace/TestJavaSE/out/production/TestSnakeGame/
        System.out.println(url);
    }
}

(2)创建窗体

public class StartGame {
    public static void main(String[] args) {
        //创建一个窗体:
        JFrame jf = new JFrame();
        //给窗体设置一个标题:
        jf.setTitle("贪吃蛇  by jayden");
        //设置窗体弹出的坐标,对应窗体的宽高:
        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);
        //默认情况下窗体是隐藏效果,必须将窗体进行显现:细节--》这个显现方法最好放在最后
        jf.setVisible(true);
    }
}

(3)创建面板

public class StartGame {
    public static void main(String[] args) {
        //创建一个窗体:
        JFrame jf = new JFrame();
        //给窗体设置一个标题:
        jf.setTitle("贪吃蛇  by jayden");
        //设置窗体弹出的坐标,对应窗体的宽高:
        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);
        //默认情况下窗体是隐藏效果,必须将窗体进行显现:细节--》这个显现方法最好放在最后
        jf.setVisible(true);
    }
}

(4)绘制静态的小蛇

/**
 * @author : jayden
 * GamePanel继承了JPanel以后,才具备面板的功能,才成为一个面板
 */
public class GamePanel extends JPanel {
    //定义两个数组
    //蛇的长度:
    int length;
    //一个数组,专门存储蛇的x轴坐标
    int[] snakeX = new int[200];
    //一个数组,专门存储蛇的y轴坐标
    int[] snakeY = new int[200];
    //定义蛇的行走方向:
    String direction ;
    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  L R
    }
    public GamePanel(){
        init();
    }
    /*
    paintComponent这个方法比较特殊,这个方法就属于图形版的main方法
    自动调用
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        //填充背景颜色:
        this.setBackground(new Color(208, 221, 227));
        //画头部图片:
        /*
        paintIcon四个参数:this指的是当前面板  g:指的是使用的画笔  x,y对应的坐标
         */
        Images.headerImg.paintIcon(this,g,-10,10);
        //调解画笔颜色:
        g.setColor(new Color(219, 226, 219));
        //画一个矩形:
        g.fillRect(10,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]);
        }
        /*//画第一节身子:
        Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]);
        //画第二节身子:
        Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);*/
        //优化为循环画蛇的身子:
        for(int i = 1;i<length;i++){
            Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
        }
    }
}

(5) 加入监听事件

/**
 * @author : jayden
 * GamePanel继承了JPanel以后,才具备面板的功能,才成为一个面板
 */
public class GamePanel extends JPanel {
    //定义两个数组
    //蛇的长度:
    int length;
    //一个数组,专门存储蛇的x轴坐标
    int[] snakeX = new int[200];
    //一个数组,专门存储蛇的y轴坐标
    int[] snakeY = new int[200];
    //游戏只有两个状态,开始,暂停:
    boolean isStart = false;//默认游戏是暂停效果
    //定义蛇的行走方向:
    String direction ;
    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  L R
    }
    public GamePanel(){
        init();
        //将焦点定位在当前操作的面板上:
        this.setFocusable(true);
        //加入监听:
        this.addKeyListener(new KeyAdapter(){
            @Override
            public void keyPressed(KeyEvent e) {//监听键盘按键的按下操作
                super.keyPressed(e);
                int keyCode = e.getKeyCode();
                System.out.println(keyCode);
                if(keyCode == 32){
                    isStart = !isStart;//监听到空格以后,游戏开始的就变成暂停的,暂停的就变成开始的
                    repaint();//重绘动作,重新调用paintComponent()方法
                }
            }
        });
    }
    /*
    paintComponent这个方法比较特殊,这个方法就属于图形版的main方法
    自动调用
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        //填充背景颜色:
        this.setBackground(new Color(208, 221, 227));
        //画头部图片:
        /*
        paintIcon四个参数:this指的是当前面板  g:指的是使用的画笔  x,y对应的坐标
         */
        Images.headerImg.paintIcon(this,g,-10,10);
        //调解画笔颜色:
        g.setColor(new Color(219, 226, 219));
        //画一个矩形:
        g.fillRect(10,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]);
        }
        /*//画第一节身子:
        Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]);
        //画第二节身子:
        Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);*/
        //优化为循环画蛇的身子:
        for(int i = 1;i<length;i++){
            Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
        }
        //如果游戏暂停的,界面中间就应该有一句提示语:
        if(isStart == false){
            //画一个文字:
            g.setColor(new Color(114, 98, 255));
            //三个参数:字体,加粗,字号
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            //画文字:三个参数:文字内容,x轴坐标,y轴坐标
            g.drawString("点击空格开始游戏",250,330);
        }
    }
}

 (6)让蛇动起来 

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 ;
    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  L R
    }
    public GamePanel(){
        init();
        //将焦点定位在当前操作的面板上:
        this.setFocusable(true);
        //加入监听:
        this.addKeyListener(new KeyAdapter(){
            @Override
            public void keyPressed(KeyEvent e) {//监听键盘按键的按下操作
                super.keyPressed(e);
                int keyCode = e.getKeyCode();
                System.out.println(keyCode);
                if(keyCode == 32){
                    isStart = !isStart;//监听到空格以后,游戏开始的就变成暂停的,暂停的就变成开始的
                    repaint();//重绘动作,重新调用paintComponent()方法
                }
            }
        });
        //对定时器进行初始化动作:
        timer = new Timer(150, new ActionListener() {
            /*
            ActionListener是 事件监听
            相当于每100ms监听一下你是否发生了一个动作
            具体的动作放入actionPerformed
             */
            @Override
            public void actionPerformed(ActionEvent e) {
                if(isStart){//游戏是开始状态的时候,蛇才动:
                    //后一节身子走到前一节身子的位置上:
                    for(int i=length-1;i>0;i--){
                        snakeX[i] = snakeX[i-1];
                        snakeY[i] = snakeY[i-1];
                    }
                    //动头:
                    snakeX[0] += 25;
                    //防止蛇超出边界:
                    if(snakeX[0]>750){
                        snakeX[0] = 25;
                    }
                    repaint();//重绘
                }
            }
        });
        //定时器必须要启动:
        timer.start();
    }

    /*
    paintComponent这个方法比较特殊,这个方法就属于图形版的main方法
    自动调用
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        //填充背景颜色:
        this.setBackground(new Color(208, 221, 227));
        //画头部图片:
        /*
        paintIcon四个参数:this指的是当前面板  g:指的是使用的画笔  x,y对应的坐标
         */
        Images.headerImg.paintIcon(this,g,-10,10);
        //调解画笔颜色:
        g.setColor(new Color(219, 226, 219));
        //画一个矩形:
        g.fillRect(10,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]);
        }
        /*//画第一节身子:
        Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]);
        //画第二节身子:
        Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);*/
        //优化为循环画蛇的身子:
        for(int i = 1;i<length;i++){
            Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
        }
        //如果游戏暂停的,界面中间就应该有一句提示语:
        if(isStart == false){
            //画一个文字:
            g.setColor(new Color(114, 98, 255));
            //三个参数:字体,加粗,字号
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            //画文字:三个参数:文字内容,x轴坐标,y轴坐标
            g.drawString("点击空格开始游戏",250,330);
        }
    }
}

(7)绘制食物和吃食物

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 ;
    //定义食物的x,y轴坐标:
    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;
        //初始化食物的坐标:
        foodX = 300;
        foodY = 200;

        //初始化蛇头的方向:
        direction = "R"; // U  D  L R
    }
    public GamePanel(){
        init();
        //将焦点定位在当前操作的面板上:
        this.setFocusable(true);
        //加入监听:
        this.addKeyListener(new KeyAdapter(){
            @Override
            public void keyPressed(KeyEvent e) {//监听键盘按键的按下操作
                super.keyPressed(e);
                int keyCode = e.getKeyCode();
                System.out.println(keyCode);
                if(keyCode == 32){
//                    isStart = !isStart;//监听到空格以后,游戏开始的就变成暂停的,暂停的就变成开始的
//                    repaint();//重绘动作,重新调用paintComponent()方法
                    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(150, new ActionListener() {
            /*
            ActionListener是 事件监听
            相当于每100ms监听一下你是否发生了一个动作
            具体的动作放入actionPerformed
             */
            @Override
            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(snakeX[0]<25){
                        snakeX[0] = 750;
                    }
                    if(snakeY[0]<100){
                        snakeY[0] = 725;
                    }
                    if(snakeY[0]>725){
                        snakeY[0] = 100;
                    }
                    //防止蛇超出边界:
                    if(snakeX[0]>750){
                        snakeX[0] = 25;
                    }
                    //检测碰撞的动作:
                    //食物的坐标和蛇头的坐标一样的时候,才是碰撞了
                    if(snakeX[0] == foodX&&snakeY[0] == foodY){
                        //蛇长度加1:
                        length++;
                        //吃上食物以后 积分加10分:
                        score += 10;
                        //食物坐标改变:随机生成坐标 --》细节:坐标必须是25的倍数
                        /*
                        [25,750] -> [1,30]*25
                        [1,30]
                        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]
                        /*
                        [100,725] -> [4,29]*25
                        [4,29]->[0,25]+4
                        [0,25]
                        new Random().nextInt(26) -> [0,26) ->[0,25]
                         */
                        foodY = (new Random().nextInt(26)+4)*25;//[100,725]
                    }
                    //死亡判定:蛇头和任意一节身子碰撞都是死亡:
                    for(int i = 1;i<length;i++){
                        if(snakeX[0]==snakeX[i]&&snakeY[0]==snakeY[i]){
                            //将死亡 状态改为:true
                            isDie = true;
                        }
                    }
                    repaint();//重绘
                }
            }
        });
        //定时器必须要启动:
        timer.start();
    }

    /*
    paintComponent这个方法比较特殊,这个方法就属于图形版的main方法
    自动调用
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        //填充背景颜色:
        this.setBackground(new Color(208, 221, 227));
        //画头部图片:
        /*
        paintIcon四个参数:this指的是当前面板  g:指的是使用的画笔  x,y对应的坐标
         */
        Images.headerImg.paintIcon(this,g,-10,10);
        //调解画笔颜色:
        g.setColor(new Color(219, 226, 219));
        //画一个矩形:
        g.fillRect(10,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]);
        }
        /*//画第一节身子:
        Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]);
        //画第二节身子:
        Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);*/
        //优化为循环画蛇的身子:
        for(int i = 1;i<length;i++){
            Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
        }
        //如果游戏暂停的,界面中间就应该有一句提示语:
        if(isStart == false){
            //画一个文字:
            g.setColor(new Color(114, 98, 255));
            //三个参数:字体,加粗,字号
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            //画文字:三个参数:文字内容,x轴坐标,y轴坐标
            g.drawString("点击空格开始游戏",250,330);
        }
        //画食物:
        Images.foodImg.paintIcon(this,g,foodX,foodY);
        //画积分:
        g.setColor(new Color(255, 248, 248));
        g.setFont(new Font("微软雅黑",Font.BOLD,20));
        g.drawString("积分:"+score,670,45);
        //画入死亡状态:
        if(isDie){
            g.setColor(new Color(255, 82, 68));
            g.setFont(new Font("微软雅黑",Font.BOLD,20));
            g.drawString("小蛇死亡,游戏停止,按下空格重新开始游戏",200,330);
        }
    }
}

(8)把游戏打包

 

 

 

 

     

好啦,今天的分享到这里就结束啦 ~🌞🌞

 觉得我分享的文章不错的话,可以关注一下哦,嘻嘻嘻🌞🌞

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值