小小贪吃蛇——JAVA

来源:互联网 发布:西宁网络电视台 编辑:程序博客网 时间:2024/06/06 19:35

回顾了一下JavaSE基础,顺便用一下午的时间写了一个小小贪吃蛇
本篇文章献给Java初学者,或者大一大二的学生朋友们。

因为当时大一下学期学习Java基础后,期末要求做一个小项目,都是一些小游戏,比如俄罗斯方块,贪吃蛇什么的。当时博主太菜了,累死累活整了4天,才弄一个半成品,而且学习效果也不咋地。。到时到处找资源,看教学视频都看不懂,。。

不过博主经过不懈的努力,终于从一个菜鸟变成了 小白(笑哭)。

希望本篇文章可以对你有帮助。每行代码几乎都有注释,我就不再多做解释了,文章末尾我会奉上源码,和马士兵的贪吃蛇教程,还有直接可以运行的程序(个人感觉他的小蛇部分做的有些复杂,我的比他的简单一些,功能也差不多)

博主这次做的算是1.0的版本吧!
界面一般,功能一般,如果你有兴趣,可以继续完善,做出 属于你自己的小蛇吧!

我的贪吃蛇除了具备一般小蛇的特性以外,有以下特性:    1、左右可穿墙(上下的墙碰到就死)    2、速度随着吃的蛋蛋的数目加快,就是吃的越多,速度越快(分数也是)咱们自己做的游戏,规则咱们可以随便定。

附上几个图片,真图为证:
这里写图片描述

可以穿墙的呦!
这里写图片描述

GAME OVER:
这里写图片描述
首先是院子,也就是地图。
废话不多说,附上代码(引入的包太占位置了,我给去了):

