《用MATLAB玩转游戏开发》打砖块:向量反射与实时物理模拟MATLAB教程

news2025/7/13 14:49:48

《用MATLAB玩转游戏开发:从零开始打造你的数字乐园》基础篇(2D图形交互)-《打砖块:向量反射与实时物理模拟》MATLAB教程 🎮

文章目录

  • 《用MATLAB玩转游戏开发:从零开始打造你的数字乐园》基础篇(2D图形交互)-《打砖块:向量反射与实时物理模拟》MATLAB教程 🎮
    • 引言:从游戏到物理模拟
    • 1. 设计思路与游戏概述 🧠
      • 1.1 物理模型关键点 ⚛️
    • 2. 核心原理详解 🔍
      • 2.1 向量反射原理 📐
      • 2.2 碰撞检测原理 🔄
      • 2.3 游戏循环结构 🔁
    • 3. 完整流程图 📊
    • 4. 分步实现教程 🛠️
      • 4.1 初始化设置
      • 4.2 创建游戏对象
      • 4.3 游戏主循环
      • 4.4 碰撞检测函数
    • 5. 完整可运行代码 🏆
    • 6. 游戏操作说明 🎮
    • 7. 扩展思路 💡

在这里插入图片描述

引言:从游戏到物理模拟

还记得小时候玩过的打砖块游戏吗?🎯 一个小球在屏幕上弹来弹去,击碎各种砖块,同时玩家控制一块挡板防止小球掉落。这看似简单的游戏背后,其实蕴含着丰富的物理和数学原理!今天,我们就用MATLAB来实现这个经典游戏,并深入探讨其中的向量反射和实时物理模拟技术。

通过本教程,你将学到:

  • 向量运算在游戏物理中的应用
  • 实时碰撞检测的实现方法
  • MATLAB动画和交互式图形编程
  • 游戏状态管理和逻辑控制

准备好你的MATLAB环境(2016b版本),让我们开始这场有趣的编程之旅吧!🚀

1. 设计思路与游戏概述 🧠

打砖块游戏(Breakout/Arkanoid)是经典的街机游戏,包含以下核心元素:

  • 一个由玩家控制的挡板(paddle)
  • 一个运动的(ball)
  • 由砖块组成的(bricks)
  • 边界(walls)

游戏目标是用挡板反弹球,消除所有砖块。每次球碰到砖块,砖块消失,玩家得分。

1.1 物理模型关键点 ⚛️

  1. 碰撞检测:判断球与边界、挡板、砖块的接触
  2. 反射计算:球碰到物体后的运动方向变化
  3. 实时渲染:游戏画面的流畅更新
  4. 游戏逻辑:得分、生命、胜负判断

2. 核心原理详解 🔍

2.1 向量反射原理 📐

球碰到平面后的反射遵循"入射角=反射角"原则。数学上可以用向量运算表示:

给定:

  • 入射向量 v = [vx, vy]
  • 法向量 n = [nx, ny] (垂直于反射平面)

反射向量 r 的计算公式为:
r = v − 2 ( v ⋅ n ) n r = v - 2(v \cdot n)n r=v2(vn)n

在MATLAB中实现:

function reflectedVec = reflectVector(inVec, normalVec)
    % 归一化法向量
    normalVec = normalVec / norm(normalVec);
    % 计算反射向量
    reflectedVec = inVec - 2 * dot(inVec, normalVec) * normalVec;
end

2.2 碰撞检测原理 🔄

我们需要检测球与以下物体的碰撞:

  1. 边界:比较球心坐标与边界位置
  2. 挡板:判断球是否在挡板的矩形区域内
  3. 砖块:类似挡板,但需要考虑砖块是否已被消除

2.3 游戏循环结构 🔁

标准游戏循环包含以下步骤:

  1. 初始化:创建游戏对象和变量
  2. 输入处理:读取玩家操作
  3. 状态更新:计算物理和游戏逻辑
  4. 渲染:绘制游戏画面
  5. 循环控制:控制帧率和退出条件

3. 完整流程图 📊

开始
初始化游戏
绘制初始场景
游戏进行中?
处理玩家输入
更新球位置
检测碰撞
处理碰撞响应
更新游戏状态
绘制新帧
显示游戏结果
结束

