超级简单JAVA实现坦克大战游戏

这个游戏我企图用我仅有的一点的java知识和面对对象的知识来编程,里面不合理的地方请不要介意,如果能留下您宝贵的意见,感激不尽。

文件目录结构


游戏主要分成:
实体类:子弹(Bullet)类、坦克(Tank)类
线程类:子弹移动类(BulletMoveThread)、英雄坦克移动类(TankMoveThread)、敌方坦克自动射击移动类(EnemyTankMoveThread)

效果图

游戏主体

package game;import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;/** 游戏主体* */
public class Game {private JFrame jf = new JFrame("坦克大战");    //创建一个JFrame对象,存放整个窗体JPanel topMenu = new JPanel(); // 头部菜单private int enemyNum; // 敌机数量private Tank[] enemy;// 敌机private EnemyTankMoveThread[] enemyTank; // 敌机的移动线程// 以下变量被我用static修饰,是为了方便我在isGameOver(判断游戏结束)方法中能使用到// 因为静态方法得使用静态变量// isGameOver在Tank类中的reduceLifeVaule(扣除生命值)方法中被调用private static JPanel jp = new JPanel(); // 游戏主体private static int heroLifeNum; // 我方生命private static JLabel heroLifeNumLabel = new JLabel(); // 提示英雄方剩余生命的标签private static JLabel enemyNumLabel = new JLabel(); // 提示敌机数量的标签private static Tank hero; // 英雄机(我方)   private static TankMoveThread heroTank; // 英雄机的移动线程public Game() {// 游戏初始化jf.setLayout(new BorderLayout()); //设置边框布局jf.setBounds(300, 100, 600, 650); //设置窗口大小和位置jf.setVisible(true); // 设置窗体可见,不写看不见jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 头部区域gameHeader();// 游戏区域init();}void gameHeader() {// 游戏头部topMenu.removeAll();JLabel enemyNumTips = new JLabel("敌机数量"); // 提示标签JLabel heroLifeNumTips = new JLabel("我方生命"); // 提示标签JButton resetButton = new JButton("新对局"); // 重置按钮resetButton.addActionListener(new ResetGame());topMenu.add(enemyNumTips);  topMenu.add(enemyNumLabel);topMenu.add(heroLifeNumTips);topMenu.add(heroLifeNumLabel);topMenu.add(resetButton);jf.add(topMenu, BorderLayout.NORTH);}void init() {jp.removeAll(); // 清空游戏主体的内容jp.setLayout(null);// 初始化(顶部栏)数据enemyNum = 10; // 敌人数量heroLifeNum = 3; // 我方生命enemyNumLabel.setText(String.valueOf(enemyNum)); heroLifeNumLabel.setText(String.valueOf(heroLifeNum));// 添加敌机enemy = new Tank[enemyNum]; // 敌机组enemyTank = new EnemyTankMoveThread[enemyNum]; // 敌机线程组for (int i=0;i<enemyNum;i++) {enemy[i] = new Tank(10,10); // 新建敌机enemy[i].setBelongTo("enemy"); // 标识为敌机enemy[i].setBackground(Color.red); // 设置颜色enemyTank[i] = new EnemyTankMoveThread(); // 新建对应线程enemyTank[i].setTank(enemy[i]); // 将坦克传入到线程中enemyTank[i].start(); // 开启线程enemyTank[i].resumeThread(); // 唤醒线程jp.add(enemy[i]); // 添加JPanel容器中}// 设置游戏主题内容hero = new Tank(jf.getSize().width-80,jf.getSize().height-140);hero.setBelongTo("hero"); // 表示为英雄机jp.add(hero);heroTank = new TankMoveThread();heroTank.setTank(hero);heroTank.start();jp.setBackground(Color.black);//设置背景色jp.addKeyListener(new keyCodeListener());jp.enableInputMethods (false); // 切换输入法状态,默认窗口打开时输入法是中文的,导致(子弹)键盘按键不可用jf.add(jp, BorderLayout.CENTER);// (如果没有这句(下面的这句代码),swing默认jframe和jpanel和jlabel是没有焦点的,// swing自动把焦点给了窗体中第一个可以获取焦点的组件,// 因为我把键盘监听事件(上一句)添加到jp,所以jp要获取焦点)jp.requestFocus();  // jp获取焦点,才能执行键盘的监听事件}public static void main(String[] args) {new Game();}public static void isGameOver() {int enemys = 0; // 敌机数量int heros = 0; // 英雄机for (int i = 0; i < jp.getComponentCount(); i++) {Object obj = jp.getComponent(i);if (obj instanceof Tank) {// 先找出坦克if (((Tank)obj).getBelongTo() == "enemy") {// 敌机enemys++;}if (((Tank)obj).getBelongTo() == "hero") {// 英雄机heros++;}}}if (enemys == 0) {// 敌机数量为0,以消灭玩所有的敌机,赢了// 停止英雄机的移动线程Game.hero.setExist(false); // 因为坦克移动线程的终止条件是坦克不存在,所以这里之间设置了坦克不存在。// 提示信息JOptionPane.showMessageDialog(Game.jp, "成功消灭所有敌机,你赢得了战争", "游戏结束", JOptionPane.ERROR_MESSAGE);}if (Game.heroLifeNum == 0) {// 停止敌机的移动线程for (int i = 0; i < jp.getComponentCount(); i++) {Object obj = jp.getComponent(i);if (obj instanceof Tank) {((Tank)obj).setExist(false);}}// 提示信息JOptionPane.showMessageDialog(Game.jp, "噢不,你输掉了战争,失去了一切", "游戏结束", JOptionPane.ERROR_MESSAGE);}if (heros == 0 && Game.heroLifeNum != 0) {// 初始化英雄坦克hero = new Tank(jp.getSize().width-70,jp.getSize().height-70);hero.setBelongTo("hero"); // 表示为英雄机// 初始化英雄坦克的移动线程heroTank = new TankMoveThread();heroTank.setTank(hero);heroTank.start();// 添加到JPanel中jp.add(hero);Game.heroLifeNum--;} // 设置页面上的对应的英雄生命数量Game.heroLifeNumLabel.setText(String.valueOf(Game.heroLifeNum));Game.enemyNumLabel.setText(String.valueOf(enemys));}public void reset() {// 停止敌机和子弹的线程for (int i = 0; i < jp.getComponentCount(); i++) {Object obj = jp.getComponent(i);if (obj instanceof Tank) {((Tank)obj).setExist(false);}if (obj instanceof Bullet) {((Bullet)obj).setExist(false);          }}// 重绘窗体jf.repaint();// 头部区域gameHeader();// 游戏区域init();}class keyCodeListener implements KeyListener{@Overridepublic void keyPressed(KeyEvent e) {// 按键按下未松开// 1号玩家坦克if (e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_RIGHT || e.getKeyCode() == KeyEvent.VK_DOWN) {switch(e.getKeyCode()) {case  KeyEvent.VK_LEFT :heroTank.setDirection("left");break;case  KeyEvent.VK_UP :heroTank.setDirection("up"); break;case  KeyEvent.VK_DOWN :heroTank.setDirection("down"); break;case  KeyEvent.VK_RIGHT : heroTank.setDirection("right"); break;}// 唤醒1号玩家坦克移动线程heroTank.resumeThread();}// 1号玩家射击if (e.getKeyCode() == KeyEvent.VK_NUMPAD1) {// 创建一个子弹线程,并传入一个子弹,字段类所需参数是坦克的方向Bullet bullet = new Bullet("hero",hero.getDirection(),hero.getPositionX(),hero.getPositionY());jp.add(bullet);new BulletMoveThread(bullet).start();}}@Overridepublic void keyReleased(KeyEvent e) {// 按键松开时// 1号玩家坦克if (e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_RIGHT || e.getKeyCode() == KeyEvent.VK_DOWN) {    //停止1号玩家坦克移动线程heroTank.pauseThread();}}@Overridepublic void keyTyped(KeyEvent e) {// 按键输入时}}class ResetGame implements ActionListener{// 重置游戏public void actionPerformed(ActionEvent event){reset();}}
}

