当前位置: 首页 > news >正文

Java笔记034-坦克大战【2】

目录

坦克大战【2】

线程-应用到坦克大战

坦克大战0.3

思路分析:

代码实现:

坦克大战0.4

增加功能

特别说明

思路分析:

代码实现:

坦克大战0.5

增加功能

思路分析:

代码实现:


坦克大战【2】

线程-应用到坦克大战

坦克大战0.3

在坦克大战游戏(0.2版)基础上添加如下功能:当玩家按一下j键,就发射一颗子弹

思路分析:

  1. 当发射一颗子弹后,就相当于启动的一个线程
  2. Hero有子弹的对象,当按下J时,就启动一个发射行为(线程),让子弹不停的移动,形成一个射击效果
  3. MyPanel需要不断地重绘,才能出现该效果
  4. 当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)

代码实现:

package com18.tank_game03;/*** @author 甲柒* @version 1.0* @title Shot* @package com18.tank_game03* @time 2023/3/29 21:11* 射击子弹*/
public class Shot implements Runnable {int x;//子弹x坐标int y;//子弹y坐标int direct = 0;//子弹方向int speed = 5;//子弹速度boolean isLive = true;//子弹是否存活//构造器public Shot(int x, int y, int direct) {this.x = x;this.y = y;this.direct = direct;}@Overridepublic void run() {//射击while (true) {//子弹线程休眠50mstry {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}//根据方向改变x,y坐标switch (direct) {case 0://上y -= speed;break;case 1://右x += speed;break;case 2://下y += speed;break;case 3://左x -= speed;break;}//测试,输出子弹的坐标System.out.println("子弹 x=" + x + " y=" + y);//当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750)) {isLive = false;break;}}}
}
package com18.tank_game03;/*** @author 甲柒* @version 1.3* @title Tank* @package com18.tank_game03* @time 2023/3/29 22:27*/
public class Tank {private int x;//坦克的横坐标private int y;//坦克的纵坐标private int direct;//坦克方向 0 上 1 右 2 下 3 左private int speed = 1;public int getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}public Tank(int x, int y) {this.x = x;this.y = y;}//上下移动方法public void moveUp() {y -= speed;}public void moveRight() {x += speed;}public void moveDown() {y += speed;}public void moveLeft() {x -= speed;}public int getDirect() {return direct;}public void setDirect(int direct) {this.direct = direct;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}
}
package com18.tank_game03;import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;/*** @author 甲柒* @version 1.3* @title MyPanel* @package com18.tank_game03* @time 2023/3/29 22:30*/
//为了监听 键盘事件,实现KeyListener
//为了让Panel 不停的重绘子弹,需要将MyPanel实现Runnable,当做一个线程使用
public class MyPanel extends JPanel implements KeyListener, Runnable {//定义我的坦克Hero hero = null;//定义敌人的坦克,放到VectorVector<EnemyTank> enemyTanks = new Vector<>();int enemyTankSize = 3;public MyPanel() {hero = new Hero(100, 100);//初始化自己的坦克//初始化敌人的坦克for (int i = 0; i < enemyTankSize; i++) {//创建一个敌人的坦克EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);//设置方向enemyTank.setDirect(2);//加入enemyTanks.add(enemyTank);}hero.setSpeed(10);}@Overridepublic void paint(Graphics g) {super.paint(g);g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色//画出坦克-封装方法drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 0);//画出hero射击的子弹if (hero.shot != null && hero.shot.isLive == true) {System.out.println("子弹被绘制~~~~~");g.draw3DRect(hero.shot.x, hero.shot.y, 2, 2, false);}//画出敌人的坦克,遍历Vectorfor (int i = 0; i < enemyTanks.size(); i++) {//取出坦克EnemyTank enemyTank = enemyTanks.get(i);drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 1);}}//编写方法,画出坦克/*** @param x      坦克的左上角x坐标* @param y      坦克的左上角y坐标* @param g      画笔* @param direct 坦克方向(上下左右)* @param type   坦克类型*/public void drawTank(int x, int y, Graphics g, int direct, int type) {switch (type) {case 0://自己的坦克g.setColor(Color.cyan);break;case 1://敌人的坦克g.setColor(Color.yellow);break;}//根据坦克的方向,来绘制对应形状坦克//direct表示方向(0:向上 1:向右 2:向下 3:向左)switch (direct) {case 0://表示向上g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克的盖子g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子g.drawLine(x + 20, y + 30, x + 20, y);//画出炮筒break;case 1://表示向右g.fill3DRect(x, y, 60, 10, false);//画出坦克左边轮子g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克的盖子g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子g.drawLine(x + 30, y + 20, x + 60, y + 20);//画出炮筒break;case 2://表示向下g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克的盖子g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子g.drawLine(x + 20, y + 30, x + 20, y + 60);//画出炮筒break;case 3://表示向左g.fill3DRect(x, y, 60, 10, false);//画出坦克左边轮子g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克的盖子g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子g.drawLine(x + 30, y + 20, x, y + 20);//画出炮筒break;default:System.out.println("暂时没有处理");}}@Overridepublic void keyTyped(KeyEvent e) {}//处理ADWS键按下的情况@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyCode() == KeyEvent.VK_W) {//按下W键//改变坦克的方向hero.setDirect(0);//修改坦克坐标 y+=1hero.moveUp();} else if (e.getKeyCode() == KeyEvent.VK_D) {//D键hero.setDirect(1);hero.moveRight();} else if (e.getKeyCode() == KeyEvent.VK_S) {//S键hero.setDirect(2);hero.moveDown();} else if (e.getKeyCode() == KeyEvent.VK_A) {//A键hero.setDirect(3);hero.moveLeft();}//如果用户按下J,就发射if (e.getKeyCode() == KeyEvent.VK_J) {System.out.println("用户按下了J开始射击~~~~");hero.shotEnemyTank();}//重绘this.repaint();}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void run() {//每隔100ms 重绘区域 刷新绘图区域while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}this.repaint();}}
}
package com18.tank_game03;/*** @author 甲柒* @version 1.3* @title Hero* @package com18.tank_game03* @time 2023/3/29 22:29*/
public class Hero extends Tank {//定义一个Shot对象,表示一个射击(线程)Shot shot = null;public Hero(int x, int y) {super(x, y);}//射击public void shotEnemyTank() {//创建Shot对象,根据当前Hero对象的位置和方向来创建Shotswitch (getDirect()) {case 0://向上shot = new Shot(getX() + 20, getY(), 0);break;case 1://向右shot = new Shot(getX() + 60, getY() + 20, 1);break;case 2://向下shot = new Shot(getX() + 20, getY() + 60, 2);break;case 3://向左shot = new Shot(getX(), getY() + 20, 3);break;}//启动Shot线程new Thread(shot).start();}
}
package com18.tank_game03;/*** @author 甲柒* @version 1.3* @title EnemyTank* @package com18.tank_game03* @time 2023/3/29 12:06* 敌人的坦克*/
public class EnemyTank extends Tank {public EnemyTank(int x, int y) {super(x, y);}
}
package com18.tank_game03;import javax.swing.*;/*** @author 甲柒* @version 1.3* @title TankGame03* @package com18.tank_game03* @time 2023/3/29 22:33*/
public class TankGame03 extends JFrame {//定义MyPanelMyPanel mp = null;public TankGame03() {mp = new MyPanel();//将mp 放入到Thread,并启动Thread thread = new Thread(mp);thread.start();this.add(mp);//把面板(就是游戏的绘图区域)this.setSize(1000, 750);this.addKeyListener(mp);//让JFrame监听mp的键盘事件this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);}public static void main(String[] args) {TankGame03 tankGame03 = new TankGame03();}
}

