GUI小游戏——贪吃蛇

GUI之贪吃蛇

    • 前言
    • *启动类 创建窗体和添加组件*
    • *游戏主体*
    • *资源*

前言

在跟着视频敲的时候出现了一些bug
可能是jdk版本问题 我用的jdk11
主要问题就是

随机玄学监听不到键盘事件
其他都是一些小问题了
可能和视频代码有出入,
一是因为改bug乱撞
二是看到24一半之后就自己敲着试试了
废话不多说上代码

启动类 创建窗体和添加组件

package snake;

import javax.swing.*;
import java.awt.*;

//启动类 主窗口 创建游戏panel、添加监听

public class StartGame extends JFrame {
    public StartGame(){
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setBounds(10,10,900,720);
        this.setResizable(false);

        Container container=this.getContentPane();
        GamePanel panel=new GamePanel();
        container.add(panel);
        //监听不到键盘事件的bug在这里把监听放到Frame里就能完美解决
        this.addKeyListener(panel);
        this.setFocusable(true);
    }

    public static void main(String[] args) {
        new StartGame();
    }
}

游戏主体

package snake;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
//游戏主体部分
public class GamePanel extends JPanel implements KeyListener , ActionListener {

//数据域
    Timer timer=new Timer(100,this);
    String direction;
    int length;
    int[][] snake =new int[900][2];
    int[] foodLocation;
    int mark;
    boolean reStart;
    boolean derectionChange;
    boolean isStart=false;
    //初始化函数 游戏启动和重开时调用
    public void init(){
        length=3;
        snake[0][0]=100;snake[0][1]=100;
        snake[1][0]=75;snake[1][1]=100;
        snake[2][0]=50;snake[2][1]=100;

        foodLocation=putFood();
        direction="R";
        mark=0;
        reStart=false;
        derectionChange=false;
    }


//游戏结束分数和重开提示

    public void paintEnd(Graphics g){
        g.setColor(Color.WHITE);
        g.setFont(new Font("微软雅黑",Font.BOLD,40));
        g.drawString("按下空格重新开始",285,420);
        g.drawString("游戏结束!",285,340);
        g.drawString("最终得分:"+String.format("%5d",mark),285,380);
        g.setColor(Color.BLACK);
    }

    //画蛇、食物、开始暂停提示等
    @Override
    public void paint(Graphics g) {
        //背景板绘制
        super.paint(g);
        setBackground(Color.WHITE);
        Data.header.paintIcon(this,g,25,11);
        g.fillRect(25,75,850,600);


        //画食物
        Data.food.paintIcon(this,g,foodLocation[0]+25,foodLocation[1]+75);

        //画蛇头 需要判断方向
        switch (direction){
            case "R":
                Data.right.paintIcon(this,g,snake[0][0]+25,snake[0][1]+75);
                break;
            case "L":
                Data.left.paintIcon(this,g,snake[0][0]+25,snake[0][1]+75);
                break;
            case "U":
                Data.up.paintIcon(this,g,snake[0][0]+25,snake[0][1]+75);
                break;
            case "D":
                Data.down.paintIcon(this,g,snake[0][0]+25,snake[0][1]+75);
                break;
        }


        //画身体
        for (int i = 1; i<length; i++) {
            Data.body.paintIcon(this,g,snake[i][0]+25,snake[i][1]+75);
        }

        //在暂停时提示空格开始
        if(!isStart){
            g.setColor(Color.WHITE);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("按下空格开始游戏",285,380);
            g.setColor(Color.BLACK);
        }

        //计分板
        g.setColor(Color.RED);
        g.setFont(new Font("微软雅黑",Font.BOLD,15));
        g.drawString("分数:"+mark,700,50);
        g.setColor(Color.BLACK);
    }

    //构造
    public GamePanel() {
        //setBackground(Color.BLACK);
        init();
        timer.start();


    }


    @Override
    public void keyTyped(KeyEvent keyEvent) {

    }