坦克类

package game;import javax.swing.JLabel;
import javax.swing.JPanel;import java.awt.Color;
import java.awt.Dimension;
/*坦克类
*/
public class Tank extends JLabel{/*坦克的属性:颜色,运动方向,移动速度,状态(生存、死亡),位置(x,y),阵营(敌机还是英雄)* */private Color tankColor = Color.yellow; // 坦克的颜色private int movingSpeed = 10; // 移动速度private int positionX = 10; // X坐标private int positionY = 10; // Y坐标private String belongTo; // 是英雄(hero)还是敌机(enemy)private String direction = "up"; // 方向,子弹类会需要这个值private int lifeValue = 3;// 生命值private boolean exist = true; // 判断是否存在的标志public Tank(int x, int y) {this.setBackground(tankColor);this.setOpaque(true); // 是否不透明,不设没颜色。。。。//this.setPreferredSize(new Dimension(50, 50)); this.positionX = x;this.positionY = y;this.setBounds(positionX, positionY, 50, 50);this.setText("↑");this.setHorizontalAlignment(JLabel.CENTER);this.setFont(new java.awt.Font("Dialog", 1, 30));}public void setTankColor(Color color) {// 设置背景颜色this.tankColor = color;}public void reduceLifeVaule() {// 扣除生命值this.lifeValue--;if (this.lifeValue == 0) {// 生命值扣完,对应坦克死亡,消除存在this.exist = false;// 从JPanel中删除JPanel jp = (JPanel)this.getParent();for (int i = 0; i < jp.getComponentCount(); i++) {Object obj = jp.getComponent(i);if (obj instanceof Tank && (Tank)obj == this) {jp.remove((Tank)obj);jp.repaint();Game.isGameOver();}}}}public void setName(String name) {this.setText(name);}public void setMovingSpeed(int speed) {// 设置移动速度this.movingSpeed = speed;}public void setPositionX(int x) {// 设置PositionXthis.positionX = x;}public void setPositionY(int y) {// 设置PositionYthis.positionY = y;}public void setExist(boolean exist) {this.exist = exist;}public void setBelongTo(String belongTo) {// 设置阵营this.belongTo = belongTo;}public String getBelongTo() {// 返回return this.belongTo;}public int getPositionX() {// 返回X轴坐标return this.positionX;}public int getPositionY() {// 返回Y轴坐标return this.positionY;}public boolean getExist() {return this.exist;}public void setPosition (String direction) {// direction 方向if (this.exist == false) return;switch(direction) {case "up":this.setText("↑");this.direction = "up";if (this.positionY > this.movingSpeed ) this.positionY -= this.movingSpeed;break;case "right":this.setText("→");this.direction = "right";// 当父容器宽度大于 当前X轴坐标+当前坦克宽度+移动速度时,目的是为了让坦克不碰到窗体边界if(this.getParent().getWidth() > this.positionX+this.getSize().width+this.movingSpeed*2) this.positionX += this.movingSpeed;break;case "down":this.setText("↓");this.direction = "down";if(this.getParent().getHeight() > this.positionY+this.getSize().height+this.movingSpeed*2) this.positionY += this.movingSpeed;break;case "left":this.setText("←");this.direction = "left";if (this.positionX > 10 ) this.positionX -= this.movingSpeed;break;}this.setBounds(positionX, positionY, 50, 50);}public String getDirection() {return this.direction;}public static void main(String[] args) {}
}

