实验二:贪吃蛇的实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实验二:贪吃蛇的实现相关的知识,希望对你有一定的参考价值。

目录

实验准备

1.实验参考 

2.实验总体思路

一. 界面设计

二. 蛇的初始化

三. 键盘监听

四. 随机生成食物

五. 判断蛇吃食物

六. 蛇的移动和防止超出边界

七. 蛇的死亡

八. 定时器

成品展示


实验准备

1.实验参考 

实验参考的是B站UP主麦数编程的教程,链接:贪吃蛇:1小时Java开发贪吃蛇游戏 [编号:J301]_哔哩哔哩_bilibili,同时在他的基础上对贪吃蛇加上一些更改和限定。

2.实验总体思路

一. 界面设计

       我使用的贪吃蛇是在Snake.java的主方法中创建了一个JFrame对象,然后在新的文件 MyPanel.java创建了一个MyPanel类继承JPanel,在JPanel中绘制贪吃蛇游戏,最后添加进JFrame对象中。

protected void paintComponent(Graphics g) 
        super.paintComponent(g);
        //自动填充背景颜色
        this.setBackground(new Color(246, 241, 200));
        //画头部图片
        //paintIcon 四个参数:this 指的是当前面板 g:知道是画笔 x,y 指的是对应坐标
        //调画笔颜色
        g.setColor(new Color(0xE7DFDF));
        //画一个矩形
        g.fillRect(10, 70, 760, 685);

        //画蛇头
        if ("R".equals(direction)) 
            Images.rightImg.paintIcon(this, g, snakeX[0], snakeY[0]);
         else if ("L".equals(direction)) 
            Images.leftImg.paintIcon(this, g, snakeX[0], snakeY[0]);
         else if ("U".equals(direction)) 
            Images.upImg.paintIcon(this, g, snakeX[0], snakeY[0]);
         else 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(0xFF7373));
            //字体 字号 大小
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            //文字内容 出现的位置
            g.drawString("点击空格开始/暂停游戏", 200, 330);
        

        Images.foodImg.paintIcon(this, g, foodX, foodY);
        g.setColor(new Color(255, 76, 76));
        g.setFont(new Font("微软雅黑", Font.BOLD, 40));
        g.drawString("积分" + ":" + score, 600, 40);

二. 蛇的初始化

       我使用的是数组来进行对蛇的初始化和存储,每吃到一个食物便对蛇身加长一次,也就是在数组当中存入一次数据,并将其加在蛇身上。

//蛇的长度:
    int length;
 public void init() 
        //初始化蛇的长度:
        length = 3;
        //图片大小为25x25
        //初始化蛇头轴坐标:
        snakeX[0] = 175;
        snakeY[0] = 175;
        //初始化第一节身子坐标:
        snakeX[1] = 150;
        snakeY[1] = 175;
        //初始化第二节身子坐标:
        snakeX[2] = 125;
        snakeY[2] = 175;
        //初始化蛇头的方向:
        direction = "R";
        //食物初始的坐标
        foodX = 300;
        foodY = 200;
        //积分
        score = 0;
    

