從零開發Java坦克大戰:架構設計與難點突破 (下)

  • 6. 游戲引擎類:

    • 6.1 完整源碼展示:?

    • import javax.swing.*;
      import java.awt.*;
      import java.awt.event.KeyEvent;
      import java.awt.event.KeyListener;
      import java.util.ArrayList;
      import java.util.HashSet;
      import java.util.Random;
      import java.util.Set;public class GamePanel extends JPanel implements KeyListener {//GamePanel類是游戲的核心控制器,負責管理游戲循環、輸入處理和游戲狀態更新。private TankA tankA;private TankB tankB;private final Set<Integer> pressedKeys = new HashSet<>();private final Timer gameTimer;private final Random ran = new Random();private final BattleMaps map;private final scorePanel sPanel;private final ArrayList<Bullet> bullets = new ArrayList<>();private boolean gameOver = false;private String winner = "";public GamePanel() {map = new BattleMaps();sPanel = new scorePanel();// 生成坦克A的合法位置tankA = generatePositionA(45, 35);tankB = generatePositionB(45, 35);// 生成坦克B的合法位置(且不與A重疊)// 初始化游戲定時器(每16ms≈60FPS)//使用游戲循環(Timer)來定期處理按鍵狀態,更新坦克位置。gameTimer = new Timer(7, e -> {processInput();// 處理輸入updateGame();// 更新游戲狀態SwingUtilities.invokeLater(this::repaint);// 請求重繪});gameTimer.start();setFocusable(true);addKeyListener(this);}private TankA generatePositionA(int width, int height) {Random ran = new Random();Rectangle tempRect;int x, y;do {x = 120 + ran.nextInt(900);y = 60 + ran.nextInt(750);tempRect = new Rectangle(x, y, width, height);} while (map.isCollidingWithWall(tempRect)); // 確保不生成在墻上return new TankA(x, y); // 或 TankB}private TankB generatePositionB(int width, int height) {Random ran = new Random();Rectangle tempRect;int x, y;do {x = 120 + ran.nextInt(900);y = 60 + ran.nextInt(750);tempRect = new Rectangle(x, y, width, height);} while (map.isCollidingWithWall(tempRect)); // 確保不生成在墻上return new TankB(x, y); // 或 TankB}private void processInput() {// 游戲結束時忽略所有輸入if (gameOver) return;// 處理坦克A// 每次循環先重置速度tankA.setSpeedX(0);tankA.setSpeedY(0);// 根據當前按下的鍵設置速度if (pressedKeys.contains(KeyEvent.VK_A)) {tankA.setDirection(0);tankA.setSpeedX(-4);}if (pressedKeys.contains(KeyEvent.VK_D)) {tankA.setDirection(2);tankA.setSpeedX(4);}if (pressedKeys.contains(KeyEvent.VK_W)) {tankA.setDirection(1);tankA.setSpeedY(-4);}if (pressedKeys.contains(KeyEvent.VK_S)) {tankA.setDirection(3);tankA.setSpeedY(4);}// 處理坦克BtankB.setSpeedX(0);tankB.setSpeedY(0);if (pressedKeys.contains(KeyEvent.VK_LEFT)) {tankB.setDirection(0);tankB.setSpeedX(-4);}if (pressedKeys.contains(KeyEvent.VK_RIGHT)) {tankB.setDirection(2);tankB.setSpeedX(4);}if (pressedKeys.contains(KeyEvent.VK_UP)) {tankB.setDirection(1);tankB.setSpeedY(-4);}if (pressedKeys.contains(KeyEvent.VK_DOWN)) {tankB.setDirection(3);tankB.setSpeedY(4);}}private void updateGame() {if (gameOver) {return;}handleTankMovement(tankA);handleTankMovement(tankB);//更新子彈位置for (Bullet bullet : new ArrayList<>(bullets)) {bullet.move();//檢測子彈與墻壁的碰撞if (map.isCollidingWithWall(bullet.getBounds())) {bullet.setActive(false);}//檢測子彈與坦克碰撞if (bullet.isActive()) {if (bullet.isFormTankA() && bullet.getBounds().intersects(tankB.getBounds())) {gameOver = true;winner = "-TankA-";bullet.setActive(false);showGameOver();} else if (!bullet.isFormTankA() && bullet.getBounds().intersects(tankA.getBounds())) {gameOver = true;winner = "-TankB-";bullet.setActive(false);showGameOver();}}}bullets.removeIf(bullet -> !bullet.isActive());//移除不活躍的子彈}private void handleTankMovement(MoveObjects tank) {//保存移動前的位置int oldX = tank.getX();int oldY = tank.getY();//移動坦克tank.move();// 獲取移動后的碰撞區域Rectangle newBounds = tank.getBounds();//檢測是否會與墻體/敵方坦克發生碰撞if (map.isCollidingWithWall(newBounds)) {//碰撞后回退位置并重置速度tank.setX(oldX);tank.setY(oldY);tank.setSpeedX(0);tank.setSpeedY(0);} else if (tankA.getBounds().intersects(tankB.getBounds())) {tank.setX(oldX);tank.setY(oldY);tank.setSpeedX(0);tank.setSpeedY(0);}}private void showGameOver() {pressedKeys.clear();// 在顯示對話框前清除按鍵狀態SwingUtilities.invokeLater(() -> {int option = JOptionPane.showConfirmDialog(this, "  " + winner + "   Wins!!!\n WANT PLAY AGAIN?", "--Game Over--", JOptionPane.YES_NO_OPTION);if (option == JOptionPane.YES_OPTION) {resetGame();} else {System.exit(0);}});}private void resetGame() {// 重置游戲前再次確保清除按鍵狀態pressedKeys.clear();tankA = generatePositionA(45, 35);tankB = generatePositionB(45, 35);bullets.clear();winner = "";gameOver = false;requestFocusInWindow();}@Overrideprotected void paintComponent(Graphics g) {//自動啟用Swing雙緩沖,避免閃爍super.paintComponent(g);// 清空背景,清除前一幀畫面 確保每次繪制都是全新的畫面,避免畫面殘留//底層原理:默認會使用組件的背景色填充整個區域Graphics2D g2d = (Graphics2D) g.create();//創建圖形上下文副本map.paintMap(g2d);tankA.drawTankA(g2d);tankB.drawTankB(g2d);//繪制所有子彈for (Bullet bullet : bullets) {bullet.draw(g2d);}sPanel.drawTankPicture(g2d);g2d.dispose();//保證圖形狀態隔離}private Bullet createBullet(MoveObjects tank, boolean fromTankA) {int tankHeadX;int tankHeadY;if (tank.getDirection() == 0 || tank.getDirection() == 2) {tankHeadX = tank.getX() + (tank.getWidth() / 2);tankHeadY = tank.getY() + (tank.getHeight() / 2) - 2;} else {tankHeadX = tank.getX() + (tank.getHeight() / 2) - 2;tankHeadY = tank.getY() + (tank.getWidth() / 2);}return new Bullet(tankHeadX, tankHeadY, tank.getDirection(), fromTankA);}@Overridepublic void keyPressed(KeyEvent e) {pressedKeys.add(e.getKeyCode());//添加子彈發射功能if (e.getKeyCode() == KeyEvent.VK_Q) {bullets.add(createBullet(tankA, true));} else if (e.getKeyCode() == KeyEvent.VK_SLASH) {bullets.add(createBullet(tankB, false));}}@Overridepublic void keyReleased(KeyEvent e) {if (gameOver) {pressedKeys.clear();// 在顯示對話框前清除按鍵狀態} else {pressedKeys.remove(e.getKeyCode());}// 處理平滑停止(可選)processInput();}@Overridepublic void keyTyped(KeyEvent e) {}
      }
      /*注意:(1)Swing的繪圖應該在事件分派線程(EDT)中進行,使用多線程可能導致不可預測的行為。因此,應該將所有繪圖邏輯放在一個主循環中,使用Swing的Timer來定期觸發重繪,而不是在獨立的線程中使用while循環和Thread.sleep(2)KeyListener的keyPressed事件機制設計為單次觸發模式,無法跟蹤組合按鍵狀態
      當同時按下多個鍵時,操作系統會快速交替觸發多個keyPressed事件,但無法保持持續狀態(3)Swing使用被動繪制機制,應重寫paintComponent()方法getGraphics()獲取的是臨
      時圖形上下文,無法持久化
      */
    • 6.2 思路與架構

      • 6.2.1 類的設計思路

        • 由于GamePanel類承載著我們整個游戲流程控制的核心方法, 核心可移動的物體(對象)部署以及游戲狀態的實時檢測與控制, 這決定了本類需要繼承JPanel父類并且實現KeyListener監聽器, 同時需要傳入整個游戲項目中的核心對象作為私有參數;?簡潔起見我們盡可能將游戲循環封裝在類的無參構造器中便于主類在實例化對象時直接啟動.
      • 6.2.2 核心屬性梳理

        • 為了便于本類的眾方法對對象的操作, 我們盡可能將所需的對象設置為全局變量, 將需要和GamePanel同時創建出來的對象于無參構造器中進行初始化
        • private TankA tankA;private TankB tankB;private final Set<Integer> pressedKeys = new HashSet<>();private final Timer gameTimer;private final Random ran = new Random();private final BattleMaps map;private final scorePanel sPanel;private final ArrayList<Bullet> bullets = new ArrayList<>();private boolean gameOver = false;private String winner = "";public GamePanel() {map = new BattleMaps();sPanel = new scorePanel();// 生成坦克A的合法位置tankA = generatePositionA(45, 35);tankB = generatePositionB(45, 35);// 生成坦克B的合法位置(且不與A重疊)// 初始化游戲定時器(每16ms≈60FPS)//使用游戲循環(Timer)來定期處理按鍵狀態,更新坦克位置。gameTimer = new Timer(7, e -> {processInput();// 處理輸入updateGame();// 更新游戲狀態SwingUtilities.invokeLater(this::repaint);// 請求重繪});gameTimer.start();setFocusable(true);addKeyListener(this);}

    • 6.3?核心方法梳理與分析

      • a. 坦克A/B坐標的初始化

        • 創建一個隨機器, 在地圖的左上角到右下角的有效空間內隨機生成坦克的x, y坐標, 利用BattleMap類中的: isCollidingWithWall()方法循環判斷是否生成在了合法位置, 最終返回一個新的坦克對象(x,y)
        • private TankA generatePositionA(int width, int height) {Random ran = new Random();Rectangle tempRect;int x, y;do {x = 120 + ran.nextInt(900);y = 60 + ran.nextInt(750);tempRect = new Rectangle(x, y, width, height);} while (map.isCollidingWithWall(tempRect)); // 確保不生成在墻上return new TankA(x, y); // 或 TankB}
      • b. 處理鍵盤對坦克的操作

        • 首先判斷游戲的狀態是否結束, 每次循環處理輸入時先將坦克的速度置零, 根據當前按下的鍵設置坦克的方向與速度(A/B同理)
        • private void processInput() {// 游戲結束時忽略所有輸入if (gameOver) return;// 處理坦克A// 每次循環先重置速度tankA.setSpeedX(0);tankA.setSpeedY(0);// 根據當前按下的鍵設置速度if (pressedKeys.contains(KeyEvent.VK_A)) {tankA.setDirection(0);tankA.setSpeedX(-4);}if (pressedKeys.contains(KeyEvent.VK_D)) {tankA.setDirection(2);tankA.setSpeedX(4);}if (pressedKeys.contains(KeyEvent.VK_W)) {tankA.setDirection(1);tankA.setSpeedY(-4);}if (pressedKeys.contains(KeyEvent.VK_S)) {tankA.setDirection(3);tankA.setSpeedY(4);}
      • c. 重寫鍵盤監聽器方法(點按, 按下, 松開)

        • 我們在設置全局變量時將pressedKey設置為了HashSet類型, 這就代表著我們不允許兩個鍵盤指令被加入到Set中, 保證了對坦克操作的特定性.
        • 1. 按下:? ?每當按下鍵盤時獲取指令并傳入Set中, 如果是子彈發射鍵則創建新的子彈對象并傳入bullets的ArrayList中進行繪制.
        • 2. 松開:? 每當松開當前按下的鍵時, 如果游戲結束直接清除Set中所有的鍵盤指令, 如果沒有則調用remove()方法移除當前指令.
        • 3. 點按:? 無需此操作.
        • @Overridepublic void keyPressed(KeyEvent e) {pressedKeys.add(e.getKeyCode());//添加子彈發射功能if (e.getKeyCode() == KeyEvent.VK_Q) {bullets.add(createBullet(tankA, true));} else if (e.getKeyCode() == KeyEvent.VK_SLASH) {bullets.add(createBullet(tankB, false));}}@Overridepublic void keyReleased(KeyEvent e) {if (gameOver) {pressedKeys.clear();// 在顯示對話框前清除按鍵狀態} else {pressedKeys.remove(e.getKeyCode());}// 處理平滑停止(可選)processInput();}@Overridepublic void keyTyped(KeyEvent e) {}

      • d. 控制坦克移動

        • 以我們的MoveObject類作為作為參數, 便于坦克狀態的集中控制, 移動前我們先獲取坦克的當前位置便于給碰撞方法傳遞參數, 之后調用移動坦克方法并獲取移動后坦克矩形的外邊界, 將邊界傳入碰撞檢測方法檢測坦克是否與墻或者另一坦克發生碰撞, 如果是則將坐標設為剛才獲取的位置并將速度置零.
        • private void handleTankMovement(MoveObjects tank) {//保存移動前的位置int oldX = tank.getX();int oldY = tank.getY();//移動坦克tank.move();// 獲取移動后的碰撞區域Rectangle newBounds = tank.getBounds();//檢測是否會與墻體/敵方坦克發生碰撞if (map.isCollidingWithWall(newBounds)) {//碰撞后回退位置并重置速度tank.setX(oldX);tank.setY(oldY);tank.setSpeedX(0);tank.setSpeedY(0);} else if (tankA.getBounds().intersects(tankB.getBounds())) {tank.setX(oldX);tank.setY(oldY);tank.setSpeedX(0);tank.setSpeedY(0);}}
      • e. 創建子彈

        • ?首先確定返回值類型為Bullet類 , 設置參數為MoveObject對象與子彈來源;? 通過簡單計算確定子彈創建的位置與坦克當前的位置的偏差, 最終返回新的子彈對象
        • private Bullet createBullet(MoveObjects tank, boolean fromTankA) {int tankHeadX;int tankHeadY;if (tank.getDirection() == 0 || tank.getDirection() == 2) {tankHeadX = tank.getX() + (tank.getWidth() / 2);tankHeadY = tank.getY() + (tank.getHeight() / 2) - 2;} else {tankHeadX = tank.getX() + (tank.getHeight() / 2) - 2;tankHeadY = tank.getY() + (tank.getWidth() / 2);}return new Bullet(tankHeadX, tankHeadY, tank.getDirection(), fromTankA);}
      • f. 組件可視化方法(游戲畫面的核心)

        • 直接先看代碼我慢慢解釋
        •  @Overrideprotected void paintComponent(Graphics g) {//自動啟用Swing雙緩沖,避免閃爍super.paintComponent(g);// 清空背景,清除前一幀畫面 確保每次繪制都是全新的畫面,避免畫面殘留//底層原理:默認會使用組件的背景色填充整個區域Graphics2D g2d = (Graphics2D) g.create();//創建圖形上下文副本map.paintMap(g2d);tankA.drawTankA(g2d);tankB.drawTankB(g2d);//繪制所有子彈for (Bullet bullet : bullets) {bullet.draw(g2d);}sPanel.drawTankPicture(g2d);g2d.dispose();//保證圖形狀態隔離}
        • paintComponent?是 Swing 組件繪制的核心方法,負責組件的可視化呈現。以下是簡明扼要的解釋:
        • 1. 基本概念
          • 作用: 自定義組件的繪制邏輯
          • 繼承關系:?JComponent.paint()?→?paintComponent()
          • 典型實現:
          • @Override
            protected void paintComponent(Graphics g) {super.paintComponent(g); // 1. 清空背景// 2. 自定義繪制代碼
            }
        • 2. 觸發調用:
        • 3. 關鍵應用:?
          • super.paintComponent(g); // 清屏Graphics2D g2d = (Graphics2D)g;map.paintMap(g2d);      // 1. 繪制地圖(底層)tankA.draw(g2d);        // 2. 繪制坦克(中層) bullets.forEach(b->b.draw(g2d)); // 3. 繪制子彈(上層)
      • g. 刷新游戲

        • 刷新的東西無非就是子彈和坦克:
        • 首先判斷游戲是否結束, 如沒有則首先控制當前坦克的動作;?其次遍歷List更新子彈位置, 移動子彈, 獲取子彈的矩形邊界 判斷子彈是否與墻壁發生碰撞 如碰則直接設置為毀滅; 之后分別判斷子彈邊界與坦克A,B是否重合, 根據情況設置游戲狀態,贏家, 展示游戲結束畫面
        • private void updateGame() {if (gameOver) {return;}handleTankMovement(tankA);handleTankMovement(tankB);//更新子彈位置for (Bullet bullet : new ArrayList<>(bullets)) {bullet.move();//檢測子彈與墻壁的碰撞if (map.isCollidingWithWall(bullet.getBounds())) {bullet.setActive(false);}//檢測子彈與坦克碰撞if (bullet.isActive()) {if (bullet.isFormTankA() && bullet.getBounds().intersects(tankB.getBounds())) {gameOver = true;winner = "-TankA-";bullet.setActive(false);showGameOver();} else if (!bullet.isFormTankA() && bullet.getBounds().intersects(tankA.getBounds())) {gameOver = true;winner = "-TankB-";bullet.setActive(false);showGameOver();}}}bullets.removeIf(bullet -> !bullet.isActive());//移除不活躍的子彈}
      • h. 重置游戲

        • 關鍵難點:? pressedKeys.clear();
        • 在游戲結束時(A坦克被擊中時), 如果玩家A仍然按著 "W" 鍵, 隨著游戲進程結束這個元素不會被remove()掉, 因此在游戲重新開始時為了防止某個坦克不受控制的向某個方向移動, 應清空Set內所有的鍵盤指令
        •  private void resetGame() {// 重置游戲前再次確保清除按鍵狀態pressedKeys.clear();tankA = generatePositionA(45, 35);tankB = generatePositionB(45, 35);bullets.clear();winner = "";gameOver = false;requestFocusInWindow();}
      • i.? 游戲結束選擇盤

        • 應用: SwingUtilities.invokeLater 來啟動EDT事件調度, 防止展示結束界面進入游戲主線程

        • private void showGameOver() {pressedKeys.clear();// 在顯示對話框前清除按鍵狀態SwingUtilities.invokeLater(() -> {int option = JOptionPane.showConfirmDialog(this, "  " + winner + "   Wins!!!\n WANT PLAY AGAIN?", "--Game Over--", JOptionPane.YES_NO_OPTION);if (option == JOptionPane.YES_OPTION) {resetGame();} else {System.exit(0);}});}
  • 7. 裝飾界面

    • 邏輯類似于坦克圖片的繪制: 獨立于GamePanel便于后續增加有趣的功能
    •  private final ImageIcon[] imgPic = new ImageIcon[2];public void drawTankPicture(Graphics2D g2d) {imgPic[0] = new ImageIcon("D:\\桌面\\Xing\\Photos\\TankB.png");imgPic[1] = new ImageIcon("D:\\桌面\\Xing\\Photos\\TankA.png");g2d.drawImage(imgPic[0].getImage(), 230, 830, 100, 60, null);g2d.drawImage(imgPic[1].getImage(), 830, 830, 100, 60, null);}

  • 8. Summary

  • 我的坦克大戰基于本地Java Swing框架, 通過gameTimer定時刷新界面實現了游戲的流暢運行,在本地實現雙人對戰非常刺激與流暢, 雖然并非契合主流游戲開發的流程與現有標準框架, 但是實現了一個教學級的坦克大戰游戲開發全流程, 非常適合新手熟悉Java的Swing框架 和 面向對象中類的設計與關聯的基本思維, 是一個有趣而簡單的實戰項目
    • 核心點再析:

    • JFrame:游戲的主窗口容器,負責處理操作系統級事件(關閉、最小化等)

    • GamePanel:繼承自JPanel的自定義組件,作為游戲繪制表面(Surface)

    • 雙緩沖機制:Swing默認啟用雙緩沖,通過RepaintManager管理后臺緩沖區

    • 繪制觸發repaint()調用會觸發Swing的異步重繪請求,最終由事件派發線程(EDT)執行paintComponent

    • 事件分發線程(EDT):所有輸入事件由Swing的EDT統一派發

  • DeepSeek對我的項目進行了理性的評估,內容如下

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/90445.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90445.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90445.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Git下載與安裝全攻略

引言 Git是當今最流行的分布式版本控制系統&#xff0c;由Linus Torvalds于2005年創建。它幫助開發者高效管理代碼變更&#xff0c;支持多人協作開發&#xff0c;是現代軟件開發不可或缺的工具。無論是個人項目還是團隊協作&#xff0c;Git都能提供強大的版本控制功能。 本文…

【Elasticsearch】快照生命周期管理 SLM(理論篇)

《Elasticsearch 集群》系列&#xff0c;共包含以下文章&#xff1a; 1?? 冷熱集群架構2?? 合適的鍋炒合適的菜&#xff1a;性能與成本平衡原理公式解析3?? ILM&#xff08;Index Lifecycle Management&#xff09;策略詳解4?? Elasticsearch 跨機房部署5?? 快照與恢…

深入理解 UDP 協議:從原理到實戰的技術解析

UDP&#xff08;User Datagram Protocol&#xff0c;用戶數據報協議&#xff09;作為 TCP 的 "輕量型伙伴"&#xff0c;在實時通信、流媒體傳輸等場景中發揮著不可替代的作用。與 TCP 的可靠傳輸不同&#xff0c;UDP 以 "簡單、快速、無連接" 為設計理念&a…

c語言-數據結構-沿順相同樹解決對稱二叉樹問題的兩種思路

二叉樹OJ前言對稱二叉樹前言 本篇繼續講解二叉樹OJ題目之對稱二叉樹 對稱二叉樹 題目鏈接&#xff1a;https://leetcode.cn/problems/symmetric-tree/description/ 該題要求比較這棵樹是否對稱&#xff0c;對稱&#xff0c;指的是結構對稱并且值也要對稱&#xff0c;即對應…

云原生可觀測-日志觀測(Loki)最佳實踐

一、Loki 簡介 云原生可觀測三大支柱 支柱工具用途MetricsPrometheus性能趨勢、系統負載LogsLoki原始事件記錄、錯誤診斷TracesTempo / Jaeger分布式鏈路追蹤 一、Loki 簡介 1.1 Loki 是什么 Loki 是由 Grafana Labs 開發的 日志聚合系統&#xff0c;與 Prometheus 架構一…

Windows Server 2003 R2系統C盤擴容教程

一、PAGreen軟件下載 下載地址&#xff1a; ExtPart.zip https://pan.baidu.com/s/1FxK61XNI0t-4JIEWK1QA8Q?pwd8888 提取碼: 8888 二、將軟件解壓縮 (1)、執行步驟一下載的程序 雙擊下圖所示可執行程序 (2)、選擇好解壓路徑&#xff0c;點擊「Unzip」進行解壓縮 (3)、磁…

Kubernetes配置管理

目錄什么是ConfigMap創建ConfigMap1&#xff1a;基于目錄創建ConfigMap1.創建conf目錄&#xff0c;放置文件2.基于目錄下的所有文件創建ConfigMap3.查看當前創建的ConfigMap2&#xff1a;基于文件創建ConfigMap1.單個文件創建ConfigMap2.使用帶有key的命令創建ConfigMap3.多個文…

golang怎么實現每秒100萬個請求(QPS),相關系統架構設計詳解

一.需求 使用Golang,以Gin框架為基礎,設計一個能夠處理每秒100萬請求(QPS 1M)的系統架構 注意:100萬QPS是一個很高的數字,單機通常難以處理,所以必須采用分布式架構,并且需要多層次的架構設計和優化 二.搭建步驟 1.系統架構設計 為了實現高并發,需要考慮以下幾個方面…

HCIA再復習

第一章.網絡基礎1.1 網絡類型分類網絡按照二層鏈路類型分為以下四種&#xff1a;多點接入網絡&#xff08;MA&#xff09;&#xff1a;1&#xff0c;廣播型多點接入&#xff08;BMA&#xff09;&#xff1a;如以太網&#xff0c;支持廣播&#xff0c;設備通過MAC地址通信&#…

Qt 數據庫連接池實現與管理

在 Qt 應用程序中&#xff0c;頻繁創建和銷毀數據庫連接會帶來顯著的性能開銷。數據庫連接池通過復用現有連接&#xff0c;避免重復創建和銷毀連接的開銷&#xff0c;從而提高應用程序的響應速度和吞吐量。本文將詳細介紹 Qt 中數據庫連接池的實現與管理方法。 一、數據庫連接池…

數據采集分析:從信息洪流中掘金的科學與藝術

——如何將原始數據轉化為商業決策的黃金&#xff1f;&#x1f310; 引言&#xff1a;我們正淹沒在數據的海洋&#xff0c;卻渴求著知識的甘泉每天全球產生 2.5萬億字節 數據&#xff08;相當于每秒下載4.5萬部高清電影&#xff09;&#xff0c;但未經分析的數據如同未提煉的原…

Oracle國產化替代:一線DBA的技術決策突圍戰

從“如履薄冰”到“游刃有余”,中國數據庫的自主之路正重塑技術人的思維地圖。 “凌晨三點的最后一次數據校驗通過,割接系統綠燈全亮——**河北移動核心賬務系統的Oracle數據庫已被GoldenDB完全替代**。”2025年6月底,這場持續兩年的攻堅戰畫上句號。當全省業務流量平穩切…

OS19.【Linux】進程狀態(1)

目錄 1.情景引入 2.操作系統學科對進程狀態的分類 運行狀態 基于時間片的輪轉調度算法 阻塞狀態 等待IO設備的例子 等待其他進程中需要獲取的數據 進程喚醒 掛起狀態(全稱為阻塞掛起狀態) 簡單談談虛擬內存管理 就緒狀態 筆面試題 3.Linux對進程狀態的分類 R和S狀…

Hadoop小文件合并技術深度解析:HAR文件歸檔、存儲代價與索引結構

HDFS小文件問題的背景與挑戰在Hadoop分布式文件系統&#xff08;HDFS&#xff09;的設計哲學中&#xff0c;"大文件、流式訪問"是核心原則。然而現實場景中&#xff0c;海量小文件&#xff08;通常指遠小于HDFS默認塊大小128MB的文件&#xff09;的涌入卻成為系統性能…

Verilog 提取信號的上升沿或者下降沿

上升沿提取代碼&#xff1a;reg [1:0] F1;always (posedge clk)beginif(rst_n 1b0) F1[1:0]<2b00;else F1[1:0]<{F1[0],start_i};endwire start_l2h (F1[1:0]2b01)?1b1:1b0;下降沿提取代碼&#xff1a;reg [1:0] F1;always (posedge clk)b…

.Net core 部署到IIS出現500.19Internal Server Error 解決方法

.Net core 部署到IIS&#xff0c;網頁出現500.19Internal Server Error 解決方法解決方法 在URL:https://dotnet.microsoft.com/zh-tw/download/dotnet/8.0下載并安裝dotnet-hosting-8.0.18-win.exe 重啟IIS服務器

Linux 基本命令整理

&#x1f427; Linux 基本命令整理 為了方便初學者快速掌握 Linux 常用命令&#xff0c;以下是經過分類整理的核心命令及用法說明。 &#x1f4c2; 目錄操作與文件管理 pwd 核心功能&#xff1a;打印當前工作目錄的絕對路徑&#xff0c;明確用戶所在位置。 實操示例&#x…

牛客周賽 Round 101(題解的token計算, 76修地鐵 ,76選數,76構造,qcjj寄快遞,冪中冪plus)

A題解的token計算要記住c中的對數函數&#xff1a;log(n) 是自然對數&#xff08;以e為底&#xff09;ln(nlog10(n) 是以10為底的對log1p(n) 是ln(1n)&#xff0c;提供更高的數值精log2(n) 是以2為底的對logl(n) 和 log10l(n) 是long double版#define _CRT_SECURE_NO_WARNINGS …

商場導航軟件:3D+AI 基于Deepseek 模型的意圖識別技術解析

本文面向室內導航工程師、商場導航系統優化師及LBS 應用開發的技術員&#xff0c;解析商場室內導航系統 3DAI 三大核心技術模塊&#xff0c;并提供可直接復用的工程解決方案。如需獲取商場導航系統技術方案可前往文章最下方獲取&#xff0c;如有項目合作及技術交流歡迎私信作者…

借助Aspose.HTML控件,使用 Python 編程將網頁轉換為 PDF

使用 Python 將網頁轉換為 PDF 有時您需要離線訪問網頁&#xff0c;使其更易于訪問。因此&#xff0c;將HTML頁面轉換為PDF即可滿足您的需求。令人驚訝的是&#xff0c;您可以在幾秒鐘內在 Python 項目中啟用 HTML 到 PDF 的轉換。本指南將為 Python 開發人員介紹一個功能強大…