坦克大战0.4

增加功能

  1. 让敌人的坦克也能发射子弹(可以有多颗子弹)
  2. 当我方坦克击中敌人时,敌人的坦克就消失,如果能做出爆炸效果更好
  3. 让敌人的坦克也可以自由随机的上下左右移动
  4. 控制我方坦克和敌方坦克在规定的范围移动

特别说明

  1. 只要能实现就行
  2. 完成上面的任务

思路分析:

让敌人的坦克也能发射子弹(可以有多颗子弹)

  1. 在敌人的坦克类,使用Vector保存多个Shot
  2. 当每创建一个敌人坦克对象,给该敌人坦克对象初始化一个Shot对象,同时启动Shot
  3. 在绘制敌人坦克时,需要遍历敌人坦克对象Vector,绘制所有的子弹,当子弹isLive == false时,就从Vector移除

让敌人的坦克也可以自由随机的上下左右移动

  1. 需要将敌人坦克当成线程使用
  2. 需要EnemyTank implements Runnable
  3. 在run方法中写上相应的业务代码
  4. 在创建敌人坦克对象时,启动线程

代码实现:

package com18.tank_game04;/*** @author 甲柒* @version 1.4* @title Tank* @package com18.tank_game04* @time 2023/3/29 22:27*/
public class Tank {private int x;//坦克的横坐标private int y;//坦克的纵坐标private int direct;//坦克方向 0 上 1 右 2 下 3 左private int speed = 1;public int getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}public Tank(int x, int y) {this.x = x;this.y = y;}//上下移动方法public void moveUp() {y -= speed;}public void moveRight() {x += speed;}public void moveDown() {y += speed;}public void moveLeft() {x -= speed;}public int getDirect() {return direct;}public void setDirect(int direct) {this.direct = direct;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}
}
package com18.tank_game04;import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;/*** @author 甲柒* @version 1.4* @title MyPanel* @package com18.tank_game04* @time 2023/3/29 22:30*/
//为了监听 键盘事件,实现KeyListener
//为了让Panel 不停的重绘子弹,需要将MyPanel实现Runnable,当做一个线程使用
public class MyPanel extends JPanel implements KeyListener, Runnable {//定义我的坦克Hero hero = null;//定义敌人的坦克,放到VectorVector<EnemyTank> enemyTanks = new Vector<>();//定义一个Vector 用于存放炸弹//说明 当子弹击中坦克时,加入一个Bomb对象到bombsVector<Bomb> bombs = new Vector<>();int enemyTankSize = 3;//定义三张炸弹图片,用于显示爆炸效果Image image1 = null;Image image2 = null;Image image3 = null;public MyPanel() {hero = new Hero(100, 100);//初始化自己的坦克//初始化敌人的坦克for (int i = 0; i < enemyTankSize; i++) {//创建一个敌人的坦克EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);//设置方向enemyTank.setDirect(2);//启动敌人坦克进程new Thread(enemyTank).start();//给该enemyTank 加入一颗子弹Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());//加入enemyTank的Vector成员enemyTank.shots.add(shot);//启动shot对象new Thread(shot).start();//加入enemyTanks.add(enemyTank);}//初始化图片对象image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));//设置我方坦克速度hero.setSpeed(10);}//编写方法,判断我方的子弹是否击中敌方的坦克public void hiTank(Shot s, EnemyTank enemyTank) {//判断s击中坦克switch (enemyTank.getDirect()) {case 0://坦克向上case 2://坦克向下if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 40&& s.y > enemyTank.getY() && s.y < enemyTank.getY() + 60) {s.isLive = false;enemyTank.isLive = false;//当我的子弹击中敌人坦克后,将enemyTank 从 Vector 拿掉enemyTanks.remove(enemyTank);//创建Bomb对象,加入到bombs集合Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());bombs.add(bomb);}break;case 1://坦克向右case 3://坦克向左if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 60&& s.y > enemyTank.getY() && s.y < enemyTank.getY() + 40) {s.isLive = false;enemyTank.isLive = false;//创建Bomb对象,加入到bombs集合Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());bombs.add(bomb);}break;}}//编写方法,画出坦克@Overridepublic void paint(Graphics g) {super.paint(g);g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色//画出坦克-封装方法drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 0);//画出hero射击的子弹if (hero.shot != null && hero.shot.isLive == true) {System.out.println("子弹被绘制~~~~~");g.draw3DRect(hero.shot.x, hero.shot.y, 2, 2, false);}//如果bombs 集合中有对象,就画出for (int i = 0; i < bombs.size(); i++) {//取出炸弹Bomb bomb = bombs.get(i);//根据当前这个bomb对象的life值去画出对应的的图片if (bomb.life > 6) {g.drawImage(image1, bomb.x, bomb.y, 60, 60, this);} else if (bomb.life > 3) {g.drawImage(image2, bomb.x, bomb.y, 60, 60, this);} else {g.drawImage(image3, bomb.x, bomb.y, 60, 60, this);}//让这个炸弹的生命值减少bomb.lifeDown();//如果bomb life 为0,就从bombs的集合中删除if (bomb.life == 0) {bombs.remove(bomb);}}//画出敌人的坦克,遍历Vectorfor (int i = 0; i < enemyTanks.size(); i++) {//从 Vector 取出坦克EnemyTank enemyTank = enemyTanks.get(i);if (enemyTank.isLive) {//当敌人坦克是存活的,才画出该坦克drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 1);//画出 enemyTank 所有子弹for (int j = 0; j < enemyTank.shots.size(); j++) {//取出子弹Shot shot = enemyTank.shots.get(j);//绘制if (shot.isLive) {//isLive == trueg.draw3DRect(shot.x, shot.y, 1, 1, false);} else {//从Vector中移除enemyTank.shots.remove(shot);}}}}}/*** @param x      坦克的左上角x坐标* @param y      坦克的左上角y坐标* @param g      画笔* @param direct 坦克方向(上下左右)* @param type   坦克类型*/public void drawTank(int x, int y, Graphics g, int direct, int type) {switch (type) {case 0://自己的坦克g.setColor(Color.cyan);break;case 1://敌人的坦克g.setColor(Color.yellow);break;}//根据坦克的方向,来绘制对应形状坦克//direct表示方向(0:向上 1:向右 2:向下 3:向左)switch (direct) {case 0://表示向上g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克的盖子g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子g.drawLine(x + 20, y + 30, x + 20, y);//画出炮筒break;case 1://表示向右g.fill3DRect(x, y, 60, 10, false);//画出坦克左边轮子g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克的盖子g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子g.drawLine(x + 30, y + 20, x + 60, y + 20);//画出炮筒break;case 2://表示向下g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克的盖子g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子g.drawLine(x + 20, y + 30, x + 20, y + 60);//画出炮筒break;case 3://表示向左g.fill3DRect(x, y, 60, 10, false);//画出坦克左边轮子g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克的盖子g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子g.drawLine(x + 30, y + 20, x, y + 20);//画出炮筒break;default:System.out.println("暂时没有处理");}}@Overridepublic void keyTyped(KeyEvent e) {}//处理ADWS键按下的情况@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyCode() == KeyEvent.VK_W) {//按下W键//改变坦克的方向hero.setDirect(0);//修改坦克坐标 y+=1if (hero.getY() > 0) {hero.moveUp();}} else if (e.getKeyCode() == KeyEvent.VK_D) {//D键hero.setDirect(1);if (hero.getX() + 60 < 1000) {hero.moveRight();}} else if (e.getKeyCode() == KeyEvent.VK_S) {//S键hero.setDirect(2);if (hero.getY() + 60 < 750) {hero.moveDown();}} else if (e.getKeyCode() == KeyEvent.VK_A) {//A键hero.setDirect(3);if (hero.getX() > 0) {hero.moveLeft();}}//如果用户按下J,就发射if (e.getKeyCode() == KeyEvent.VK_J) {System.out.println("用户按下了J开始射击~~~~");hero.shotEnemyTank();}//重绘this.repaint();}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void run() {//每隔100ms 重绘区域 刷新绘图区域while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}//判断是否击中了敌人的坦克if (hero.shot != null && hero.shot.isLive) {//当我的子弹还存活//遍历敌人的所有坦克for (int i = 0; i < enemyTanks.size(); i++) {EnemyTank enemyTank = enemyTanks.get(i);hiTank(hero.shot, enemyTank);}}this.repaint();}}
}
package com18.tank_game04;/*** @author 甲柒* @version 1.4* @title Hero* @package com18.tank_game04* @time 2023/3/29 22:29*/
public class Hero extends Tank {//定义一个Shot对象,表示一个射击(线程)Shot shot = null;public Hero(int x, int y) {super(x, y);}//射击public void shotEnemyTank() {//创建Shot对象,根据当前Hero对象的位置和方向来创建Shotswitch (getDirect()) {case 0://向上shot = new Shot(getX() + 20, getY(), 0);break;case 1://向右shot = new Shot(getX() + 60, getY() + 20, 1);break;case 2://向下shot = new Shot(getX() + 20, getY() + 60, 2);break;case 3://向左shot = new Shot(getX(), getY() + 20, 3);break;}//启动Shot线程new Thread(shot).start();}
}
package com18.tank_game04;/*** @author 甲柒* @version 1.4* @title Shot* @package com18.tank_game04* @time 2023/3/29 21:11* 射击子弹*/
public class Shot implements Runnable {int x;//子弹x坐标int y;//子弹y坐标int direct = 0;//子弹方向int speed = 5;//子弹速度boolean isLive = true;//子弹是否存活//构造器public Shot(int x, int y, int direct) {this.x = x;this.y = y;this.direct = direct;}@Overridepublic void run() {//射击while (true) {//子弹线程休眠50mstry {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}//根据方向改变x,y坐标switch (direct) {case 0://上y -= speed;break;case 1://右x += speed;break;case 2://下y += speed;break;case 3://左x -= speed;break;}//测试,输出子弹的坐标System.out.println("子弹 x=" + x + " y=" + y);//当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)//当子弹碰到敌人坦克时,也应该结束线程if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && isLive)) {isLive = false;break;}}}
}
package com18.tank_game04;import java.util.Vector;/*** @author 甲柒* @version 1.4* @title EnemyTank* @package com18.tank_game04* @time 2023/3/29 12:06* 敌人的坦克*/
public class EnemyTank extends Tank implements Runnable {//在敌人的坦克类,使用Vector保存多个ShotVector<Shot> shots = new Vector<>();boolean isLive = true;public EnemyTank(int x, int y) {super(x, y);}@Overridepublic void run() {while (true) {//根据坦克的方向来继续移动switch (getDirect()) {case 0://向上for (int i = 0; i < 100; i++) {if (getY() > 0) {moveUp();}//让坦克保持一个方向 走30步try {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}}break;case 1://向右for (int i = 0; i < 100; i++) {if (getX() + 60 < 1000) {moveRight();}//让坦克保持一个方向 走30步try {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}}break;case 2://向下for (int i = 0; i < 100; i++) {if (getY() + 60 < 750) {moveDown();}//让坦克保持一个方向 走30步try {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}}break;case 3://向左for (int i = 0; i < 100; i++) {if (getX() > 0) {moveLeft();}//让坦克保持一个方向 走30步try {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}}break;}//休眠50mstry {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}//然后随机地改变坦克方向 0-3setDirect((int) (Math.random() * 4));//注意 写并发程序 一定要考虑清楚 该线程什么时候结束if (!isLive) {break;//退出程序}}}
}
package com18.tank_game04;/*** @author 甲柒* @version 1.0* @title Bomb* @package com18.tank_game04* @time 2023/3/29 22:47* 炸弹*/
public class Bomb {int x, y;//炸弹的坐标int life = 9;//炸弹的生命周期boolean isLive = true;//是否存活public Bomb(int x, int y) {this.x = x;this.y = y;}//减少生命值public void lifeDown() {//配合图片爆炸的效果if (life > 0) {life--;} else {isLive = false;}}
}
package com18.tank_game04;import javax.swing.*;/*** @author 甲柒* @version 1.4* @title TankGame04* @package com18.tank_game04* @time 2023/3/29 22:33*/
public class TankGame04 extends JFrame {//定义MyPanelMyPanel mp = null;public TankGame04() {mp = new MyPanel();//将mp 放入到Thread,并启动Thread thread = new Thread(mp);thread.start();this.add(mp);//把面板(就是游戏的绘图区域)this.setSize(1000, 750);this.addKeyListener(mp);//让JFrame监听mp的键盘事件this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);}public static void main(String[] args) {TankGame04 tankGame04 = new TankGame04();}
}

