java之贪吃蛇

java之贪吃蛇

素材资源

right
left
food
down

body
up
header

代码实现

  • 逻辑思路

    1. 使用图片素材
    2. 创建游戏主界面
    3. 游戏状态设置,开始态和死亡态和暂停态
    4. 事件绑定
    5. 定时器使用
    6. 得分信息和小蛇长度
  • 主要技术

    1. Java swing
    2. Java awt
  • 代码部分

    图片素材部分

    public class Data {
        public static void main(String[] args) {
            new Data();
         }
        static URL up=Data.class.getResource("上.png");
        static URL down=Data.class.getResource("下.png");
        static URL right=Data.class.getResource("右.png");
        static URL left=Data.class.getResource("左.png");
        static URL body=Data.class.getResource("身体.png");
        static URL food=Data.class.getResource("食物.png");
        static URL header=Data.class.getResource("header.png");
        static ImageIcon iconUp = new ImageIcon(up);
        static ImageIcon iconDown = new ImageIcon(down);
        static ImageIcon iconRight = new ImageIcon(right);
        static ImageIcon iconLeft = new ImageIcon(left);
        static ImageIcon iconBody = new ImageIcon(body);
        static ImageIcon iconFood = new ImageIcon(food);
        static ImageIcon iconHeader = new ImageIcon(header);
        public Data() {
        }
    }
    

    类名的class的getResource方法可以获取文件资源,返回值为URL类型,再通过图片图标的构造方法创建图片图标

    启动类

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

    主界面设计

    class frame extends JFrame{
        void load(){
            setTitle("贪吃蛇");
            setResizable(false);		//界面大小不可改变
            setLayout(new BorderLayout());
            setBounds(100,100,918,720);
            setVisible(true);
            setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            Container contentPane = getContentPane();
            //contentPane.setBackground(Color.black);
            contentPane.add(new GamePanel());
        }
        public frame(){
            load();
        }
    

    游戏面板

    public class GamePanel extends JPanel implements KeyListener, ActionListener {
        public GamePanel() {
            init();
            //此语句不能重复执行,既不能写到init里
            addKeyListener(this);
        }
        void init(){
            score=0;
            isFail=false;
            timer.start();                                                          //监听事件只能是ActionListener,需要调用start开启
            setFocusable(true);                 //设置聚焦属性
            direct="R";
            len=3;
            snakex[0]=100;snakey[0]=100;
            snakex[1]=75;snakey[1]=100;
            snakex[2]=50;snakey[2]=100;
            foodx=25*(random.nextInt(33)+1);
            foody=25*(random.nextInt(23)+3);
        }
        private int score;
        private Timer timer = new Timer(100,this);                        //定时器,每隔一定时间执行监听事件,此处是this
        private boolean isStart=false;          //游戏状态
        private String direct="R";
        private int len;                        //小蛇长度
        private int []snakex=new int[500];      //小蛇坐标存储
        private int[]snakey=new int[500];
        private int foodx,foody;                //食物坐标
        private Random random = new Random();
        private boolean isFail=false;           //游戏结束判定
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.fillRect(25,75,850,600);
            Data.iconFood.paintIcon(this,g,foodx,foody);            //食物绘制
            Data.iconHeader.paintIcon(this,g,25,10);            //头部绘制
            g.setColor(Color.WHITE);
            g.setFont(new Font("微软雅黑",24,20));
            g.drawString("长度"+" "+len,650,31);                     //长度显示
            g.drawString("积分"+" "+score,650,55);                     //积分显示
            this.setBackground(Color.darkGray);                             //面板背景颜色
            g.setColor(Color.BLACK);                                            //画笔颜色
    
                                                                            //头部绘制
            switch (direct){
                case "R":
                    Data.iconRight.paintIcon(this,g,snakex[0],snakey[0]);
                    break;
                case "L":
                    Data.iconLeft.paintIcon(this,g,snakex[0],snakey[0]);
                    break;
                case "U":
                    Data.iconUp.paintIcon(this,g,snakex[0],snakey[0]);
                    break;
                case "D":
                    Data.iconDown.paintIcon(this,g,snakex[0],snakey[0]);
                    break;
                default:
                    Data.iconRight.paintIcon(this,g,snakex[0],snakey[0]);
            }
            for (int i=1;i<len;i++)                                         //身体绘制
            {
                Data.iconBody.paintIcon(this,g,snakex[i],snakey[i]);
            }
            //游戏状态
            if (isFail)
            {
                g.setColor(Color.red);
                g.setFont(new Font("微软雅黑",24,50));                          //设置字体
                g.drawString("游戏失败",300,350);
            }
            else
            {
                if (!isStart)
                {
                    g.setColor(Color.WHITE);
                    g.setFont(new Font("微软雅黑",24,50));                          //设置字体
                    g.drawString("按下空格继续游戏",300,350);
                }
            }
    
        }
    
    
    
        @Override
        public void keyPressed(KeyEvent e) {
                int keycode=e.getKeyCode();
                if (keycode==KeyEvent.VK_SPACE)
                {
                    //判断游戏状态
                    if (isFail)
                    {
                        init();
                        isStart=false;
                        this.repaint();
                    }
                    else
                    {
                        isStart=!isStart;
                        this.repaint();//改变游戏状态
                    }
    
                }
                if (isStart)
                {
                    if (keycode==KeyEvent.VK_UP)
                        direct="U";
                    else if (keycode==KeyEvent.VK_DOWN)
                        direct="D";
                    else if (keycode==KeyEvent.VK_LEFT)
                        direct="L";
                    else if (keycode==KeyEvent.VK_RIGHT)
                        direct="R";
                }
    
            }
    
    
        @Override                                                       //事件监听
        public void actionPerformed(ActionEvent e) {
            //判断小蛇是否吃到食物
            if (snakex[0]==foodx&&snakey[0]==foody)
            {   len++;
                score+=10;
                foodx=25*(random.nextInt(33)+1);
                foody=25*(random.nextInt(23)+3);
            }
            if (!isFail)
            {
                for (int i=1;i<len;i++)
                {
                    if (snakex[0]==snakex[i]&&snakey[0]==snakey[i])
                    {
                        isFail=true;
                        isStart=false;                                      //让游戏停止
                    }
                }
            }
            if (isStart)
            {
                if (direct.equals("R"))
                {
                    for (int i=len-1;i>0;i--)
                    {
                        snakex[i]=snakex[i-1];
                        snakey[i]=snakey[i-1];
                    }
                    snakex[0]+=25;
                    if (snakex[0]>850)
                        snakex[0]=25;
                }if (direct.equals("L"))
                {
                    for (int i=len-1;i>0;i--)
                    {
                        snakex[i]=snakex[i-1];
                        snakey[i]=snakey[i-1];
                    }
                    snakex[0]-=25;
                    if (snakex[0]<25)
                        snakex[0]=850;
                }if (direct.equals("U"))
                {
                    for (int i=len-1;i>0;i--)
                    {
                        snakex[i]=snakex[i-1];
                        snakey[i]=snakey[i-1];
                    }
                    snakey[0]-=25;
                    if (snakey[0]<75)
                        snakey[0]=650;
                }if (direct.equals("D"))
                {
                    for (int i=len-1;i>0;i--)
                    {
                        snakex[i]=snakex[i-1];
                        snakey[i]=snakey[i-1];
                    }
                    snakey[0]+=25;
                    if (snakey[0]>650)
                        snakey[0]=75;
                }
            }
            //每隔一段时间进行窗口重绘
            this.repaint();
        }
        
        //无影响代码
        @Override
        public void keyReleased(KeyEvent e) {
        }
        @Override
        public void keyTyped(KeyEvent e) {
        }
    }
    

