当前位置:   article > 正文

Java小游戏之贪吃蛇_java贪吃蛇

java贪吃蛇

文章目录

一:窗口的绘制

1.1 定义窗口类——SnakeGame

import javax.swing.*;

public class SnakeGame extends JFrame {

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

1.2 设置窗口的参数

import javax.swing.*;

public class SnakeGame extends JFrame {
    public void launch(){
        //设置窗口是否可见
        this.setVisible(true);
        //设置窗口的大小
        this.setSize(600,600);
        //设置窗口的位置在屏幕上居中
        this.setLocationRelativeTo(null);
        //设置窗口的标题
        this.setTitle("贪吃蛇");
    }

    public static void main(String[] args) {
        GameWin gameWin = new GameWin();
        gameWin.launch();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

1.3 启动main方法

![在这里插入图片描述](https://img-blog.csdnimg.cn/84d5e157e3c143979e31c11c3c9efc53.png

二:窗口网格的绘制

	@Override
    public void paint(Graphics g) {
        //灰色背景
        g.setColor(Color.gray);
        //绘制矩形,和窗口一样,宽和高都是600
        g.fillRect(0,0,600,600);
        //网格线
        g.setColor(Color.black);
        //横线
        for (int i = 0; i <= 20 ; i++) {
            //横线
            g.drawLine(0,i * 30,600,i * 30);
            //竖线
            g.drawLine(i * 30,0,i * 30,600);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2.1 重写paint方法

2.1.1 为什么要重写paint方法

当我们使用JFrame创建出窗体时,遇到窗体的尺寸改变(ie.拉伸窗体),或者窗体的部分像素被移动到屏幕之外,都会导致窗体的刷新。窗体有一个系统自带的刷新方法。但这时如果窗体中有此前绘制出的图像,则图像会随窗体的刷新而消失,这时候我们就需要将绘制图像的方法重写入JFrame的paint方法中,让图像随窗体的刷新而同步再次被绘制出来。

2.1.2 实现方式

函数要在类继承JFrame或者JPanel两个属性下才能实现重写,并且这个方法是系统自动调用的。
重写绘制方法的本质是将图像数据化、对象化。将图像的属性(eg. 坐标、颜色、图形类型……)和其绘制方法写入paint()。

2.2 Graphics

  1. ​实际生活中如果需要画图,首先我们得准备一张纸,然后在拿一支画笔,配和一些颜色,就可以在纸上画出来各种各样的图形,例如圆圈、矩形等等。

  2. 程序中绘图也一样,也需要画布,画笔,颜料等等。AWT中提供了Canvas类充当画布,提供了Graphics类来充当画笔,通过调用Graphics对象的setColor()方法可以给画笔设置颜色。

2.3 设置网格线的参数

		//灰色背景
        g.setColor(Color.gray);
        //绘制矩形,和窗口一样,宽和高都是600
        g.fillRect(0,0,600,600);
        //网格线颜色
        g.setColor(Color.black);
        //绘制网格线
        for (int i = 0; i <= 20 ; i++) {
            //横线
            g.drawLine(0,i * 30,600,i * 30);
            //竖线
            g.drawLine(i * 30,0,i * 30,600);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在这里插入图片描述

三:游戏物体父类的创建——SnakeEntity

import com.sysg.game.sanke.SnakeGame;
import java.awt.*;

public class SnakeEntity{

    //图片
    Image img;
    //坐标
    int x;
    int y;
    //宽高
    int width = 30;
    int height = 30;
    //窗口类的引用
    GameWin frame;

    public Image getImg() {
        return img;
    }

    public void setImg(Image img) {
        this.img = img;
    }

    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 int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public GameWin getFrame() {
        return frame;
    }

    public void setFrame(GameWin frame) {
        this.frame = frame;
    }

    public SnakeEntity() {
    }

    public SnakeEntity(Image img, int x, int y, int width, int height, GameWin frame) {
        this.img = img;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.frame = frame;
    }

    //绘制自身
    public void paintSelf(Graphics g){
        g.drawImage(img,x,y,null);
    }
}

  • 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

四:游戏工具类的创建——SnakeUtil

import java.awt.*;
public class SnakeUtil{
    //蛇头
    public static Image upImg = Toolkit.getDefaultToolkit().getImage("img/up.png");
    public static Image downImg = Toolkit.getDefaultToolkit().getImage("img/down.png");
    public static Image leftImg = Toolkit.getDefaultToolkit().getImage("img/left.png");
    public static Image rightImg = Toolkit.getDefaultToolkit().getImage("img/right.png");
    //蛇身
    public static Image bodyImg = Toolkit.getDefaultToolkit().getImage("img/body.png");
    //食物
    public static Image foodImg = Toolkit.getDefaultToolkit().getImage("img/food.png");

    //绘制文字
    public static void drawWord(Graphics g,String str,Color color,int size,int x,int y){
        g.setColor(color);
        g.setFont(new Font("仿宋",Font.BOLD,size));
        g.drawString(str,x,y);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

4.1 获取蛇头的图片

	public static Image upImg = Toolkit.getDefaultToolkit().getImage("img/up.png");
    public static Image downImg = Toolkit.getDefaultToolkit().getImage("img/down.png");
    public static Image leftImg = Toolkit.getDefaultToolkit().getImage("img/left.png");
    public static Image rightImg = Toolkit.getDefaultToolkit().getImage("img/right.png");
  • 1
  • 2
  • 3
  • 4

4.2 获取蛇身的图片

public static Image bodyImg = Toolkit.getDefaultToolkit().getImage("img/body.png");
  • 1

4.3 获取食物的图片

public static Image foodImg = Toolkit.getDefaultToolkit().getImage("img/food.png");
  • 1

4.4 绘制文字

	//绘制文字
    public static void drawWord(Graphics g,String str,Color color,int size,int x,int y){
        g.setColor(color);
        g.setFont(new Font("仿宋",Font.BOLD,size));
        g.drawString(str,x,y);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

五:蛇头部的绘制——SnakeHeadEntity

import java.awt.*;

public class SnakeHeadEntity extends SnakeEntity{
    //方向 up down left right
    private String direction = "right";

    public String getDirection() {
        return direction;
    }

    public void setDirection(String direction) {
        this.direction = direction;
    }

    public SnakeHeadEntity (Image img, int x, int y, GameWin frame) {
        super(img, x, y, frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

5.1 设置蛇头的方向

//方向 up down left right
private String direction = "right";
  • 1
  • 2

默认蛇头的方向是向右的!

5.2 绘制自身

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

六:蛇头的简单移动

6.1 在HeadObj添加move方法

/**
     * 蛇的移动
     * 蛇身体的移动的代码一定要写在蛇头移动的前面
     */
    public void  move(){
        //蛇头的移动
        switch (direction) {
            case "up":
                y -= height;
                break;
            case "down":
                y += height;
                break;
            case "left":
                x -= width;
                break;
            case "right":
                x += width;
                break;
            default:
                break;
        }

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

6.2 在paintSelf方法中添加move方法

@Override
    public void paintSelf(Graphics g) {
        //设置蛇头的位置
        super.paintSelf(g);
        //移动蛇头
        move();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

6.3 蛇的重复移动需要调用repaint()方法

 /**
     * 窗口的绘制
     */
    public void launch(){
        //设置窗口是否可见、默认是false不可见
        this.setVisible(true);
        //设置窗口的大小
        this.setSize(winWidth,winHeight);
        //设置窗口的位置在屏幕居中
        this.setLocationRelativeTo(null);
        //设置窗口的标题
        this.setTitle("贪吃蛇");  
        //移动蛇头
        while(true){
           // repaint()方法是一个具有刷新页面效果的方法,若不调用repaint方法图形发生变化后不会立刻显示
           repaint();
            try {
                //一秒会调用五次
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
  • 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

七:键盘控制蛇的方向

7.1 在SnakeHeadEntity中添加键盘监听事件

public SnakeHeadEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
        //监听键盘
        this.frame.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //控制蛇头的移动
                changeDirection(e);
            }
        });
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

7.2 编写changeDirection方法

   /**
     * 控制蛇头的移动
     * w->a->s->d
     */
    public void changeDirection(KeyEvent e) {
        switch (e.getKeyCode()){
            //按下A键->朝左移动
            case KeyEvent.VK_A:
                if(!"right".equals(direction)){
                    //将方向改为左边
                    direction = "left";
                    //修改蛇头图片的方向
                    img = SnakeUtil.leftSnakeHeadImg;
                }
                break;

            //按下D键->朝右移动
            case KeyEvent.VK_D:
                if(!"left".equals(direction)){
                    //将方向改为右边
                    direction = "right";
                    //修改蛇头图片的方向
                    img = SnakeUtil.rightSnakeHeadImg;
                }
                break;

            //按下W键->朝上移动
            case KeyEvent.VK_W:
                if(!"down".equals(direction)){
                    //将方向改为上边
                    direction = "up";
                    //修改蛇头图片的方向
                    img = SnakeUtil.upSnakeHeadImg;
                }
                break;

            //按下S键->朝下移动
            case KeyEvent.VK_S:
                if(!"up".equals(direction)){
                    //将方向改为上边
                    direction = "down";
                    //修改蛇头图片的方向
                    img = SnakeUtil.downSnakeHeadImg;
                }
                break;
            default:
                break;
        }

    }
  • 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

八:蛇越界后的处理

1.编写checkIndex()方法

注:标题栏高度为30,所以y<30,不是y<0

/**
     * 贪吃蛇的越界处理
     */
    public void checkIndex(){
        if(x < 0){
            x = 570;
        } else if (x > 570){
            x = 0;
        } else if (y < 30){
            y = 570;
        } else if (y > 570){
            y = 30;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

2.在paintSelf方法中添加checkIndex()方法

@Override
    public void paintSelf(Graphics g) {
        //设置蛇头的位置
        super.paintSelf(g);
        //移动蛇头
        move();
        checkIndex();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

九:蛇身的添加和移动

9.1 新建蛇身实体类——SnakeBodyEntity

/**
 * 蛇身体
 */
public class SnakeBodyEntity extends SnakeEntity {

    public SnakeBodyEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

9.2 在SnakeGame定义蛇身集合

/**
* 蛇身集合
*/
public List snakeBodyEntityList = new ArrayList<>();

9.3 在launch()方法对蛇身进行初始化

//蛇身初始化
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,30,570,this));
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,0,570,this));
  • 1
  • 2
  • 3

9.4 在paint方法绘制蛇身体

防止身体重叠,所以进行反向遍历

//绘制蛇身体
        for (int i = snakeBodyEntityList.size() - 1; i >= 0; i--) {
            snakeBodyEntityList.get(i).paintSelf(graphicsImage);
        }
  • 1
  • 2
  • 3
  • 4

9.5 在move方法中添加身体移动逻辑

//蛇身体的移动
        List<SnakeBodyEntity> snakeBodyEntityList = this.frame.snakeBodyEntityList;
        for (int i = snakeBodyEntityList.size() - 1; i >= 1; i--) {
            //蛇的移动就是上一个坐标和当前坐标相等
            snakeBodyEntityList.get(i).x = snakeBodyEntityList.get(i-1).x;
            snakeBodyEntityList.get(i).y = snakeBodyEntityList.get(i-1).y;
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

十:食物的随机生成

食物的坐标需要满足x->(0-570),y->(30,570)并且是30的倍数

10.1 新建食物实体类——SnakeFoodEntity

/**
 * 食物实体类
 */
public class SnakeFoodEntity extends SnakeEntity {

    /**
     * 随机
     */
    Random r = new Random();

    public SnakeFoodEntity() {
        super();
    }

    public SnakeFoodEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
    }

    /**
     * 获取食物
     * x:0->570
     * y.3:0->570
     * @return
     */
    public SnakeFoodEntity getFood(){
        return new SnakeFoodEntity(SnakeUtil.snakeFoodImg,r.nextInt(20) * 30,(r.nextInt(19) + 1) * 30,this.frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}
  • 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

10.2 获取食物

/**
     * 获取食物
     * x:0->570
     * y.3:0->570
     * @return
     */
    public SnakeFoodEntity getFood(){
        return new SnakeFoodEntity(SnakeUtil.snakeFoodImg,r.nextInt(20) * 30,(r.nextInt(19) + 1) * 30,this.frame);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

10.3 在SnakeGame中添加食物实体类

   /**
     * 食物
     */
    public SnakeFoodEntity snakeFoodEntity = new SnakeFoodEntity().getFood();
  • 1
  • 2
  • 3
  • 4

10.4 在paint中绘制食物

    //食物绘制
    snakeFoodEntity.paintSelf(g);
  • 1
  • 2

十一:蛇吃食物和食物的重新生成

11.1 在SnakeHeadEntity中的paintSelf添加获取食物的对象

     //食物
    SnakeFoodEntity snakeFoodEntity = this.frame.snakeFoodEntity;
  • 1
  • 2

注:此方法需要放在move()之前

11.2 判断蛇头和食物是否重合

if(this.x == snakeFoodEntity.x && this.y == snakeFoodEntity.y ){
     //此时蛇头和食物重合了
     this.frame.snakeFoodEntity = snakeFoodEntity.getFood();
 }
  • 1
  • 2
  • 3
  • 4

十二:蛇的增长

蛇的增长本质就是给蛇身添加一个元素,根据集合的最后一个位置确定

12.1 定义身体最后一节的坐标

//身体最后一节的坐标
        Integer newX = null;
        Integer newY = null;
        if(this.x == snakeFoodEntity.x && this.y == snakeFoodEntity.y ){
            //此时蛇头和食物重合了
            this.frame.snakeFoodEntity = snakeFoodEntity.getFood();
            //获取蛇身的最后一个元素
            SnakeBodyEntity lastSnakeBodyEntity = this.frame.snakeBodyEntityList.get(this.frame.snakeBodyEntityList.size() - 1);
            newX = lastSnakeBodyEntity.x;
            newY = lastSnakeBodyEntity.y;
           
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

12.2 在move方法后添加元素

if(newX != null && newY != null){
   this.frame.snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,newX,newY,this.frame));
}
  • 1
  • 2
  • 3

12.3 修改move方法的遍历顺序

 /**
     * 蛇的移动
     * 蛇身体的移动的代码一定要写在蛇头移动的前面
     */
    public void  move(){
        //蛇身体的移动
        List<SnakeBodyEntity> snakeBodyEntityList = this.frame.snakeBodyEntityList;
        for (int i = snakeBodyEntityList.size() - 1; i >= 1; i--) {
            //蛇的移动就是上一个坐标和当前坐标相等
            snakeBodyEntityList.get(i).x = snakeBodyEntityList.get(i-1).x;
            snakeBodyEntityList.get(i).y = snakeBodyEntityList.get(i-1).y;
        }
        snakeBodyEntityList.get(0).x = this.x;
        snakeBodyEntityList.get(0).y = this.y;
        //蛇头的移动
        switch (direction) {
            case "up":
                y -= height;
                break;
            case "down":
                y += height;
                break;
            case "left":
                x -= width;
                break;
            case "right":
                x += width;
                break;
            default:
                break;
        }

    }
  • 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

十三:计分面板的编写

13.1 在SnakeGame定义窗口的宽高

//窗口宽高
int winWidth = 800;
int winHeight = 600;
  • 1
  • 2
  • 3

注:将之前定义的600,600替换为winWidth ,winHeight

13.2 定义游戏分数,并且在paint绘制出来

//当前分数
public int score = 0;

//分数绘制
SnakeUtil.drawWord(graphicsImage,score  +"分" , Color.BLUE , 50,650,330);
  • 1
  • 2
  • 3
  • 4
  • 5

13.3 蛇吃食物,分数加一

在SnakeHeadEntity的paintSelf添加对应方法

@Override
    public void paintSelf(Graphics g) {
        //设置蛇头的位置
        super.paintSelf(g);
        //食物
        SnakeFoodEntity snakeFoodEntity = this.frame.snakeFoodEntity;
        //身体最后一节的坐标
        Integer newX = null;
        Integer newY = null;
        if(this.x == snakeFoodEntity.x && this.y == snakeFoodEntity.y ){
            //此时蛇头和食物重合了
            this.frame.snakeFoodEntity = snakeFoodEntity.getFood();
            //获取蛇身的最后一个元素
            SnakeBodyEntity lastSnakeBodyEntity = this.frame.snakeBodyEntityList.get(this.frame.snakeBodyEntityList.size() - 1);
            newX = lastSnakeBodyEntity.x;
            newY = lastSnakeBodyEntity.y;
            //分数+1
            this.frame.score ++;
        }
        //移动蛇头
        move();
        if(newX != null && newY != null){
            this.frame.snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,newX,newY,this.frame));
        }
        //贪吃蛇的越界处理,移动后新的身体对象添加到snakeBodyEntityList
        checkIndex();
    }
  • 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

十四:游戏开始的提示语

14.1 在SnakeGame定义游戏状态

//游戏状态 0-未开始 1-游戏中 2-暂停 3-失败 4-通关 5-失败后重启 6-下一关
    public static int state = 0;
  • 1
  • 2

14.2 在while语句中添加判断,只有状态为1,才需要重复执行repaint()方法

/**
     * 窗口的绘制
     */
    public void launch(){
        //设置窗口是否可见、默认是false不可见
        this.setVisible(true);
        //设置窗口的大小
        this.setSize(winWidth,winHeight);
        //设置窗口的位置在屏幕居中
        this.setLocationRelativeTo(null);
        //设置窗口的标题
        this.setTitle("贪吃蛇");
        //蛇身初始化
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,30,570,this));
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,0,570,this));
        //对开始游戏添加键盘事件
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //点击空格
                if(e.getKeyCode() == KeyEvent.VK_SPACE){
                    switch (state){
                        case 0:
                            //未开始
                            state = 1;
                            break;
                        case 1:
                            //游戏中
                            state = 2;
                            repaint();
                            break;
                        case 2:
                            //游戏暂停
                            state = 1;
                            break;
                        case 3:
                            //失败后重启
                            state = 5;
                            break;

                        case 4:
                            //游戏通关,进入下一关
                            state = 6;
                            break;
                        default:
                            break;

                    }
                }
            }
        });
        //移动蛇头
        while(true){
            //只有状态为游戏中,才需要反复执行repaint()方法
            if(state == 1){
                // repaint()方法是一个具有刷新页面效果的方法,若不调用repaint方法图形发生变化后不会立刻显示
                repaint();
            }
            try {
                //一秒会调用五次
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

  • 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

14.3 绘制提示语

/**
     * 绘制提示语
     * @param g
     */
    void prompt(Graphics g){
        //未开始
        if(state == 0){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"按下空格开始游戏",Color.yellow,35,150,290);
        }
      
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

14.4 在paint方法添加提示语

/**
     * 绘制
     * @param g
     */
    @Override
    public void paint(Graphics g){
       

        //灰色背景
        g.setColor(Color.gray);
        //绘制矩形,和窗口一样,宽和高都是600
        g.fillRect(0,0,winWidth,winHeight);
        //网格线颜色
        g.setColor(Color.black);
        //绘制网格线
        for (int i = 0; i <= 20 ; i++) {
            //横线
            g.drawLine(0,i * 30,600,i * 30);
            //竖线
            g.drawLine(i * 30,0,i * 30,600);
        }
        //绘制蛇身体
        for (int i = snakeBodyEntityList.size() - 1; i >= 0; i--) {
            snakeBodyEntityList.get(i).paintSelf(g);
        }
        //绘制蛇头
        snakeHeadEntity.paintSelf(g);
        //食物绘制
        snakeFoodEntity.paintSelf(g);
        //关卡绘制
        SnakeUtil.drawWord(g,"第"+SnakeUtil.level+"关",Color.orange,40,650,260);
        //分数绘制
        SnakeUtil.drawWord(g,score  +"分" , Color.BLUE , 50,650,330);
        //绘制提示语
        g.setColor(Color.gray);
        prompt(g);
    }
  • 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

在这里插入图片描述

十五:游戏开始和暂停的键盘事件以及通关判断

15.1 在SnakeGame的launch方法添加键盘函数

//对开始游戏添加键盘事件
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //点击空格
                if(e.getKeyCode() == KeyEvent.VK_SPACE){
                    switch (state){
                        case 0:
                            //未开始
                            state = 1;
                            break;
                        case 1:
                            //游戏中
                            state = 2;
                            repaint();
                            break;
                        case 2:
                            //游戏暂停
                            state = 1;
                            break;
                        case 3:
                            //失败后重启
                            state = 5;
                            break;

                        case 4:
                            //游戏通关,进入下一关
                            state = 6;
                            break;
                        default:
                            break;

                    }
                }
            }
        });
  • 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

15.2 通关判断

在SnakeHeadEntity的paintSelf中添加

//通关判断
        if(this.frame.score >= 3){
            //通关
            SnakeGame.state = 4;
        }
  • 1
  • 2
  • 3
  • 4
  • 5

15.3 添加通关提示语

/**
     * 绘制提示语
     * @param g
     */
    void prompt(Graphics g){
        //未开始
        if(state == 0){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"按下空格开始游戏",Color.yellow,35,150,290);
        }

        //游戏暂停
        if(state == 2){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"按下空格开始游戏",Color.yellow,35,150,290);
        }

        //通关
        if(state == 4){
            g.fillRect(120,240,400,70);
            if(SnakeUtil.level == 3){
                SnakeUtil.drawWord(g,"达成条件,游戏通关",Color.green,35,150,290);
            } else {
                SnakeUtil.drawWord(g,"达成条件,点击空格开始下一关",Color.green,35,150,290);
            }

        }
    }
  • 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

十六:蛇和身体碰撞判断

16.1 在move方法中添加代码

//蛇头和身体碰撞判断
            if(this.x == snakeBodyEntityList.get(i).x && this.y == snakeBodyEntityList.get(i).y){
                //蛇咬到自己,失败
                SnakeGame.state = 3;
            }
  • 1
  • 2
  • 3
  • 4
  • 5

16.2 在prompt方法中添加游戏失败的提示语

//失败
        if(state == 3){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"失败,按下空格重新开始",Color.red,35,150,290);
        }
  • 1
  • 2
  • 3
  • 4
  • 5

十七:双缓存解决画面闪烁

原因:每次刷新都是重新绘制图片

//定义双缓存图片
    Image offScreenImage = null;
  • 1
  • 2
/**
     * 绘制
     * @param g
     */
    @Override
    public void paint(Graphics g){
        //初始化双缓存图片
        if(offScreenImage == null){
            offScreenImage = this.createImage(winWidth,winHeight);
        }
        //获取图片对应的Graphics对象
        Graphics graphicsImage = offScreenImage.getGraphics();

        //灰色背景
        graphicsImage.setColor(Color.gray);
        //绘制矩形,和窗口一样,宽和高都是600
        graphicsImage.fillRect(0,0,winWidth,winHeight);
        //网格线颜色
        graphicsImage.setColor(Color.black);
        //绘制网格线
        for (int i = 0; i <= 20 ; i++) {
            //横线
            graphicsImage.drawLine(0,i * 30,600,i * 30);
            //竖线
            graphicsImage.drawLine(i * 30,0,i * 30,600);
        }
        //绘制蛇身体
        for (int i = snakeBodyEntityList.size() - 1; i >= 0; i--) {
            snakeBodyEntityList.get(i).paintSelf(graphicsImage);
        }
        //绘制蛇头
        snakeHeadEntity.paintSelf(graphicsImage);
        //食物绘制
        snakeFoodEntity.paintSelf(graphicsImage);
        //关卡绘制
        SnakeUtil.drawWord(graphicsImage,"第"+SnakeUtil.level+"关",Color.orange,40,650,260);
        //分数绘制
        SnakeUtil.drawWord(graphicsImage,score  +"分" , Color.BLUE , 50,650,330);
        //绘制提示语
        graphicsImage.setColor(Color.gray);
        prompt(graphicsImage);
        //将双缓存图片绘制到主窗口中
        g.drawImage(offScreenImage,0,0,null);
    }
  • 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

十八:游戏失败后重新开始

18.1 SnakeGame添加resetGame方法

/**
     * 失败后,重置游戏
     */
    void resetGame(){
        //关闭当前窗口

        //开启新的窗口
        String[] args = {};
        main(args);

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

18.2 修改Switch语句

/**
     * 窗口的绘制
     */
    public void launch(){
        //设置窗口是否可见、默认是false不可见
        this.setVisible(true);
        //设置窗口的大小
        this.setSize(winWidth,winHeight);
        //设置窗口的位置在屏幕居中
        this.setLocationRelativeTo(null);
        //设置窗口的标题
        this.setTitle("贪吃蛇");
        //蛇身初始化
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,30,570,this));
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,0,570,this));
        //对开始游戏添加键盘事件
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //点击空格
                if(e.getKeyCode() == KeyEvent.VK_SPACE){
                    switch (state){
                        case 0:
                            //未开始
                            state = 1;
                            break;
                        case 1:
                            //游戏中
                            state = 2;
                            repaint();
                            break;
                        case 2:
                            //游戏暂停
                            state = 1;
                            break;
                        case 3:
                            //失败后重启
                            state = 5;
                            break;

                        case 4:
                            //游戏通关,进入下一关
                            state = 6;
                            break;
                        default:
                            break;

                    }
                }
            }
        });
        //移动蛇头
        while(true){
            //只有状态为游戏中,才需要反复执行repaint()方法
            if(state == 1){
                // repaint()方法是一个具有刷新页面效果的方法,若不调用repaint方法图形发生变化后不会立刻显示
                repaint();
            }
            //失败重启
            if(state == 5){
                state = 0;
                resetGame();
            }
            //进入下一关
            if(state == 6 && SnakeUtil.level != 3){
                state = 1;
                SnakeUtil.level++;
                resetGame();
            }
            try {
                //一秒会调用五次
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
  • 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

十九:源码奉上

19.1 SnakeGame

package com.sysg.game.sanke;

import com.sysg.game.sanke.entity.SnakeBodyEntity;
import com.sysg.game.sanke.entity.SnakeFoodEntity;
import com.sysg.game.sanke.entity.SnakeHeadEntity;
import com.sysg.game.sanke.utils.SnakeUtil;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ikun
 */
public class SnakeGame extends JFrame {

    //定义双缓存图片
    Image offScreenImage = null;

    //游戏状态 0-未开始 1-游戏中 2-暂停 3-失败 4-通关 5-失败后重启 6-下一关
    public static int state = 0;


    //当前分数
    public int score = 0;

    //窗口宽高
    int winWidth = 800;
    int winHeight = 600;


    /**
     * 创建蛇头对象
     * 默认为右边、坐标为30,570、窗口为当前this
     */
    SnakeHeadEntity snakeHeadEntity = new SnakeHeadEntity(SnakeUtil.rightSnakeHeadImg,60,570,this);

    /**
     * 蛇身集合
     */
    public List<SnakeBodyEntity> snakeBodyEntityList = new ArrayList<>();

    /**
     * 食物
     */
    public SnakeFoodEntity snakeFoodEntity = new SnakeFoodEntity().getFood();

    /**
     * 窗口的绘制
     */
    public void launch(){
        //设置窗口是否可见、默认是false不可见
        this.setVisible(true);
        //设置窗口的大小
        this.setSize(winWidth,winHeight);
        //设置窗口的位置在屏幕居中
        this.setLocationRelativeTo(null);
        //设置窗口的标题
        this.setTitle("贪吃蛇");
        //蛇身初始化
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,30,570,this));
        snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,0,570,this));
        //对开始游戏添加键盘事件
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //点击空格
                if(e.getKeyCode() == KeyEvent.VK_SPACE){
                    switch (state){
                        case 0:
                            //未开始
                            state = 1;
                            break;
                        case 1:
                            //游戏中
                            state = 2;
                            repaint();
                            break;
                        case 2:
                            //游戏暂停
                            state = 1;
                            break;
                        case 3:
                            //失败后重启
                            state = 5;
                            break;

                        case 4:
                            //游戏通关,进入下一关
                            state = 6;
                            break;
                        default:
                            break;

                    }
                }
            }
        });
        //移动蛇头
        while(true){
            //只有状态为游戏中,才需要反复执行repaint()方法
            if(state == 1){
                // repaint()方法是一个具有刷新页面效果的方法,若不调用repaint方法图形发生变化后不会立刻显示
                repaint();
            }
            //失败重启
            if(state == 5){
                state = 0;
                resetGame();
            }
            //进入下一关
            if(state == 6 && SnakeUtil.level != 3){
                state = 1;
                SnakeUtil.level++;
                resetGame();
            }
            try {
                //一秒会调用五次
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 绘制
     * @param g
     */
    @Override
    public void paint(Graphics g){
        //初始化双缓存图片
        if(offScreenImage == null){
            offScreenImage = this.createImage(winWidth,winHeight);
        }
        //获取图片对应的Graphics对象
        Graphics graphicsImage = offScreenImage.getGraphics();

        //灰色背景
        graphicsImage.setColor(Color.gray);
        //绘制矩形,和窗口一样,宽和高都是600
        graphicsImage.fillRect(0,0,winWidth,winHeight);
        //网格线颜色
        graphicsImage.setColor(Color.black);
        //绘制网格线
        for (int i = 0; i <= 20 ; i++) {
            //横线
            graphicsImage.drawLine(0,i * 30,600,i * 30);
            //竖线
            graphicsImage.drawLine(i * 30,0,i * 30,600);
        }
        //绘制蛇身体
        for (int i = snakeBodyEntityList.size() - 1; i >= 0; i--) {
            snakeBodyEntityList.get(i).paintSelf(graphicsImage);
        }
        //绘制蛇头
        snakeHeadEntity.paintSelf(graphicsImage);
        //食物绘制
        snakeFoodEntity.paintSelf(graphicsImage);
        //关卡绘制
        SnakeUtil.drawWord(graphicsImage,"第"+SnakeUtil.level+"关",Color.orange,40,650,260);
        //分数绘制
        SnakeUtil.drawWord(graphicsImage,score  +"分" , Color.BLUE , 50,650,330);
        //绘制提示语
        graphicsImage.setColor(Color.gray);
        prompt(graphicsImage);
        //将双缓存图片绘制到主窗口中
        g.drawImage(offScreenImage,0,0,null);
    }

    /**
     * 绘制提示语
     * @param g
     */
    void prompt(Graphics g){
        //未开始
        if(state == 0){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"按下空格开始游戏",Color.yellow,35,150,290);
        }

        //游戏暂停
        if(state == 2){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"按下空格开始游戏",Color.yellow,35,150,290);
        }


        //失败
        if(state == 3){
            g.fillRect(120,240,400,70);
            SnakeUtil.drawWord(g,"失败,按下空格重新开始",Color.red,35,150,290);
        }

        //通关
        if(state == 4){
            g.fillRect(120,240,400,70);
            if(SnakeUtil.level == 3){
                SnakeUtil.drawWord(g,"达成条件,游戏通关",Color.green,35,150,290);
            } else {
                SnakeUtil.drawWord(g,"达成条件,点击空格开始下一关",Color.green,35,150,290);
            }

        }
    }

    /**
     * 失败后,重置游戏
     */
    void resetGame(){
        //关闭当前窗口

        //开启新的窗口
        String[] args = {};
        main(args);

    }

    public static void main(String[] args) {
        SnakeGame snakeGame = new SnakeGame();
        snakeGame.launch();
    }



}


  • 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
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232

