文章目录

  • 一、飞机大战
    • 1.1 封装所有飞行物公共属性和功能的父类
    • 1.2 封装英雄机属性和功能类
    • 1.3 封装敌机属性和功能的类
    • 1.4 封装大飞机属性和功能的类
    • 1.5 子弹类
    • 1.6 飞机大战射击的主方法
    • 1.7 测试结果
    • 1.8 下载地址

一、飞机大战

1.1 封装所有飞行物公共属性和功能的父类

import java.awt.image.BufferedImag/*** 封装所有飞行物的公共属性和功能的父类*/
public abstract class Flyer {protected int x; //飞行物左上角x坐标protected int y; //飞行物左上角y坐标protected int height; //飞行物的高度protected int width; //飞行物的宽度protected BufferedImage image; //飞行物的图片/*** 要求所有飞行物必须都能移动* 但移动的方式由子类自己实现*/public abstract void step();/*** 检查越界的方法* @return 是否越界*/public abstract boolean outOfBounds();/*** 专门检测两个矩形飞行物是否碰撞的工具方法* 和具体对象无关,所以定义为静态方法* @param f1 飞行对象1* @param f2 飞行对象2* @return 是否碰撞*/public static boolean boom(Flyer f1,Flyer f2){//step1: 求出两个矩形的中心点int f1x = f1.x + f1.width/2;int f1y = f1.y + f1.height/2;int f2x = f2.x + f2.width/2;int f2y = f2.y + f2.height/2;//step2: 横向和纵向碰撞检测boolean H = Math.abs(f1x - f2x) < (f1.width + f2.width)/2;boolean V = Math.abs(f1y -f2y) < (f1.height + f2.height)/2;//step3: 必须两个方向同时碰撞return H&V;}}

1.2 封装英雄机属性和功能类

import java.util.Random;/*** 封装英雄机的属性和功能类*/
public class Hero extends Flyer {private int doubleFire; //双倍火力子弹数private int life; //生命值private int score; //得分//对外提供读取生命值的方法public int getLife(){return life;}//对外提供的获取得分的方法public int getScore(){return score;}/*** 英雄机对象的无参构造方法*/public Hero(){image = ShootGame.hero0;height = image.getHeight();width = image.getWidth();x = 127;y = 388;doubleFire = 0;life = 3;score = 0;}/*** 实现英雄机的动画效果的方法* 让英雄机的图片在hero0和hero1之斗切换*/@Overridepublic void step() {Random r = new Random();if(r.nextInt(2) == 0){image = ShootGame.hero0;}else{image = ShootGame.hero1;}}@Overridepublic boolean outOfBounds() {// TODO Auto-generated method stubreturn false;}/*** 英雄机随鼠标移动的方法* 要求传入鼠标当前的位置* @param x 鼠标位置的x坐标* @param y 鼠标位置的y坐标*/public void move(int x,int y){//传入的x,y是鼠标的坐标//move的作用是让英雄机的中心位置和鼠标位置一致this.x = x - width / 2;this.y = y - height / 2;}/*** 英雄机获得分数或奖励的方法* @param f 是一个飞行物父类方法,可以指向敌机或者大飞机*/public void getScore_Award(Flyer f){//先判断敌人对象的类型if(f instanceof Airplane){ //如果敌人是敌机//获得敌机对象中的分数,加到当现分数上score += ((Airplane)f).getScore();}else{ //如果对象是大飞机//继续判断大飞机对象中保存的奖励类型if(((BigPlane)f).getAwardType() == BigPlane.DOUBLE_FIRE){//如果保存的是双倍火力doubleFire += 20;}else{//如果保存的是生命值奖励life += 1;}}}/*** 英雄机发射子弹的方法* @return 新创建出来的子弹对名*          可能是一发,也可能 是两发,用数组保存*/public Bullet[] shoot(){Bullet[] bullets = null;//何时开启双倍火力:if(doubleFire != 0){ //创建双倍火力bullets = new Bullet[2];Bullet b1 = new Bullet(x + width/4 - ShootGame.bullet.getWidth()/2,y + ShootGame.bullet.getWidth());Bullet b2 = new Bullet(x + width*3/4 - ShootGame.bullet.getWidth()/2,y + ShootGame.bullet.getWidth());bullets[0] = b1;bullets[1] = b2;//每创建一个双倍火力,doubleFire-1doubleFire -= 1;}else{//单倍火力://子弹x坐标:x+英雄机宽度/2-子弹宽度/2//子弹y坐标:y-子弹高度bullets = new Bullet[1];bullets[0] = new Bullet(x + width/2 - ShootGame.bullet.getWidth()/2,y - ShootGame.bullet.getHeight());}return bullets;}/*** 英雄机自带和敌人碰撞检测方法* @param f 可能发生碰撞的敌人*          可能是敌机也可能是大飞机* @return 是否碰撞*/public boolean hit(Flyer f){//调用碰撞检测方法,检测是否碰撞boolean r = Flyer.boom(this, f);if(r){ //如果碰撞life--;doubleFire = 0;}return r;}}

1.3 封装敌机属性和功能的类


import java.util.Random;/*** 封装敌机属性和功能的类*/
public class Airplane extends Flyer {private int speed = 2; //敌机每次下落2个单位长度private int score = 5; //敌机包含的奖励分数//对外提供的读取敌机奖励分数的方法public int getScore(){return score;}/*** 敌机类的无参构造方法*/public Airplane(){image = ShootGame.airplane;width = image.getWidth();height = image.getHeight();y = -height;Random r = new Random();x = r.nextInt(ShootGame.WIDTH - width);}@Overridepublic void step() {//敌机每次向下移动一个speed长度y += speed;}@Overridepublic boolean outOfBounds() {//敌机y坐标>游戏界面,越界return y > ShootGame.HEIGHT;}}

1.4 封装大飞机属性和功能的类

import java.util.Random;/*** 封装大飞机属性和功能的类*/
public class BigPlane extends Flyer {/*定义奖励类型的备选项常量*/public static final int DOUBLE_FIRE = 0; //奖励类型是0,说明奖励双倍火力public static final int FILE = 1; //奖励类型是1,说明奖励一次生命/*大飞机类私有成员*/private int xspeed = 1; //水平移动的速度为1private int yspeed = 2; //垂直移动的速度为2private int awardType; //当前大飞机保存的奖励类型//对外提供的读取大飞机奖励类型的方法public int getAwardType(){return awardType;}/*** 大飞机的无参构造方法*/public BigPlane(){//step1: 从主程序中获取大飞机图片的静态变量——bigplaneimage = ShootGame.bigplane;//step2: 使用图片宽高设置对象宽高width = image.getWidth();height= image.getHeight();//step3: 设置大飞机开始下落的高度y = -height;//step4:  大飞机对象开始下落的x坐标在0~(界面宽度 - 大飞机图片宽度)之前随机Random r = new Random();x = r.nextInt(ShootGame.WIDTH - width);//在0和1之间随机先择一种奖励类型awardType = r.nextInt(2);}@Overridepublic void step() {//每次x移动一个xspeed,y移动一个yspeedx += xspeed;y += yspeed;//大飞机不能起出边界,一旦超出那么xspeed*(-1),相当于反向移动if(x < 0 || x > ShootGame.WIDTH - width){xspeed *= -1;}}@Overridepublic boolean outOfBounds() {//大飞机的y坐标>游戏界面,越界return y > ShootGame.HEIGHT;}
}

1.5 子弹类


public class Bullet extends Flyer{private int speed = 5; //子弹上升的速度为3/*** 子弹类的带参构造方法* 因为子弹对象创造的位置要根据英雄机的位置决定* 所以子弹对名的x和y要从外界传入* @param x 英雄机指定子弹创造位置的x坐标* @param y 英雄机指定子弹创造位置的y坐标*/public Bullet(int x,int y){image = ShootGame.bullet;width = image.getWidth();height = image.getHeight();this.x = x;this.y = y;}@Overridepublic void step() {//子弹每次向上移动一个speed长度y -= speed;}@Overridepublic boolean outOfBounds() {//子弹的y坐标+子弹的高度<0,越界return (y + height) < 0;}
}

1.6 飞机大战射击的主方法

import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;public class ShootGame extends JPanel {private static final long serialVersionUID = 1L;//背景图片的大小320*568public static final int WIDTH = 320;public static final int HEIGHT = 568;//游戏界面固定大小336*607public static final int FRAME_WIDTH = 336;public static final int FRAME_HEIGHT = 607;/** 游戏启动第一件事是从硬盘加载所有要用到的图片到内存当中* 而且仅在启动时加载一次——静态块* 缓存在程序中的所有图片,都会反复使用,仅保存一份——静态变量* 下面,为每张图片加载一个静态变量,然后在静态块加加载每张图片*/public static BufferedImage background; //背景图片public static BufferedImage start; //开始图片public static BufferedImage airplane; //敌机图片public static BufferedImage bigplane; //大飞机public static BufferedImage hero0; //英雄机状态0public static BufferedImage hero1; //英雄机状态1public static BufferedImage bullet; //子弹public static BufferedImage pause; //暂停图片public static BufferedImage gameover; //游戏结束//静态块,在类加载到方法区时执行一次,专门加载静态资源static{/** java从硬盘中加载图片到内存中:* ImageIO.read方法:专门从硬盘中加载图片的静态方法* 不用实例化,直接调用* ShootGame.class:获得当前类的加载器所在路径* ShootGame.class.getRerource("文件名"); 从当前类所在路径加载指定文件到程序中*/try {background = ImageIO.read(ShootGame.class.getResource("background.png"));airplane = ImageIO.read(ShootGame.class.getResource("airplane.png"));bigplane = ImageIO.read(ShootGame.class.getResource("bigplane.png"));bullet = ImageIO.read(ShootGame.class.getResource("bullet.png"));start = ImageIO.read(ShootGame.class.getResource("start.png"));pause = ImageIO.read(ShootGame.class.getResource("pause.png"));hero0 = ImageIO.read(ShootGame.class.getResource("hero0.png"));hero1 = ImageIO.read(ShootGame.class.getResource("hero1.png"));gameover = ImageIO.read(ShootGame.class.getResource("gameover.png"));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}/** 为游戏中的角色定义数据结构,包括:* 1个英雄机对象* 1个存储所有敌人(敌机和大飞机)的对象数组* 1个存储所有子弹的对象数组*/public Hero hero = new Hero();public Flyer[] flyers = {}; //存储所有敌人对象的数组public Bullet[] bullets = {}; //存储所有子弹对象的数组//定义游戏状态:当前状态变量:默认为开始状态private int state = START;//定义游戏状态的备选项常量:public static final int START = 0;public static final int RUNNING = 1;public static final int PAUSE = 2;public static final int GAME_OVER = 3;public static void main(String[] args) {/** java中绘制窗体:JFrame对象——窗框* 要想在窗体中绘制内容,还需要嵌入背景面板——JPanel*/JFrame frame = new JFrame("ShootGame");frame.setSize(FRAME_WIDTH,FRAME_HEIGHT);//(336, 607);frame.setAlwaysOnTop(true); //设置窗体置顶//设置窗体关闭同时,退出程序frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setLocationRelativeTo(null); //设置窗体的位置,null表示居中/*在窗体中嵌入背景面板对象——JPanel*/ShootGame game = new ShootGame(); //创建背景面板对象frame.add(game); //将背景面板对象嵌入到窗体对象中/*窗体默认不可见!必须调用setVisible方法才能显示窗体*/frame.setVisible(true); //自动调用窗体的paint方法game.action();}/*** 游戏启动时要做的事*/public void action(){/*游戏开始时,要定义鼠标事件的监听*///step1: 创建MouseAdapter匿名内部类——事件的响应程序MouseAdapter l = new MouseAdapter(){//step2: 重写希望的鼠标事件——鼠标移动@Overridepublic void mouseMoved(MouseEvent e) {//只有在RUNNING状态下英雄机才跟随鼠标移动if(state == RUNNING){//step3: 获得鼠标新位置int x = e.getX();int y = e.getY();//step4: 将鼠标位置传给英雄机的move方法hero.move(x, y);}}@Overridepublic void mouseClicked(MouseEvent e) {if(state == START || state == PAUSE){ //START或者PAUSE状态,单击才会改改为RUNNING状态state = RUNNING;}else if(state == RUNNING){ //游戏点击暂停state = PAUSE;}else if(state == GAME_OVER){ //游戏结束后单击,游戏初始化state = START;//从GAME_OVER到START,要重新初始化游戏数据flyers = new Flyer[0];bullets = new Bullet[0];hero = new Hero();}}@Overridepublic void mouseExited(MouseEvent e) {if(state == RUNNING){//仅在处于RUNNING状态下,鼠标移出才暂停state = PAUSE;}}@Overridepublic void mouseEntered(MouseEvent e) {if(state == PAUSE){state = RUNNING;}}}; //匿名内部类要以分号结尾/*step5: 要响应鼠标事件,必须将鼠标事件添加到程序的监听器中*/this.addMouseMotionListener(l); //支持鼠标的移动事件,不支持鼠标单击事件this.addMouseListener(l);; //支持鼠标单击事件//step1: 创建定时器Timer timer = new Timer();//step2: 调用定时器对象的schedule方法,做计划//       第一个参数:TimerTask类型的匿名内部类//               必须重写run方法——核心——要做什么事timer.schedule(new TimerTask(){//首先定义一个计时器变量index,记录run方法运行的次数private int runTimes = 0;@Overridepublic void run() {//除了repaint方法,其余功能只在RUNNING状态下执行if(state == RUNNING){//每执行一次run方法,runTimes就+1runTimes++;//每500亳秒生成一次敌人if(runTimes % 50 == 0){nextOne(); //自动随机创建敌人对象}//遍历每一个对象,调用对象的step方法,移动一次对象的位置for(int i = 0;i < flyers.length;i++){flyers[i].step();}//每300亳秒生成一次子弹if(runTimes % 30 == 0){shoot(); //创建一次子弹}//遍历子弹数组的每一个对象,移动位置for(int i = 0;i < bullets.length;i++){bullets[i].step();}//英雄机动画效果hero.step();//添加子弹和敌人的碰撞检测boom();//英雄机碰撞检测hit();//添加越界检测outOfBounds();}/*强调:只要界面发生变化,必须调用repaint方法重新绘制界面*/repaint();}}, 10,10); //界面每隔10亳秒变化一次}@Overridepublic void paint(Graphics g) {//step1: 绘制背景图片g.drawImage(background, 0, 0, null);//step2: 绘制英雄机paintHero(g);//step3: 批量绘制敌人数组paintFlyers(g);//step4: 批量绘制子弹数组paintBullets(g);//绘制分数和生命值paintScore_Life(g);//根据游戏状态绘制不同图片if(state == START){g.drawImage(start, 0, 0, null);}else if(state == PAUSE){g.drawImage(pause, 0, 0, null);}else if(state == GAME_OVER){g.drawImage(gameover, 0, 0, null);}}/*** 绘制英雄机对象的方法* @param g 画笔*/public void paintHero(Graphics g){g.drawImage(hero.image, hero.x, hero.y, null);}/*** 遍历敌人数组,批量绘制所有敌人的方法* @param g*/public void paintFlyers(Graphics g){for(int i = 0;i < flyers.length;i++){g.drawImage(flyers[i].image, flyers[i].x, flyers[i].y, null);}}/*** 遍历子弹数组,批量绘制所有子弹的方法* @param g*/public void paintBullets(Graphics g){for(int i = 0;i < bullets.length;i++){g.drawImage(bullets[i].image, bullets[i].x, bullets[i].y, null);}}/*** 随机生成1个敌人对象* 每生成一个新敌人, flyers数组就要扩容1* 然后将新敌人放入数组最后一个元素*/public void nextOne(){Random r = new Random();Flyer f = null;if(r.nextInt(20) == 0){ //只有随机数取0时才创建大飞机f = new BigPlane();}else{ //其余全部生成敌机f = new Airplane();}//对flyers数组扩容1flyers = Arrays.copyOf(flyers, flyers.length + 1);//将新敌人放入数组末尾flyers[flyers.length - 1] = f;}/*** 获得英雄机对象发射的子弹对象* 将新的子弹对象保存到子弹数组中,统一管理*/public void shoot(){Bullet[] newBullets = hero.shoot(); //获得英雄机返回的新子弹数组//根据返回新子弹的数量,扩容子弹数组bullets = Arrays.copyOf(bullets, bullets.length + newBullets.length);//从newBullets数组中拷贝所有元素到bullets数组末尾System.arraycopy(newBullets, 0, bullets, bullets.length - newBullets.length, newBullets.length);}/*** 遍历子弹数组和敌人数组,进行碰撞检测* 一旦发生碰撞,子弹和敌人都减少一个*/public void boom(){for(int i = 0;i < bullets.length;i++){for(int j = 0;j < flyers.length;j++){if(Flyer.boom(bullets[i], flyers[j])){//为英雄机获得分数和奖励hero.getScore_Award(flyers[j]);//从敌人数组中删除被击中的敌机//step1: 使用敌人数组最后一个元素替换被击中的敌机flyers[j] = flyers[flyers.length - 1];//step2: 压缩数组flyers = Arrays.copyOf(flyers, flyers.length - 1);//从子弹数组中删除击中敌机的子弹bullets[i] = bullets[bullets.length - 1];bullets = Arrays.copyOf(bullets, bullets.length -1);i--; //第发现一次碰撞,子弹就要退一个元素,重新检测当前位置break; //只要发现碰撞就退出当前敌人数组的循环}}}}/*** 绘制分数和生命值的方法* @param g*/public void paintScore_Life(Graphics g){int x = 10; //文字在左上角的x坐标int y = 15; //文字在左上角的y坐标Font font = new Font(Font.SANS_SERIF,Font.BOLD,14);g.setFont(font); //设置字体的画笔对象//绘制第一行:分数g.drawString("SCORE: " + hero.getScore(), x, y);//绘制第二行:生命值,y坐标下移20个单位y += 20;g.drawString("LIFE: " + hero.getLife(), x, y);}/*** 检查所有飞行物是否越界*/public void outOfBounds(){//检查所有敌人是否越界Flyer[] Flives = new Flyer[flyers.length];//遍历敌人数组,将存活的敌人对象存到新数组中//设置Flives数组的计数器index: 1.标示下一个存活对象的位置//                        2.统计Flives中一共有多少元素int index = 0;for(int i = 0;i < flyers.length;i++){if(!flyers[i].outOfBounds()){ //没有越界的对象Flives[index] = flyers[i];index++;} //遍历结束后://index是存活对象的个数//Flives数组里是存活的对象,个数为index//把Flives数组压缩为index大小//压缩后的新数组 应替换回flyers数组}flyers = Arrays.copyOf(Flives, index);//检测所有子弹是否越界Bullet[] Blives = new Bullet[bullets.length];index = 0;for(int i = 0;i < bullets.length;i++){if(!bullets[i].outOfBounds()){Blives[index] = bullets[i];index++;}}bullets = Arrays.copyOf(Blives, index);}/*** 遍历敌人数组,判断英雄机和每个敌人是否碰撞*/public void hit(){Flyer[] lives = new Flyer[flyers.length];//记录存活的敌人int index = 0;for(int i = 0;i < flyers.length;i++){if(!hero.hit(flyers[i])){lives[index] = flyers[i];index++;}}if(hero.getLife() <= 0){ //如果英雄机生命值小于等于0,游戏结束state = GAME_OVER;}//压缩敌人数组,并替换数组flyers = Arrays.copyOf(lives, index);}
}

1.7 测试结果

1.8 下载地址

https://download.csdn.net/download/m0_66345324/83175539

【Java开发】Java实现飞机大战相关推荐

