用Java写一个贪吃蛇游戏

目录

创建窗体

创建游戏棋盘

创建蛇的节点

创建蛇身

让蛇移动

添加键盘监听

添加边界处理

把食物绘制到棋盘上

吃食物


创建窗体

创建一个MainFrame类继承JFrame,表示主窗体。

public class MainFrame extends JFrame {
    //创建窗体对象时,初始化船体参数
    public MainFrame(){
        initFrame();
    }
}

MainFrame类中写一个initFrame方法,初始化窗体参数

//1.初始化窗体参数
private void initFrame() {
    //设置窗体标题
    setTitle("黑马贪吃蛇");
    //设置窗体大小
    setSize(610, 640);
    //设置窗体位置
    setLocation(400, 400);
    //设置窗体大小不能改变
    setResizable(false);
    //设置窗体关闭按钮的作用,是正常退出
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

在MainFrame中添加一个main方法,创建窗体并运行,就可以看到窗体了

//主方法
public static void main(String[] args) {
    //创建窗体,并显示在屏幕上
    new MainFrame().setVisible(true);
}

创建游戏棋盘

在JFrame类中写一个initGamePanel方法,初始化游戏棋盘

//初始化游戏面板
private void initGamePanel() {
    JPanel jPanel = new JPanel() {
        //paint是用来绘制面板中的内容
        @Override
        public void paint(Graphics g) {
            //设置画笔颜色
            g.setColor(Color.black); //设置画笔颜色是黑色
            //绘制40条横线(起点横坐标,起点纵坐标,终点横坐标,终点纵坐标)
            for(int i=1;i<=40;i++){
                g.drawLine(0,15*i,600,15*i);
            }

            //绘制40条竖线
            for (int i=1;i<=40;i++){
                g.drawLine(15*i,0,15*i,600);
            }
        }
    };
    add(jPanel);
}

创建蛇的节点

创建一个Node类表示节点,一条蛇有若干个节点组成,每一个节点其实就是一个小方格,我们用行和列来定义节点在棋盘中的位置。

public class Node {
    private int x; //横坐标
    private int y; //纵坐标

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

创建蛇身

创建Snake类表示蛇,一条蛇有多个节点使用LinkedList集合存储Node节点,蛇出生的时候 有3个节点。

public class Snake {
    //body
    private LinkedList<Node> body;
    
    //创建蛇对象时,初始化蛇身
    public Snake() {
        initSnake();
    }

    //初始化蛇身 3个节点
    public void initSnake(){
        //创建蛇的躯体
        body=new LinkedList<>();
        //给蛇添加3个节点,在棋盘的中心位置横向排列
        body.add(new Node(20,20));
        body.add(new Node(21,20));
        body.add(new Node(22,20));
    }
  
    //获取蛇蛇身
    public LinkedList<Node> getBody(){
        return body;
    }
}

把蛇绘制到棋盘上

在MainFrame中添加一个创建Snake的成员变量,表示窗体中有一条蛇

public class MainFrame extends JFrame {
    //定义成员变量
    private Snake snake=new Snake();
	....
}

在绘制棋盘的paint方法中,添加下面的代码绘制把蛇绘制到棋盘上

//绘制横线
...
//绘制竖线
...

//绘制蛇,根据每一个节点的坐标在棋盘上绘制矩形
for (Node node : snake.getBody()) {
    //每一个节点的宽度和高度是15
    g.fillRect(node.getX()*15,node.getY()*15,15,15);
} 

 再次运行,就可以看到有一条蛇静静的躺在棋盘中间了

让蛇移动

定义一个枚举类型,表示运动的4个方向

public enum  Direction {
    UP,DOWN,LEFT,RIGHT
}

在Snake类中定义一个移动方向的变量成员变量,和move方法。

public class Snake{
    //蛇头运动的方向
    private Direction direction;
    
    //移动的方法: 每次移动在蛇头运动方向添加一个节点,再删除最后一个节点
    public void move(){
        //获取蛇头的节点
        Node head = body.getFirst();
        //新的蛇头节点
        Node newHead=null;
        //检查移动的方向
        switch (direction){
            //如果向左移动
            case LEFT:
                //创建一个新的蛇头节点
                 newHead=new Node(head.getX()-1,head.getY());
                //把心得蛇头节点添加到body的第一个元素
                body.addFirst(newHead);
                //删除蛇尾
                body.removeLast();
                break;
            case RIGHT:
                //创建一个新的蛇头节点
                newHead=new Node(head.getX()-1,head.getY());
                //把心得蛇头节点添加到body的第一个元素
                body.addFirst(newHead);
                //删除蛇尾
                body.removeLast();
                break;
            case UP:
                //创建一个新的蛇头节点
                newHead=new Node(head.getX(),head.getY()-1);
                //把心得蛇头节点添加到body的第一个元素
                body.addFirst(newHead);
                //删除蛇尾
                body.removeLast();
                break;
            case DOWN:
                //创建一个新的蛇头节点
                newHead=new Node(head.getX(),head.getY()+1);
                //把心得蛇头节点添加到body的第一个元素
                body.addFirst(newHead);
                //删除蛇尾
                body.removeLast();
                break;
        }
    }
}

 在MainFrame类中,创建一个定时器每100毫秒,重绘游戏棋盘

public class MainFrame extends JFrame {
    ...
    //游戏棋盘面板
    JPanel jPanel=null;
    //定义定时器
    private Timer timer;
    
    public MainFrame() throws HeadlessException {
        //初始化窗体参数
        initFrame();
        //初始化窗体中的游戏面板
        initGamePanel();
        //初始化定时器
        initTimer();
    }
    
    //2.初始化游戏棋盘
    private void initGamePanel() {
         jPanel = new JPanel() {
            //paint是用来绘制面板中的内容
            @Override
            public void paint(Graphics g) {
				//每次重绘时清空面板中的内容
                g.clearRect(0,0,getWidth(),getHeight());
               	....
            }
        };
        add(jPanel);
    }

    //3.初始化定时器
    private void initTimer() {
        TimerTask task=new TimerTask() {
            @Override
            public void run() {
                //调用蛇移动的方法
                snake.move();
                //每次移动重绘游戏棋盘,会自动调用jPanel的paint方法
                jPanel.repaint();
            }
        };
        timer=new Timer();
        timer.scheduleAtFixedRate(task,0,100);
    }
}

添加键盘监听

在MainFrame类中,添加一个setKeyListener的方法,监听上下左右四个键

public class MainFrame extends JFrame {
    ...
    public MainFrame() throws HeadlessException {
       	...
        //添加键盘监听
        setkeyListener();
    }
    
    //添加键盘监听
    private void setkeyListener() {
        //对上下左右键进行监听
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode()){
                    //按下上键
                    case KeyEvent.VK_UP:
                        //蛇头方向改为上
                        snake.setDirection(Direction.UP);
                        break;
                    //按下下键
                    case KeyEvent.VK_DOWN:
                        //蛇头方向改为下
                        snake.setDirection(Direction.DOWN);
                        break;
                    //按下左键
                    case KeyEvent.VK_LEFT:
                        //蛇头方向改为左
                        snake.setDirection(Direction.LEFT);
                        break;
                    //按下右键
                    case KeyEvent.VK_RIGHT:
                        //蛇头方向改为右
                        snake.setDirection(Direction.RIGHT);
                        break;
                }
            }
        });
    }
}