坦克大战0.5

增加功能

  1. 我方坦克在发射的子弹消亡后,才能发射新的子弹 =》拓展(发射多颗子弹,控制5颗子弹)
  2. 让敌方坦克发射的子弹消亡后,可以再次发射子弹
  3. 当敌方坦克击中我方坦克时,我方坦克消失,并出现爆炸效果

思路分析:

我方坦克在发射的子弹消亡后,才能发射新的子弹 =》拓展(发射多颗子弹,控制5颗子弹)

  1. 在按下J键,判断当前hero对象的子弹,是否已经销毁
  2. 如果没有销毁,就不去触发shotEnemyTank
  3. 如果已经销毁,才去触发shotEnemyTank
  4. 如果要发射多颗子弹,就使用Vector保存
  5. 在绘制我方子弹时,需要遍历该Vector集合

当敌方坦克击中我方坦克时,我方坦克消失,并出现爆炸效果

  1. 编写方法,判断敌方坦克是否击中我方坦克

代码实现:

package com18.tank_game04;/*** @author 甲柒* @version 1.4* @title Tank* @package com18.tank_game04* @time 2023/3/29 22:27*/
public class Tank {boolean isLive = true;private int x;//坦克的横坐标private int y;//坦克的纵坐标private int direct;//坦克方向 0 上 1 右 2 下 3 左private int speed = 1;public Tank(int x, int y) {this.x = x;this.y = y;}public int getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}//上下移动方法public void moveUp() {y -= speed;}public void moveRight() {x += speed;}public void moveDown() {y += speed;}public void moveLeft() {x -= speed;}public int getDirect() {return direct;}public void setDirect(int direct) {this.direct = direct;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}
}
package com18.tank_game04;/*** @author 甲柒* @version 1.4* @title Hero* @package com18.tank_game04* @time 2023/3/29 22:29*/
public class Hero extends Tank {//定义一个Shot对象,表示一个射击(线程)Shot shot = null;//可以发射多颗子弹
//    Vector<Shot> shots = new Vector<>();public Hero(int x, int y) {super(x, y);}//射击public void shotEnemyTank() {//控制只有5颗子弹
//        if (shots.size() == 5) {
//            return;
//        }//创建Shot对象,根据当前Hero对象的位置和方向来创建Shotswitch (getDirect()) {case 0://向上shot = new Shot(getX() + 20, getY(), 0);break;case 1://向右shot = new Shot(getX() + 60, getY() + 20, 1);break;case 2://向下shot = new Shot(getX() + 20, getY() + 60, 2);break;case 3://向左shot = new Shot(getX(), getY() + 20, 3);break;}//把新创建的shot加入到集合shots中
//        shots.add(shot);//启动Shot线程new Thread(shot).start();}
}
package com18.tank_game04;import java.util.Vector;/*** @author 甲柒* @version 1.4* @title EnemyTank* @package com18.tank_game04* @time 2023/3/29 12:06* 敌人的坦克*/
@SuppressWarnings({"all"})
public class EnemyTank extends Tank implements Runnable {//在敌人的坦克类,使用Vector保存多个ShotVector<Shot> shots = new Vector<>();boolean isLive = true;public EnemyTank(int x, int y) {super(x, y);}@Overridepublic void run() {while (true) {//这里判断如果shots size() == 0//创建一颗子弹 放入到shots 集合 并启动if (isLive && shots.size() < 1) {Shot s = null;//判断坦克的方向,创建对应的子弹switch (getDirect()) {case 0://上s = new Shot(getX() + 20, getY(), 0);break;case 1://右s = new Shot(getX() + 60, getY() + 20, 1);break;case 2://下s = new Shot(getX() + 20, getY() + 60, 2);break;case 3://左s = new Shot(getX(), getY() + 20, 3);break;}shots.add(s);//启动new Thread(s).start();}//根据坦克的方向来继续移动switch (getDirect()) {case 0://向上for (int i = 0; i < 50; i++) {if (getY() > 0) {moveUp();}//让坦克保持一个方向 走50步try {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}}break;case 1://向右for (int i = 0; i < 50; i++) {if (getX() + 60 < 1000) {moveRight();}//让坦克保持一个方向 走30步try {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}}break;case 2://向下for (int i = 0; i < 50; i++) {if (getY() + 60 < 750) {moveDown();}//让坦克保持一个方向 走30步try {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}}break;case 3://向左for (int i = 0; i < 50; i++) {if (getX() > 0) {moveLeft();}//让坦克保持一个方向 走30步try {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}}break;}//休眠50mstry {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}//然后随机地改变坦克方向 0-3setDirect((int) (Math.random() * 4));//注意 写并发程序 一定要考虑清楚 该线程什么时候结束if (!isLive) {break;//退出程序}}}
}
package com18.tank_game04;/*** @author 甲柒* @version 1.4* @title Shot* @package com18.tank_game04* @time 2023/3/29 21:11* 射击子弹*/
public class Shot implements Runnable {int x;//子弹x坐标int y;//子弹y坐标int direct = 0;//子弹方向int speed = 5;//子弹速度boolean isLive = true;//子弹是否存活//构造器public Shot(int x, int y, int direct) {this.x = x;this.y = y;this.direct = direct;}@Overridepublic void run() {//射击while (true) {//子弹线程休眠50mstry {Thread.sleep(50);} catch (InterruptedException e) {throw new RuntimeException(e);}//根据方向改变x,y坐标switch (direct) {case 0://上y -= speed;break;case 1://右x += speed;break;case 2://下y += speed;break;case 3://左x -= speed;break;}//测试,输出子弹的坐标System.out.println("子弹 x=" + x + " y=" + y);//当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)//当子弹碰到敌人坦克时,也应该结束线程if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && isLive)) {isLive = false;break;}}}
}
package com18.tank_game04;/*** @author 甲柒* @version 1.0* @title Bomb* @package com18.tank_game04* @time 2023/3/29 22:47* 炸弹*/
public class Bomb {int x, y;//炸弹的坐标int life = 9;//炸弹的生命周期boolean isLive = true;//是否存活public Bomb(int x, int y) {this.x = x;this.y = y;}//减少生命值public void lifeDown() {//配合图片爆炸的效果if (life > 0) {life--;} else {isLive = false;}}
}
package com18.tank_game04;import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;/*** @author 甲柒* @version 1.4* @title MyPanel* @package com18.tank_game04* @time 2023/3/29 22:30*/
//为了监听 键盘事件,实现KeyListener
//为了让Panel 不停的重绘子弹,需要将MyPanel实现Runnable,当做一个线程使用
public class MyPanel extends JPanel implements KeyListener, Runnable {//定义我的坦克Hero hero = null;//定义敌人的坦克,放到VectorVector<EnemyTank> enemyTanks = new Vector<>();//定义一个Vector 用于存放炸弹//说明 当子弹击中坦克时,加入一个Bomb对象到bombsVector<Bomb> bombs = new Vector<>();int enemyTankSize = 3;//定义三张炸弹图片,用于显示爆炸效果Image image1 = null;Image image2 = null;Image image3 = null;public MyPanel() {hero = new Hero(600, 100);//初始化自己的坦克//初始化敌人的坦克for (int i = 0; i < enemyTankSize; i++) {//创建一个敌人的坦克EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);//设置方向enemyTank.setDirect(2);//启动敌人坦克进程new Thread(enemyTank).start();//给该enemyTank 加入一颗子弹Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());//加入enemyTank的Vector成员enemyTank.shots.add(shot);//启动shot对象new Thread(shot).start();//加入enemyTanks.add(enemyTank);}//初始化图片对象image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));//设置我方坦克速度hero.setSpeed(10);}//如果我方坦克可以发射多个子弹//在判断我方子弹是否击中敌方坦克时,就需要把我们的子弹集合中//所有的子弹,都取出和敌人的所有坦克,进行判断public void hitEnemyTank() {
//        //遍历我们的子弹
//        for (int j = 0; j < hero.shots.size(); j++) {
//            Shot shot = hero.shots.get(j);
//            //判断我方子弹是否击中了敌人的坦克
//            if (shot != null && shot.isLive) {//当我的子弹还存活
//
//                //遍历敌人的所有坦克
//                for (int i = 0; i < enemyTanks.size(); i++) {
//                    EnemyTank enemyTank = enemyTanks.get(i);
//                    hiTank(shot, enemyTank);
//                }
//            }
//        }//单颗子弹if (hero.shot != null && hero.shot.isLive) {//当我的子弹还存活//遍历敌人的所有坦克for (int i = 0; i < enemyTanks.size(); i++) {EnemyTank enemyTank = enemyTanks.get(i);hiTank(hero.shot, enemyTank);}}}//编写方法,判断敌方坦克是否击中我方坦克public void hitHero() {//遍历所有敌方坦克for (int i = 0; i < enemyTanks.size(); i++) {//取出敌方坦克EnemyTank enemyTank = enemyTanks.get(i);//遍历enemyTank对象的所有子弹for (int j = 0; j < enemyTank.shots.size(); j++) {//取出子弹Shot shot = enemyTank.shots.get(j);//判断shot是否击中我方坦克if (hero.isLive && shot.isLive) {hiTank(shot, hero);}}}}//编写方法,判断我方的子弹是否击中敌方的坦克public void hiTank(Shot s, Tank enemyTank) {//判断s击中坦克switch (enemyTank.getDirect()) {case 0://坦克向上case 2://坦克向下if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 40&& s.y > enemyTank.getY() && s.y < enemyTank.getY() + 60) {s.isLive = false;enemyTank.isLive = false;//当我的子弹击中敌人坦克后,将enemyTank 从 Vector 拿掉enemyTanks.remove(enemyTank);//创建Bomb对象,加入到bombs集合Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());bombs.add(bomb);}break;case 1://坦克向右case 3://坦克向左if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 60&& s.y > enemyTank.getY() && s.y < enemyTank.getY() + 40) {s.isLive = false;enemyTank.isLive = false;//创建Bomb对象,加入到bombs集合Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());bombs.add(bomb);}break;}}//编写方法,画出坦克@Overridepublic void paint(Graphics g) {super.paint(g);g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色if (hero != null && hero.isLive) {//画出坦克-封装方法drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 0);}//画出hero射击的子弹,单颗子弹if (hero.shot != null && hero.shot.isLive == true) {System.out.println("子弹被绘制~~~~~");g.draw3DRect(hero.shot.x, hero.shot.y, 2, 2, false);}//多颗子弹//将hero的子弹集合shots,遍历取出绘制
//        for (int i = 0; i < hero.shots.size(); i++) {
//            Shot shot = hero.shots.get(i);
//            if (shot != null && shot.isLive) {
//                System.out.println("子弹被绘制~~~~~");
//                g.draw3DRect(shot.x, shot.y, 2, 2, false);
//            } else {//如果该shot对象已经无效,就从shots集合中拿掉
//                hero.shots.remove(shot);
//            }
//        }//如果bombs 集合中有对象,就画出for (int i = 0; i < bombs.size(); i++) {//取出炸弹Bomb bomb = bombs.get(i);//根据当前这个bomb对象的life值去画出对应的的图片if (bomb.life > 6) {g.drawImage(image1, bomb.x, bomb.y, 60, 60, this);} else if (bomb.life > 3) {g.drawImage(image2, bomb.x, bomb.y, 60, 60, this);} else {g.drawImage(image3, bomb.x, bomb.y, 60, 60, this);}//让这个炸弹的生命值减少bomb.lifeDown();//如果bomb life 为0,就从bombs的集合中删除if (bomb.life == 0) {bombs.remove(bomb);}}//画出敌人的坦克,遍历Vectorfor (int i = 0; i < enemyTanks.size(); i++) {//从 Vector 取出坦克EnemyTank enemyTank = enemyTanks.get(i);if (enemyTank.isLive) {//当敌人坦克是存活的,才画出该坦克drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 1);//画出 enemyTank 所有子弹for (int j = 0; j < enemyTank.shots.size(); j++) {//取出子弹Shot shot = enemyTank.shots.get(j);//绘制if (shot.isLive) {//isLive == trueg.draw3DRect(shot.x, shot.y, 1, 1, false);} else {//从Vector中移除enemyTank.shots.remove(shot);}}}}}/*** @param x      坦克的左上角x坐标* @param y      坦克的左上角y坐标* @param g      画笔* @param direct 坦克方向(上下左右)* @param type   坦克类型*/public void drawTank(int x, int y, Graphics g, int direct, int type) {switch (type) {case 0://自己的坦克g.setColor(Color.cyan);break;case 1://敌人的坦克g.setColor(Color.yellow);break;}//根据坦克的方向,来绘制对应形状坦克//direct表示方向(0:向上 1:向右 2:向下 3:向左)switch (direct) {case 0://表示向上g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克的盖子g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子g.drawLine(x + 20, y + 30, x + 20, y);//画出炮筒break;case 1://表示向右g.fill3DRect(x, y, 60, 10, false);//画出坦克左边轮子g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克的盖子g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子g.drawLine(x + 30, y + 20, x + 60, y + 20);//画出炮筒break;case 2://表示向下g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克的盖子g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子g.drawLine(x + 20, y + 30, x + 20, y + 60);//画出炮筒break;case 3://表示向左g.fill3DRect(x, y, 60, 10, false);//画出坦克左边轮子g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克右边轮子g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克的盖子g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子g.drawLine(x + 30, y + 20, x, y + 20);//画出炮筒break;default:System.out.println("暂时没有处理");}}@Overridepublic void keyTyped(KeyEvent e) {}//处理ADWS键按下的情况@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyCode() == KeyEvent.VK_W) {//按下W键//改变坦克的方向hero.setDirect(0);//修改坦克坐标 y+=1if (hero.getY() > 0) {hero.moveUp();}} else if (e.getKeyCode() == KeyEvent.VK_D) {//D键hero.setDirect(1);if (hero.getX() + 60 < 1000) {hero.moveRight();}} else if (e.getKeyCode() == KeyEvent.VK_S) {//S键hero.setDirect(2);if (hero.getY() + 60 < 750) {hero.moveDown();}} else if (e.getKeyCode() == KeyEvent.VK_A) {//A键hero.setDirect(3);if (hero.getX() > 0) {hero.moveLeft();}}//如果用户按下J,就发射if (e.getKeyCode() == KeyEvent.VK_J) {System.out.println("用户按下了J开始射击~~~~");//判断hero的子弹是否销毁,发射一颗子弹if (hero.shot == null || !hero.shot.isLive) {hero.shotEnemyTank();}//发射多颗子弹
//            hero.shotEnemyTank();}//重绘this.repaint();}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void run() {//每隔100ms 重绘区域 刷新绘图区域while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}//判断敌我方坦克是否击中敌方坦克hitEnemyTank();//判断敌方坦克是否击中了我方坦克hitHero();this.repaint();}}
}
package com18.tank_game04;import javax.swing.*;/*** @author 甲柒* @version 1.4* @title TankGame04* @package com18.tank_game04* @time 2023/3/29 22:33*/
public class TankGame04 extends JFrame {//定义MyPanelMyPanel mp = null;public TankGame04() {mp = new MyPanel();//将mp 放入到Thread,并启动Thread thread = new Thread(mp);thread.start();this.add(mp);//把面板(就是游戏的绘图区域)this.setSize(1200, 950);this.addKeyListener(mp);//让JFrame监听mp的键盘事件this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);}public static void main(String[] args) {TankGame04 tankGame04 = new TankGame04();}
}