  1. 雷电飞机大战游戏|基于Java开发实现雷电飞机大战游戏

    作者主页:编程千纸鹤 作者简介:Java.前端.Pythone开发多年,做过高程,项目经理,架构师 主要内容:Java项目开发.毕业设计开发.面试技术整理.最新技术分享 收藏点赞不迷路  关注作者有好 ...

  2. Java多线程编写简易飞机大战(一)

    ** Java多线程编写简易飞机大战(一) ** 利用多线程编写飞机大战,主要有3个关键: ①继承Thread类,重写run方法: ②线程工作代码在run方法中写: ③启动时,调用线程对象的start ...

  3. 用JAVA制作小游戏——飞机大战(三)

    本篇博客是对飞机大战游戏项目完整代码的展示 详细代码讲解: 用JAVA制作小游戏--飞机大战(一) 用JAVA制作小游戏--飞机大战(二) 最下方附整个程序的文件下载链接 代码展示 主界面 impor ...

  4. 用JAVA制作小游戏——飞机大战(二)

    本篇博客是对飞机大战游戏使用代码的展示 重难点: 首先需要鼠标能够控制战机,使鼠标在窗口内时始终能够使战机的位置与鼠标相同,实现鼠标控制战斗机移动. 其次需要能够以一定的速度产生子弹和敌机,并且以一定 ...

