实验二 贪吃蛇游戏开发

目录

一.项目要求

二.项目平台

三.项目实现过程

1.实现键盘控制:

2.游戏画面及内容设置:

3.食物随机产生:

4.触碰墙与身体的判定:

5.移动与身体加长:

6.开始加载音乐

四、项目实现效果

1.运行界面:

2.完整代码


一.项目要求

(1)实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子,    上下左右控制“蛇”的移动,吃到“豆子”以后“蛇”的身体加长一点。

(2)“蛇”碰到边界或蛇头与蛇身相撞,蛇死亡,游戏结束。

(3)为游戏设计友好的交互界面;例如欢迎界面,游戏界面,游戏结束界面。要有开始键、暂停键和停止退出的选项。

(4)对蛇吃到豆子进行分值计算,可以设置游戏速度,游戏音乐    等拓展元素。

二.项目平台

IDEA.Java Swing

三.项目实现过程

1.实现键盘控制:

public void keyPressed(KeyEvent e) {
        // 键盘按下,未释放
        //获取按下的键盘是哪个键
        int keyCode = e.getKeyCode();

        if (keyCode == KeyEvent.VK_SPACE) { //如果按下的是空格键
            if (isDie) {    //失败,游戏再来一遍
                isDie = false;
                init(); //重新初始化游戏
            } else {    //暂停游戏
                isStart = !isStart;
            }
            repaint();  //刷新界面
        }

        //键盘控制走向
        if (keyCode == KeyEvent.VK_LEFT) { //如果按下的是空格键
            fx = "L";
        } else if (keyCode == KeyEvent.VK_RIGHT) { //如果按下的是空格键
            fx = "R";
        } else if (keyCode == KeyEvent.VK_UP) { //如果按下的是空格键
            fx = "U";
        } else if (keyCode == KeyEvent.VK_DOWN) { //如果按下的是空格键
            fx = "D";
        }
    }

2.游戏画面及内容设置:

protected void paintComponent(Graphics g) {
        super.paintComponent(g);    //清屏
        this.setBackground(Color.BLACK);//设置背景的颜色

        //绘制积分框
        Data.header.paintIcon(this, g, 0, 0);

        //绘制游戏区域
        g.fillRect(0, 75, 1000, 625);

  
        //画一条静态的蛇
        if (fx.equals("R")) {
            Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("L")) {
            Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("U")) {
            Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("D")) {
            Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
        }

        //蛇的身体长度通过length来控制
        for (int i = 1; i < length; i++) {
            Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
        }

        //画食物
        Data.food.paintIcon(this, g, foodx, foody);

        //画积分
        g.setColor(Color.white); //设置画笔颜色
        g.setFont(new Font("微软雅黑", Font.BOLD, 18));
        g.drawString("长度:" + length, 750, 35);
        g.drawString("分数:" + score, 750, 55);

        //游戏提示:是否开始
        if (isStart == false) {
            //画一段文字
            g.setColor(Color.white); //设置画笔颜色
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("按下空格开始游戏", 300, 300);
        }

        //失败提醒
        if (isDie) {
            //画一段文字
            g.setColor(Color.red); //设置画笔颜色
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("游戏失败,按下空格重新开始", 200, 300);
        }
    }

3.食物随机产生:

  public void init() {
        length = 3;
        snakeX[0] = 100;
        snakeY[0] = 100; //头部坐标
        snakeX[1] = 75;
        snakeY[1] = 100; //第一个身体坐标
        snakeX[2] = 50;
        snakeY[2] = 100; //第二个身体坐标
        fx = "R";    //默认蛇向右

        foodx = 50 + 25 * random.nextInt(32);
        foody = 125 + 75 * random.nextInt(6);
        
        score = 0;
    }