public class Yard extends JFrame{    //定义院子的大小    public static final int ROWS = 40;  //行数    public static final int COLS = 50; //列数    public static final int BLOCK_SIZE = 20; //每个小格子的尺寸    private static int score = 0;   //分数    private static int count = 0;   //吃蛋蛋的次数    private static int speed = 10;  //速度    Snake snake = new Snake(this);  //初始化一条小蛇    Egg egg = new Egg();            //初始化一个蛋蛋    public static void main(String[] args){        new Yard().launch();        //启动游戏    }    Image offScreenImage = null;    //解决闪烁    @Override    //解决闪烁    public void update(Graphics g) {        if(offScreenImage == null) {            offScreenImage = this.createImage(COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE);        }        Graphics gOff = offScreenImage.getGraphics();        paint(gOff);        g.drawImage(offScreenImage, 0, 0,  null);    }    //来一个院子    public void launch(){        this.setLocation(500, 200); //设置窗口初始位置        this.setSize(COLS*BLOCK_SIZE,ROWS*BLOCK_SIZE);  //设置窗口大小        this.addWindowListener(new WindowAdapter(){     //当关闭窗口时,同时关闭java正在运行的虚拟机            @Override            public void windowClosing(WindowEvent e) {                System.exit(0);     //关闭虚拟机            }        });        this.setVisible(true);      //让窗口可显示        new Thread(new PaintThread()).start();  //开启线程,让小蛇动起来        this.addKeyListener(new KeyMonitor());  //加入监听器    }    //画板    @Override    public void paint(Graphics g) {        // TODO Auto-generated method stub        Color c = g.getColor();     //获取画板color,用于设置颜色        g.setColor(c.gray);         //设置当前颜色为灰色        g.fillRect(0, 0, COLS*BLOCK_SIZE, ROWS*BLOCK_SIZE); //把颜色填充到整个窗口        for (int i = 1; i < COLS-1; i++) {            g.setColor(c.white);    //设置当前颜色为白色            g.fill3DRect(i*BLOCK_SIZE,2*BLOCK_SIZE,BLOCK_SIZE,BLOCK_SIZE,true); //上边的墙            g.fill3DRect(i*BLOCK_SIZE,(ROWS-2)*BLOCK_SIZE,BLOCK_SIZE,BLOCK_SIZE,true);  //上边的墙        }        g.setColor(c.darkGray);        //画横线        for (int i = 1; i < ROWS; i++) {            g.drawLine(BLOCK_SIZE, i*BLOCK_SIZE, (COLS-1)*BLOCK_SIZE, i*BLOCK_SIZE);        }        //画竖线        for (int i = 1; i < COLS; i++) {            g.drawLine(i * BLOCK_SIZE, BLOCK_SIZE*2, i * BLOCK_SIZE, (ROWS-1) * BLOCK_SIZE);        }        g.setColor(c.yellow);        g.setFont(new Font("宋体",Font.BOLD,25)); //设置上下文字体        g.drawString("score:"+score, 20, 80);       //用于显示score分数        g.drawString("speed:"+speed, 20, 110);      //用于显示speed速度        snake.paint(g);     //在这个画板中画一条小蛇        if(snake.eat(egg)){ //如果小蛇吃到了蛋蛋            count++;        //吃蛋蛋的次数+1,            score += 10*count;//加分,吃的越多,分加的越高            speed += 5; //速度增加        }        egg.draw(g);        //画一个蛋蛋        if(snake.isGameOver()){     //如果GAME OVER了,在中间显示一个GANE OVER            g.setColor(c.yellow);            g.setFont(new Font("宋体",Font.BOLD,80));            g.drawString("GAME OVER!", 300, 400);        }    }    //线程内部类,本线程用于整个游戏的运行    private class PaintThread implements Runnable{        @Override        public void run() {            // TODO Auto-generated method stub            while(!snake.isGameOver()){                repaint();  //刷新页面                try {                    snake.move();       //蛇移动                    Thread.sleep(300/speed*10);     //这里控制蛇移动的速度                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }            repaint();  //游戏结束后刷新一下页面,用于显示GAME OVER        }    }    //监听器    private class KeyMonitor extends KeyAdapter{        //监听键盘的指令        @Override        public void keyPressed(KeyEvent e) {            snake.keyPressed(e);            }    }}

接着是小蛇:

public class Snake {    //一下分别是四个方向的状态码,用来标识方向    public static final int DIR_UP = 1;     //向上走    public static final int DIR_DOWN = 2;   //向下走    public static final int DIR_LEFT = 3;   //向左走    public static final int DIR_RIGHT = 4;  //像右走    //默认的DIR为4,即往右走    public static int DIR = 4;    //size标识每个小格子的大小    int size = Yard.BLOCK_SIZE;    private Yard yard;  //用来绑定对应的院子    LinkedList<Point> snake = new LinkedList<Point>();  //用链表来存储蛇身子,方便加头去尾    public Snake(Yard yard){//用来绑定对应的院子        initSnake();    //初始化小蛇        this.yard = yard;   //绑定院子    }    //初始化蛇    public void initSnake(){        //先来三个节点,作为初始的身子        snake.addFirst(new Point(Yard.BLOCK_SIZE*(Yard.COLS-2)/2,Yard.BLOCK_SIZE*Yard.ROWS/2));        snake.addFirst(new Point(Yard.BLOCK_SIZE*(Yard.COLS)/2,Yard.BLOCK_SIZE*Yard.ROWS/2));        snake.addFirst(new Point(Yard.BLOCK_SIZE*(Yard.COLS+2)/2,Yard.BLOCK_SIZE*Yard.ROWS/2));    }    //创建蛇的头,方便使用    Point head = new Point();    //画蛇    public void paint(Graphics g){        Color c = g.getColor();        g.setColor(c.darkGray);        head = this.snake.getFirst();   //单独做了一个蛇头,用圆角矩形表示        g.fillRoundRect(head.x, head.y, Yard.BLOCK_SIZE, Yard.BLOCK_SIZE,10,10);        g.setColor(c.black);        //遍历链表,来画出整条小蛇        for (int i = 1; i < snake.size(); i++) {    //蛇身子用普通的矩形表示            g.fillRect(snake.get(i).x, snake.get(i).y, Yard.BLOCK_SIZE, Yard.BLOCK_SIZE);        }    }    //蛇移动    //移动的原理就加头去尾    //用链表可以很轻松的实现,他封装了一些的方法,使用起来很方便,可以查一下api文档    //在这里,如果到左右边界了,可以穿过去,实现穿墙操作    public void move(){        head = this.snake.getFirst();   //获取当前的头节点        switch (DIR) {      //根据不同的方向,对应不同的移动方案        case DIR_UP:            this.snake.addFirst(new Point(head.x,head.y-size)); //添加一个头节点            this.snake.removeLast();        //去尾操作,去掉尾巴节点            break;        case DIR_DOWN:            this.snake.addFirst(new Point(head.x,head.y+size));            this.snake.removeLast();            break;        case DIR_LEFT:            if(head.x == size){ //到了左边的边界                this.snake.addFirst(new Point((yard.COLS-2)*size,head.y));  //穿墙            }else{                this.snake.addFirst(new Point(head.x-size,head.y));            }            this.snake.removeLast();            break;        case DIR_RIGHT:            if(head.x == (yard.COLS-2)*size){   //到了右边边界                this.snake.addFirst(new Point(size,head.y));        //穿墙            }else{                this.snake.addFirst(new Point(head.x+size,head.y));            }            this.snake.removeLast();            break;        default:            break;        }    }    //判断是否撞墙或者咬到自己,游戏结束    public boolean isGameOver(){        head = this.snake.getFirst();        //撞墙(上下的墙)(左右的墙可以穿过去)        if( head.y <= 2*size || head.y >= (yard.ROWS-2)*size){            return true;        }        //咬到自己        for (int i = 1; i < this.snake.size(); i++) {            if(head.x == this.snake.get(i).x && head.y == this.snake.get(i).y){                return true;            }        }        return false;    }    //监听键盘,用来改变方向    public void keyPressed(KeyEvent e) {        switch (e.getKeyCode()){    //获取键的对应的码        case KeyEvent.VK_UP:    //向上的键,下面的同理            if(DIR != DIR_DOWN){    //这里控制不能直接反方向走                DIR = DIR_UP;            }            break;        case KeyEvent.VK_DOWN:            if(DIR != DIR_UP)                DIR = DIR_DOWN;            break;        case KeyEvent.VK_LEFT:            if(DIR != DIR_RIGHT)                DIR = DIR_LEFT;            break;        case KeyEvent.VK_RIGHT:            if(DIR != DIR_LEFT)                DIR = DIR_RIGHT;            break;        }    }    //吃蛋蛋    //吃着了就加一个尾巴,就可以实现变长了    public boolean eat(Egg egg){        if(egg.x == this.head.x && egg.y == this.head.y){            egg.createFood();       //重新创建一个蛋蛋            Point last = this.snake.getLast();  //获取当前的尾巴节点            this.snake.addLast(last);   //添加一个新的尾巴节点            return true;        }        return false;    }}

最后是要吃的食物(蛋蛋):

package MySnake;import java.awt.Color;import java.awt.Graphics;import java.awt.Point;import java.util.Random;public class Egg {    private static Random random = new Random();    //用来随机产生蛋蛋的对象    int size = Yard.BLOCK_SIZE;     //每个小格子的大小    //食物的坐标    public int x;    public int y;    public Egg(){   //构造方法,产生一个蛋蛋        createFood();    }    //创建食物    public void createFood(){        this.x = (random.nextInt(Yard.COLS-3)+2)*size;  //因为边框的问题,所以这里有改动,可以试验一下        this.y = (random.nextInt(Yard.ROWS-5)+3)*size;    }    //画出食物    public void draw(Graphics g){        Color c = g.getColor();        g.setColor(c.red);        g.fillOval(x, y, size, size);   //画一个圆形来表示蛋蛋    }}

目前这个版本还是1.0,仅供初学者参考,(写太复杂了反而违背了本意)
以上是全部代码。。可能你还是看不懂,没关系,源码给你,慢慢研究:
http://pan.baidu.com/s/1hsjApxU

并附上马士兵的教程以及源码:
http://pan.baidu.com/s/1nvHVWYP

我顺便把程序打包了 ,双击直接运行,下面这个是在有JRE环境的电脑上可以运行:
http://pan.baidu.com/s/1geHmby7

后来考虑到个别小伙伴想在没有jre环境的电脑上运行,于是我花了半下午的时间又打包成真正的桌面应用程序,安装之后,随处都可运行:
http://pan.baidu.com/s/1eRJpTIE

个人感觉马士兵老师讲的这个贪吃蛇的小蛇部分有些复杂繁琐,可以参考我的代码结合着老师的视频,做出属于自己的贪吃蛇吧!!

拯救不开心!!!

原创粉丝点击