  5. java飞机场模拟程序_java 飞机大战 小游戏源码

    [实例简介] 本项目是一个使用java做的一个飞机大战的小游戏,一个英雄机,初始有三次生命,当打中蜜蜂会有一次生命奖励,当打中敌机会有相应分数奖励,但如果被敌机打中会失去一次生命机会.如果生命都失去, ...

  6. 编程语言用 Java 开发一个打飞机小游戏(附完整源码)

    编程语言用 Java 开发一个打飞机小游戏(附完整源码) 上图 写在前面 技术源于分享,所以今天抽空把自己之前用java做过的小游戏整理贴出来给大家参考学习.java确实不适合写桌面应用,这里只是通过 ...

  7. HTML5游戏开发(四):飞机大战之显示场景和元素

    <HTML5游戏开发>系列文章的目的有:一.以最小的成本去入门egret小项目开发,官方的教程一直都是面向中重型:二.egret可以非常轻量:三.egret相比PIXI.js和sprite ...

  8. Java网课简易飞机大战

    因之前用unity做过飞机大战的小游戏,用的脚本是C#.现在上了几节网课,又用java做的简单功能的小游戏,再次记录一下.功能非常简单.鼠标控制飞机一定,子弹发射,敌机出现以及子弹和敌机的碰撞检测.爆 ...