4.触碰墙与身体的判定:

 public void actionPerformed(ActionEvent e) {
        //如果游戏处于开始状态,并且游戏没有结束
        if (isStart && isDie == false) {
            //右移
            for (int i = length - 1; i > 0; i--) {    //身体移动
                snakeX[i] = snakeX[i - 1];
                snakeY[i] = snakeY[i - 1];
            }
            
            if(fx.equals("R")){
                snakeX[0] = snakeX[0] + 25; //头部移动
                // 边界判断
                if(snakeX[0]>925 ) {isDie=true;}
            }else if(fx.equals("L")){
                snakeX[0] = snakeX[0] - 25; //头部移动
                // 边界判断
                if(snakeX[0]<25){isDie=true;}
            }else if(fx.equals("U")){
                snakeY[0] = snakeY[0] - 25; //头部移动
                // 边界判断
                if(snakeY[0]<100){isDie=true;}
            }else if(fx.equals("D")){
                snakeY[0] = snakeY[0] + 25; //头部移动
                // 边界判断
                if(snakeY[0]>625){isDie=true;}
            }

                //如果小蛇的头和食物坐标重合
            if (snakeX[0] == foodx && snakeY[0] == foody) {
                //长度+1
                length++;
                //重新生成食物
                foodx = 25 + 25 * random.nextInt(32);
                foody = 100 + 75 * random.nextInt(6);
              
                score += 10;
            }

            //如果小蛇的头和小蛇的身体坐标重合,失败,(把小蛇设置为撞到身体不死)
            for(int i=1;i<length;i++){
               if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
                   isDie=true;
               }
            }
           
            //刷新界面
            repaint();
        }
        timer.start();  //让时间动起来
    }

5.移动与身体加长:

if (snakeX[0] == foodx && snakeY[0] == foody) {
                //长度+1
                length++;
                //重新生成食物
                foodx = 25 + 25 * random.nextInt(32);
                foody = 100 + 75 * random.nextInt(6);
               
                //积分+10
                score += 10;
            }

            //如果小蛇的头和小蛇的身体坐标重合,失败,(把小蛇设置为撞到身体不死)
            for(int i=1;i<length;i++){
               if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
                   isDie=true;
               }
            }
            
            //刷新界面
            repaint();
        }

6.开始加载音乐


public class Music extends Thread {
    private String fileName;
    private final int EXTERNAL_BUFFER_SIZE = 524288;

    public Music(String wavFile) {
        this.fileName = wavFile;
    }

    @SuppressWarnings("unused")
    public void run() {
        File soundFile = new File(fileName); // 播放音乐的文件名
        if (!soundFile.exists()) {
            System.err.println("Wave file not found:" + fileName);
            return;
        }
        while (true) { // 设置循环播放
            AudioInputStream audioInputStream = null; // 创建音频输入流对象
            try {
                audioInputStream = AudioSystem.getAudioInputStream(soundFile); // 创建音频对象
            } catch (UnsupportedAudioFileException e1) {
                e1.printStackTrace();
                return;
            } catch (IOException e1) {
                e1.printStackTrace();
                return;
            }
            AudioFormat format = audioInputStream.getFormat(); // 音频格式
            SourceDataLine auline = null; // 源数据线
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
            try {
                auline = (SourceDataLine) AudioSystem.getLine(info);
                auline.open(format);
            } catch (LineUnavailableException e) {
                e.printStackTrace();
                return;
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
            if (auline.isControlSupported(FloatControl.Type.PAN)) {
                FloatControl pan = (FloatControl) auline.getControl(FloatControl.Type.PAN);
            }
            auline.start();
            int nBytesRead = 0;
            byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
            try {
                while (nBytesRead != -1) {
                    nBytesRead = audioInputStream.read(abData, 0, abData.length);
                    if (nBytesRead >= 0)
                        auline.write(abData, 0, nBytesRead);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return;
            } finally {
                auline.drain();
            // auline.close();
            }
        }
    }
}

四、项目实现效果

1.运行界面:

2.完整代码

package com.zsx.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;
import java.util.Random;

public class GamePanel extends JPanel implements KeyListener, ActionListener {

    int length; //蛇的长度
    int[] snakeX = new int[600];    //蛇的坐标X
    int[] snakeY = new int[500];    //蛇的坐标Y
    String fx;  //R:右     	L:左 	U:上 	D:下

    static boolean isStart = false;   //游戏是否开始
    boolean isDie = false;     //判断蛇是否死亡
    Timer timer = new Timer(125, this);//定时器

    //定义食物:
    int foodx;
    int foody;
    Random random = new Random();

    //定义墙体
    //int wallx[]=new int[100];
    //int wally[]=new int[100];

    //积分系统
    int score;

    //这里可设置障碍
    public void map1() {
        //wallx[0]=250+75;wally[0]=475;
        //wallx[1]=250+75;wally[1]=500;
        //wallx[2]=250+75;wally[2]=525;
        //wallx[3]=250+75;wally[3]=550;
        //wallx[4]=250+75;wally[4]=575;
        //wallx[5]=250+100;wally[5]=475;
        //wallx[6]=250+100;wally[6]=575;
        //wallx[7]=250+125;wally[7]=475;
        //wallx[8]=250+125;wally[8]=575;
    }

    //初始化数据
    public void init() {
        length = 3;
        snakeX[0] = 100;
        snakeY[0] = 100; //头部坐标
        snakeX[1] = 75;
        snakeY[1] = 100; //第一个身体坐标
        snakeX[2] = 50;
        snakeY[2] = 100; //第二个身体坐标
        fx = "R";    //默认蛇向右

        foodx = 50 + 25 * random.nextInt(32);
        foody = 125 + 75 * random.nextInt(6);
        // for(int a=0;a<9;a++){
        //  if(foodx==wallx[a]&&foody==wally[a]){
        //    foodx = 100;
        //    foody = 100;
        //    break;
        //    }
        // }
        score = 0;
    }

    //构造器调用初始化数据
    public GamePanel() {
        init();
        //获取键盘的监听事件
        this.setFocusable(true);
        this.addKeyListener(this);
        timer.start();  //让时间动起来
    }

    //画板:画界面,画蛇
    //Graphics:画笔
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);    //清屏
        this.setBackground(Color.BLACK);//设置背景的颜色

        //绘制积分框
        Data.header.paintIcon(this, g, 0, 0);

        //绘制游戏区域
        g.fillRect(0, 75, 1000, 625);

        //调用地图1
        //map1();
        //for(int a=0;a<21;a++){
        //    Data.wall.paintIcon(this, g, wallx[a], wally[a]);
        //}

        //画一条静态的蛇
        if (fx.equals("R")) {
            Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("L")) {
            Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("U")) {
            Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("D")) {
            Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
        }

        //蛇的身体长度通过length来控制
        for (int i = 1; i < length; i++) {
            Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
        }

        //画食物
        Data.food.paintIcon(this, g, foodx, foody);

        //画积分
        g.setColor(Color.white); //设置画笔颜色
        g.setFont(new Font("微软雅黑", Font.BOLD, 18));
        g.drawString("长度:" + length, 750, 35);
        g.drawString("分数:" + score, 750, 55);

        //游戏提示:是否开始
        if (isStart == false) {
            //画一段文字
            g.setColor(Color.white); //设置画笔颜色
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("按下空格开始游戏", 300, 300);
        }

        //失败提醒
        if (isDie) {
            //画一段文字
            g.setColor(Color.red); //设置画笔颜色
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("游戏失败,按下空格重新开始", 200, 300);
        }
    }