4. 分步实现教程 🛠️

4.1 初始化设置

function breakoutGame()
    % 清除工作区和图形窗口
    clc; clear; close all;
    
    % 游戏参数设置
    gameParams = struct(...
        'paddleWidth', 100, ...    % 挡板宽度
        'paddleHeight', 15, ...    % 挡板高度
        'ballRadius', 10, ...      % 球半径
        'brickRows', 5, ...        % 砖块行数
        'brickCols', 10, ...       % 砖块列数
        'brickWidth', 60, ...      % 砖块宽度
        'brickHeight', 20, ...     % 砖块高度
        'brickOffsetTop', 50, ...  % 砖块顶部偏移
        'brickPadding', 5, ...     % 砖块间距
        'ballSpeed', 8, ...        % 球初始速度
        'lives', 3, ...            % 初始生命数
        'score', 0 ...             % 初始得分
    );
    
    % 创建图形窗口
    fig = figure('Name', 'MATLAB打砖块', ...
                 'NumberTitle', 'off', ...
                 'Position', [100, 100, 800, 600], ...
                 'KeyPressFcn', @keyDown, ...
                 'KeyReleaseFcn', @keyUp, ...
                 'WindowButtonDownFcn', @mouseClick);
    
    % 创建坐标轴
    ax = axes('Parent', fig, ...
              'Position', [0.05, 0.05, 0.9, 0.9], ...
              'XLim', [0, 800], ...
              'YLim', [0, 600], ...
              'Color', [0.1, 0.1, 0.3], ...
              'XTick', [], ...
              'YTick', []);
    hold(ax, 'on');
    axis equal;

4.2 创建游戏对象

    % 创建挡板
    paddle = rectangle('Parent', ax, ...
                      'Position', [350, 30, gameParams.paddleWidth, gameParams.paddleHeight], ...
                      'FaceColor', [0.8, 0.2, 0.2], ...
                      'EdgeColor', 'none', ...
                      'Curvature', [0.2, 0.2]);
    
    % 创建球
    theta = rand * 2 * pi;  % 随机初始角度
    ballVel = [gameParams.ballSpeed * cos(theta), gameParams.ballSpeed * sin(theta)];
    ball = rectangle('Parent', ax, ...
                    'Position', [400, 200, gameParams.ballRadius*2, gameParams.ballRadius*2], ...
                    'FaceColor', [0.9, 0.9, 0.1], ...
                    'EdgeColor', 'none', ...
                    'Curvature', [1, 1]);
    
    % 创建砖块
    bricks = gobjects(gameParams.brickRows, gameParams.brickCols);
    brickColors = hsv(gameParams.brickRows);  % 每行不同颜色
    
    for r = 1:gameParams.brickRows
        for c = 1:gameParams.brickCols
            brickX = (c-1) * (gameParams.brickWidth + gameParams.brickPadding);
            brickY = 550 - (r-1) * (gameParams.brickHeight + gameParams.brickPadding);
            bricks(r,c) = rectangle('Parent', ax, ...
                                   'Position', [brickX, brickY, gameParams.brickWidth, gameParams.brickHeight], ...
                                   'FaceColor', brickColors(r,:), ...
                                   'EdgeColor', 'w');
        end
    end
    
    % 创建文本显示
    scoreText = text(ax, 20, 580, sprintf('得分: %d', gameParams.score), ...
                    'Color', 'w', 'FontSize', 12);
    livesText = text(ax, 700, 580, sprintf('生命: %d', gameParams.lives), ...
                    'Color', 'w', 'FontSize', 12);
    startText = text(ax, 400, 300, '点击开始游戏', ...
                    'Color', 'w', 'FontSize', 24, ...
                    'HorizontalAlignment', 'center');