子弹类

package game;import java.awt.Color;
import java.awt.Rectangle;import javax.swing.JLabel;
import javax.swing.JPanel;/*子弹类*/
public class Bullet extends JLabel{/*属性:速度, 方向, 大小,状态(消失、出现)方法:* */private Color bulletColor = Color.yellow; // 子弹的颜色private int movingSpeed = 5; // 移动速度private int positionX = 0; // X坐标private int positionY = 0; // Y坐标private String direction; // 移动方向private boolean exist = true; // // 判断是否存在的标志private String belongTo; // 是英雄(hero)的子弹还是敌机(enemy)的子弹public Bullet(String belongTo,String direction, int x, int y) {// 传入三个参数,方向,坦克的XY轴坐标this.setBackground(bulletColor);this.setOpaque(true); // 是否不透明,不设没颜色。。。。this.belongTo = belongTo; // 是英雄的子弹还是敌机的子弹this.positionX = x+20; // 加上20是为了让子弹到坦克的中间this.positionY = y+20;this.setBounds(positionX, positionY, 10, 10);this.direction = direction;}public void setExist(boolean exist) {this.exist = exist;}public void setPosition () {// direction 方向// switch 内部的if判断是为了不让子弹超出边界if (this.exist == false) return;switch(direction) {case "up":if (this.positionY > this.movingSpeed ) this.positionY -= this.movingSpeed; else this.exist = false;break;case "right":if(this.getParent().getParent().getWidth() > this.positionX+this.getSize().width+this.movingSpeed*2) this.positionX += this.movingSpeed;  else this.exist = false;break;case "down":if(this.getParent().getParent().getHeight() > this.positionY+this.getSize().height*5+this.movingSpeed*2) this.positionY += this.movingSpeed;  else this.exist = false;break;case "left":if (this.positionX > 10 ) this.positionX -= this.movingSpeed; else this.exist = false;break;}this.setBounds(positionX, positionY, 10, 10);isRam(); // 判断子弹是否碰撞其他单位,如果撞击会修改exist的值if (!this.exist){/*如果子弹撞到边界或是撞击了其他单位*/clearBullet(); /*执行清除方法*/}}private void isRam() {// 判断子弹是否碰撞其他单位JPanel jp = (JPanel)this.getParent();for (int i = 0; i < jp.getComponentCount(); i++) {if (jp.getComponent(i) != null) {Object obj = jp.getComponent(i);if (obj instanceof Tank && ((Tank) obj).getBelongTo() != this.belongTo) {// 找出所有的坦克并且不是跟子弹的发出阵营相同的坦克Tank tank = (Tank)obj;Rectangle currentBullet = new Rectangle(positionX,positionY,5,5); // x轴坐标,y轴坐标,宽和高,均为int类型Rectangle currentTank = new Rectangle(tank.getPositionX(),tank.getPositionY(),50,50); if (currentBullet.intersects(currentTank)) {// 发生了碰撞,修改子弹的存在状态this.exist = false;// 被撞击的坦克,生命值减1tank.reduceLifeVaule();}}}}}private void clearBullet() {// 找出JPanel中的子弹,如果是当前子弹就将此子弹从JPnael中清除掉JPanel jp = (JPanel)this.getParent();for (int i = 0; i < jp.getComponentCount(); i++) {if (jp.getComponent(i) != null ) {Object obj = jp.getComponent(i);if (obj instanceof Bullet) {// 如果类型是子弹if ((Bullet)obj == this) {// 如果是当前子弹//this.setVisible(false);jp.remove((Bullet)obj); // 移除子弹jp.repaint(); // 重绘JPanel}}}}}public boolean getExist() {// 返回exist值return this.exist;}public static void main(String[] args) {}
}

