【Java Swing】实现贪吃蛇

【Java Swing】贪吃蛇

前些日子看了youtube上bro code的贪吃蛇代码视频 于是自己跟着视频实现了一下 顺便写了一下注释 。视频链接(需特殊工具才可以浏览 进不去就别进了 直接看我写的注释和代码):snakegame

该项目主要包含三个class:SnakeGame,GamePanel,GameFrame

下面上代码和代码注释:

首先新建三个class:SnakeGame,GamePanel,GameFrame(别写同一个大类里,放在同一个包里 分别新建三个类)

class SnakeGame

public class SnakeGame {
    public static void main(String[] args){
         new GameFrame();//直接new一个新的GameFrame实例 剩下的全都交给GamePanel和GameFrame做
    }
}

class GameFrame

import javax.swing.JFrame;
//GameFrame继承自JFrame用于生成贪吃蛇程序的初始化窗体
public class GameFrame  extends JFrame {
    GameFrame(){
        this.add(new GamePanel());//添加Panel面板
        this.setTitle("Snake");//窗口标题为Snake
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//添加关闭按钮 确保窗口可关闭
        this.setResizable(false);//窗口大小无法被使用者调整,由程序员写死
        this.pack();//调整此窗口的大小,以适合其子组件的首选大小和布局
        this.setVisible(true);//窗口可视化
        this.setLocationRelativeTo(null);//调节窗口相对于指定组件的位置 为null则默认窗口在屏幕中央弹出
    }
}

class GamePanel



import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.Timer.*;

