基础项目实战——3D赛车(c++)

news2025/1/30 14:13:36

目录

  • 前言
  • 一、渲染引擎
  • 二、关闭事件
  • 三、梯形绘制
  • 四、轨道绘制
  • 五、边缘绘制
  • 六、草坪绘制
  • 七、前后移动
  • 八、左右移动​
  • 九、曲线轨道​
  • 十、课山坡轨道​
  • 十一、循环轨道​
  • 十二、背景展示​
  • 十三、引入速度​
  • 十四、物品绘制​
  • 十五、课数字路障​
  • 十六、分数展示​
  • 十七、重新生成​
  • 十八、跳跃功能​
  • 十九、课音效播放
  • 二十、音乐播放​
  • 二十一、音乐切换​

前言

这一期我们一起学期3d赛车这个项目实战,这个项目比之前的那几个难度高了很多,所以做起来会比较复杂,里面会涉及一些数学思想。这个项目做完了之后非常有意思还是值得一做的。

完整工程文件,提取码为1111
(蓝色字体可以点进去)

一、渲染引擎

做这个项目我们要自己到网上下载一些库,要配置环境。所以配置环境可以看我上一期扫雷(蓝色字体可以点进去)

#include <SFML/Graphics.hpp>
using namespace sf;const int WinWidth = 1024;const int WinHeight = 768;int main() {​
RenderWindow win(VideoMode(WinWidth, WinHeight), "Racing");​
    win.setFramerateLimit(60);  // 设置帧率为 60 帧​   
while (win.isOpen()) {}return 0;
}

运行之后我不得到一个不可以移动的窗口。

二、关闭事件

这样就可以关闭和移动窗口了。

    while (win.isOpen()) {​
        Event e;while (win.pollEvent(e)) {if (e.type == Event::Closed) {​
                win.close();}}}

三、梯形绘制

这个梯形就代表每一块道路的图案


void DrawTrape(RenderWindow& window, Color c, int x1, int y1, int w1, int x2, int y2, int w2) {
	ConvexShape polygon(4);//梯形的四个定点
	polygon.setFillColor(c);//设置梯形填充的颜色
	polygon.setPoint(0, Vector2f(x1 - w1, y1));
	polygon.setPoint(1, Vector2f(x2 - w2, y2));
	polygon.setPoint(2, Vector2f(x2 + w2, y2));
	polygon.setPoint(3, Vector2f(x1 + w1, y1));
	window.draw(polygon);
}


win.clear();DrawTrape(win, Color::White, WinWidth / 2, 500, 200, WinWidth / 2, 300, 100);​
        win.display();

在这里插入图片描述

四、轨道绘制

const int roadWidth = 1800;
const int roadSegLength = 180;
const int roadCount = 1884;

对于每个轨道,用一个结构体来实现,小写的 x,y,z 代表,每个轨道的中心,在 3D 世界中的坐标,大写的 X 和 Y,则是 3D 映射到 2D 时的屏幕坐标,大写的 W 代表这条轨道映射到屏幕后,它的宽度。​
实现一个带参构造函数,利用初始化列表进行初始化。​
然后实现一个 project 函数,代表 3D 到 2D 的映射,camX,camY,camZ 代表的是 3D 相机的位置,接下来我会讲一些数学的概念。听不懂没有关系,只要你能够自己跟着把代码写出来,并且通过修改每个参数,运行后得到你想要的效果就可以了。不用太计较这里的数学计算。​
首先,当相机位置 camZ 确定时,z 越大,那么这条轨道就应该越小,所以实现这么一个反比例函数,计算缩放比例 scale。​
利用这个缩放比例,可以计算出 X 和 Y,像这样。​
最后计算 W,也就是每个轨道的实际屏幕宽度,和 scale 强相关,所以作为系数乘上去。

struct Road {float x, y, z;float X, Y, W;float scale;Road(int _x, int _y, int _z): x(_x), y(_y), z(_z) {}void project(int camX, int camY, int camZ) {​
        scale = 1.0 / (z - camZ);​
        X = (1 + (x - camX) * scale) * WinWidth / 2;​
        Y = (1 - (y - camY) * scale) * WinHeight / 2;​
        W = scale * roadWidth * WinWidth / 2;}};