子弹移动线程类

package game;/** https://www.cnblogs.com/bieyaoxiguan/p/11493590.html 此线程类参考借鉴了这个博客* // 1.创建自己的线程MyThread myThread = new MyThread();// 2.在合适的地方启动线程(你需要在什么地方启动它)myThread.start();// 3.启动后线程的 阻塞/暂停myThread.pauseThread();// 4.以及 阻塞/暂停 线程后的 唤醒/继续myThread.resumeThread();* */
public class BulletMoveThread extends Thread {//-------------------------------------------------------------//无意义private final Object lock = new Object();//标志线程阻塞情况private boolean pause = false;/*** 设置线程是否阻塞*/public void pauseThread() {this.pause = true;}/*** 调用该方法实现恢复线程的运行*/public void resumeThread() {this.pause = false;synchronized (lock) {//唤醒线程lock.notify();}}/*** 这个方法只能在run 方法中实现,不然会阻塞主线程,导致页面无响应*/void onPause() {synchronized (lock) {try {//线程 等待/阻塞lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}
//-------------------------------------------------以上内容不适合修改  private Bullet bullet; // 子弹public BulletMoveThread(Bullet bullet) {// 构造子弹线程时,传入子弹this.bullet = bullet;}@Overridepublic void run() {super.run();//一直循环while (bullet.getExist()) {// 如果子弹已经达到边界,即返回值为false,此线程结束try {//程序每20毫秒执行一次 值可更改Thread.sleep(20);// 子弹移动bullet.setPosition();// 判断子弹是否碰到其他坦克} catch (Exception e) {e.printStackTrace();break;}}}
}

英雄坦克移动线程类