4.3 游戏主循环

    % 游戏状态变量
    gameState = struct(...
        'isRunning', false, ...    % 游戏是否进行中
        'paddleDir', 0, ...        % 挡板移动方向 (-1:左, 0:停止, 1:右)
        'paddleSpeed', 15, ...     % 挡板移动速度
        'activeBricks', true(gameParams.brickRows, gameParams.brickCols) ... % 活跃砖块
    );
    
    % 键盘控制回调函数
    function keyDown(~, event)
        switch event.Key
            case 'leftarrow'
                gameState.paddleDir = -1;
            case 'rightarrow'
                gameState.paddleDir = 1;
            case 'escape'
                gameState.isRunning = false;
        end
    end
    
    function keyUp(~, event)
        switch event.Key
            case {'leftarrow', 'rightarrow'}
                gameState.paddleDir = 0;
        end
    end
    
    % 鼠标点击开始游戏
    function mouseClick(~, ~)
        if ~gameState.isRunning
            gameState.isRunning = true;
            delete(startText);
            startText = [];
        end
    end
    
    % 主游戏循环
    while ishandle(fig)
        if gameState.isRunning
            % 更新挡板位置
            paddlePos = get(paddle, 'Position');
            newX = paddlePos(1) + gameState.paddleSpeed * gameState.paddleDir;
            
            % 限制挡板不超出边界
            newX = max(0, min(newX, 800 - gameParams.paddleWidth));
            set(paddle, 'Position', [newX, paddlePos(2), paddlePos(3), paddlePos(4)]);
            
            % 更新球位置
            ballPos = get(ball, 'Position');
            newBallX = ballPos(1) + ballVel(1);
            newBallY = ballPos(2) + ballVel(2);
            
            % 检测碰撞
            [ballVel, gameParams, gameState] = checkCollisions(...
                [newBallX, newBallY], ballVel, gameParams, gameState, paddle, bricks);
            
            % 更新球位置
            set(ball, 'Position', [newBallX, newBallY, ballPos(3), ballPos(4)]);
            
            % 更新文本显示
            set(scoreText, 'String', sprintf('得分: %d', gameParams.score));
            set(livesText, 'String', sprintf('生命: %d', gameParams.lives));
            
            % 检查游戏结束条件
            if newBallY < 0  % 球落到底部
                gameParams.lives = gameParams.lives - 1;
                if gameParams.lives <= 0
                    gameState.isRunning = false;
                    text(ax, 400, 300, '游戏结束!', ...
                        'Color', 'r', 'FontSize', 36, ...
                        'HorizontalAlignment', 'center');
                else
                    % 重置球位置
                    set(ball, 'Position', [400, 200, gameParams.ballRadius*2, gameParams.ballRadius*2]);
                    theta = rand * 2 * pi;
                    ballVel = [gameParams.ballSpeed * cos(theta), gameParams.ballSpeed * sin(theta)];
                    pause(1);
                end
            end
            
            % 检查胜利条件
            if ~any(gameState.activeBricks(:))
                gameState.isRunning = false;
                text(ax, 400, 300, '恭喜通关!', ...
                    'Color', 'g', 'FontSize', 36, ...
                    'HorizontalAlignment', 'center');
            end
        end
        
        % 控制帧率
        pause(0.02);
    end

4.4 碰撞检测函数