定义一个轨道的 vector,每个轨道的 x 和 y 都是 0,z 坐标按照 i 进行平铺。​

    vector<Road> roads;for (int i = 0; i < roadCount; ++i) {​
Road r(0, 0, (i+1) * roadSegLength);​
        roads.push_back(r);}

因为近大远小的关系,所以屏幕上只显示 300 个轨道,对于每个轨道,调用 project 计算投影,传入的是相机的位置,其中 y 代表竖直方向,设定为 1600。​
获取当前轨道和前一个轨道,分别为 now 和 pre,利用这两个轨道,可以计算出一个梯形,并且设置好颜色,稍微做点差异化,产生相间的效果。运行看下效果。​

 
for (int i = 0; i < 300; ++i) {​
            Road& now = roads[i % roadCount];​
            now.project(0, 1600, 0);if (!i) {continue;}​
            Road& pre = roads[(i - 1) % roadCount];​
            Color road = i % 2 ? Color(105, 105, 105) :DrawTrape(win, road, pre.X, pre.Y, pre.W, now.X, now.Y, now.W);}

当然,可以在 i 这里除上一个数,使得两个颜色区分的时候,不会那么密集。看下效果。这里如果你不理解,怎么办呢?你就多试几个数字,试着试着感觉就有了。​

Color road = (i/3) % 2 ? Color(105, 105, 105) : Color(101, 101, 101);

五、边缘绘制

Color edge = (i/3) % 2 ? Color(0, 0, 0) : Color(255, 255, 255);
DrawTrape(win, edge, pre.X, pre.Y, pre.W*1.3, now.X, now.Y, now.W*1.3);

六、草坪绘制

Color grass = i / 3 % 2 ? Color(16, 210, 16) : Color(0, 199, 0);
DrawTrape(win, grass, pre.X, pre.Y, WinWidth, now.X, now.Y, WinWidth);