    //接受键盘的输入:监听
    @Override
    public void keyPressed(KeyEvent e) {
        // 键盘按下,未释放
        //获取按下的键盘是哪个键
        int keyCode = e.getKeyCode();

        if (keyCode == KeyEvent.VK_SPACE) { //如果按下的是空格键
            if (isDie) {    //失败,游戏再来一遍
                isDie = false;
                init(); //重新初始化游戏
            } else {    //暂停游戏
                isStart = !isStart;
            }
            repaint();  //刷新界面
        }

        //键盘控制走向
        if (keyCode == KeyEvent.VK_LEFT) { //如果按下的是空格键
            fx = "L";
        } else if (keyCode == KeyEvent.VK_RIGHT) { //如果按下的是空格键
            fx = "R";
        } else if (keyCode == KeyEvent.VK_UP) { //如果按下的是空格键
            fx = "U";
        } else if (keyCode == KeyEvent.VK_DOWN) { //如果按下的是空格键
            fx = "D";
        }
    }

    //定时器:监听时间流动;执行定时操作
    @Override
    public void actionPerformed(ActionEvent e) {
        //如果游戏处于开始状态,并且游戏没有结束
        if (isStart && isDie == false) {
            //右移
            for (int i = length - 1; i > 0; i--) {    //身体移动
                snakeX[i] = snakeX[i - 1];
                snakeY[i] = snakeY[i - 1];
            }
            //碰到墙壁
            // for(int i=0;i<9;i++){
            //    if(snakeX[0]==wallx[i]&&snakeY[0]==wally[i]){
            //       isDie=true;
            //  }
            //}
            //通过控制方向让头部移动
            //这里可以控制蛇撞到四周墙壁不死
        /*    if (fx.equals("R")) {
                snakeX[0] = snakeX[0] + 25; //头部移动
                //边界判断
                for (int i = 0; i < snakeX.length; i++) {
                    if (snakeX[i] > 1000) {
                        snakeX[i] = snakeX[0] - 1000;                   //{isDie=true;}
                    }
                }
            } else if (fx.equals("L")) {
                snakeX[0] = snakeX[0] - 25; //头部移动
                //边界判断
                for (int i = 0; i < snakeX.length; i++) {
                    if (snakeX[i] < 0) {
                        snakeX[i] = snakeX[0] + 1000;                   //{isDie=true;}
                    }
                }
                //if(snakeX[0]<25){isDie=true;}
            } else if (fx.equals("U")) {
                snakeY[0] = snakeY[0] - 25; //头部移动
                //边界判断
                for (int i = 0; i < snakeY.length; i++) {
                    if (snakeY[i] < 90) {
                        snakeY[i] = snakeY[0] + 600;                   //{isDie=true;}
                    }
                }
                //if(snakeY[0]<75){isDie=true;}
            } else if (fx.equals("D")) {
                snakeY[0] = snakeY[0] + 25; //头部移动
                //边界判断
                for (int i = 0; i < snakeY.length; i++) {
                    if (snakeY[i] > 600) {
                        snakeY[i] = snakeY[0] - 525;                   //{isDie=true;}
                    }
                }
                //if(snakeY[0]>625){isDie=true;}
            }*/

            if(fx.equals("R")){
                snakeX[0] = snakeX[0] + 25; //头部移动
                // 边界判断
                if(snakeX[0]>925 ) {isDie=true;}
            }else if(fx.equals("L")){
                snakeX[0] = snakeX[0] - 25; //头部移动
                // 边界判断
                if(snakeX[0]<25){isDie=true;}
            }else if(fx.equals("U")){
                snakeY[0] = snakeY[0] - 25; //头部移动
                // 边界判断
                if(snakeY[0]<100){isDie=true;}
            }else if(fx.equals("D")){
                snakeY[0] = snakeY[0] + 25; //头部移动
                // 边界判断
                if(snakeY[0]>625){isDie=true;}
            }

                //如果小蛇的头和食物坐标重合
            if (snakeX[0] == foodx && snakeY[0] == foody) {
                //长度+1
                length++;
                //重新生成食物
                foodx = 25 + 25 * random.nextInt(32);
                foody = 100 + 75 * random.nextInt(6);
                //  for(int a=0;a<9;a++){
                //     if(foodx==wallx[a]&&foody==wally[a]){
                //         foodx = 100;
                //        foody = 100;
                //       break;
                //    }
                //  }
                //积分+10
                score += 10;
            }

            //如果小蛇的头和小蛇的身体坐标重合,失败,(把小蛇设置为撞到身体不死)
            for(int i=1;i<length;i++){
               if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
                   isDie=true;
               }
            }
            /*for(int i=1;i<length;i++){
                if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
                    isDie=true;
                }
            }*/
            //刷新界面
            repaint();
        }
        timer.start();  //让时间动起来
    }

    @Override
    public void keyReleased(KeyEvent arg0) {
        // 释放某个键		不实现
    }

    @Override
    public void keyTyped(KeyEvent arg0) {
        // 键盘按下,弹起		不实现
    }


}
public class Data {