package game;
/** https://www.cnblogs.com/bieyaoxiguan/p/11493590.html* // 1.创建自己的线程MyThread myThread = new MyThread();// 2.在合适的地方启动线程(你需要在什么地方启动它)myThread.start();// 3.启动后线程的 阻塞/暂停myThread.pauseThread();// 4.以及 阻塞/暂停 线程后的 唤醒/继续myThread.resumeThread();* */
public class TankMoveThread extends Thread {//-------------------------------------------------------------//无意义private final Object lock = new Object();//标志线程阻塞情况private boolean pause = false;/*** 设置线程是否阻塞*/public void pauseThread() {this.pause = true;}/*** 调用该方法实现恢复线程的运行*/public void resumeThread() {this.pause = false;synchronized (lock) {//唤醒线程lock.notify();}}/*** 这个方法只能在run 方法中实现,不然会阻塞主线程,导致页面无响应*/void onPause() {synchronized (lock) {try {//线程 等待/阻塞lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}
//-------------------------------------------------以上内容不适合修改  private String direction = ""; // 坦克移动方向private Tank tank; // 坦克public void setDirection(String direction) {// 设置移动方向this.direction = direction;}public void setTank(Tank tank) {// 设置该线程对应的坦克this.tank = tank;}@Overridepublic void run() {super.run();int i = 0;//一直循环while (tank.getExist()) {if (pause || direction == "") {//线程 阻塞/等待onPause();}try {//程序每50毫秒执行一次 值可更改Thread.sleep(50);// 坦克移动tank.setPosition(direction);} catch (Exception e) {e.printStackTrace();break;}}}
}

敌方坦克(自动行走及射击)线程类

package game;import java.util.Random;public class EnemyTankMoveThread extends Thread{//-------------------------------------------------------------//无意义private final Object lock = new Object();//标志线程阻塞情况private boolean pause = false;/*** 设置线程是否阻塞*/public void pauseThread() {this.pause = true;}/*** 调用该方法实现恢复线程的运行*/public void resumeThread() {this.pause = false;synchronized (lock) {//唤醒线程lock.notify();}}/*** 这个方法只能在run 方法中实现,不然会阻塞主线程,导致页面无响应*/void onPause() {synchronized (lock) {try {//线程 等待/阻塞lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}
//-------------------------------------------------以上内容不适合修改  private Tank tank; // 坦克private  Random r = new Random(1); // 随机数private int step = 0; // 坦克移动的步数,到了就换方向private int rate = 0; // 射击频率private String direction; // 移动方向public void setTank(Tank tank) {// 设置该线程对应的坦克this.tank = tank;}@Overridepublic void run() {super.run();//一直循环while (tank.getExist()) {if (pause) {//线程 阻塞/等待onPause();}try {// 敌机坦克射击(射击频率)if (rate == 0) {// 如果射击频率运行到了0,就射击while(rate == 0) {/* 为0就循环,直到不为0*/rate = (int)(Math.random()*20);}Bullet bullet = new Bullet("enemy",tank.getDirection(),tank.getPositionX(),tank.getPositionY());if (tank.getParent()!= null ) {// 在点击新对局(重置)按钮的时候,由于tank.getParent()即JPanel容器未存在//就无法添加子弹到其中,所以加此判断tank.getParent().add(bullet);new BulletMoveThread(bullet).start();}}// 决定何时改变坦克的移动方向Thread.sleep(200);if (step == 0) {// 如果坦克步骤运行到了0,就转向while(step == 0) {// 为0就循环,直到不为0step = (int)(Math.random()*20);}// 随机决定坦克移动的方向int number=(int)(Math.random()*4);switch(number) {case 0:direction = "up";break;case 1:direction = "right";break;case 2:direction = "down";break;case 3:direction = "left";break;} }step--;rate--;tank.setPosition(direction); // 调用坦克的位置移动方法} catch (Exception e) {e.printStackTrace();break;}}}
}