19.2 SnakeUtil

package com.sysg.game.sanke.utils;

import java.awt.*;

/**
 * 贪吃蛇工具类
 * @author ikun
 */
public class SnakeUtil {

    //蛇头
    public static Image upSnakeHeadImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/up.png");
    public static Image downSnakeHeadImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/down.png");
    public static Image rightSnakeHeadImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/right.png");
    public static Image leftSnakeHeadImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/left.png");
    //蛇身
    public static Image snakeBodyImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/body.png");
    //食物
    public static Image snakeFoodImg = Toolkit.getDefaultToolkit().getImage("src/main/resources/static/img/snake/food.png");
    //关卡,默认是第一关
    public static int level = 1;




    /**
     * 绘制文字
     * @param g 绘图的实体类
     * @param str 字符串的内容
     * @param color 字符串的颜色
     * @param strFontSize 字符串的字体大小
     * @param x 字符串的横坐标
     * @param y 字符串的纵坐标
     */
    public static void drawWord(Graphics g,String str,Color color,int strFontSize,int x,int y){
        g.setColor(color);
        //设置字体样式,Font.BOLD->粗体
        g.setFont(new Font("仿宋",Font.BOLD,strFontSize));
        //将文字绘制到屏幕上
        g.drawString(str,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
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

19.3 SnakeEntity

package com.sysg.game.sanke.entity;

import com.sysg.game.sanke.SnakeGame;

import java.awt.*;

/**
 * 贪吃蛇实体类
 */
public class SnakeEntity {

    //物体的图片
    Image img;

    //物体的坐标
    int x,y;

    //物体的宽高,都为30,与方格保持一致
    int width = 30,height = 30;

    //窗口类的引用
    SnakeGame frame;

    public Image getImg() {
        return img;
    }

    public void setImg(Image img) {
        this.img = img;
    }

    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 int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public SnakeGame getFrame() {
        return frame;
    }

    public void setFrame(SnakeGame frame) {
        this.frame = frame;
    }

    /**
     * 有参构造
     * @param img
     * @param x
     * @param y
     * @param frame
     */
    public SnakeEntity(Image img, int x, int y, SnakeGame frame) {
        this.img = img;
        this.x = x;
        this.y = y;
        this.frame = frame;
    }

    /**
     * 有参构造
     * @param img
     * @param x
     * @param y
     * @param width
     * @param height
     * @param frame
     */
    public SnakeEntity(Image img, int x, int y, int width, int height, SnakeGame frame) {
        this.img = img;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.frame = frame;
    }

    /**
     * 无参构造
     */
    public SnakeEntity() {
    }

    //绘制自身的方法
    public void paintSelf(Graphics g){
        g.drawImage(img,x,y,null);
    }
}


  • 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
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116

19.4 SnakeHeadEntity

package com.sysg.game.sanke.entity;

import com.sysg.game.sanke.SnakeGame;
import com.sysg.game.sanke.utils.SnakeUtil;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;

/**
 * 蛇头实体类
 * @author ikun
 */
public class SnakeHeadEntity extends SnakeEntity{
    /**
     * 蛇头方向 up down left right
     * 默认为right
     */
    private String direction = "right";

    public String getDirection() {
        return direction;
    }

    public void setDirection(String direction) {
        this.direction = direction;
    }

    public SnakeHeadEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
        //监听键盘
        this.frame.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //控制蛇头的移动
                changeDirection(e);
            }
        });
    }

    /**
     * 控制蛇头的移动
     * w->a->s->d
     */
    public void changeDirection(KeyEvent e) {
        switch (e.getKeyCode()){
            //按下A键->朝左移动
            case KeyEvent.VK_A:
                if(!"right".equals(direction)){
                    //将方向改为左边
                    direction = "left";
                    //修改蛇头图片的方向
                    img = SnakeUtil.leftSnakeHeadImg;
                }
                break;

            //按下D键->朝右移动
            case KeyEvent.VK_D:
                if(!"left".equals(direction)){
                    //将方向改为右边
                    direction = "right";
                    //修改蛇头图片的方向
                    img = SnakeUtil.rightSnakeHeadImg;
                }
                break;

            //按下W键->朝上移动
            case KeyEvent.VK_W:
                if(!"down".equals(direction)){
                    //将方向改为上边
                    direction = "up";
                    //修改蛇头图片的方向
                    img = SnakeUtil.upSnakeHeadImg;
                }
                break;

            //按下S键->朝下移动
            case KeyEvent.VK_S:
                if(!"up".equals(direction)){
                    //将方向改为上边
                    direction = "down";
                    //修改蛇头图片的方向
                    img = SnakeUtil.downSnakeHeadImg;
                }
                break;
            default:
                break;
        }

    }

    /**
     * 蛇的移动
     * 蛇身体的移动的代码一定要写在蛇头移动的前面
     */
    public void  move(){
        //蛇身体的移动
        List<SnakeBodyEntity> snakeBodyEntityList = this.frame.snakeBodyEntityList;
        for (int i = snakeBodyEntityList.size() - 1; i >= 1; i--) {
            //蛇的移动就是上一个坐标和当前坐标相等
            snakeBodyEntityList.get(i).x = snakeBodyEntityList.get(i-1).x;
            snakeBodyEntityList.get(i).y = snakeBodyEntityList.get(i-1).y;
            //蛇头和身体碰撞判断
            if(this.x == snakeBodyEntityList.get(i).x && this.y == snakeBodyEntityList.get(i).y){
                //蛇咬到自己,失败
                SnakeGame.state = 3;
            }
        }
        snakeBodyEntityList.get(0).x = this.x;
        snakeBodyEntityList.get(0).y = this.y;
        //蛇头的移动
        switch (direction) {
            case "up":
                y -= height;
                break;
            case "down":
                y += height;
                break;
            case "left":
                x -= width;
                break;
            case "right":
                x += width;
                break;
            default:
                break;
        }

    }


    @Override
    public void paintSelf(Graphics g) {
        //设置蛇头的位置
        super.paintSelf(g);
        //食物
        SnakeFoodEntity snakeFoodEntity = this.frame.snakeFoodEntity;
        //身体最后一节的坐标
        Integer newX = null;
        Integer newY = null;
        if(this.x == snakeFoodEntity.x && this.y == snakeFoodEntity.y ){
            //此时蛇头和食物重合了
            this.frame.snakeFoodEntity = snakeFoodEntity.getFood();
            //获取蛇身的最后一个元素
            SnakeBodyEntity lastSnakeBodyEntity = this.frame.snakeBodyEntityList.get(this.frame.snakeBodyEntityList.size() - 1);
            newX = lastSnakeBodyEntity.x;
            newY = lastSnakeBodyEntity.y;
            //分数+1
            this.frame.score ++;
        }
        //通关判断
        if(this.frame.score >= 3){
            //通关
            SnakeGame.state = 4;
        }

        //移动蛇头
        move();
        if(newX != null && newY != null){
            this.frame.snakeBodyEntityList.add(new SnakeBodyEntity(SnakeUtil.snakeBodyImg,newX,newY,this.frame));
        }
        //贪吃蛇的越界处理,移动后新的身体对象添加到snakeBodyEntityList
        checkIndex();
    }

    /**
     * 贪吃蛇的越界处理
     */
    public void checkIndex(){
        if(x < 0){
            x = 570;
        } else if (x > 570){
            x = 0;
        } else if (y < 30){
            y = 570;
        } else if (y > 570){
            y = 30;
        }
    }


}


  • 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
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184

19.5 SnakeBodyEntity

package com.sysg.game.sanke.entity;

import com.sysg.game.sanke.SnakeGame;

import java.awt.*;

/**
 * 蛇身体
 */
public class SnakeBodyEntity extends SnakeEntity {

    public SnakeBodyEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

19.6 SnakeFoodEntity

package com.sysg.game.sanke.entity;

import com.sysg.game.sanke.SnakeGame;
import com.sysg.game.sanke.utils.SnakeUtil;

import java.awt.*;
import java.util.Random;

/**
 * 食物实体类
 */
public class SnakeFoodEntity extends SnakeEntity {

    /**
     * 随机
     */
    Random r = new Random();

    public SnakeFoodEntity() {
        super();
    }

    public SnakeFoodEntity(Image img, int x, int y, SnakeGame frame) {
        super(img, x, y, frame);
    }

    /**
     * 获取食物
     * x:0->570
     * y.3:0->570
     * @return
     */
    public SnakeFoodEntity getFood(){
        return new SnakeFoodEntity(SnakeUtil.snakeFoodImg,r.nextInt(20) * 30,(r.nextInt(19) + 1) * 30,this.frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}

  • 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
声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号