    //头部的图片
    public static URL headerURL = Data.class.getResource("/image/header.png");
    public static ImageIcon header = new ImageIcon(headerURL);

    //蛇的头部:
    public static URL upURL = Data.class.getResource("/image/up.png");
    public static URL downURL = Data.class.getResource("/image/down.png");
    public static URL leftURL = Data.class.getResource("/image/left.png");
    public static URL rightURL = Data.class.getResource("/image/right.png");
    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 URL bodyURL = Data.class.getResource("/image/body.png");
    public static ImageIcon body = new ImageIcon(bodyURL);

    //食物:
    public static URL foodURL = Data.class.getResource("/image/food.png");
    public static ImageIcon food = new ImageIcon(foodURL);

    //墙的图片
    public static URL wallURL = Data.class.getResource("/image/wall.png");
    public static ImageIcon wall = new ImageIcon(wallURL);
}

public class GameJMenuBar extends JMenuBar implements ActionListener {


    public void init() {
        //创建菜单对象
        JMenu menu1 = new JMenu("游戏选项");
        JMenu menu2 = new JMenu("帮助");
        //添加菜单到工具栏对象
        this.add(menu1);
        this.add(menu2);
        //创建菜单项对象
        JMenuItem item1 = new JMenuItem("退出");
        //添加菜单项到菜单对象menu1中
        menu1.add(item1);
        //创建菜单项对象
        JMenuItem item3 = new JMenuItem("操作方法");
        //添加菜单项到菜单对象menu1中
        menu2.add(item3);
        //创建菜单项对象
        JMenuItem item2 = new JMenuItem("注意事项");
        //添加菜单项到菜单对象menu1中
        menu2.add(item2);

        item1.addActionListener(this);// 为菜单项添加事件监听器
        item2.addActionListener(this);// 为菜单项添加事件监听器
        item3.addActionListener(this);// 为菜单项添加事件监听器

    }