  9. java 雷霆战机游戏 飞机大战 全过程教学+免费素材(附全部源代码)

    这个游戏已是我第二次编写了,之前写过一个简易版的飞机大战类似demo.这次在上一次基础上添加了许多元素,增添了可玩性. 游戏效果图如下: ps :完整源码+视频教程+论文文档 :java雷霆战机完整资 ...

  10. java小游戏之飞机大战

    飞机大战脚本组成 1.有一个所有物体的父物体GameObject,然后就是一堆物体继承于他,等到他的属性于函数. 2.窗口组件 3.工具脚本(负责做一些杂事和存放图片) 代码 GameObject p ...

最新文章

  1. 字符串创建XML文档
  2. 武汉网络推广优化中网站关键词如何更合理布局分布?
  3. 简约之美Jodd-http--深入源码理解http协议
  4. 【CIO说】转型SaaS,为什么Oracle、SAP的第一选择是人力资源软件
  5. CentOS生成自签名证书配置Apache https
  6. Cortex-M3-建立堆栈
  7. 昨天,我的大学学习[2]
  8. 【编程珠玑】第十一章 排序 (插入排序和快速排序的深度优化)
  9. 如何在面试时搞定 Java 虚拟机?
  10. 前端工程师---软必备
  11. 2022大众点评商家数据
  12. LR11.0 下载及破解
  13. 几种Web服务器比较-(Apache、IIS、Lighttpd、Nginx、LiteSpeed、Zeus
  14. Python还原微信好友已撤回的微信消息
  15. 全国计算机等级考试(NCRE)
  16. html增加语音朗读功能,给wordpress主题添加上语音播放文章内容文本朗读功能
  17. GMap常用属性(方法)简介
  18. 必应壁纸php,PHP 自动保存Bing 每日壁纸
  19. 对接阿里云内容安全服务(机审视频检测)
  20. ALEXA站长全攻略(转)

热门文章

  1. 全网最全的BigDecimal的newScale(保留小数位)和roundingMode(舍入模式),详细介绍roundingMode(重点)
  2. JavaEE颠覆者:spring-boot实战随书源码
  3. html5如何插入图片
  4. 每周值得关注的人工智能头条:Google让我自动做AI,Julia让我学好数学
  5. vue php 前后台分离 模板项目
  6. 解决CentOS7控制台中文显示乱码
  7. Python修改docx文档格式
  8. RGB渐变颜色转换公式及例程
  9. PHPMaker 2019绿色破解版
  10. 华为服务器设置raid0为系统盘,服务器raid0设置