贪吃蛇的java代码分析(二)

  1. 代码剖析

贪吃蛇是一款十分经典的小游戏,对初入coding的朋友来说,拿贪吃蛇这样一个案例来练手十分合适,并不高的难度和成功后的成就感都是学习所必须的。下面我将依照我当时的思路,来逐步分析实现的整个过程。

让我们逐一分析。首先,整个游戏最基本的元素是地图。在java中用于绘图的类是swing和awt,在这里主要用到swing类。swing中用于窗口显示的类有JFrame及其子类。JFrame可以直接添加组件,但其本质是将组件添加到JFrame中的一个默认面板里,为了代码清晰,我会使用JPanel面板来绘制全部的动画,之后再将面板添加到JFrame窗体之中即可。

我们可能会疑惑于贪吃蛇的蛇身,它是由什么组成的?如何实现移动?我们可以把贪吃蛇的蛇身理解成一个集合,它有固定的起始元素,代表游戏一开始时的蛇身。当贪吃蛇吃到点时,集合就添加一个元素,蛇的长度就加一。那么,集合中的元素是什么呢?要理解这个问题,首先得关注蛇身移动所处的环境。在JFrame窗体中,是由X、Y轴坐标对位置进行区分。贪吃蛇的蛇身可以看做是一个一个联系紧密的点,在坐标轴上显示出来。每当朝某个方向移动时,蛇的坐标就按照某个规律变化。例如,我们操控贪吃蛇向上移动时,蛇的全体坐标的Y轴就减一;如果蛇的第一个坐标与蛇身的某个坐标重合,就代表贪吃蛇碰到自己;如果蛇的第一个坐标碰到了边界,蛇就撞墙。这就是贪吃蛇的本质。 
我们来建立建立蛇身上每一个点的对象,蛇身就是由一个一个这样的对象所组成的:

public class snakeNode {
    private int x;
    private int y;
    private String color;
    public snakeNode() {};
    public snakeNode(int x, int y, String color) {
        this.x = x;
        this.y = y;
        this.color = color;
        }
    public int getX() {
        return x;
        }
    public void setX(int x) {
        this.x = x;
        }
    public int getY() {
        return y;
        }
    public void setY(int Y) {
        this.y = y;
        }
    public String getColor() {
        return color;
        }
    public void setColor(String color) {
        this.color = color;
        }
            这串代码表示蛇身上的每一个点,通过建立snakeNode的对象,指定不同的X轴和Y轴的值,就能组成一个蛇身。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

接下来我们要给每一个蛇身上的点设置范围,因为贪吃蛇有移动范围的限制,超过某个距离或者长度,就会越界导致游戏的终止。经过考虑,我们将范围设置在:

public class mainMap extends JPanel {
    private int width = 20;
    private int length = 30;
    private int unit = 20;
    }
    上面的代码定义了一个面板类,我们之后的操作都要在上面进行。类中定义了变量width和length。我们将蛇身的移动范围限制在X轴上0~20,Y轴上0~30,至于变量unit,稍后再进行分析。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

接着,我们需要一个集合,用来存储蛇身上的各个点。我们需要定义一个变量,用来表示随机出现的点(贪吃蛇的目标),并且定义一个变量Length用来表示蛇的长度。代码如下:

public class mainMap extends JPanel {
    private final int width = 20;
    private final int length = 30;
    private final int unit = 20;
    private ArrayList<snakeNode> snake = new ArrayList<>();
    private snakeNode newNode = new snakeNode(0,0,Color.WHITE);
    private int Length;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

定义类的成员变量之后,我们开始定义构造方法,这样在构造mainMap的对象后程序就会开始运行。我们需要在构造方法中给集合添加一些元素,代表初始蛇身,也需要使用一个方法,用来创造随机点。代码如下:

public mainMap() {
    snake.add(new snakeNode(width/2,length/2,Color.RED);
    snake.add(new snakeNode(width/2,length/2+1,Color.BLUE);
    snake.add(new snakeNode(width/2,length/2+2,Color.GREY);
    Length = snake.size();
    createNode();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

createNode是创造随机点的方法,让我们思考一下:创造随机点有哪些要求?首先,随机点的范围肯定不能超出限制,否则游戏将无法继续;其次,随机点不能出现在蛇身上,也就是随机点的坐标不能和蛇身体上的任意坐标相同,否则就会出现BUG。按照此要求,我们创作出代码如下:

public void createNode() {
    int newX = 0;
    int newY = 0;
    boolean flag = true;
    while(flag){
    X = new Random().nextInt(width);
    Y = new Random().nextInt(length);
    for(int x = 0; x < Length; x++) {
        if(snake.get(x).getX() == newX && snake.get(x).getY() == newY) {
        flag = true;
        break;
        }
        flag = false;
    }
}
    Color color = new Color(new Random().nextInt(255),new Random().nextInt(255),new Random().nextInt(255));
    newNode.setX(newX);
    newNode.setY(newY);
    newNode.setColor(color);
    }
    这个方法随机产生0~width,0~length的随机数,通过循环判断是否与蛇身的点重合来产生随机点,同时产生随机的颜色,这里使用了Color的构造方法,不清楚的话可以通过API来查询。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

接下来是我们进行游戏中至关重要的一点,就是对蛇的移动进行控制。我们使用“wsad”或者键盘上的“上下左右”来控制蛇身的移动变化。这其中的原理想必很多人都能马上想到:监听器。这里我们要设置监听器的对象不再是一个按钮,一个标签,而是整个面板。我们要对整个面板增加一个键盘监听器,用来监听自己在键盘上的动作。这里我们统一一下,用”↑↓←→”来控制方向。当我们使用键盘捕捉到相应的动作后,该如何继续呢?该如何编写事件的处理?

我们来翻阅一下API。查看API中的KeyListener,我们可以查到KeyEvent,他有静态的常量用来表示键盘上相应的点触。VK_UP代表上箭头,VK_DOWN代表下箭头,VK_LEFT代表左箭头,VK_RIGHT代表右箭头。我们马上可以联想到:通过getKeyCode方法获取到键盘事件,和四个常量进行比较,如果符合,就可以按照对应的方向调用方法,来移动蛇身。我们可以定义一个Move()方法,并且定义一个变量direction代表方向,通过对direction不同的赋值传递给Move(),来对蛇身产生不同的移动效果。接下来贴代码:

public mainMap() {
    snake.add(new snakeNode(width/2,length/2,Color.RED);
    snake.add(new snakeNode(width/2,length/2+1,Color.BLUE);
    snake.add(new snakeNode(width/2,length/2+2,Color.GREY);
    Length = snake.size();
    createNode();
    this.addKeyListener(new KeyAdaper() {
        public void KeyPressed(KeyEvent e) {
            int direction = 0;
            switch(e.getKeyCode()) {
                case KeyEvent.VK_UP:
                    direction = 1;
                    break;
                case KeyEvent.VK_DOWN:
                    direction = -1;
                    break;
                case KeyEvent.VK_LEFT:
                    direction = 2;
                    break;
                case KeyEvent.VK_RIGHT:
                    direction = -2;
                    break;
                default:
                    break;
                }
            Move(direction);
            }
        });
    }
    //通过按下不同的方向键,我们得到了不同的direction变量,接下来我们定义一个Move()方法,传递direction变量来控制坐标的移动,从而得到蛇身变化的效果。 

    public void Move(int direction) {
        int firstX = snake.get(0).getX();
        int firstY = snake.get(0).getY();
        switch(direction) {
            case 1:
                firstY--;
                break;
            case -1:
                firstY++;
                break;
            case 2:
                firstX--;
                break;
            case -2:
                firstX++;
                break;
            default:
                break;
            }
        for(int x = 0; x < Length; x++) {
            if(snake.get(x).getX()==firstX&&snake.get(x).getY()==firstY) {
            Dead("不好意思,您碰到自己啦~~~~!!!!");
            }
        }//这个方法遍历蛇身集合中的每一个元素,拿出X轴和Y轴的值进行比较,来保证蛇头的第一个点没有触碰到蛇身的其他点。如果碰到了,就调用Dead()方法结束游戏,Dead()方法随后定义

        if(firstX < 0 || firstX > width - 1 || firstY < 0 || firstY > length -1) {
        Dead("不好意思,您撞墙啦");
        }//很简单,判断蛇头的坐标有没有超出界限

        for(int x = Length - 1; x >0; x--) {
            snake.get(x).setX(snake.get(x-1).getX());
            snake.get(x).setY(snake.get(x-1).getY());
        }
        snake.get(0).setX(firstX);
        snake.get(0).setY(firstY);
        }//这段代码从后往前遍历集合,把最后一个集合的X轴和Y轴赋值为前一个元素的X轴和Y轴,把移动后的firstX和firstY坐标赋值给第一个元素,那么蛇身的整体位置就进行了变化,也就可以达到蛇身移动的效果了。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

通过以上代码,我们已经初步搭建了贪吃蛇的基本逻辑框架。我们造出了蛇身,设置了按键后的蛇身移动的规律,也设置了蛇移动的范围。我们先给出总览的代码,这样有助于查漏补缺:

public class mainMap extends JPanel {
    private final int width = 20;
    private final int length = 30;
    private final int unit = 20;
    private ArrayList<snakeNode> snake = new ArrayList<>();
    private snakeNode newNode = new snakeNode(0,0,Color.WHITE);
    private int Length;

    public mainMap() {//这是构造方法
    snake.add(new snakeNode(width/2,length/2,Color.RED);
    snake.add(new snakeNode(width/2,length/2+1,Color.BLUE);
    snake.add(new snakeNode(width/2,length/2+2,Color.GREY);
    Length = snake.size();

    createNode();//这是创造随机点的方法

    this.addKeyListener(new KeyAdaper() {//这是设置键盘事件的方法
        public void KeyPressed(KeyEvent e) {
            int direction = 0;
            switch(e.getKeyCode()) {
                case KeyEvent.VK_UP:
                    direction = 1;
                    break;
                case KeyEvent.VK_DOWN:
                    direction = -1;
                    break;
                case KeyEvent.VK_LEFT:
                    direction = 2;
                    break;
                case KeyEvent.VK_RIGHT:
                    direction = -2;
                    break;
                default:
                    break;
                }
            Move(direction);
            }
        });
    }
    }
    public void Move(int direction) {//这是移动蛇身的方法
        int firstX = snake.get(0).getX();
        int firstY = snake.get(0).getY();
        switch(direction) {
            case 1:
                firstY--;
                break;
            case -1:
                firstY++;
                break;
            case 2:
                firstX--;
                break;
            case -2:
                firstX++;
                break;
            default:
                break;
            }
        for(int x = 0; x < Length; x++) {
                            if(snake.get(x).getX()==firstX&&snake.get(x).getY()==firstY) {
            Dead("不好意思,您碰到自己啦~~~~!!!!");
            }
        }

        if(firstX < 0 || firstX > width - 1 || firstY < 0 || firstY > length -1) {
        Dead("不好意思,您撞墙啦");
        }
        for(int x = Length - 1; x >0; x--) {
            snake.get(x).setX(snake.get(x-1).getX());
            snake.get(x).setY(snake.get(x-1).getY());
        }
        snake.get(0).setX(firstX);
        snake.get(0).setY(firstY);
        }

    public void createNode() {//这是创造随机点的方法
    int newX = 0;
    int newY = 0;
    boolean flag = true;
    while(flag){
    X = new Random().nextInt(width);
    Y = new Random().nextInt(length);
    for(int x = 0; x < Length; x++) {
        if(snake.get(x).getX() == newX && snake.get(x).getY() == newY) {
        flag = true;
        break;
        }
        flag = false;
    }
}
    Color color = new Color(new Random().nextInt(255),new Random().nextInt(255),new Random().nextInt(255));
    newNode.setX(newX);
    newNode.setY(newY);
    newNode.setColor(color);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

以上就是我们共同完成的步骤,如果全部实现并且加以理解,那么其实整个贪吃蛇的整体思路基本已经是掌握了。但这并没有结束,我们还有许多的细节问题需要完成。我将在下一节中继续来完成剩下的部分,包括蛇的定时移动,吃掉点的方法,已经画出蛇的样子。

时间: 2024-08-04 22:21:38

贪吃蛇的java代码分析(二)的相关文章

贪吃蛇的java代码分析(一)

自我审视 最近自己学习java已经有了一个多月的时间,从一开始对变量常量的概念一无所知,到现在能勉强写几个小程序玩玩,已经有了长足的进步.今天没有去学习,学校里要进行毕业答辩和拍毕业照了,于是请了几天的假,自己也就有了一点空余的时间.回想这一个多月,自己做到好的地方是把大部分时间都用在了看书和码代码上,学习的重点放在了追求对知识的理解和内容的广度之上.书籍方面阅读了<java核心技术>和<java编程思想>,虽然说没有理解全部的内容,<编程思想>一书也只看了300多页,

java代码分析及分析工具

java代码分析及分析工具 一个项目从搭建开始,开发的初期往往思路比较清晰,代码也比较清晰.随着时间的推移,业务越来越复杂.代码也就面临着耦合,冗余,甚至杂乱,到最后谁都不敢碰. 作为一个互联网电子商务网站的业务支撑系统,业务复杂不言而喻.从09年开始一直沿用到现在,中间代码经过了多少人的手,留下了多少的坑,已经记不清楚了,谁也说不清了. 代码的维护成本越来越高.代码已经急需做调整和改善.最近项目组专门设立了一个小组,利用业余时间做代码分析的工作,目标对核心代码进行分析并进行设计重构. 代码分析

HDFS API的java代码分析与实例

HDFS API的java代码分析与实例 1.HDFS常用的方法,我已经写好,我们看一下 // Create()方法,直接在HDFS中写入一个新的文件,path为写入路径,text为写入的文本内容 public static void  Create(String path,String text) throws IOException {             Configuration conf=new Configuration();                  conf.set(

Android4.0图库Gallery2代码分析(二) 数据管理和数据加载

Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 2012-09-07 11:19 8152人阅读 评论(12) 收藏 举报 代码分析android相册优化工作 Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 一 图库数据管理 Gallery2的数据管理 DataManager(职责:管理数据源)- MediaSource(职责:管理数据集) - MediaSet(职责:管理数据项).DataManager中初始化所有的数据源(LocalSo

java代码解析二维码

java代码解析二维码一般步骤 本文采用的是google的zxing技术进行解析二维码技术,解析二维码的一般步骤如下: 一.下载zxing-core的jar包: 二.创建一个BufferedImageLuminanceSource类继承LuminanceSource,此类在google的源码中有,但是为了使用方便,下面有此类的源码,可以直接复制使用: private final BufferedImage image; private final int left; private final

贪吃蛇C语言代码

贪吃蛇C语言代码 贪吃蛇C语言代码 手动贪吃蛇 智能贪吃蛇 1.手动贪吃蛇 /*蛇越长跑得越快*/ /*作者:SGAFPZ*/ #include <stdio.h> #include <windows.h> #include <stdlib.h> #include <math.h> //#include <unistd.h> #include <conio.h> #include <string.h> #include &

Java实现贪吃蛇游戏【代码】

花了两个下午写了一个贪吃蛇小游戏,本人想写这游戏很长时间了.作为以前诺基亚手机上的经典游戏,贪吃蛇和俄罗斯方块一样,都曾经在我们的童年给我们带来了很多乐趣.世间万物斗转星移,诺基亚曾经作为手机业的龙头老大,现如今也一步步走向衰落,被收购,再过不久估计就要退出手机业务了,而贪吃蛇这款游戏也基本上没人玩了,甚至在新一代人的印象中都已毫无记忆了...但是,这款游戏在它基础上经过改造其实可以弄出很多花样,也确实可以在一定程度上锻炼自己的编程能力.前不久十分火热的贪吃蛇大作战其实就可以看做是在这款游戏的基

贪吃蛇 HTML5 Canvas代码

首先建立一个二维类 function Class_Dim(cx, cy){ var x = cx; var y = cy; this.getx = function(){ return x; }; this.gety = function(){ return y; }; this.setx = function(tx){ x = tx; }; this.sety = function(ty){ y = ty; }; }; 然后设置一些全局变量 var gameRunning = true;//游

js贪吃蛇 纯手打 代码比较复杂 自己瞎弄的 bug 比较多 自己一点一点排除弄 完全原创

//虽然代码没有别人写的简单,但是这是自己的思想,通过这次实例,学到了很多,也发现了很多不足,努力学习啊,小小的贪吃蛇也包含了很多东西还有 //好多问题需要解决,比如,如何判断蛇头碰到蛇身,如何让食物不出现在蛇的身上等,欢迎大家一起探讨 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dt