到此蛇就可以跟随键盘移动了

添加边界处理

当蛇移动到边界处就游戏结束,把标记改为false

public class Snake{
    ...
    //定义一个标记true表示蛇是活的,可以运动
    private boolean isLive=true;
    
    //检查蛇是否碰壁
    private void checkOver() {
        //获取蛇头
        Node head = body.getFirst();
        int x=head.getX();
        int y=head.getY();
        if(x<0||y<0||x>=40||y>=40){
            isLive=false;
        }
    }
}

在定时器中调用checkOver()方法

//3.初始化定时器
private void initTimer() {
    TimerTask task=new TimerTask() {
        @Override
        public void run() {
            //移动
            snake.move();
            //检查是否碰壁
            snake.checkOver();
        }
    };
    timer=new Timer();
    timer.scheduleAtFixedRate(task,0,100);
}

把食物绘制到棋盘上

创建一个Food类表示食物,其实食物也是一个节点,所以让Food继承Node

public class Food extends Node {
    //创建食物的时候,随机产生一个位置
    public Food() {
        reset();
    }
    //随产生位置
    public void reset(){
        //随机生成食物的坐标
        Random r=new Random();
        setX(r.nextInt(40));
        setY(r.nextInt(40));
    }
}

在MainFrame中定义一个成员Food表示食物,并把食物绘制到棋盘上