public class GamePanel extends JPanel implements ActionListener {
    //窗口大小 默认600*600 单位大小为贪吃蛇地图大小 数字越大地图越大 判定点越大。
    static final int SCREEN_WIDTH = 600;
    static final int SCREEN_HEIGHT = 600;
    static final int UNIT_SIZE = 20;
    static final int GAME_UNITS = (SCREEN_WIDTH*SCREEN_HEIGHT)/UNIT_SIZE;
    static final int DELAY = 75; //DELAY为贪吃蛇移动速度 数字越小 贪吃蛇移动速度越快
    final int[] x=new int[GAME_UNITS];//
    final int[] y=new int[GAME_UNITS];
    int bodyParts = 1;//蛇身初始化长度为1
    int applesEaten;//纪录蛇吃了多少苹果
    int appleX;//苹果的坐标
    int appleY;
    char direction = 'R';//默认初始化窗口贪吃蛇的运动方向为向右
    boolean running =false;
    Timer timer;//引入计时器参数timer
    Random random;//随机数random
    GamePanel(){//面板构造器
        random = new Random();
        this.setPreferredSize(new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT));//组件高度长度确定为刚才设定的SCREEN_WIDTH和SCREEN_HEIGHT
        this.setBackground(Color.BLACK);//背景面板颜色设置为黑色
        this.setFocusable(true);//让窗口可以被操作 改为false 那么无法用键盘操纵蛇
        this.addKeyListener(new MyKeyAdapter());//确保窗口内的东西可以被键盘指定键操控
        startGame();//开始游戏
    }
    public void startGame(){
        newApple();//生成新苹果
        running =true;//开始运行
        timer = new Timer(DELAY,this);//计时器启动
        timer.start();
    }
    public void paintComponent(Graphics g){
        super.paintComponent(g);//绘制组件
        draw(g);//绘制容器
    }
    public void draw(Graphics g){
        if(running){
            for(int i = 0;i<SCREEN_HEIGHT/UNIT_SIZE;i++){
                g.drawLine(i*UNIT_SIZE,0,i*UNIT_SIZE,SCREEN_HEIGHT);
                g.drawLine(0,i*UNIT_SIZE,SCREEN_HEIGHT,i*UNIT_SIZE);//绘制地图 根据窗口大小来画出每次蛇移动的格子
            }
            g.setColor(Color.red);
            g.fillOval(appleX,appleY,UNIT_SIZE,UNIT_SIZE);//苹果占一个格子
            for(int i = 0 ; i< bodyParts;i++){
                if(i == 0){
                    g.setColor(Color.green);
                    g.fillRect(x[i],y[i],UNIT_SIZE,UNIT_SIZE);
                }//画出初始化绿色的蛇头位置,前面设定的x[],y[]用来确认蛇头
                else{
                    g.setColor(new Color(45,180,0));//绿色
                    g.fillRect(x[i],y[i],UNIT_SIZE,UNIT_SIZE);//确认蛇身
                }
            }
            g.setColor(Color.red);
            g.setFont(new Font("Ink Free",Font.BOLD,40));
            FontMetrics metrics = getFontMetrics(g.getFont());
            g.drawString("Score:"+applesEaten,(SCREEN_WIDTH - metrics.stringWidth("Score:"+applesEaten))/2,g.getFont().getSize());//画出分数 分数的位置在窗口最上方中间
        }
        else{
            gameOver(g);
        }
    }
    public void newApple(){
        appleX = random.nextInt((int) SCREEN_WIDTH/UNIT_SIZE)*UNIT_SIZE;
        appleY = random.nextInt((int) SCREEN_HEIGHT/UNIT_SIZE)*UNIT_SIZE;//随机生成新苹果

    }
    public void move(){
        for(int i = bodyParts;i>0;i--){
            x[i] = x[i-1];
            y[i] = y[i-1];
        }
        switch (direction){
            case 'U':
                y[0] = y [0] - UNIT_SIZE;
                break;//当向上移动时,蛇头的纵坐标变为原纵坐标-单位长度
            case 'D':
                y[0] = y [0] + UNIT_SIZE;
                break;//当向下移动时,蛇头的纵坐标变为原纵坐标+单位长度
            case 'L':
                x[0] = x [0] - UNIT_SIZE;
                break;//当向左移动时,蛇头的横坐标变为原横坐标-单位长度
            case 'R':
                x[0] = x [0] + UNIT_SIZE;
                break;//当向右移动时,蛇头的横坐标变为原横坐标+单位长度
        }
    }
    public void checkApple(){
        if((x[0] == appleX) &&(y[0] == appleY)){
            bodyParts++;
            applesEaten++;
            newApple();//当蛇头坐标与苹果坐标相同时,蛇身变长,分数加一,然后再生成新苹果
        }
    }
    public void checkCollisions(){
       //如果蛇头和蛇身相撞 停止运行
        for(int i  = bodyParts;i>0;i--){
            if((x[0] == x[i]) && (y[0] ==y[i])){
                running = false;
            }
        }
        //如果蛇头撞到窗口左边界 停止运行
        if(x[0] < 0){
            running = false;
        }
        //如果蛇头撞到窗口右边界 停止运行
        if (x[0] > SCREEN_WIDTH){
            running = false;
        }
        //如果蛇头撞到窗口上边界 停止运行
        if(y[0]<0){
            running = false;
        }
        //如果蛇头撞到窗口下边界 停止运行
        if(y[0]>SCREEN_HEIGHT){
            running = false;
        }
        //如果停止运行,则计时器也停止
        if (!running){
            timer.stop();
        }
    }
    public void gameOver(Graphics g){
        //当游戏失败时,也显示分数
        g.setColor(Color.red);
        g.setFont(new Font("Ink Free",Font.BOLD,40));
        FontMetrics metrics1 = getFontMetrics(g.getFont());
        g.drawString("Score:"+applesEaten,(SCREEN_WIDTH - metrics1.stringWidth("Score:"+applesEaten))/2,g.getFont().getSize());

        //游戏失败时,显示gameover
        g.setColor(Color.red);
        g.setFont(new Font("Ink Free",Font.BOLD,75));
        FontMetrics metrics2 = getFontMetrics(g.getFont());
        g.drawString("Game Over",(SCREEN_WIDTH - metrics2.stringWidth("Game Over"))/2,SCREEN_HEIGHT/2);
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if(running){
            move();//窗口运行时,让蛇开始运动
            checkApple();//检测蛇是否吃到苹果
            checkCollisions();//检测蛇头是否撞到了边界或者蛇身
        }
        repaint();//停止运行就改变画面

    }
    public class MyKeyAdapter extends KeyAdapter{
        //首先我们要弄清楚一件事便是,当蛇前进时,是不能后退的,只能向左或向右,同理,蛇向左运动时,是没有办法向右的。
        public void keyPressed(KeyEvent e){
            switch (e.getKeyCode()){
                case KeyEvent.VK_LEFT:
                    if(direction!= 'R'){//键盘侦听,接受到的键为←时,如果这时蛇没有向右运动,则方向可变为←
                        direction='L';
                    }
                    break;
                case KeyEvent.VK_RIGHT:
                    if(direction != 'L'){//接受到的键为→时,如果这时蛇没有向左运动,则方向可变为→
                        direction='R';
                    }
                    break;
                case KeyEvent.VK_UP:
                    if(direction != 'D'){//接受到的键为↑时,如果这时蛇没有向下运动,则方向可变为↑
                        direction='U';
                    }
                    break;
                case KeyEvent.VK_DOWN:
                    if(direction != 'U'){//接受到的键为↓时,如果这时蛇没有向右运动,则方向可变为↓
                        direction='D';
                    }
                    break;
            }
        }
    }
}


实现效果

snake1
snake2
snake3

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值