相关文章:

Java笔记034-坦克大战【2】

目录 坦克大战【2】 线程-应用到坦克大战 坦克大战0.3 思路分析&#xff1a; 代码实现&#xff1a; 坦克大战0.4 增加功能 特别说明 思路分析&#xff1a; 代码实现&#xff1a; 坦克大战0.5 增加功能 思路分析&#xff1a; 代码实现&#xff1a; 坦克大战【2】 …...

【算法】【数组与矩阵模块】桶排序思想解决无序数组排序后相邻数间的最大差值

目录前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本思考感悟写在最后前言 当前所有算法都使用测试用例运行过&#xff0c;但是不保证100%的测试用例&#xff0c;如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识&#xff01; 问题介绍 …...

C语言—函数

函数库函数自定义函数函数的参数函数的调用函数的嵌套调用和链式访问函数的声明和定义函数递归递归与迭代函数递归的经典题目维基百科&#xff08;台湾方面维护的&#xff0c;翻译形式跟大陆有所差异&#xff09;中对函数的定义&#xff1a;子程序在计算机科学中&#xff0c;子…...

Autosar模式管理实战系列03-基于Davinci工具的WDGM配置

本文框架 前言1.WdgMConfigSet 配置2. 新建监控实体(SE)2.1 新建检测点(Checkpoint)2.2 设置 WdgMInternalTransitions3. WdgMLocalStatusParams配置4. WdgMAliveSupervision配置5. 代码插入指导前言 前面我们介绍了WdgM(看门狗管理)是一个 AutoSAR 的基础模块,负责管理看门…...

