使用Java制作貪吃蛇小游戲

在這篇文章中,我將帶你一步步實現一個經典的貪吃蛇小游戲。我們將使用Java語言和Swing庫來構建這個游戲,它包含了貪吃蛇游戲的基本功能:蛇的移動、吃食物、計分以及游戲結束判定。

游戲設計思路

貪吃蛇游戲的基本原理是:玩家控制一條蛇在屏幕上移動,蛇會吃隨機出現的食物,每吃一次食物蛇就會變長一節,同時玩家得分增加。如果蛇撞到墻壁或自己的身體,游戲就結束。

我們將使用面向對象的方法設計這個游戲,主要包含以下幾個類:

  • SnakeGame:游戲主類,負責初始化游戲窗口和游戲循環
  • GamePanel:游戲面板類,繼承自JPanel,負責繪制游戲界面和處理游戲邏輯
  • Snake:蛇類,管理蛇的位置、移動和狀態
  • Food:食物類,管理食物的位置和生成

下面讓我們開始實現這個游戲吧!

第一步:創建游戲主類

首先,我們需要創建一個主類來啟動游戲。這個類將設置游戲窗口并啟動游戲循環。

import javax.swing.JFrame;public class SnakeGame {public static void main(String[] args) {// 創建游戲窗口JFrame frame = new JFrame("貪吃蛇游戲");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setResizable(false);// 創建游戲面板并添加到窗口GamePanel gamePanel = new GamePanel();frame.add(gamePanel);// 調整窗口大小以適應游戲面板frame.pack();// 居中顯示窗口frame.setLocationRelativeTo(null);// 顯示窗口frame.setVisible(true);// 啟動游戲gamePanel.startGame();}
}

這個類很簡單,它創建了一個JFrame窗口,并將游戲面板添加到窗口中。然后設置窗口的基本屬性,最后調用游戲面板的startGame()方法來啟動游戲。

第二步:創建游戲面板類

接下來,我們創建游戲面板類,它將繼承自JPanel,并實現游戲的主要邏輯和繪制功能。

import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.Timer;public class GamePanel extends JPanel implements ActionListener, KeyListener {// 游戲區域的尺寸private static final int WIDTH = 600;private static final int HEIGHT = 600;// 蛇和食物的大小private static final int UNIT_SIZE = 20;// 游戲區域的單元數量private static final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE);// 游戲速度控制private static final int DELAY = 75;// 蛇的身體部分位置數組private final int[] x = new int[GAME_UNITS];private final int[] y = new int[GAME_UNITS];// 蛇的初始長度private int bodyParts = 6;// 吃掉的食物數量private int applesEaten;// 食物的位置private int appleX;private int appleY;// 蛇的移動方向private char direction = 'R'; // 初始向右移動private boolean running = false;private Timer timer;public GamePanel() {// 設置面板屬性setPreferredSize(new Dimension(WIDTH, HEIGHT));setBackground(Color.BLACK);setFocusable(true);// 添加鍵盤監聽器addKeyListener(this);// 初始化游戲initGame();}public void initGame() {// 初始化蛇的位置for (int i = 0; i < bodyParts; i++) {x[i] = 100 - i * UNIT_SIZE;y[i] = 50;}// 生成第一個食物newApple();// 啟動游戲running = true;timer = new Timer(DELAY, this);timer.start();}@Overrideprotected void paintComponent(Graphics g) {super.paintComponent(g);draw(g);}public void draw(Graphics g) {if (running) {// 繪制網格(可選,僅用于輔助查看)for (int i = 0; i < HEIGHT / UNIT_SIZE; i++) {g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, HEIGHT);g.drawLine(0, i * UNIT_SIZE, WIDTH, i * UNIT_SIZE);}// 繪制食物g.setColor(Color.RED);g.fillOval(appleX, appleY, UNIT_SIZE, UNIT_SIZE);// 繪制蛇for (int i = 0; i < bodyParts; i++) {if (i == 0) {// 蛇頭g.setColor(Color.GREEN);} else {// 蛇身g.setColor(new Color(45, 180, 0));// 或者使用不同顏色創建漸變效果// g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255)));}g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);}// 繪制分數g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics = getFontMetrics(g.getFont());g.drawString("分數: " + applesEaten, (WIDTH - metrics.stringWidth("分數: " + applesEaten)) / 2, g.getFont().getSize());} else {gameOver(g);}}public void newApple() {// 隨機生成食物位置appleX = (int)(Math.random() * (WIDTH / UNIT_SIZE)) * UNIT_SIZE;appleY = (int)(Math.random() * (HEIGHT / UNIT_SIZE)) * UNIT_SIZE;// 確保食物不會出現在蛇身上for (int i = 0; i < bodyParts; i++) {if ((x[i] == appleX) && (y[i] == appleY)) {newApple();}}}public void move() {// 移動蛇的身體部分for (int i = bodyParts; i > 0; i--) {x[i] = x[i - 1];y[i] = y[i - 1];}// 根據方向移動蛇頭switch (direction) {case 'U':y[0] = y[0] - UNIT_SIZE;break;case 'D':y[0] = y[0] + UNIT_SIZE;break;case 'L':x[0] = x[0] - UNIT_SIZE;break;case 'R':x[0] = x[0] + UNIT_SIZE;break;}}public void checkApple() {// 檢查蛇頭是否碰到食物if ((x[0] == appleX) && (y[0] == appleY)) {bodyParts++;applesEaten++;newApple();}}public void checkCollisions() {// 檢查蛇頭是否碰到自己的身體for (int i = bodyParts; i > 0; i--) {if ((x[0] == x[i]) && (y[0] == y[i])) {running = false;}}// 檢查蛇頭是否碰到左邊界if (x[0] < 0) {running = false;}// 檢查蛇頭是否碰到右邊界if (x[0] >= WIDTH) {running = false;}// 檢查蛇頭是否碰到上邊界if (y[0] < 0) {running = false;}// 檢查蛇頭是否碰到下邊界if (y[0] >= HEIGHT) {running = false;}// 如果游戲結束,停止計時器if (!running) {timer.stop();}}public void gameOver(Graphics g) {// 繪制游戲結束文本g.setColor(Color.RED);g.setFont(new Font("Ink Free", Font.BOLD, 75));FontMetrics metrics1 = getFontMetrics(g.getFont());g.drawString("游戲結束", (WIDTH - metrics1.stringWidth("游戲結束")) / 2, HEIGHT / 2 - 50);// 繪制最終分數g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics2 = getFontMetrics(g.getFont());g.drawString("分數: " + applesEaten, (WIDTH - metrics2.stringWidth("分數: " + applesEaten)) / 2, HEIGHT / 2 + 50);// 繪制重新開始提示g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 20));FontMetrics metrics3 = getFontMetrics(g.getFont());g.drawString("按空格鍵重新開始", (WIDTH - metrics3.stringWidth("按空格鍵重新開始")) / 2, HEIGHT / 2 + 100);}public void startGame() {initGame();}@Overridepublic void actionPerformed(ActionEvent e) {if (running) {move();checkApple();checkCollisions();}repaint();}@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyCode();// 根據按鍵改變蛇的移動方向,但不能直接反向移動switch (key) {case KeyEvent.VK_LEFT:if (direction != 'R') {direction = 'L';}break;case KeyEvent.VK_RIGHT:if (direction != 'L') {direction = 'R';}break;case KeyEvent.VK_UP:if (direction != 'D') {direction = 'U';}break;case KeyEvent.VK_DOWN:if (direction != 'U') {direction = 'D';}break;case KeyEvent.VK_SPACE:if (!running) {startGame();}break;}}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void keyTyped(KeyEvent e) {}
}

這個類是游戲的核心部分,它處理了游戲的主要邏輯:

  1. 游戲面板的初始化和設置
  2. 游戲循環的控制(通過Timer實現)
  3. 游戲元素的繪制(蛇、食物和分數)
  4. 蛇的移動和方向控制
  5. 食物的生成和檢測
  6. 碰撞檢測(包括邊界和自身)
  7. 游戲結束的處理

第三步:改進游戲結構(可選)

上面的實現已經可以運行一個簡單的貪吃蛇游戲了,但代碼結構還可以進一步優化。我們可以將蛇和食物單獨封裝成類,使代碼更加模塊化。

以下是優化后的代碼結構:

// Snake.java
public class Snake {private int[] x;private int[] y;private int bodyParts;private char direction;public Snake() {x = new int[GamePanel.GAME_UNITS];y = new int[GamePanel.GAME_UNITS];bodyParts = 6;direction = 'R';// 初始化蛇的位置for (int i = 0; i < bodyParts; i++) {x[i] = 100 - i * GamePanel.UNIT_SIZE;y[i] = 50;}}// Getters and setterspublic int[] getX() { return x; }public int[] getY() { return y; }public int getBodyParts() { return bodyParts; }public char getDirection() { return direction; }public void setDirection(char direction) { this.direction = direction; }public void move() {// 移動蛇的身體部分for (int i = bodyParts; i > 0; i--) {x[i] = x[i - 1];y[i] = y[i - 1];}// 根據方向移動蛇頭switch (direction) {case 'U':y[0] = y[0] - GamePanel.UNIT_SIZE;break;case 'D':y[0] = y[0] + GamePanel.UNIT_SIZE;break;case 'L':x[0] = x[0] - GamePanel.UNIT_SIZE;break;case 'R':x[0] = x[0] + GamePanel.UNIT_SIZE;break;}}public void grow() {bodyParts++;}public boolean checkSelfCollision() {// 檢查蛇頭是否碰到自己的身體for (int i = bodyParts; i > 0; i--) {if ((x[0] == x[i]) && (y[0] == y[i])) {return true;}}return false;}public boolean checkBoundaryCollision() {// 檢查蛇頭是否碰到邊界return x[0] < 0 || x[0] >= GamePanel.WIDTH || y[0] < 0 || y[0] >= GamePanel.HEIGHT;}
}// Food.java
import java.util.Random;public class Food {private int x;private int y;private Random random;public Food() {random = new Random();newPosition();}public void newPosition() {// 隨機生成食物位置x = random.nextInt(GamePanel.WIDTH / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;y = random.nextInt(GamePanel.HEIGHT / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;}// Getterspublic int getX() { return x; }public int getY() { return y; }public boolean isEaten(Snake snake) {// 檢查食物是否被蛇吃掉return snake.getX()[0] == x && snake.getY()[0] == y;}
}

使用這些類重構后的GamePanel類:

// 優化后的GamePanel.java
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.Timer;public class GamePanel extends JPanel implements ActionListener, KeyListener {private static final int WIDTH = 600;private static final int HEIGHT = 600;private static final int UNIT_SIZE = 20;private static final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE);private static final int DELAY = 75;private Snake snake;private Food food;private int applesEaten;private boolean running = false;private Timer timer;public GamePanel() {setPreferredSize(new Dimension(WIDTH, HEIGHT));setBackground(Color.BLACK);setFocusable(true);addKeyListener(this);initGame();}public void initGame() {snake = new Snake();food = new Food();applesEaten = 0;running = true;timer = new Timer(DELAY, this);timer.start();}@Overrideprotected void paintComponent(Graphics g) {super.paintComponent(g);draw(g);}public void draw(Graphics g) {if (running) {// 繪制網格for (int i = 0; i < HEIGHT / UNIT_SIZE; i++) {g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, HEIGHT);g.drawLine(0, i * UNIT_SIZE, WIDTH, i * UNIT_SIZE);}// 繪制食物g.setColor(Color.RED);g.fillOval(food.getX(), food.getY(), UNIT_SIZE, UNIT_SIZE);// 繪制蛇int[] snakeX = snake.getX();int[] snakeY = snake.getY();for (int i = 0; i < snake.getBodyParts(); i++) {if (i == 0) {g.setColor(Color.GREEN);} else {g.setColor(new Color(45, 180, 0));}g.fillRect(snakeX[i], snakeY[i], UNIT_SIZE, UNIT_SIZE);}// 繪制分數g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics = getFontMetrics(g.getFont());g.drawString("分數: " + applesEaten, (WIDTH - metrics.stringWidth("分數: " + applesEaten)) / 2, g.getFont().getSize());} else {gameOver(g);}}public void gameOver(Graphics g) {// 繪制游戲結束文本g.setColor(Color.RED);g.setFont(new Font("Ink Free", Font.BOLD, 75));FontMetrics metrics1 = getFontMetrics(g.getFont());g.drawString("游戲結束", (WIDTH - metrics1.stringWidth("游戲結束")) / 2, HEIGHT / 2 - 50);// 繪制最終分數g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics2 = getFontMetrics(g.getFont());g.drawString("分數: " + applesEaten, (WIDTH - metrics2.stringWidth("分數: " + applesEaten)) / 2, HEIGHT / 2 + 50);// 繪制重新開始提示g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 20));FontMetrics metrics3 = getFontMetrics(g.getFont());g.drawString("按空格鍵重新開始", (WIDTH - metrics3.stringWidth("按空格鍵重新開始")) / 2, HEIGHT / 2 + 100);}@Overridepublic void actionPerformed(ActionEvent e) {if (running) {snake.move();checkFood();checkCollisions();}repaint();}public void checkFood() {if (food.isEaten(snake)) {snake.grow();applesEaten++;food.newPosition();}}public void checkCollisions() {if (snake.checkSelfCollision() || snake.checkBoundaryCollision()) {running = false;}if (!running) {timer.stop();}}@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch (key) {case KeyEvent.VK_LEFT:if (snake.getDirection() != 'R') {snake.setDirection('L');}break;case KeyEvent.VK_RIGHT:if (snake.getDirection() != 'L') {snake.setDirection('R');}break;case KeyEvent.VK_UP:if (snake.getDirection() != 'D') {snake.setDirection('U');}break;case KeyEvent.VK_DOWN:if (snake.getDirection() != 'U') {snake.setDirection('D');}break;case KeyEvent.VK_SPACE:if (!running) {initGame();}break;}}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void keyTyped(KeyEvent e) {}
}

完整代碼

下面是完整的貪吃蛇游戲代碼,包含了所有類的實現:

// SnakeGame.java
import javax.swing.JFrame;public class SnakeGame {public static void main(String[] args) {JFrame frame = new JFrame("貪吃蛇游戲");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setResizable(false);GamePanel gamePanel = new GamePanel();frame.add(gamePanel);frame.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);gamePanel.startGame();}
}// GamePanel.java
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.Timer;public class GamePanel extends JPanel implements ActionListener, KeyListener {private static final int WIDTH = 600;private static final int HEIGHT = 600;private static final int UNIT_SIZE = 20;private static final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE);private static final int DELAY = 75;private Snake snake;private Food food;private int applesEaten;private boolean running = false;private Timer timer;public GamePanel() {setPreferredSize(new Dimension(WIDTH, HEIGHT));setBackground(Color.BLACK);setFocusable(true);addKeyListener(this);initGame();}public void initGame() {snake = new Snake();food = new Food();applesEaten = 0;running = true;timer = new Timer(DELAY, this);timer.start();}@Overrideprotected void paintComponent(Graphics g) {super.paintComponent(g);draw(g);}public void draw(Graphics g) {if (running) {// 繪制網格for (int i = 0; i < HEIGHT / UNIT_SIZE; i++) {g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, HEIGHT);g.drawLine(0, i * UNIT_SIZE, WIDTH, i * UNIT_SIZE);}// 繪制食物g.setColor(Color.RED);g.fillOval(food.getX(), food.getY(), UNIT_SIZE, UNIT_SIZE);// 繪制蛇int[] snakeX = snake.getX();int[] snakeY = snake.getY();for (int i = 0; i < snake.getBodyParts(); i++) {if (i == 0) {g.setColor(Color.GREEN);} else {g.setColor(new Color(45, 180, 0));}g.fillRect(snakeX[i], snakeY[i], UNIT_SIZE, UNIT_SIZE);}// 繪制分數g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics = getFontMetrics(g.getFont());g.drawString("分數: " + applesEaten, (WIDTH - metrics.stringWidth("分數: " + applesEaten)) / 2, g.getFont().getSize());} else {gameOver(g);}}public void gameOver(Graphics g) {// 繪制游戲結束文本g.setColor(Color.RED);g.setFont(new Font("Ink Free", Font.BOLD, 75));FontMetrics metrics1 = getFontMetrics(g.getFont());g.drawString("游戲結束", (WIDTH - metrics1.stringWidth("游戲結束")) / 2, HEIGHT / 2 - 50);// 繪制最終分數g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics2 = getFontMetrics(g.getFont());g.drawString("分數: " + applesEaten, (WIDTH - metrics2.stringWidth("分數: " + applesEaten)) / 2, HEIGHT / 2 + 50);// 繪制重新開始提示g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 20));FontMetrics metrics3 = getFontMetrics(g.getFont());g.drawString("按空格鍵重新開始", (WIDTH - metrics3.stringWidth("按空格鍵重新開始")) / 2, HEIGHT / 2 + 100);}@Overridepublic void actionPerformed(ActionEvent e) {if (running) {snake.move();checkFood();checkCollisions();}repaint();}public void checkFood() {if (food.isEaten(snake)) {snake.grow();applesEaten++;food.newPosition();}}public void checkCollisions() {if (snake.checkSelfCollision() || snake.checkBoundaryCollision()) {running = false;}if (!running) {timer.stop();}}public void startGame() {initGame();}@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch (key) {case KeyEvent.VK_LEFT:if (snake.getDirection() != 'R') {snake.setDirection('L');}break;case KeyEvent.VK_RIGHT:if (snake.getDirection() != 'L') {snake.setDirection('R');}break;case KeyEvent.VK_UP:if (snake.getDirection() != 'D') {snake.setDirection('U');}break;case KeyEvent.VK_DOWN:if (snake.getDirection() != 'U') {snake.setDirection('D');}break;case KeyEvent.VK_SPACE:if (!running) {initGame();}break;}}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void keyTyped(KeyEvent e) {}
}// Snake.java
public class Snake {private int[] x;private int[] y;private int bodyParts;private char direction;public Snake() {x = new int[GamePanel.GAME_UNITS];y = new int[GamePanel.GAME_UNITS];bodyParts = 6;direction = 'R';// 初始化蛇的位置for (int i = 0; i < bodyParts; i++) {x[i] = 100 - i * GamePanel.UNIT_SIZE;y[i] = 50;}}public int[] getX() { return x; }public int[] getY() { return y; }public int getBodyParts() { return bodyParts; }public char getDirection() { return direction; }public void setDirection(char direction) { this.direction = direction; }public void move() {// 移動蛇的身體部分for (int i = bodyParts; i > 0; i--) {x[i] = x[i - 1];y[i] = y[i - 1];}// 根據方向移動蛇頭switch (direction) {case 'U':y[0] = y[0] - GamePanel.UNIT_SIZE;break;case 'D':y[0] = y[0] + GamePanel.UNIT_SIZE;break;case 'L':x[0] = x[0] - GamePanel.UNIT_SIZE;break;case 'R':x[0] = x[0] + GamePanel.UNIT_SIZE;break;}}public void grow() {bodyParts++;}public boolean checkSelfCollision() {// 檢查蛇頭是否碰到自己的身體for (int i = bodyParts; i > 0; i--) {if ((x[0] == x[i]) && (y[0] == y[i])) {return true;}}return false;}public boolean checkBoundaryCollision() {// 檢查蛇頭是否碰到邊界return x[0] < 0 || x[0] >= GamePanel.WIDTH || y[0] < 0 || y[0] >= GamePanel.HEIGHT;}
}// Food.java
import java.util.Random;public class Food {private int x;private int y;private Random random;public Food() {random = new Random();newPosition();}public void newPosition() {// 隨機生成食物位置x = random.nextInt(GamePanel.WIDTH / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;y = random.nextInt(GamePanel.HEIGHT / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;}public int getX() { return x; }public int getY() { return y; }public boolean isEaten(Snake snake) {// 檢查食物是否被蛇吃掉return snake.getX()[0] == x && snake.getY()[0] == y;}
}

如何運行游戲

  1. 將上面的代碼復制到四個Java文件中:SnakeGame.java, GamePanel.java, Snake.java, 和 Food.java
  2. 確保所有文件在同一個目錄下
  3. 使用Java編譯器編譯這些文件:javac SnakeGame.java
  4. 運行編譯后的程序:java SnakeGame

游戲操作說明

  • 使用方向鍵(上、下、左、右)控制蛇的移動方向
  • 吃到紅色的食物會增加分數并讓蛇變長
  • 如果蛇撞到邊界或自己的身體,游戲結束
  • 游戲結束后按空格鍵可以重新開始

游戲改進建議

  1. 添加難度級別:隨著分數增加,蛇的移動速度加快
  2. 添加不同類型的食物:有些食物提供額外分數,有些食物讓蛇加速或減速
  3. 添加音效:吃到食物、游戲結束等事件添加音效
  4. 實現高分榜:記錄最高分并顯示在游戲界面

希望這篇文章能幫助你理解如何使用Java制作一個簡單的貪吃蛇游戲!如果你有任何問題或建議,歡迎留言討論。

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

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

相關文章

【linux】umask權限掩碼

umask這個接口在一些程序初始化的時候經常會見到&#xff0c;處于安全性&#xff0c;可以縮小進程落盤文件的權限。 1、linux文件系統的權限規則 文件的默認權限由系統決定&#xff08;通常是 0666&#xff0c;即所有人可讀可寫&#xff09;。 目錄的默認權限通常是 0777&am…

esp32cmini SK6812 2個方式

1 #include <SPI.h> // ESP32-C系列的SPI引腳 #define MOSI_PIN 7 // ESP32-C3/C6的SPI MOSI引腳 #define NUM_LEDS 30 // LED燈帶實際LED數量 - 確保與實際數量匹配&#xff01; #define SPI_CLOCK 10000000 // SPI時鐘頻率 // 顏色結構體 st…

互聯網大廠Java求職面試:Spring Cloud微服務架構設計中的挑戰與解決方案

互聯網大廠Java求職面試&#xff1a;Spring Cloud微服務架構設計中的挑戰與解決方案 面試場景設定 鄭薪苦是一位擁有豐富實戰經驗的Java開發者&#xff0c;他正在參加一場由某知名互聯網大廠的技術總監主持的面試。這場面試將圍繞Spring Cloud微服務架構展開&#xff0c;涵蓋…

品鑒JS的魅力之防抖與節流【JS】

前言 小水一波&#xff0c;函數的防抖與節流。 文章目錄 前言介紹實現方式防抖節流 介紹 防抖與節流的優化邏輯&#xff0c;在我們的日常開發中&#xff0c;有著一定的地位。 防抖和節流是兩種常用的性能優化技術&#xff0c;用于限制某個函數在一定時間內被觸發的次數,減少不…

# 使用 Hugging Face Transformers 和 PyTorch 實現信息抽取

使用 Hugging Face Transformers 和 PyTorch 實現信息抽取 在自然語言處理&#xff08;NLP&#xff09;領域&#xff0c;信息抽取是一種常見的任務&#xff0c;其目標是從文本中提取特定類型的結構化信息。本文將介紹如何使用 Hugging Face Transformers 和 PyTorch 實現基于大…

Firecrawl MCP Server 深度使用指南

無論是市場分析師洞察行業動態、研究者收集學術資料&#xff0c;還是開發者為智能應用采集數據&#xff0c;都對網絡數據采集工具提出了極高的要求。Firecrawl MCP Server 應運而生&#xff0c;它宛如一把犀利的 “數字手術刀”&#xff0c;能夠精準地剖析網頁&#xff0c;為用…

OceanBase數據庫全面指南(基礎入門篇)

文章目錄 一、OceanBase 簡介與安裝配置指南1.1 OceanBase 核心特點1.2 架構解析1.3 安裝部署實戰1.3.1 硬件要求1.3.2 安裝步驟詳解1.3.3 配置驗證二、OceanBase 基礎 SQL 語法入門2.1 數據查詢(SELECT)2.1.1 基礎查詢語法2.1.2 實際案例演示2.2 數據操作(INSERT/UPDATE/DE…

幾種環境下的Postgres數據庫安裝

1. Postgres 數據庫介紹 PostgreSQL&#xff08;又稱 Postgres&#xff09;是一種強大、開源的關系型數據庫管理系統&#xff08;RDBMS&#xff09;&#xff0c;它具備高度的可靠性、穩定性和可擴展性&#xff0c;主要特點如下&#xff1a; 開源&#xff1a;PostgreSQL 是基于開…

函數[x]和{x}在數論中的應用

函數[x]和{x}在數論中的應用 函數[x]和{x}的定義與基本性質&#xff08;定義1&#xff0c;命題1&#xff09;定義1例1命題1 函數[x]和{x}的應用&#xff08;定理1&#xff0c;推論1-推論3&#xff09;例2定理1注解5推論1例3例4推論2推論3命題2 函數[x]和{x}的定義與基本性質&am…

Python爬蟲(32)Python爬蟲高階:動態頁面處理與Scrapy+Selenium+BeautifulSoup分布式架構深度解析實戰

目錄 引言一、動態頁面爬取的技術背景1.1 動態頁面的核心特征1.2 傳統爬蟲的局限性 二、技術選型與架構設計2.1 核心組件分析2.2 架構設計思路1. 分層處理2. 數據流 三、代碼實現與關鍵技術3.1 Selenium與Scrapy的中間件集成3.2 BeautifulSoup與Scrapy Item的整合3.3 分布式爬取…

FreeSWITCH rtcp-mux 測試

rtcp 跟 rtp 占用同一個端口&#xff0c;這就是 rtcp 復用 Fs 呼出是這樣的&#xff1a; originate [rtcp_muxtrue][rtcp_audio_interval_msec5000]user/1001 &echo 需要同時指定 rtcp_audio_interval_msec&#xff0c;否則 rtcp_mux 不能生效 Fs 呼入不需要配置&#xf…

day019-特殊符號、正則表達式與三劍客

文章目錄 1. 磁盤空間不足-排查流程2. 李導推薦書籍2.1 大話存儲2.2 性能之巔 3. 特殊符號3.1 引號系列&#xff08;面試題&#xff09;3.2 重定向符號3.2.1 cat與重定向3.2.2 tr命令&#xff1a;替換字符3.2.3 xargs&#xff1a;參數轉換3.2.4 標準全量追加重定向 4. 正則表達…

Vue3 watch 使用與注意事項

watch 的第一個參數可以是不同形式的“數據源”&#xff1a;它可以是一個 ref (包括計算屬性)、一個響應式對象、一個 getter 函數、或多個數據源組成的數組&#xff1a; 1&#xff1a;reactive監聽對象 <template><div><h1>情況二&#xff1a;watchEffect…

醫學寫作供應商管理全流程優化

1. 供應商篩選與評估 1.1 資質審核 1.1.1 行業認證核查 核查供應商的行業認證,如AMWA醫學寫作認證、EMWA會員資格、ISO 9001等,確保其專業資質。 1.1.2 團隊背景評估 評估團隊成員專業背景,包括醫學/藥學學位、臨床試驗經驗、發表記錄,保障專業能力。 1.1.3 國際規范熟悉…

固態硬盤顆粒類型、選型與應用場景深度解析

一、固態硬盤顆粒類型的技術演進與特性 固態硬盤&#xff08;SSD&#xff09;的性能核心在于存儲單元結構的設計&#xff0c;這種設計直接決定了數據的存儲密度、讀寫速度、耐久度及成本效益。當前主流的閃存顆粒類型呈現從單層到多層架構的梯度演進&#xff0c;其技術特征與應…

CAPL自動化-診斷Demo工程

文章目錄 前言一、診斷控制面板二、診斷定義三、發送診斷通過類.方法的方式req.SetParameterdiagSetParameter四、SendRequestAndWaitForResponse前言 本文將介紹CANoe的診斷自動化測試,工程可以從CANoe的 Sample Configruration 界面打開,也可以參考下面的路徑中打開(以實…

嵌入式預處理鏈接腳本lds和map文件

在嵌入式開發中&#xff0c;.lds.S 文件是一個 預處理后的鏈接腳本&#xff08;Linker Script&#xff09;&#xff0c;它結合了 C 預處理器&#xff08;Preprocessor&#xff09; 的功能和鏈接腳本的語法。它的核心作用仍然是 定義內存布局和鏈接規則&#xff0c;但通過預處理…

PT5F2307觸摸A/D型8-Bit MCU

1. 產品概述 ● PT5F2307是一款51內核的觸控A/D型8位MCU&#xff0c;內置16K*8bit FLASH、內部256*8bit SRAM、外部512*8bit SRAM、觸控檢測、12位高精度ADC、RTC、PWM等功能&#xff0c;抗干擾能力強&#xff0c;適用于滑條遙控器、智能門鎖、消費類電子產品等電子應用領域。 …

RabbitMQ——消息確認

一、消息確認機制 生產者發送的消息&#xff0c;可能有以下兩種情況&#xff1a; 1> 消息消費成功 2> 消息消費失敗 為了保證消息可靠的到達消費者&#xff08;&#xff01;&#xff01;&#xff01;注意&#xff1a;消息確認機制和前面的工作模式中的publisher confi…

C++異步(1)

什么是異步? 異步就是多個線程是同時執行的&#xff0c;與之相對的就是線程同步&#xff0c;二者都應用在并發的場景上。 異步的特點 異步執行的任務無需等待其他任務完成&#xff0c;其本身是通過非阻塞的方式執行的&#xff0c;不依賴前驅任務&#xff0c;通常用于IO密集…