    //键盘事件监听
    @Override
    public void keyPressed(KeyEvent keyEvent) {
        //如果按下和游戏无关键位直接退出
        if(keyEvent.getKeyCode()!=KeyEvent.VK_DOWN
                &&keyEvent.getKeyCode()!=KeyEvent.VK_UP
                &&keyEvent.getKeyCode()!=KeyEvent.VK_LEFT
                &&keyEvent.getKeyCode()!=KeyEvent.VK_RIGHT
                &&keyEvent.getKeyCode()!=KeyEvent.VK_SPACE){
            return;
        }


        //获取按下键键码
        int keyCode= keyEvent.getKeyCode();

        /*
        * 按下不同键位实行不同操作
        * 空格开始/暂停游戏
        * 上下左右键改变方向
        * 注意:不能直接回头
        * */
        switch (keyCode){

            case KeyEvent.VK_SPACE:
                //判断:如果是游戏结束后重开,需要重新对游戏进行初始化操作
                if(reStart){
                    init();
                    isStart=true;
                    break;
                }
                isStart=!isStart;
                break;

            case KeyEvent.VK_RIGHT:
                //方向改变 先判断现在方向是不是和按键相反方向 如果是 不能转向
                //同时 判定在一个定时器时间内是否已经进行过方向的改变
                //如果是,那么不允许再次转向
                //否则会出现两次快速转向自杀的情况(比如初始向右,快速连续按上左将会直接向左自杀)
                //转向成功后把标记是否转向的变量置为Ture
                if(direction!="L"){
                    if (direction!="R"&&!derectionChange){
                        direction="R";
                        derectionChange=true;
                    }
                }
                break;
            case KeyEvent.VK_LEFT:
                if(direction!="R"){
                    if (direction!="L"&&!derectionChange){
                        direction="L";
                        derectionChange=true;
                    }
                }
                break;
            case KeyEvent.VK_UP:
                if(direction!="D"){
                    if (direction!="U"&&!derectionChange){
                        direction="U";
                        derectionChange=true;
                    }
                }
                break;
            case KeyEvent.VK_DOWN:
                if(direction!="U"){
                    if (direction!="D"&&!derectionChange){
                        direction="D";
                        derectionChange=true;
                    }
                }
                break;
        }
        repaint();

    }

    @Override
    public void keyReleased(KeyEvent keyEvent) {

    }


    //定时器操作
    @Override
    public void actionPerformed(ActionEvent actionEvent) {

        //判断蛇头是否碰到身体,如果是 游戏结束打印计分板
        for (int i = 1; i < length; i++) {
            if(snake[0][0]==snake[i][0]&&snake[0][1]==snake[i][1]){
                isStart=false;
                paintEnd(this.getGraphics());
                reStart=true;
                return;
            }
        }


        //游戏在进行状态下 蛇身向前移动 蛇头向现在所朝向的方向移动
        if(isStart){
            int[] temp={snake[0][0],snake[0][1]};
            for (int i = length-1; i >0; i--) {
                snake[i][0]=snake[i-1][0];
                snake[i][1]=snake[i-1][1];
            }
            switch (direction){
                case "R":
                    snake[0][0]+=25;
                    snake[0][0]%=850;
                    break;
                case "L":
                    snake[0][0]+=825;
                    snake[0][0]%=850;
                    break;
                case "U":
                    snake[0][1]+=575;
                    snake[0][1]%=600;
                    break;
                case "D":
                    snake[0][1]+=25;
                    snake[0][1]%=600;
                    break;
            }
            repaint();
            //重置转向的标记
            derectionChange=false;
        }


        //判断是否吃到食物 如果吃到 加一节身体叠在现在最后一节身体上 让图像更平滑
        //同时重新放置食物和加分
        if (snake[0][0]==foodLocation[0]&&snake[0][1]==foodLocation[1]){
            foodLocation=putFood();
            length++;
            snake[length-1][0]=snake[length-2][0];
            snake[length-1][1]=snake[length-2][1];
            mark+=50;
        }


    }

    //放置食物,产生随机坐标 和蛇身比较,若和蛇身重合,则重新放置
    public int[] putFood(){
        int x=(int)(Math.random()*34);
        int y=(int)(Math.random()*24);
        x*=25;
        y*=25;
        for (int i = 0; i < length; i++) {
            if(x==snake[i][0]&&y==snake[i][1]){
                return putFood();
            }
        }
        return new int[]{x,y};
    }
}

资源

package snake;

import javax.swing.*;
import java.net.URL;
//取得蛇身蛇头等元素
public class Data {
    public  static URL headerURL =Data.class.getResource("header.png");
    public  static URL upURL =Data.class.getResource("up.png");
    public  static URL downURL =Data.class.getResource("down.png");
    public  static URL leftURL =Data.class.getResource("left.png");
    public  static URL rightURL =Data.class.getResource("right.png");
    public  static URL foodURL =Data.class.getResource("food.png");
    public  static URL bodyURL =Data.class.getResource("body.png");

    public static ImageIcon header=new ImageIcon(headerURL);
    public static ImageIcon up=new ImageIcon(upURL);
    public static ImageIcon down=new ImageIcon(downURL);
    public static ImageIcon left=new ImageIcon(leftURL);
    public static ImageIcon right=new ImageIcon(rightURL);
    public static ImageIcon food=new ImageIcon(foodURL);
    public static ImageIcon body=new ImageIcon(bodyURL);
}

教材链接~

你可能感兴趣的:(追随狂神学Java)