function [newVel, gameParams, gameState] = checkCollisions(ballPos, ballVel, gameParams, gameState, paddle, bricks)
    % 获取球参数
    ballX = ballPos(1) + gameParams.ballRadius;
    ballY = ballPos(2) + gameParams.ballRadius;
    
    % 边界碰撞检测
    if ballX <= gameParams.ballRadius || ballX >= 800 - gameParams.ballRadius
        ballVel(1) = -ballVel(1);  % 水平反转
    end
    if ballY >= 600 - gameParams.ballRadius
        ballVel(2) = -ballVel(2);  % 垂直反转
    end
    
    % 挡板碰撞检测
    paddlePos = get(paddle, 'Position');
    if ballY <= paddlePos(2) + paddlePos(4) + gameParams.ballRadius && ...
       ballY >= paddlePos(2) && ...
       ballX >= paddlePos(1) - gameParams.ballRadius && ...
       ballX <= paddlePos(1) + paddlePos(3) + gameParams.ballRadius
        
        % 计算碰撞点相对于挡板中心的位置 (-1到1)
        hitPos = (ballX - (paddlePos(1) + paddlePos(3)/2)) / (paddlePos(3)/2);
        
        % 根据碰撞点调整反射角度
        maxAngle = pi/3;  % 最大反射角度 (60度)
        angle = hitPos * maxAngle;
        
        % 计算新速度向量
        speed = norm(ballVel);
        ballVel = [speed * sin(angle), speed * cos(angle)];
        
        % 增加一点速度让游戏更有挑战性
        ballVel = ballVel * 1.02;
    end
    
    % 砖块碰撞检测
    for r = 1:gameParams.brickRows
        for c = 1:gameParams.brickCols
            if gameState.activeBricks(r,c)
                brickPos = get(bricks(r,c), 'Position');
                
                % 检查球是否与砖块相交
                if ballX + gameParams.ballRadius > brickPos(1) && ...
                   ballX - gameParams.ballRadius < brickPos(1) + brickPos(3) && ...
                   ballY + gameParams.ballRadius > brickPos(2) && ...
                   ballY - gameParams.ballRadius < brickPos(2) + brickPos(4)
                    
                    % 确定碰撞边 (简化版)
                    if ballY < brickPos(2) || ballY > brickPos(2) + brickPos(4)
                        ballVel(2) = -ballVel(2);  % 上下碰撞
                    else
                        ballVel(1) = -ballVel(1);  % 左右碰撞
                    end
                    
                    % 标记砖块为不活跃并隐藏
                    gameState.activeBricks(r,c) = false;
                    set(bricks(r,c), 'Visible', 'off');
                    
                    % 增加分数
                    gameParams.score = gameParams.score + 10;
                    
                    % 只需要处理一次碰撞
                    break;
                end
            end
        end
    end
    
    newVel = ballVel;
end

5. 完整可运行代码 🏆

将以下所有代码段按顺序组合成一个.m文件即可运行:

function breakoutGame()
    % 清除工作区和图形窗口
    clc; clear; close all;
    
    % 游戏参数设置
    gameParams = struct(...
        'paddleWidth', 100, ...    % 挡板宽度
        'paddleHeight', 15, ...    % 挡板高度
        'ballRadius', 10, ...      % 球半径
        'brickRows', 5, ...        % 砖块行数
        'brickCols', 10, ...       % 砖块列数
        'brickWidth', 60, ...      % 砖块宽度
        'brickHeight', 20, ...     % 砖块高度
        'brickOffsetTop', 50, ...  % 砖块顶部偏移
        'brickPadding', 5, ...     % 砖块间距
        'ballSpeed', 8, ...        % 球初始速度
        'lives', 3, ...            % 初始生命数
        'score', 0 ...             % 初始得分
    );
    
    % 创建图形窗口
    fig = figure('Name', 'MATLAB打砖块', ...
                 'NumberTitle', 'off', ...
                 'Position', [100, 100, 800, 600], ...
                 'KeyPressFcn', @keyDown, ...
                 'KeyReleaseFcn', @keyUp, ...
                 'WindowButtonDownFcn', @mouseClick);
    
    % 创建坐标轴
    ax = axes('Parent', fig, ...
              'Position', [0.05, 0.05, 0.9, 0.9], ...
              'XLim', [0, 800], ...
              'YLim', [0, 600], ...
              'Color', [0.1, 0.1, 0.3], ...
              'XTick', [], ...
              'YTick', []);
    hold(ax, 'on');
    axis equal;
    
    % 创建挡板
    paddle = rectangle('Parent', ax, ...
                      'Position', [350, 30, gameParams.paddleWidth, gameParams.paddleHeight], ...
                      'FaceColor', [0.8, 0.2, 0.2], ...
                      'EdgeColor', 'none', ...
                      'Curvature', [0.2, 0.2]);
    
    % 创建球
    theta = rand * 2 * pi;  % 随机初始角度
    ballVel = [gameParams.ballSpeed * cos(theta), gameParams.ballSpeed * sin(theta)];
    ball = rectangle('Parent', ax, ...
                    'Position', [400, 200, gameParams.ballRadius*2, gameParams.ballRadius*2], ...
                    'FaceColor', [0.9, 0.9, 0.1], ...
                    'EdgeColor', 'none', ...
                    'Curvature', [1, 1]);
    
    % 创建砖块
    bricks = gobjects(gameParams.brickRows, gameParams.brickCols);
    brickColors = hsv(gameParams.brickRows);  % 每行不同颜色
    
    for r = 1:gameParams.brickRows
        for c = 1:gameParams.brickCols
            brickX = (c-1) * (gameParams.brickWidth + gameParams.brickPadding);
            brickY = 550 - (r-1) * (gameParams.brickHeight + gameParams.brickPadding);
            bricks(r,c) = rectangle('Parent', ax, ...
                                   'Position', [brickX, brickY, gameParams.brickWidth, gameParams.brickHeight], ...
                                   'FaceColor', brickColors(r,:), ...
                                   'EdgeColor', 'w');
        end
    end
    
    % 创建文本显示
    scoreText = text(ax, 20, 580, sprintf('得分: %d', gameParams.score), ...
                    'Color', 'w', 'FontSize', 12);
    livesText = text(ax, 700, 580, sprintf('生命: %d', gameParams.lives), ...
                    'Color', 'w', 'FontSize', 12);
    startText = text(ax, 400, 300, '点击开始游戏', ...
                    'Color', 'w', 'FontSize', 24, ...
                    'HorizontalAlignment', 'center');
    
    % 游戏状态变量
    gameState = struct(...
        'isRunning', false, ...    % 游戏是否进行中
        'paddleDir', 0, ...        % 挡板移动方向 (-1:左, 0:停止, 1:右)
        'paddleSpeed', 15, ...     % 挡板移动速度
        'activeBricks', true(gameParams.brickRows, gameParams.brickCols) ... % 活跃砖块
    );
    
    % 键盘控制回调函数
    function keyDown(~, event)
        switch event.Key
            case 'leftarrow'
                gameState.paddleDir = -1;
            case 'rightarrow'
                gameState.paddleDir = 1;
            case 'escape'
                gameState.isRunning = false;
        end
    end
    
    function keyUp(~, event)
        switch event.Key
            case {'leftarrow', 'rightarrow'}
                gameState.paddleDir = 0;
        end
    end
    
    % 鼠标点击开始游戏
    function mouseClick(~, ~)
        if ~gameState.isRunning
            gameState.isRunning = true;
            delete(startText);
            startText = [];
        end
    end
    
    % 主游戏循环
    while ishandle(fig)
        if gameState.isRunning
            % 更新挡板位置
            paddlePos = get(paddle, 'Position');
            newX = paddlePos(1) + gameState.paddleSpeed * gameState.paddleDir;
            
            % 限制挡板不超出边界
            newX = max(0, min(newX, 800 - gameParams.paddleWidth));
            set(paddle, 'Position', [newX, paddlePos(2), paddlePos(3), paddlePos(4)]);
            
            % 更新球位置
            ballPos = get(ball, 'Position');
            newBallX = ballPos(1) + ballVel(1);
            newBallY = ballPos(2) + ballVel(2);
            
            % 检测碰撞
            [ballVel, gameParams, gameState] = checkCollisions(...
                [newBallX, newBallY], ballVel, gameParams, gameState, paddle, bricks);
            
            % 更新球位置
            set(ball, 'Position', [newBallX, newBallY, ballPos(3), ballPos(4)]);
            
            % 更新文本显示
            set(scoreText, 'String', sprintf('得分: %d', gameParams.score));
            set(livesText, 'String', sprintf('生命: %d', gameParams.lives));
            
            % 检查游戏结束条件
            if newBallY < 0  % 球落到底部
                gameParams.lives = gameParams.lives - 1;
                if gameParams.lives <= 0
                    gameState.isRunning = false;
                    text(ax, 400, 300, '游戏结束!', ...
                        'Color', 'r', 'FontSize', 36, ...
                        'HorizontalAlignment', 'center');
                else
                    % 重置球位置
                    set(ball, 'Position', [400, 200, gameParams.ballRadius*2, gameParams.ballRadius*2]);
                    theta = rand * 2 * pi;
                    ballVel = [gameParams.ballSpeed * cos(theta), gameParams.ballSpeed * sin(theta)];
                    pause(1);
                end
            end
            
            % 检查胜利条件
            if ~any(gameState.activeBricks(:))
                gameState.isRunning = false;
                text(ax, 400, 300, '恭喜通关!', ...
                    'Color', 'g', 'FontSize', 36, ...
                    'HorizontalAlignment', 'center');
            end
        end
        
        % 控制帧率
        pause(0.02);
    end
    
    % 碰撞检测函数
    function [newVel, gameParams, gameState] = checkCollisions(ballPos, ballVel, gameParams, gameState, paddle, bricks)
        % 获取球参数
        ballX = ballPos(1) + gameParams.ballRadius;
        ballY = ballPos(2) + gameParams.ballRadius;
        
        % 边界碰撞检测
        if ballX <= gameParams.ballRadius || ballX >= 800 - gameParams.ballRadius
            ballVel(1) = -ballVel(1);  % 水平反转
        end
        if ballY >= 600 - gameParams.ballRadius
            ballVel(2) = -ballVel(2);  % 垂直反转
        end
        
        % 挡板碰撞检测
        paddlePos = get(paddle, 'Position');
        if ballY <= paddlePos(2) + paddlePos(4) + gameParams.ballRadius && ...
           ballY >= paddlePos(2) && ...
           ballX >= paddlePos(1) - gameParams.ballRadius && ...
           ballX <= paddlePos(1) + paddlePos(3) + gameParams.ballRadius
            
            % 计算碰撞点相对于挡板中心的位置 (-1到1)
            hitPos = (ballX - (paddlePos(1) + paddlePos(3)/2)) / (paddlePos(3)/2);
            
            % 根据碰撞点调整反射角度
            maxAngle = pi/3;  % 最大反射角度 (60度)
            angle = hitPos * maxAngle;
            
            % 计算新速度向量
            speed = norm(ballVel);
            ballVel = [speed * sin(angle), speed * cos(angle)];
            
            % 增加一点速度让游戏更有挑战性
            ballVel = ballVel * 1.02;
        end
        
        % 砖块碰撞检测
        for r = 1:gameParams.brickRows
            for c = 1:gameParams.brickCols
                if gameState.activeBricks(r,c)
                    brickPos = get(bricks(r,c), 'Position');
                    
                    % 检查球是否与砖块相交
                    if ballX + gameParams.ballRadius > brickPos(1) && ...
                       ballX - gameParams.ballRadius < brickPos(1) + brickPos(3) && ...
                       ballY + gameParams.ballRadius > brickPos(2) && ...
                       ballY - gameParams.ballRadius < brickPos(2) + brickPos(4)
                        
                        % 确定碰撞边 (简化版)
                        if ballY < brickPos(2) || ballY > brickPos(2) + brickPos(4)
                            ballVel(2) = -ballVel(2);  % 上下碰撞
                        else
                            ballVel(1) = -ballVel(1);  % 左右碰撞
                        end
                        
                        % 标记砖块为不活跃并隐藏
                        gameState.activeBricks(r,c) = false;
                        set(bricks(r,c), 'Visible', 'off');
                        
                        % 增加分数
                        gameParams.score = gameParams.score + 10;
                        
                        % 只需要处理一次碰撞
                        break;
                    end
                end
            end
        end
        
        newVel = ballVel;
    end