AutoML-sklearn and torch

一、auto-sklearn 1.1 环境依赖 额外安装swig 第三方库 linux 支持, mac&#xff0c;windows不支持 1.2 示例代码 time_left_for_this_task 设定任务最大时间 per_run_time_limit 每个子任务最大训练时间 include 可以限制任务训练的模型 import autosklearn.classific…...

《扬帆优配》算力概念股大爆发,主力资金大扫货

3月22日&#xff0c;9股封单金额超亿元&#xff0c;工业富联、鸿博股份、鹏鼎控股分别为3.01亿元、2.78亿元、2.37亿元。 今日三大指数团体收涨&#xff0c;收盘共34股涨停&#xff0c;首要集中于数字经济方向&#xff0c;其间云核算、CPO大迸发。除去5只ST股&#xff0c;算计2…...

机械臂+底盘三维模型从solidworks到moveit配置功能包

文章目录 导出底盘STEP加载机械臂模型组合机械臂和底盘三维模型导出URDF在moveit中进行配置新建工作目录设置ROS工作空间的环境变量进入moveit setup加载URDF文件self-CollisionsPlanning groupsRobot posesControllersSimulationAuthor information生成配置包在rviz中进行可视…...

高并发系统设计:缓存、降级、限流、(熔断)

高并发系统设计&#xff1a;缓存、降级、限流、(熔断) 在开发高并发系统时有三把利器用来保护系统&#xff1a;缓存、降级和限流。 非核心服务可以采用降级、熔断&#xff0c;核心服务采用缓存和限流&#xff08;隔离流量可以最大限度的保障业务无损&#xff09;。 缓存 缓…...