三. 键盘监听

       要对蛇进行上下左右的控制就需要我们队蛇进行键盘的监听,我们可以通过KeyListener来对键盘进行监听    相关方法:KeyListener_java_5666666的博客-CSDN博客_keylistener

       同时,我加入了按空格来对游戏的开始、暂停以及重新开始,同时还有一个限定条件,比如:当蛇在向上移动的时候,我们按键盘的下和上蛇应该是不会有任何反应的,否则便会出现蛇直接回头将自己吃掉的情况。

 this.addKeyListener(new KeyAdapter() 
            @Override
            public void keyPressed(KeyEvent e) //监听键盘按键的按下操作
                super.keyPressed(e);
                int keyCode = e.getKeyCode();
                //System.out.println(keyCode);  32
                if (keyCode == KeyEvent.VK_SPACE) //监听空格
                    if (isDie) 
                        init();
                        isDie = false;
                     else 
                        isStart = !isStart;
                    
                    repaint();//重绘游戏
                
                //监听上下左右
                switch (keyCode) 
                    case KeyEvent.VK_UP:
                        if (!direction.equals("D"))
                            direction = "U";
                        
                        break;
                    case KeyEvent.VK_DOWN:
                        if (!direction.equals("U"))
                            direction = "D";
                        
                        break;
                    case KeyEvent.VK_RIGHT:
                        if (!direction.equals("L"))
                            direction = "R";
                        
                        break;
                    case KeyEvent.VK_LEFT:
                        if (!direction.equals("R"))
                            direction = "L";
                        
                        break;
                
            
        

       我的代码当中,是定义了一个direction来存储蛇的行动方向,同时也通过其中存放的字母来判断蛇可以向哪个方向更改。

四. 随机生成食物

       为了防止食物的生成会和蛇的位置重叠,需要在生成的坐标后面进行判断,遍历蛇的所以位置,一旦相同,重新生成一个。

private void setMinFood() 
        Boolean setFood;
        do 
            setFood = true;
            foodx = 25 + 25 * rand.nextInt(34);
            foody = 110 + 25 * rand.nextInt(24);
            p = first;
            // 防止生成的食物在蛇身上
            while (p != null) 
                if (p.getX() == foodx && p.getY() == foody) 
                    setFood = false;
                    break;
                
                p = p.next;
            
            if ((foodx == bigFoodx && foody == bigFoody)
                    || (foodx == bigFoodx -25 && foody == bigFoody)
                    || (foodx == bigFoodx && foody == bigFoody - 25)
                    || (foodx == bigFoodx -25 && foody == bigFoody - 25)) 
                setFood = false;
            
         while (!setFood);

    

五. 判断蛇吃食物

       每次出现的食物都会有一个属于它的坐标,我们只需要判断蛇头的坐标和食物的坐标是否重合便可以判断蛇是否吃到了食物。

 if (snakeX[0] == foodX && snakeY[0] == foodY) 
                        //长度加+
                        length++;
                        //随机生成坐标
                        foodX = ((int) (Math.random() * 30) + 1) * 25;//[25,750]
                        foodY = (new Random().nextInt(26) + 4) * 25;//[100,750]
                        score += 10;
                    

六. 蛇的移动和防止超出边界

       通过一开始定义的蛇的数组来实现蛇的移动,我们只需要将蛇的每一节放置在界面的坐标当中,然后通过判定方向来对蛇身的每一节进行坐标的加减即可。同时,如果蛇头碰到了边界坐标,那么我们就会判定蛇死亡。

                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;
                     else if ("U".equals(direction)) 
                        snakeY[0] -= 25;
                     else if ("D".equals(direction)) 
                        snakeY[0] += 25;
                     else if ("L".equals(direction)) 
                        snakeX[0] -= 25;
                    

                    //防止蛇超出边界:
                    if (snakeX[0] > 750) 
                        isDie = true;
                     else if (snakeY[0] < 100) 
                        isDie = true;
                     else if (snakeX[0] < 25) 
                        isDie = true;
                     else if (snakeY[0] > 725) 
                        isDie = true;
                    

七. 蛇的死亡

       除了上面的蛇头碰到边界我们判定蛇死亡之外,还有如果蛇碰到了自己的身体我们也会判定蛇死亡。同样的我们只需要判定蛇头的坐标和蛇身的坐标是否在同一时间处于同一个坐标,如果是的话,那么我们便可以判断蛇死亡。同时进行画面的重绘。

                    //死亡判断
                    for (int i = 1; i < length; i++) 
                        if (snakeX[i] == snakeX[0] && snakeY[i] == snakeY[0]) 
                            isDie = true;
                        
                    
                    repaint();

八. 定时器

 最后我们需要加入一个定时器来实现画面的移动,否则我们的贪吃蛇将不能移动。

timer = new Timer(100, new ActionListener() 
timer.start(); //定时器启动

成品展示

小蛇死亡:

以上是关于实验二:贪吃蛇的实现的主要内容,如果未能解决你的问题,请参考以下文章

结对-贪吃蛇项目-结对项目总结

2019 春第二次课程设计实验报告

JavaScript贪吃蛇的实现

贪吃蛇的java代码分析

重做贪吃蛇 万向移动型 蛇的移动和吃食部分C# wpf版

用C语言编写 贪吃蛇的思路啥怎么样的