end

来看看我这个菜鸡玩了一局的效果,屏幕前的你也可以试试看看能的多少分~
在这里插入图片描述

6. 游戏操作说明 🎮

  • 左右箭头键:移动挡板
  • ESC键:退出游戏
  • 鼠标点击:开始游戏

7. 扩展思路 💡

如果你想进一步提升这个游戏,可以考虑:

  1. 增加音效:使用audioplayer添加碰撞音效
  2. 多种砖块:不同颜色砖块需要多次击中才能消除
  3. 特殊道具:球碰到某些砖块会掉落道具,如加长挡板、额外生命等
  4. 关卡设计:设计不同布局的砖块排列
  5. 粒子效果:砖块消除时添加爆炸效果

希望你喜欢这个MATLAB打砖块游戏教程!通过这个项目,你不仅学会了向量反射的原理,还掌握了实时物理模拟和游戏开发的基本技巧。Happy coding! 🚀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2373497.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue配置代理解决前端跨域的问题

文章目录 一、概述二、报错现象三、通过配置代理来解决修改request.js中的baseURL为/api在vite.config.js中增加代理配置 四、参考资料 一、概述 跨域是指由于浏览器的同源策略限制&#xff0c;向不同源(不同协议、不同域名、不同端口)发送ajax请求会失败 二、报错现象 三、…