《辉煌优配》放量大涨,A股成交额重回万亿!PCB板块继续领跑

多只绩优PCB概念股超跌。 今日A股放量反弹&#xff0c;成交额从头站上万亿关口。芯片板块掀涨停潮&#xff0c;景嘉微、芯原股份20cm涨停&#xff0c;紫光国微、兆易创新、跃岭股份等封板&#xff1b;AI算力、存储器、光模块、云核算等板块全线拉升&#xff0c;板块内个股再度批…...

Vue封装的过度与动画

动画效果 先把样式封装好&#xff0c;然后设置一个动画 不需要vue也能实现的动画的效果&#xff0c;我们只需要判断一下&#xff0c;然后动态的添加和删除类名即可 那能不能不自己写动态&#xff0c;就靠vue 首先我们要靠<transition>标签把需要动画的包裹起来 vue中…...

流量监控-ntopng

目录介绍安装使用介绍 ntopng是原始ntop的下一代版本&#xff0c;ntop是监视网络使用情况的网络流量探测器。ntopng基于libpcap&#xff0c;并且以可移植的方式编写&#xff0c;以便实际上可以在每个Unix平台&#xff0c;MacOSX和Windows上运行。 ntopng&#xff08;是的&…...

C++ 21 set容器

目录 一、set容器 1.1 简介 1.2 构造和赋值 1.3 大小和交换 1.4 插入和删除 1.5 查找和统计 1.6 set和multiset区别 1.7 内置类型指定排序规则 1.8 自定义数据类型指定排序规则 一、set容器 1.1 简介 ① set容器中所有元素在插入时自动被排序。 ② set容器和multise…...