JAVA简单实现坦克对战(只有坦克和子弹)相关推荐

  1. 手把手教你用Java实现一个简易联网坦克对战小游戏

    作者:炭烧生蚝 cnblogs.com/tanshaoshenghao/p/10708586.html 介绍 通过本项目能够更直观地理解应用层和运输层网络协议, 以及继承封装多态的运用. 网络部分是本 ...

  2. Java实现简易联网坦克对战小游戏(内涵源码)//Java+Java游戏+拓展学习+资源分享

    介绍 通过本项目能够更直观地理解应用层和运输层网络协议, 以及继承封装多态的运用. 网络部分是本文叙述的重点, 你将看到如何使用Java建立TCP和UDP连接并交换报文, 你还将看到如何自己定义一个简 ...

  3. java怎么实现网络对战平台_手把手教你用Java实现一个简易联网坦克对战小游戏...

    介绍 通过本项目能够更直观地理解应用层和运输层网络协议, 以及继承封装多态的运用. 网络部分是本文叙述的重点, 你将看到如何使用Java建立TCP和UDP连接并交换报文, 你还将看到如何自己定义一个简 ...

  4. java联机_Java实现简易联网坦克对战小游戏

    介绍 通过本项目能够更直观地理解应用层和运输层网络协议, 以及继承封装多态的运用. 网络部分是本文叙述的重点, 你将看到如何使用Java建立TCP和UDP连接并交换报文, 你还将看到如何自己定义一个简 ...

  5. 如何用java让坦克发射子弹_手把手教你用Java实现一个简易联网坦克对战小游戏 !...

    介绍 通过本项目能够更直观地理解应用层和运输层网络协议, 以及继承封装多态的运用. 网络部分是本文叙述的重点, 你将看到如何使用Java建立TCP和UDP连接并交换报文, 你还将看到如何自己定义一个简 ...

  6. unity实现简单坦克对战

    unity实现简单坦克对战 游戏要求 使用"感知-思考-行为"模型,建模 AI 坦克 场景中要放置一些障碍阻挡对手视线 坦克需要放置一个矩阵包围盒触发器,以保证 AI 坦克能使用射 ...

  7. java实现游戏对战过程_【Java实战】Java实现简易坦克对战小游戏

    //此程序用来实现一个简易的坦克对战小游戏! //Version:1.0 // @Author:Yongchun_zha package cha09; import javax.swing.*; im ...

  8. canvas+js实现简单的双人坦克对战小游戏

    相信有很多人对坦克大战的游戏模仿很有兴趣,在实现经典的坦克大战之前,我先写了个双人的坦克对战,实现了基本的对战功能.下面就开始介绍游戏的编写. 首先创建一个基本的html文件,添加canvas标签以实 ...

  9. 【Java实战】Java实现简易坦克对战小游戏

    摘要:前期学习了Java入门的相关基础,现在通过这个小项目来熟悉巩固所学.该程序主要实现了一个简易的坦克对战小游戏,提供UI界面 //此程序用来实现一个简易的坦克对战小游戏! //Version:1. ...

最新文章

  1. PANS最新脑神经科学研究:激活一种新语言并不费力气
  2. 架设nagios+rrdtool+pnp4nagios监控windows主机
  3. c语言中文件如何插入数据,急求如何将下列C语言程序数据存储到文件中?
  4. 【转】WCF Data Service 使用小结(二) —— 使用WCF Data Service 创建OData服务
  5. linux查询内核参数命令,Linux内核启动参数详解
  6. vlc集成c#_C#WinForm程序调用VLC异常
  7. 开源 serverless 产品原理剖析 - Kubeless 1
  8. 神经网络中的Softmax激活函数
  9. 【C语言】统计素数并求和
  10. 30首唐诗,道尽人生苦乐
  11. CIO如何计算信息化的投资回报率?
  12. 企业微信第三方应用开发小白版
  13. 易车网李斌:一个放牛娃的梦想(转载)
  14. Flutter Navigator路由传参
  15. 文件,图片(C语言)
  16. guzzlehttp resulted in a `409 Conflict` response 访问网址 laravel thinkphp
  17. 颗粒粒径分析方法汇总
  18. 【腾讯位置服务】使用地点云实现企业官网中的门店地图
  19. 微信小程序 企业微信客户服务插件【联系我】自定义样式
  20. 自媒体赚钱系列连载03:音乐人有收益自媒体平台大全

热门文章

  1. Android SDK 完整版
  2. Android系统下 SD卡各文件夹
  3. 成员介绍网页模板html,HTML5 CSS3 SVG团队成员介绍卡片页面模板
  4. ARM7开发板模拟器Skyeye安装设置全攻略
  5. 架构师教大家如何用SpringBoot技术快速实现天气预报系统
  6. 硬件工程师成长之路(9)——检测标准
  7. C# Windows Service入门
  8. 2017,我们所经历的一切
  9. Python处理DICOM(02)--DICOM转PNG
  10. HTML -超文本标记语言