public class MainFrame extends JFrame {
    //定义食物
    private Node food=new Node();
    
    public MainFrame() throws HeadlessException {
        //初始化窗体参数
        initFrame();
        //初始化窗体中的游戏面板
        initGamePanel();
        //初始化定时器
        initTimer();
        //添加键盘监听
        setkeyListener();
    }
    
    //2.初始化游戏棋盘
    private void initGamePanel() {
         jPanel = new JPanel() {
            //paint是用来绘制面板中的内容
            @Override
            public void paint(Graphics g) {
                //清空棋盘
                g.clearRect(0,0,600,600);
                
                //绘制横线、绘制竖线、绘制蛇

                //绘制食物
                g.fillRect(food.getX()*15,food.getY()*15,15,15);
            }
        };
        add(jPanel);
    }
}

吃食物

在Snake类中添加一个eatFood方法

//吃食物
public void eatFood() {
    //获取蛇头
    Node head = body.getFirst();
    //如果蛇头和食物的位置重合,就在蛇头添加一个元素
  	if(head.getX()==MainFrame.food.getX()
     	&&head.getY()==MainFrame.food.getY()){
        //沿着蛇头运动方向创建一个节点
        //新的蛇头节点
        Node newHead=null;
        //检查移动的方向
        switch (direction){
                //如果向左移动
            case LEFT:
                //创建一个新的蛇头节点
                newHead=new Node(head.getX()-1,head.getY());
                //把心得蛇头节点添加到body的第一个元素
                body.addFirst(newHead);
                break;
            case RIGHT:
                //创建一个新的蛇头节点
                newHead=new Node(head.getX()+1,head.getY());
                //把心得蛇头节点添加到body的第一个元素
                body.addFirst(newHead);
                break;
            case UP:
                //创建一个新的蛇头节点
                newHead=new Node(head.getX(),head.getY()-1);
                //把心得蛇头节点添加到body的第一个元素
                body.addFirst(newHead);
                break;
            case DOWN:
                //创建一个新的蛇头节点
                newHead=new Node(head.getX(),head.getY()+1);
                //把心得蛇头节点添加到body的第一个元素
                body.addFirst(newHead);
                break;
        }
        //每次吃完食物,让食物重置
        MainFrame.food.reset();
    }
}

在定时器中调用吃食物的方法

//2.初始化游戏棋盘
private void initGamePanel() {
    jPanel = new JPanel() {
        //paint是用来绘制面板中的内容
        @Override
        public void paint(Graphics g) {
            //清空棋盘
            g.clearRect(0,0,600,600);

            //绘制横线、绘制竖线、绘制蛇

            //绘制食物
            g.fillRect(food.getX()*15,food.getY()*15,15,15);
        }
    };
    add(jPanel);
}

猜你喜欢

转载自blog.csdn.net/2301_76549195/article/details/134489845