什么是JWT

JSON Web Token&#xff08;缩写 JWT&#xff09;是目前最流行的跨域认证解决方案。 传统的session认证 http协议本身是一种无状态的协议&#xff0c;而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证&#xff0c;那么下一次请求时&#xff0c;用户还要再一…...

Gradle7.4安装

前置&#xff1a;本文基于IntelliJ IDEA 2022.2.1 、jdk1.8进行安装 目录 1.挑选Gradle版本 2.系统变量设置 1.挑选Gradle版本 gradle兼容性差&#xff0c; 1.跟idea会有版本问题。 2.跟springboot也有兼容问题Spring Boot Gradle Plugin Reference Guide 首先查询版本&…...

【华为OD机试 2023最新 】 箱子之字形摆放(C++ 100%)

文章目录 题目描述输入描述输出描述备注用例题目解析C++题目描述 有一批箱子(形式为字符串,设为str), 要求将这批箱子按从上到下以之字形的顺序摆放在宽度为 n 的空地,请输出箱子的摆放位置。 例如:箱子ABCDEFG,空地宽度为3,摆放结果如图: 则输出结果为: AFG BE CD …...

Matplotlib库入门

Matplotlib库的介绍 什么是Matplotlib库&#xff1f; Matplotlib是一个Python的数据可视化库&#xff0c;用于绘制各种类型的图表&#xff0c;包括线图、散点图、条形图、等高线图、3D图等等。它是一个非常强大和灵活的库&#xff0c;被广泛用于数据科学、机器学习、工程学、…...