七、前后移动

    for (int i = 0; i < roadCount; ++i) {​
Road r(0, 0, (i+1) * roadSegLength);​
        roads.push_back(r);}int cameraZ = 0;while (win.isOpen()) {if (Keyboard::isKeyPressed(Keyboard::Up)) cameraZ += roadSegLength;if (Keyboard::isKeyPressed(Keyboard::Down)) cameraZ -= roadSegLength;​
        win.clear();int roadIndex = cameraZ / roadSegLength;for (int i = roadIndex; i < roadIndex + 300; ++i) {​
            Road& now = roads[i % roadCount];​
            now.project(0, 1600, cameraZ );

八、左右移动​

除了前后移动,左右也可以移动。同样是控制相机的坐标,定义 cameraX 代表相机的 x坐标。​

int cameraZ = 0;int cameraX = 0;

分别按下左键和右键时,更改 cameraX 的值。​

if (Keyboard::isKeyPressed(Keyboard::Left)) cameraX -= 100;
if (Keyboard::isKeyPressed(Keyboard::Right)) cameraX += 100;


然后在这里把 cameraX 代替原来 0 的值。​

now.project(cameraX, 1600, cameraZ);

运行,发现露馅了。​没事,宽度乘10就好了。​

DrawTrape(win, grass, pre.X, pre.Y, 10*WinWidth, now.X, now.Y, 10*WinWidth);

九、曲线轨道​

这节课我们想办法让这条路,能够变成弯的,看起来更加的真实,在原来的路上,加上一个曲线因子。​

float scale, curve;Road(int _x, int _y, int _z, float _c): x(_x), y(_y), z(_z), curve(_c) {}



然后在实例化 Road 的时候,当 i 在 0 到 300 之间,曲线因子就是 0.5,否则就是负的 0.5。构造的时候,传参传进去。​

float curve =  (i > 0 && i < 300) ? 0.5 : -0.5;​

Road r(0, 0, (i+1) * roadSegLength, curve);

然后定义一个 x 和 dx,初始化都为 0,这段代码怎么去理解呢?这里的 now.curve 就理解成加速度,那么 dx 就是速度,而 x 就是位移,这样这条路弯曲起来就看起来非常的连续了,看下效果。​

int roadIndex = cameraZ / roadSegLength;float x = 0, dx = 0;for (int i = roadIndex; i < roadIndex + 300; ++i) {​
            Road& now = roads[i % roadCount];​
            now.project(cameraX - x, 1600, cameraZ);​
            x += dx;​
            dx += now.curve;

十、课山坡轨道​

然后我希望这个轨道,有一种跌宕起伏的感觉,三角函数可以做到这一点,所以每个轨道的中心的 y 坐标,用一个三角函数 sin 来实现,振幅 1600,像这样:​

相机的位置从 1600 作为基准,再加上起始轨道的 y 坐标,像这样。​

int cameraY = 1600 + roads[roadIndex].y;int minY = WinHeight;


这里的 1600 就可以改成这个 cameraY 了。所以这个 cameraY 的范围,就根据正弦函数的值,变成了 0 到 3200。​

now.project(cameraX - x, cameraY, cameraZ);

这时候我们发现,效果好像不对,问题出在哪里呢?​
原因是这样的。​
需要注意的是,一旦出现跌宕起伏,那么如果出现一个 Y 值最小的轨道,后面比 Y 值大的轨道,就不应该被绘制出来,注意这里用的屏幕坐标系,所以越往上值越小。​

int roadIndex = cameraZ / roadSegLength;
float x = 0, dx = 0;int cameraY = 1600 + roads[roadIndex].y;int minY = WinHeight;

那么判断当前的 Y 是否比最小的 Y 小,如果小,那么记录这个最小值;否则直接 continue,代表这条轨道不用绘制,来看看效果。​

if (now.Y < minY) {​

                minY = now.Y;else {continue;}

十一、循环轨道​

然后我们希望整条路,能够产生循环,这样就可以,用有限的 Road 对象来展现无限的路。​
计算这条路的总长度 totalLength,如果发现 cameraZ 的位置已经大于总长度了,就减去总长度,如果小于总长度,就变成负数了,那么加上总长度。​
其实就是让 cameraZ 的值,始终保持在 [0, totalLength) 之间。​

int totalLength = roadCount * roadSegLength;while (cameraZ >= totalLength) cameraZ -= totalLength;while (cameraZ < 0) cameraZ += totalLength;
now.project(cameraX - x, cameraY, cameraZ - (i >= roadCount ? totalLength : 0) );

然后你会发现,这里出现了一些断层,这个不是很合理。​
根据 PI 计算一下,roadCount 让它是 3.14 的倍数就好了,那就 3.14 乘上 600,变成 1884 ,看下效果。​

const int roadCount = 1884;

十二、背景展示​

准备一张云的图片,加载一个纹理,并且生成一个精灵。宽度是窗口宽度,高度是窗口高度的一半。​

    Texture bg;​
    bg.loadFromFile("cloud.png");​
Sprite s(bg, IntRect(0, 0, WinWidth, WinHeight/2));

然后在每次绘制轨道的时候,把它绘制出来。​

if (now.Y < minY) {​
                minY = now.Y;}else {continue;}​
win.draw(s);

十三、引入速度​

引入一个赛车前进的速度,speed 初始化为 0。​

int cameraZ = 0;int cameraX = 0;int speed = 100;

当键盘按下 UP 和 DOWN 的时候,不再修改 cameraZ 的值,而是修改速度的值,然后最终,cameraZ 把这个速度累加上就好了。​
这样一来,往前往后,修改的就是速度,不再是位移。​

if (Keyboard::isKeyPressed(Keyboard::Up)) {​
if (speed > 1000) speed = 1000;​
}​
if (Keyboard::isKeyPressed(Keyboard::Down)) {​
speed -= 2;​
if (speed < 100) speed = 100;​
}​
cameraZ += speed;

十四、物品绘制​

接下来在这条路上,间隔的绘制物品,每个物品在图片的宽高是 450,这个作为常量,根据你图片的大小,进行修改即可。​

const int itemSize = 450;

Road 的结构体中,定义一个精灵 spr。​

struct Road {float x, y, z;float scale, curve;​
    Sprite spr;

实现一个 drawItem 的函数,设置好纹理的矩形,缩放比例,以及位置,位置的计算方式比较简单,X 坐标和这条路保持一致,Y 坐标减去 W。然后给它绘制出来。​

    s.setScale(W / itemSize, W / itemSize);​
    s.setPosition(X, Y - W);​
    win.draw(s);}

然后定义一个物品的纹理对象,加载对应的图片,生成一个精灵对象。​

    Texture item;​
    item.loadFromFile("item.png");​
Sprite sitem(item);

把精灵对象通过传参,传到 Road 对象中。​

Road r(0, sin(i/30.0)*1600, (i + 1) * roadSegLength, curve, sitem);


然后一个 for 循环,注意从后往前绘制,否则遮挡关系会不对。为了不产生密集恐惧症,我们可以 % 上一个 20,每 20 个轨道,出现一个物品。​

for (int i = roadIndex + 300; i > roadIndex; --i) {if (i % 20 == 0)​
                roads[i % roadCount].drawItem(win);}
 Road r(0, 0, (i + 1) * roadSegLength, curve, sitem);

十五、课数字路障​

我们把路上的这些物品,显示成一些不同的数字,有数字,有符号。​
首先定义这么一个字符串,和这张图片中的每个图片一一对应。​

const char charItem[] = "1234567890+*/-%";

然后在 Road 中定义两个变量,operatorIndex 代表符号在 charItem 中的下标,numberIndex 代表数字 charItem 中的下标。​

int operatorIndex;int numberIndex;


接下来就可以开始初始化了,为了数字不会太密集,采用随机数的方式,如果是 200 的倍数,才出现物品。同样是通过随机的方式,尽量不出现 0,因为 除 0 和 模 0 都没意义。​
operatorIndex 等于 -1 代表这个 Road 上没有东西。​

    Road(int _x, int _y, int _z, float _c, Sprite _spr): x(_x), y(_y), z(_z), curve(_c), spr(_spr){if (rand() % 200 == 0) {​
            operatorIndex = (rand() % 5) + 10;​
            numberIndex = rand() % 10;if (numberIndex == 9) {​
                numberIndex = 0;}}else {​
            operatorIndex = -1;}}

然后我们重载原先的 drawItem,并且加入一个新的参数 ,index 代表的是 charItem 中的下标,xPlacement 则表示 x 方向的偏移。然后 left 和 top 则代表的是在这张图上的(对应数字或者符号)的左上角坐标。​

void drawItem(RenderWindow& win, int index, int xPlacement) {​
        Sprite s = spr;int left = (index % 5) * itemSize;int top = (index / 5) * itemSize;​
        s.setTextureRect(IntRect(left, top, itemSize, itemSize));​
        s.setScale(W / itemSize, W / itemSize);​
        s.setPosition(X + xPlacement*W, Y - W);​
        win.draw(s);}void drawItem(RenderWindow& win) {if (operatorIndex == -1) {return;}drawItem(win, operatorIndex, -1);drawItem(win, numberIndex, 0);}


这里的取模就可以去掉了。​

for (int i = roadIndex + 300; i > roadIndex; --i) {​
            roads[i % roadCount].drawItem(win);}

十六、分数展示​

我们在窗口的左上角,展示一个分数,并且还是这张图片。先定义一个分数 score,尽量考虑到所有情况,所以初始化 - 的 1234567890。​

然后实现一个 DrawNumber 函数,sItem 代表数字对应那个精灵,x 和 y 代表显示在屏幕的左上角坐标。然后把 number 转换成字符串,存储到 ch 中。​
遍历这个字符串,并且去 charItem 中找到对应的下标,利用相同的绘制方式,把它绘制在屏幕上。​

void DrawNumber(RenderWindow& win, Sprite sItem, int number, int x, int y) {char ch[100] = {'\0'};_itoa_s(number, ch, 10);int len = strlen(ch);for (int i = 0; i < len; ++i) {​
        Sprite s = sItem;int index = -1;for (int j = 0; charItem[j]; ++j) {if (charItem[j] == ch[i]) {​
                index = j;break;}}int left = (index % 5) * itemSize;int top = (index / 5) * itemSize;​
        s.setTextureRect(IntRect(left, top, itemSize, itemSize));​
        s.setScale(0.18, 0.18);​
        s.setPosition(x + 0.13 * itemSize * i, y);​
        win.draw(s);}}


然后调用即可。​

    s.setTextureRect(IntRect(0, 0, WinWidth, minY));​
            win.draw(s);DrawNumber(win, sitem, score, 10, 10);

十七、重新生成​

如果每次路过都把数字清空,那么迟早有一天,路上就没有数字了,于是实现一个重新生成的接口,这里做一点小改动,这个 Road 一开始,是通过随机计算的。​
当然,如果 generateItem 直接传一个 true,那么必定产生数字。​

Road(int _x, int _y, int _z, float _c, Sprite _spr): x(_x), y(_y), z(_z), curve(_c), spr(_spr){generateItem(false);}void generateItem(bool bAlwaysGen) {if (bAlwaysGen || rand() % 200 == 0) {​
            operatorIndex = (rand() % 5) + 10;​
            numberIndex = rand() % 10;if (numberIndex == 9) {​
                numberIndex = 0;}}else {​
            operatorIndex = -1;}}

所以当前这条路如果正好出屏幕外,那么就把 i + 1500 的轨道,生成一个新的数字。​

now.operatorIndex = -1;​
roads[(i + 1500) % roadCount].generateItem(

十八、跳跃功能​

为了增加趣味性,可以引入跳跃功能,从而可以跳过这个数字。加入一个状态叫 isJumping ,一开始是 false,代表没有跳跃。​
跳跃会改变 z 的坐标,所以 z 代表实际偏移的 z ,dz 代表跳跃时的速度。​

bool isJumping = false;float z = 0, dz = 0;


如果按下空格,当非跳跃状态,则切换到跳跃状态,并且把起跳速度设置为 150。​

if (Keyboard::isKeyPressed(Keyboard::Space)) {if (isJumping == false) {​
                isJumping = true;​
                dz = 150;}}


然后如果一直在跳跃中,则减去 5,这里就是在模拟自由落体,这里的 5 就是加速度,然后 z 累加 dz 的过程,就是模拟的 位移 和 速度,当 z 小于等于 0,说明落地了,isJumping 置为 false。​

if (isJumping) {​
            dz -= 5;​
            z += dz;if (z <= 0) {​
                z = 0;​
                isJumping = false;}}


最后,当遇到数字的时候,如果非跳跃状态,才会生效,否则没有任何效果。​

if (now.Y >= WinHeight) {if (!isJumping && now.operatorIndex != -1) {​
                    score = caculateScore(score, now.operatorIndex, now.numberIndex);​
                    now.operatorIndex = -1;​
                    roads[(i + 1500) % roadCount].generateItem(true);}}

十九、课音效播放

接下来,我们加入一些音效,让游戏更加的带感。引入一个头文件。​

初始化三个音效缓存,分别代表 碰到数字、起跳、落地 音效。​

buffer[1].loadFromFile("jump.mp3"); ​
buffer[2].loadFromFile("falldown.mp3");


起跳可以这么写。​

if (isJumping == false) {​
                sound.setBuffer(buffer[1]);​
                sound.play();​
                isJumping = true;​
                dz = 150;}

落地可以这么写。​

if (z <= 0) {​
                z = 0;​
                isJumping = false;​
                sound.setBuffer(buffer[2]);​
                sound.play();}

碰到数字可以这么写。​

if (!isJumping && now.operatorIndex != -1) {​
                    score = caculateScore(score, now.operatorIndex, now.numberIndex);​
                    now.operatorIndex = -1;​
                    roads[(i + 1500) % roadCount].generateItem(true);​
                    sound.setBuffer(buffer[0]);​
                    sound.play();}

二十、音乐播放​

再加上一个 bgm。​

 SoundBuffer buffer[5];​
    Sound sound, bgm;​
    buffer[0].loadFromFile("get.mp3");​
    buffer[1].loadFromFile("jump.mp3"); ​
    buffer[2].loadFromFile("falldown.mp3");​
    buffer[3].loadFromFile("tianfuyue.mp3");​
    buffer[4].loadFromFile("liumaishenjian.mp3");


在窗口 while 之前,调用 play 接口。​

bgm.setBuffer(buffer[3]);​
bgm.setLoop(true);​
bgm.play();

二十一、音乐切换​

音乐可以随着赛车的速度,进行切换,当开的快的时候,播放 4 号 音乐;否则,播放 5 号音乐。​

if (Keyboard::isKeyPressed(Keyboard::Up)) {​
            speed += 2;if (speed > 1000) speed = 1000;if (speed == 500) {​
                speed = 502;​
                bgm.setBuffer(buffer[4]);​
                bgm.play();}}if (Keyboard::isKeyPressed(Keyboard::Down)) {​
            speed -= 2;if (speed < 100) speed = 100;if (speed == 500) {​
                speed = 498;​
                bgm.setBuffer(buffer[3]);​
                bgm.play();}}

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

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

相关文章

【SpringBoot教程】Spring Boot + MySQL + HikariCP 连接池整合教程

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 在前面一篇文章中毛毛张介绍了SpringBoot中数据源与数据库连接池相关概念&#xff0c;今天毛毛张要分享的是关于SpringBoot整合HicariCP连接池相关知识点以及底层源码…

一文讲解Java中Object类常用的方法

在Java中&#xff0c;经常提到一个词“万物皆对象”&#xff0c;其中的“万物”指的是Java中的所有类&#xff0c;而这些类都是Object类的子类&#xff1b; Object主要提供了11个方法&#xff0c;大致可以分为六类&#xff1a; 对象比较&#xff1a; public native int has…

操作系统之输入输出

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

【Convex Optimization Stanford】Lec3 Function

【Convex Optimization Stanford】Lec3 Function 前言凸函数的定义对凸函数在一条线上的限制增值扩充&#xff1f; 一阶条件二阶条件一些一阶/二阶条件的例子象集和sublevel set关于函数凸性的扩展&#xff08;Jesen Inequality)保持函数凸性的操作非负加权和 & 仿射函数的…

【Linux探索学习】第二十七弹——信号(一):Linux 信号基础详解

Linux学习笔记&#xff1a; https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言&#xff1a; 前面我们已经将进程通信部分讲完了&#xff0c;现在我们来讲一个进程部分也非常重要的知识点——信号&#xff0c;信号也是进程间通信的一…

SpringBoot或SpringAI对接DeekSeek大模型

今日除夕夜&#xff0c;deepseek可是出尽了风头&#xff0c;但是我看网上还没有这方面的内容对接&#xff0c;官网也并没有&#xff0c;故而本次对接是为了完成这个空缺 我看很多的博客内容是流式请求虽然返回时正常的&#xff0c;但是他并不是实时返回&#xff0c;而是全部响应…

Funnel-Transformer:通过过滤序列冗余实现高效语言处理

摘要 随着语言预训练的成功&#xff0c;开发更具扩展性且能高效利用大量未标注数据的架构变得尤为重要。为了提高效率&#xff0c;我们研究了在维持完整token级别表示时的冗余问题&#xff0c;尤其是对于仅需要序列单向量表示的任务。基于这一直觉&#xff0c;我们提出了Funne…

【搜索回溯算法】:BFS的魔力--如何使用广度优先搜索找到最短路径

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;搜索回溯算法篇–CSDN博客 文章目录 一.广度优先搜索&#xff08;BFS&#xff09;解决最短路…

【算法】经典博弈论问题——威佐夫博弈 python

目录 威佐夫博弈(Wythoff Game)【模板】 威佐夫博弈(Wythoff Game) 有两堆石子&#xff0c;数量任意&#xff0c;可以不同&#xff0c;游戏开始由两个人轮流取石子 游戏规定&#xff0c;每次有两种不同的取法 1)在任意的一堆中取走任意多的石子 2)可以在两堆中同时取走相同数量…

CUDA学习-内存访问

一 访存合并 1.1 说明 本部分内容主要参考: 搞懂 CUDA Shared Memory 上的 bank conflicts 和向量化指令(LDS.128 / float4)的访存特点 - 知乎 1.2 share memory结构 图1.1 share memory结构 放在 shared memory 中的数据是以 4 bytes(即 32 bits)作为 1 个 word,依…

力扣动态规划-13【算法学习day.107】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;建议灵神的题单和代码随想录&#xff09;和记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关…

《剪映5.9官方安装包》免费自动生成字幕

&#xff08;避免失效建议存自己网盘后下载&#xff09;剪映5.9官方Win.Mac 链接&#xff1a;https://pan.xunlei.com/s/VOHc-Fg2XRlD50MueEaOOeW1A1?pwdawtt# 官方唯一的免费版&#xff0c;Win和Mac都有&#xff0c;此版本官方已下架&#xff0c;觉得有用可转存收藏&#xf…

Brave132 编译指南 Windows 篇:安装 Visual Studio 2022(二)

1. 引言 在着手编译 Brave 浏览器的 132 版本之前&#xff0c;构建一个完备的开发环境至关重要。Visual Studio 2022 作为一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;为 Brave 浏览器的编译提供了坚实的工具链和技术支持。它不仅提供了高效的代码编辑…

DBO-高斯回归预测matlab

蜣螂优化算法(Dung Beetle Optimizer, DBO)是一种新型的群智能优化算法&#xff0c;在2022年底提出&#xff0c;主要是受蜣螂的的滚球、跳舞、觅食、偷窃和繁殖行为的启发。 本次研究使用的是 Excel 格式的股票预测数据。数据集按照 8&#xff1a;1&#xff1a;1 的比例&#x…

2025美国大学生数学建模竞赛美赛E题成品参考论文(48页)(含模型,可运行代码,求解结果)

2025美国大学生数学建模竞赛E题成品参考论文 目录 一、问题重述 二、问题分析 三、模型假设 四、模型建立与求解 4.1问题1 4.1.1问题1思路分析 4.1.2问题1模型建立 4.1.3问题1代码&#xff08;仅供参考&#xff09; 4.1.4问题1求解结果&#xff08;仅供参考&…

VMware 中Ubuntu无网络连接/无网络标识解决方法【已解决】

参考文档 Ubuntu无网络连接/无网络标识解决方法_ubuntu没网-CSDN博客 再我们正常使用VMware时&#xff0c;就以Ubuntu举例可能有时候出现无网络连接&#xff0c;甚至出现无网络标识的情况&#xff0c;那么废话不多说直接上教程 环境&#xff1a;无网络 解决方案&#…

基于RIP的MGRE VPN综合实验

实验拓扑 实验需求 1、R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;其所有地址均配为公有IP地址&#xff1b; 2、R1和R5间使用PPP的PAP认证&#xff0c;R5为主认证方&#xff1b; R2与R5之间使用ppp的CHAP认证&#xff0c;R5为主认证方&#xff1b; R3与R5之间使用HDLC封…

Autosar-Os是怎么运行的?(Os基础模块)

写在前面&#xff1a; 入行一段时间了&#xff0c;基于个人理解整理一些东西&#xff0c;如有错误&#xff0c;欢迎各位大佬评论区指正&#xff01;&#xff01;&#xff01; 书接上文 Autosar-Os是怎么运行的&#xff1f;&#xff08;一&#xff09;-CSDN博客 目录 1.Resourc…

OPencv3.4.1安装及配置教程

来到GitHub上opencv的项目地址 https://github.com/opencv/opencv/releases/tag/3.4.1 以上资源包都是 OpenCV 3.4.1 版本相关资源&#xff0c;它们的区别如下&#xff1a; (1). opencv-3.4.1-android-sdk.zip&#xff1a;适用于 Android 平台的软件开发工具包&#xff08;SDK…

选择困难?直接生成pynput快捷键字符串

from pynput import keyboard# 文档&#xff1a;https://pynput.readthedocs.io/en/latest/keyboard.html#monitoring-the-keyboard # 博客(pynput相关源码)&#xff1a;https://blog.csdn.net/qq_39124701/article/details/145230331 # 虚拟键码(十六进制)&#xff1a;https:/…