java+vert.x实现内网穿透jrp-nat

用java vert.x开发一个内网穿透工具 内网穿透概述技术原理常见内网穿透工具用java vert.x开发内网穿透工具 jrp-nat为什么用java开发内网穿透工具&#xff1f;jrp-nat功能实现图解jrp-nat内网穿透工具介绍jrp-nat内网穿透工具特点jrp-nat软件架构jrp-nat安装教程jrp-nat程序下载…

【程序员AI入门:应用开发】8.LangChain的核心抽象

一、 LangChain 的三大核心抽象 1. ChatModel&#xff08;聊天模型&#xff09; 核心作用&#xff1a;与大模型&#xff08;如 GPT-4、Claude&#xff09;交互的入口&#xff0c;负责处理输入并生成输出。关键功能&#xff1a; 支持同步调用&#xff08;model.invoke&#xf…

每天五分钟机器学习:KTT条件

本文重点 在前面的课程中,我们学习了拉格朗日乘数法求解等式约束下函数极值,如果约束不是等式而是不等式呢?此时就需要KTT条件出手了,KTT条件是拉格朗日乘数法的推广。KTT条件不仅统一了等式约束与不等式约束的优化问题求解范式,KTT条件给出了这类问题取得极值的一阶必要…

Facebook的元宇宙新次元:社交互动如何改变?

科技的浪潮正将我们推向一个全新的时代——元宇宙时代。Facebook&#xff0c;这个全球最大的社交网络平台&#xff0c;已经宣布将公司名称更改为 Meta&#xff0c;全面拥抱元宇宙概念。那么&#xff0c;元宇宙究竟是什么&#xff1f;它将如何改变我们的社交互动方式呢&#xff…

概统期末复习--速成

随机事件及其概率 加法公式 推三个的时候ABC&#xff0c;夹逼准则 减法准则 除法公式 相互独立定义 两种分析 两个解法 古典概型求概率&#xff08;排列组合&#xff09; 分步相乘、分类相加 全概率公式和贝叶斯公式 两阶段问题 第一个小概率*A在小概率的概率。。。累计 …

n8n系列(1)初识n8n:工作流自动化平台概述

1. 引言 随着各类自动化工具的涌现,n8n作为一款开源的工作流自动化平台,凭借其灵活性、可扩展性和强大的集成能力,正在获得越来越多技术团队的青睐。 本文作为n8n系列的开篇,将带您全面了解这个强大的自动化平台,探索其起源、特性以及与其他工具的差异,帮助您判断n8n是否…

QT6 源(82):阅读与注释日历类型 QCalendar,本类并未完结,儒略历,格里高利历原来就是公历,

&#xff08;1&#xff09;本代码来自于头文件 qcalendar . h &#xff1a; #ifndef QCALENDAR_H #define QCALENDAR_H#include <limits>#include <QtCore/qglobal.h> #include <QtCore/qlocale.h> #include <QtCore/qstring.h> #include <QtCore/…

CVE体系若消亡将如何影响网络安全防御格局

CVE体系的核心价值与当前危机 由MITRE运营的通用漏洞披露&#xff08;CVE&#xff09;项目的重要性不容低估。25年来&#xff0c;它始终是网络安全专业人员理解和缓解安全漏洞的基准参照系。通过提供标准化的漏洞命名与分类方法&#xff0c;这套体系为防御者建立了理解、优先级…

OpenKylin安装Elastic Search8

一、环境准备 Java安装 安装过程此处不做赘述&#xff0c;使用以下命令检查是否安装成功。 java -version 注意&#xff1a;Elasticsearch 自 7.0 版本起内置了 OpenJDK&#xff0c;无需单独安装。但如需自定义 JDK&#xff0c;可设置 JAVA_HOME。 二、安装Elasticsearch …