难点分析

  1. 小蛇头部朝向和食物显示重叠,只需更改小蛇头部绘制与食物绘制代码的先后顺序即可。

     		 Data.iconFood.paintIcon(this,g,foodx,foody);            //食物绘制
             Data.iconHeader.paintIcon(this,g,25,10);            //头部绘制
    
  2. 键盘监听更改游戏状态

    public void keyPressed(KeyEvent e) {
                int keycode=e.getKeyCode();
                if (keycode==KeyEvent.VK_SPACE)
                {
                    //判断游戏状态
                    if (isFail)
                    {
                        init();
                        isStart=false;
                        this.repaint();
                    }
                    else
                    {
                        isStart=!isStart;
                        this.repaint();//改变游戏状态
                    }
    
                }
                if (isStart)
                {
                    if (keycode==KeyEvent.VK_UP)
                        direct="U";
                    else if (keycode==KeyEvent.VK_DOWN)
                        direct="D";
                    else if (keycode==KeyEvent.VK_LEFT)
                        direct="L";
                    else if (keycode==KeyEvent.VK_RIGHT)
                        direct="R";
                }
    
            }
    

    键盘监听判断按下键位是否是空格,当游戏正在start时,更改游戏状态为暂停状,反之亦然更改为开始态。如果是死亡态,则更改游戏为暂停态并进行游戏初始化。

    repaint方法为重新绘制界面,仅仅为界面信息,并不会初始化游戏信息。

  3. 游戏结束判定

            if (!isFail)
            {
                for (int i=1;i<len;i++)
                {
                    if (snakex[0]==snakex[i]&&snakey[0]==snakey[i])
                    {
                        isFail=true;
                        isStart=false;                                      //让游戏停止
                    }
                }
            }
    

    当小蛇头部与身体部位重合则游戏结束

  4. 小蛇移动,坐标信息更改

    if (isStart)
            {
                if (direct.equals("R"))
                {
                    for (int i=len-1;i>0;i--)
                    {
                        snakex[i]=snakex[i-1];
                        snakey[i]=snakey[i-1];
                    }
                    snakex[0]+=25;
                    if (snakex[0]>850)
                        snakex[0]=25;
                }if (direct.equals("L"))
                {
                    for (int i=len-1;i>0;i--)
                    {
                        snakex[i]=snakex[i-1];
                        snakey[i]=snakey[i-1];
                    }
                    snakex[0]-=25;
                    if (snakex[0]<25)
                        snakex[0]=850;
                }if (direct.equals("U"))
                {
                    for (int i=len-1;i>0;i--)
                    {
                        snakex[i]=snakex[i-1];
                        snakey[i]=snakey[i-1];
                    }
                    snakey[0]-=25;
                    if (snakey[0]<75)
                        snakey[0]=650;
                }if (direct.equals("D"))
                {
                    for (int i=len-1;i>0;i--)
                    {
                        snakex[i]=snakex[i-1];
                        snakey[i]=snakey[i-1];
                    }
                    snakey[0]+=25;
                    if (snakey[0]>650)
                        snakey[0]=75;
                }
            }
    

    该部分主要难点就是,小蛇移动后,小蛇后一个身体部分坐标等于前一个身体,该部分赋值需要有后向前。

  5. 小蛇吃到食物,食物随机坐标显示

    if (snakex[0]==foodx&&snakey[0]==foody)
            {   len++;
                score+=10;
                foodx=25*(random.nextInt(33)+1);
                foody=25*(random.nextInt(23)+3);
            }
    

    当小蛇头部坐标与食物坐标重合即为吃到食物,同时食物更新存储,通过random方法。

  6. 通过定时器制作小蛇移动效果

     private Timer timer = new Timer(100,this);                      //定时器,每隔一定时间执行监听事件,此处是this
    	timer.start();   
    

    创建定时器参数为执行时延和执行事件,需要调用start方法来开启

        {   len++;
            score+=10;
            foodx=25*(random.nextInt(33)+1);
            foody=25*(random.nextInt(23)+3);
        }
    
    
    > 当小蛇头部坐标与食物坐标重合即为吃到食物,同时食物更新存储,通过random方法。
    
    
  7. 通过定时器制作小蛇移动效果

     private Timer timer = new Timer(100,this);                      //定时器,每隔一定时间执行监听事件,此处是this
    	timer.start();   
    

    创建定时器参数为执行时延和执行事件,需要调用start方法来开启

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值