    public GameJMenuBar() {
        init();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String cmd = e.getActionCommand();
        if (cmd.equals("退出")) {
            System.exit(0);
        }
        if (cmd.equals("注意事项")) {

            JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
            JLabel Label1 = new JLabel("请注意正确使用");
            JLabel Label2 = new JLabel("游戏结束请按空格重新开始");
            JLabel Label3 = new JLabel("暂停游戏也可以按空格");
            panel.add(Label1);
            panel.add(Label2);
            panel.add(Label3);

            GamePanel.isStart = false;
            JOptionPane.showMessageDialog(this, panel, "注意事项", JOptionPane.PLAIN_MESSAGE);
            repaint();  //刷新界面
        }
        if (cmd.equals("操作方法")) {
            JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
            JLabel Label1 = new JLabel("按下空格可以暂停/开始游戏");
            //JLabel Label2 = new JLabel("目前死亡的唯一方式:暂停,并退出");
            JLabel Label2 = new JLabel("目前死亡的唯一方式:碰到自己的身体");
            JLabel Label3 = new JLabel("按下方向键可以控制蛇的移动");

            panel.add(Label1);
            panel.add(Label2);
            panel.add(Label3);

            GamePanel.isStart = false;
            JOptionPane.showMessageDialog(this, panel, "操作方法", JOptionPane.PLAIN_MESSAGE);
            repaint();  //刷新界面,repaint()方法用来重新绘制图像,图像发生改变时立即显示,paint()方法用来绘制图像,
        }
    }
}
public class Music extends Thread {
    private String fileName;
    private final int EXTERNAL_BUFFER_SIZE = 524288;

    public Music(String wavFile) {
        this.fileName = wavFile;
    }

    @SuppressWarnings("unused")
    public void run() {
        File soundFile = new File(fileName); // 播放音乐的文件名
        if (!soundFile.exists()) {
            System.err.println("Wave file not found:" + fileName);
            return;
        }
        while (true) { // 设置循环播放
            AudioInputStream audioInputStream = null; // 创建音频输入流对象
            try {
                audioInputStream = AudioSystem.getAudioInputStream(soundFile); // 创建音频对象
            } catch (UnsupportedAudioFileException e1) {
                e1.printStackTrace();
                return;
            } catch (IOException e1) {
                e1.printStackTrace();
                return;
            }
            AudioFormat format = audioInputStream.getFormat(); // 音频格式
            SourceDataLine auline = null; // 源数据线
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
            try {
                auline = (SourceDataLine) AudioSystem.getLine(info);
                auline.open(format);
            } catch (LineUnavailableException e) {
                e.printStackTrace();
                return;
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
            if (auline.isControlSupported(FloatControl.Type.PAN)) {
                FloatControl pan = (FloatControl) auline.getControl(FloatControl.Type.PAN);
            }
            auline.start();
            int nBytesRead = 0;
            byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
            try {
                while (nBytesRead != -1) {
                    nBytesRead = audioInputStream.read(abData, 0, abData.length);
                    if (nBytesRead >= 0)
                        auline.write(abData, 0, nBytesRead);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return;
            } finally {
                auline.drain();
            // auline.close();
            }
        }
    }
}
public class StartGame {
    static final int WIDTH = 1000;
    static final int HEIGHT = 750;

    public static void main(String args[]) {
        //1、绘制一个静态窗口 JFrame
        JFrame jf = new JFrame();
        jf.setTitle("王校长吃面包");
        //设置界面大小
        jf.setSize(WIDTH, HEIGHT);
        //窗口大小不可以改变
        jf.setResizable(false);
        Toolkit kit = Toolkit.getDefaultToolkit();
        Dimension screenSize = kit.getScreenSize();
        //获取屏幕的宽度和高度
        int width = screenSize.width;
        int height = screenSize.height;
        int x = (width - WIDTH) / 2;
        int y = (height - HEIGHT) / 2;

        //背景音乐启动
        Music audioPlayWave = new Music("music.wav");// 开音乐 音樂名
        audioPlayWave.start();
        @SuppressWarnings("unused")
        int musicOpenLab = 1;


        jf.setLocation(x, y);
        //设置关闭事件
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //2、面板 JPanel
        jf.add(new GamePanel());

        //3、菜单栏 JMenuBar
        jf.setJMenuBar(new GameJMenuBar());

        jf.setVisible(true);

    }

}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>