【ARM AMBA AHB 入门 3 -- AHB 总线介绍】

请阅读【ARM AMBA 总线 文章专栏导读】 文章目录 AHB Bus 简介AHB Bus 构成AHB BUS 工作机制AHB 传输阶段 AHB InterfacesAHB仲裁信号 AHB 数据访问零等待传输(no waitstatetransfer)等待传输(transfers with wait states)多重传送(multipletransfer)--Pipeline AHB 控制信号 A…

多模态大模型中的视觉分词器(Tokenizer)前沿研究介绍

文章目录 引言MAETok背景方法介绍高斯混合模型&#xff08;GMM&#xff09;分析模型架构 实验分析总结 FlexTok背景方法介绍模型架构 实验分析总结 Emu3背景方法介绍模型架构训练细节 实验分析总结 InternVL2.5背景方法介绍模型架构 实验分析总结 LLAVA-MINI背景方法介绍出发点…

sqli-labs靶场第二关——数字型

一&#xff1a;查找注入类型&#xff1a; 输入 ?id1--与第一关的差别&#xff1a;报错; 说明不是字符型 渐进测试&#xff1a;?id1--&#xff0c;结果正常&#xff0c;说明是数字型 二&#xff1a;判断列数和回显位 ?id1 order by 3-- 正常&#xff0c; 说明有三列&am…

[模型选择与调优]机器学习-part4

七 模型选择与调优 1 交叉验证 (1) 保留交叉验证HoldOut HoldOut Cross-validation&#xff08;Train-Test Split&#xff09; 在这种交叉验证技术中&#xff0c;整个数据集被随机地划分为训练集和验证集。根据经验法则&#xff0c;整个数据集的近70%被用作训练集&#xff…

【计算机网络-数据链路层】以太网、MAC地址、MTU与ARP协议

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 上篇文章&#xff1a;传输层-TCP协议TCP核心机制与可靠性保障 下篇文章&#xff1a; 网络…

Kafka 与 RabbitMQ、RocketMQ 有何不同?

一、不同的诞生背景&#xff0c;塑造了不同的“性格” 名称 背景与目标 产品定位 Kafka 为了解决 LinkedIn 的日志收集瓶颈&#xff0c;强调吞吐与持久化 更像一个“可持久化的分布式日志系统” RabbitMQ 出自金融通信协议 AMQP 的实现&#xff0c;强调协议标准与广泛适…

【MATLAB源码-第277期】基于matlab的AF中继系统仿真,AF和直传误码率对比、不同中继位置误码率对比、信道容量、中继功率分配以及终端概率。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 在AF&#xff08;放大转发&#xff09;中继通信系统中&#xff0c;信号的传输质量和效率受到多个因素的影响&#xff0c;理解这些因素对于系统的优化至关重要。AF中继通信的基本架构由发射端、中继节点和接收端组成。发射端负…

webRtc之指定摄像头设备绿屏问题

摘要&#xff1a;最近发现&#xff0c;在使用navigator.mediaDevices.getUserMedia({ deviceId: ‘xxx’}),指定设备的时候&#xff0c;video播放总是绿屏&#xff0c;发现关闭浏览器硬件加速不会出现&#xff0c;但显然这不是一个最好的方案; 播放后张这样 修复后 上代码 指定…

2023年03月青少年软件编程(图形化)等级考试四级编程题

求和 1.准备工作 &#xff08;1&#xff09;保留舞台中的小猫角色和白色背景。 2.功能实现 &#xff08;1&#xff09;计算1&#xff5e;100中&#xff0c;可以被3整除的数之和&#xff1b; &#xff08;2&#xff09;说出被3整除的数之和。 标准答案&#xff1a; 参考程序&…

ensp的华为小实验

1.先进行子网划分 2.进行接口的IP地址配置和ospf的简易配置&#xff0c;先做到全网小通 3.进行ospf优化 对区域所有区域域间路由器进行一个汇总 对区域1进行优化 对区域2.3进行nssa设置 4.对ISP的路由进行协议配置 最后ping通5.5.5.5