学生党用什么蓝牙耳机比较好?300内高性价比蓝牙耳机排行

随着蓝牙技术的发展&#xff0c;蓝牙耳机越来越普及&#xff0c;不同价位、不同性能的蓝牙耳机数不胜数。那么&#xff0c;学生党用什么蓝牙耳机比较好&#xff1f;下面&#xff0c;我来给大家推荐几款三百内高性价比蓝牙耳机&#xff0c;一起来看看吧。 一、南卡小音舱蓝牙耳…...

Lambda 表达式与函数式接口

函数式接口 如果一个接口&#xff0c;只有一个抽象方法&#xff0c;该接口即为函数式接口。函数式接口&#xff0c;即可使用 Lambda 表达式。 如下面的接口 public interface Translate {void translate();}目前该接口的抽象方法为无参数无返回值 Lambda 表达式 无参无返回值…...

后端代码规范

1、报文入参尽量避免使用实体类&#xff08;如果用实体类接受参数&#xff0c;一定要写好注解&#xff0c;具体用到了实体类的哪一个属性&#xff09; /*** * Description: 新增玉米观测记录主表信息* param param params* param return 参数* return Result 返回类型* author…...

web自动化测试:Selenium+Python基础方法封装(建议收藏)

01、目的 web自动化测试作为软件自动化测试领域中绕不过去的一个“香饽饽”&#xff0c;通常都会作为广大测试从业者的首选学习对象&#xff0c;相较于C/S架构的自动化来说&#xff0c;B/S有着其无法忽视的诸多优势&#xff0c;从行业发展趋、研发模式特点、测试工具支持&…...

while实现1到100相加求和-课后程序(JavaScript前端开发案例教程-黑马程序员编著-第2章-课后作业)

【案例2-7】while实现1到100相加求和 一、案例描述 考核知识点 while循环语句 练习目标 掌握while循环语句。 需求分析 1-100之间的数相加求和&#xff0c;本案例通过while循环语句来实现。 案例分析 效果如图2-10所示。1-100所有数的和 具体实现步骤如下&#xff1a; 在&l…...

Thingsboard(2.4 postgresql版)数据库表结构说明

本文描述的表结构是根据thingsboard2.4&#xff08;postgresql版&#xff09;数据库中整理出来的&#xff0c;不一定完整&#xff0c;后续有新的发现再补充文档。 一、数据库E-R关系 Thingsboard2.4社区版共22个表&#xff0c;主要包括实体信息表、关系信息表、字典表和系统配…...

IDS反病毒与APT的具体介绍

文章目录一&#xff0c;IDS1. 什么是IDS&#xff1f;2. IDS和防火墙有什么不同&#xff1f;3. IDS工作原理&#xff1f;4. IDS的主要检测方法有哪些详细说明&#xff1f;5. IDS的部署方式有哪些&#xff1f;6. IDS的签名是什么意思&#xff1f;签名过滤器有什么作用&#xff1f…...

while do..while验证用户名和密码-课后程序(JavaScript前端开发案例教程-黑马程序员编著-第2章-课后作业)

【案例2-8】while do..while验证用户名和密码 一、案例描述 考核知识点 while、do…while循环语句 练习目标 掌握while语句。do…while循环语句。 需求分析 在网站上登录时会用到表单&#xff0c;让用户属于用户名和密码&#xff0c;输入正确才可以进入&#xff0c;本案例将…...

tmux常用操作指令

创建会话tmux new -s 会话名 恢复会话tmux at -t 会话名 tmux attach -t 会话名 杀死会话tmux kill-session -t 编号 tmux kill-session -t 会话名 查询会话tmux ls tmux list-session 划分窗格划分上下两个窗格&#xff1a; tmux split-window 划分左右两个窗格&#xff1a;…...

【Linux】线程安全

线程安全&#xff1a;在多线程运行的时候&#xff0c;不论线程的调度顺序怎样&#xff0c;最终的结果都是 一样的、正确的&#xff0c;这个线程就是安全的。 保证线程安全的要求&#xff1a; 1. 对线程同步&#xff0c;保证同一时刻只有一个线程访问临界资源。 2.在多线程中使用…...

Redis-mysql 缓存实战

本文基于Springboot&#xff0c;mybatis plus&#xff0c;mysql&#xff0c;redis&#xff0c; Jedis模拟redis缓存实现 目录 1. 添加所需maven依赖 2. 设置数据库及数据表 3. 构建实体类 4. 构建工具类实现 redis 数据库连接池&#xff0c;redis 的读取&#xff0c;写入功…...

蓝桥杯:通电

蓝桥杯&#xff1a; 通电https://www.lanqiao.cn/problems/162/learning/ 目录 题目描述 输入描述 输出描述 输入输出样例 输入 输出 题目分析(最小生成树)&#xff1a; AC代码(Java) 题目描述 2015 年&#xff0c;全中国实现了户户通电。作为一名电力建设者&#xff0…...

一文搞懂 Kubernetes 的 Limits 和 Requests

当在Kubernetes中使用容器时&#xff0c;重要的是要知道所涉及的资源是什么以及如何需要它们。有些进程比其他进程需要更多的CPU或内存。有些是关键的&#xff0c;不应该被饿死。知道了这一点&#xff0c;我们应该正确配置我们的容器和Pod&#xff0c;以获得两者的最佳效果。在…...

【C++】手撕红黑树

文章目录前言一、红黑树的概念二、红黑树的节点结构三、红黑树的插入四、红黑树的调整1、叔叔存在且为红2、叔叔不存在或存在且为黑3、插入完整代码4、总结五、红黑树的验证六、红黑树的删除七、红黑树与 AVL 树的比较八、红黑树的代码实现前言 在网络上流传着这样一张图片&am…...