从0到1:C++ 开启游戏开发奇幻之旅(一)

目录

为什么选择 C++ 进行游戏开发

性能卓越

内存管理精细

跨平台兼容性强

搭建 C++ 游戏开发环境

集成开发环境(IDE)

Visual Studio

CLion

图形库

SDL(Simple DirectMedia Layer)

SFML(Simple and Fast Multimedia Library)

C++ 游戏开发基础知识

面向对象编程(OOP)

内存管理

C++ 标准库(STL)


为什么选择 C++ 进行游戏开发

在游戏开发的广袤领域中,编程语言的选择犹如基石,奠定着整个项目的成败与走向。C++ 凭借其卓越的特性,在众多编程语言中脱颖而出,成为游戏开发的中流砥柱,深受开发者们的青睐。

性能卓越

游戏,尤其是大型 3A 游戏,对性能有着近乎苛刻的要求。每一次画面的渲染、每一个物理效果的模拟、每一次玩家操作的响应,都需要在极短的时间内完成,以确保游戏的流畅运行和玩家的沉浸体验。C++ 在性能方面的表现堪称惊艳。它允许开发者直接对内存进行操作,这意味着可以精准地控制数据的存储和读取位置,大大提高了数据的访问速度。在处理大量的图形数据、物理模拟数据以及音频数据时,这种直接内存操作的能力显得尤为关键。例如,在渲染一个复杂的 3D 游戏场景时,C++ 能够快速地将顶点数据、纹理数据等传递给图形处理器(GPU),从而实现高效的图形渲染,使得游戏画面更加细腻、逼真,帧率更加稳定。

不仅如此,C++ 的代码经过编译后,会直接转化为机器码,运行时无需解释器或虚拟机的介入,这使得它的执行速度大幅提升。与一些需要在虚拟机环境中运行的编程语言相比,C++ 能够更充分地利用计算机硬件的性能,减少了额外的性能开销。这种高效的执行速度,让游戏能够以更高的帧率运行,为玩家带来更加流畅、丝滑的游戏体验。在激烈的游戏对战中,每一帧的流畅都可能影响着玩家的操作和决策,C++ 的高性能无疑为游戏的竞技性和娱乐性提供了坚实的保障。

内存管理精细

内存管理是游戏开发中至关重要的一环。游戏在运行过程中,需要动态地分配和释放大量的内存,以存储各种游戏资源,如角色模型、场景地图、纹理贴图等。如果内存管理不善,就会导致内存泄漏、内存碎片化等问题,进而影响游戏的性能和稳定性,甚至可能导致游戏崩溃。C++ 赋予了开发者手动管理内存的能力,通过 new 和 delete 操作符(或者 malloc 和 free 函数),开发者可以精确地控制内存的分配和释放时机。这对于游戏开发来说意义重大。在创建和销毁游戏对象(如角色、道具等)时,能够准确地分配和回收内存,避免了内存的浪费和泄漏。在一个大型的多人在线游戏中,同时存在着大量的玩家角色和游戏道具,精细的内存管理可以确保游戏在长时间运行过程中,内存的使用始终保持在合理的范围内,保证游戏的稳定运行。

此外,C++ 还提供了智能指针(如 std::shared_ptr、std::unique_ptr 等)等工具,帮助开发者更方便地管理内存,减少手动管理内存带来的错误风险。智能指针能够自动跟踪对象的引用计数,当对象不再被使用时,自动释放其所占用的内存,有效地避免了内存泄漏的问题。在处理复杂的游戏对象层次结构和资源管理时,智能指针的使用可以大大简化代码,提高代码的可读性和可维护性。

跨平台兼容性强

在当今多元化的游戏市场中,跨平台开发已成为游戏开发者们必须面对的需求。玩家们使用着各种各样的设备和操作系统来玩游戏,包括 Windows、MacOS、Linux 等桌面操作系统,以及 iOS、Android 等移动操作系统,还有各种游戏主机。C++ 作为一种跨平台的编程语言,能够在多个操作系统和硬件平台上编译和运行。这意味着开发者可以使用相同的代码库,针对不同的平台进行简单的适配和优化,就能够创建出多个版本的游戏,大大减少了开发和维护的工作量。

许多流行的游戏引擎,如 Unreal Engine、Unity(底层部分也有 C++ 支持)、Cocos2d - x 等,都是基于 C++ 构建的。这些引擎提供了强大的跨平台支持,开发者可以借助这些引擎,轻松地将游戏移植到不同的平台上,实现一次开发,多平台发布。以 Unreal Engine 为例,它使用 C++ 作为核心编程语言,通过其提供的一系列工具和接口,开发者可以方便地将游戏部署到 PC、游戏机、移动设备等多种平台上,并且能够充分利用各个平台的硬件特性,为玩家提供一致的游戏体验。这种跨平台的能力,不仅扩大了游戏的受众范围,还提高了游戏的商业价值。

搭建 C++ 游戏开发环境

“工欲善其事,必先利其器”,搭建一个高效的开发环境是 C++ 游戏开发的首要任务。一个好的开发环境能够极大地提高开发效率,减少开发过程中的错误和麻烦。下面我们将详细介绍常用的开发工具和库,以及它们的安装和配置步骤。

集成开发环境(IDE)

Visual Studio

Visual Studio 是一款由微软开发的功能强大的集成开发环境,广泛应用于 Windows 平台下的 C++ 开发。它提供了丰富的功能,包括代码编辑、调试、智能感知、代码分析等,能够帮助开发者高效地编写和调试代码。

安装步骤如下:

  1. 进入 Visual Studio 官网 (https://visualstudio.microsoft.com/),选择下载 Windows 版,并选择 Community 2019 社区版本(社区版对于个人开发者和小型团队是免费的,功能也非常齐全,足以满足大多数游戏开发的需求)进行下载,保存软件到电脑中。
  1. 双击运行下载的安装文件,弹出安装界面,选择 “使用 C++ 的桌面开发” 这一选项,如需其他,自行勾选。点击安装按钮开始安装。安装时间会依据网速、电脑设备等因素而有所不同,在此期间可以稍作等待,或者做一些其他的事情。
  1. 安装成功后提示重启,点击重启完成剩余配置。
  1. 在开始菜单找到 Visual Studio 2019 并且点击运行,弹出初始界面,点击 “创建新项目” 按钮 ,如果出现 C++ 项目模板选项,证明安装成功,并可以创建 C++ 项目。
CLion

CLion 是一款由 JetBrains 开发的跨平台 C++ 集成开发环境,它以其智能的代码编辑、强大的调试功能和对多种构建系统的支持而受到开发者的喜爱。无论是在 Windows、MacOS 还是 Linux 系统上,CLion 都能提供一致的高效开发体验。

安装步骤如下:

  1. 首先,从 CLion 官网 (https://www.jetbrains.com/clion/download/) 下载 Clion 安装文件。
  1. 下载完成后,解压缩安装文件,并运行 clion.exe 文件(在 Windows 系统下)。
  1. 进入 Clion 的安装界面,可以选择自定义安装选项或者选择默认选项,然后点击 “Next” 按钮。
  1. 勾选用户协议并继续。
  1. 在安装选项中,可以选择安装路径、添加图标等信息,然后点击 “Install” 按钮。
  1. 安装完成后,进行一些配置才能使用 Clion。在 Clion 主界面中,点击 “File” 菜单,然后选择 “Settings” 选项;找到 “Build, Execution, Deployment” 选项,并选择 “CMake” 选项;在 “CMake” 选项中,设置 CMake 和编译器的路径,以及其他相关选项;设置完成后,点击 “Apply” 按钮保存更改;最后,在 Clion 中创建一个新项目,并将代码添加到项目中。

图形库

SDL(Simple DirectMedia Layer)

SDL 是一个跨平台的多媒体库,它提供了对音频、键盘、鼠标、游戏杆和图形硬件的低级访问,非常适合用于开发 2D 游戏和多媒体应用程序。SDL 的设计目标是简单易用,同时又具有足够的灵活性和强大的功能,能够满足不同类型游戏的开发需求。

安装步骤如下(以 Windows 系统为例):

  1. 从 SDL 官网 (https://www.libsdl.org/download-2.0.php) 下载对应操作系统版本的 SDL2 库。
  1. 解压文件,将下载的压缩包解压至任意位置,得到类似如下的目录结构:
SDL2-2.26.1/
├── include/
│   └── SDL2/
├── lib/
│   ├── x86/
│   │   ├── SDL2.dll
│   │   ├── SDL2main.lib
│   │   └── SDL2.lib
│   └── x64/
│       ├── SDL2.dll
│       ├── SDL2main.lib
│       └── SDL2.lib
└── share/└── doc/└── SDL2/
  1. 配置开发环境(以 Visual Studio 为例):打开 Visual Studio,创建一个新的 C++ 项目,在项目中右键单击 “项目名称”,选择 “属性”;在左侧选择 “C/C++” -> “常规”,在 “附加包含目录” 中添加 SDL2-2.26.1/include 目录;在左侧选择 “链接器” -> “常规”,在 “附加库目录” 中添加 SDL2-2.26.1/lib/x64(如果是 x86 项目,则选择 x86 目录)目录;在左侧选择 “链接器” -> “输入”,在 “附加依赖项” 中添加 SDL2.lib 和 SDL2main.lib;将 SDL2-2.26.1/lib/x64(或 x86)目录下的 SDL2.dll 文件复制到项目的输出目录(通常是 Debug 或 Release 文件夹)。
SFML(Simple and Fast Multimedia Library)

SFML 也是一个跨平台的 C++ 多媒体库,它提供了简单直观的 API,用于处理图形、音频、网络和窗口等功能。SFML 的优势在于其简洁易用的接口和丰富的文档,对于初学者来说是一个很好的选择,能够快速上手并开发出有趣的 2D 游戏。

安装步骤如下(以 Windows 系统为例):

  1. 从 SFML 官网 (https://www.sfml-dev.org/download/sfml/2.6.0/) 下载适用于 Visual Studio 的 SFML 库。
  1. 解压文件,将下载的压缩包解压至任意位置,得到类似如下的目录结构:
SFML-2.6.0/
├── include/
│   └── SFML/
├── lib/
│   ├── libsfml-graphics-d.lib
│   ├── libsfml-window-d.lib
│   ├── libsfml-system-d.lib
│   ├── libsfml-audio-d.lib
│   ├── libsfml-network-d.lib
│   ├── libsfml-graphics.lib
│   ├── libsfml-window.lib
│   ├── libsfml-system.lib
│   ├── libsfml-audio.lib
│   └── libsfml-network.lib
└── share/└── sfml/├── cmake/└──...
  1. 配置开发环境(以 Visual Studio 为例):打开 Visual Studio,创建一个新的 C++ 项目,在项目中右键单击 “头文件”,选择 “添加现有项”,并选择 SFML-2.6.0/include 目录下的所有.hpp 文件,以添加 SFML 的头文件;在同样的位置右键单击 “源文件”,选择 “添加现有项”,并选择 SFML-2.6.0/lib 目录下与编译器相匹配的所有库文件(.lib 或.a)。例如,如果使用的是 64 位的编译器,就应该添加 SFML-2.6.0/lib/x64 下的所有库文件;在项目中右键单击,选择 “属性” 窗口。在左侧选择 “C/C++” -> “常规”,在 “附加包含目录” 中添加 SFML-2.6.0/include 目录;在左侧选择 “链接器” -> “常规”,在 “附加库目录” 中添加 SFML-2.6.0/lib 目录;在左侧选择 “链接器” -> “输入”,在 “附加依赖项” 中添加以下库文件(根据需要添加即可):sfml-graphics.lib、sfml-window.lib、sfml-system.lib、sfml-audio.lib、opengl32.lib、freetype.lib、winmm.lib、gdi32.lib ;如果使用的是静态库,应该添加 SFML_STATIC 编译器预处理器定义;将 SFML-2.6.0/bin 目录下的所有.dll 文件复制到项目的输出目录(通常是 Debug 或 Release 文件夹)。

C++ 游戏开发基础知识

在 C++ 游戏开发的旅程中,掌握一些基础知识是开启成功之门的关键。这些知识构成了游戏开发的基石,无论是小型的休闲游戏,还是大型的 3A 游戏,都离不开它们的支撑。下面,让我们深入探讨面向对象编程、内存管理以及 C++ 标准库在游戏开发中的重要性和应用。

面向对象编程(OOP)

面向对象编程(OOP)是 C++ 的核心特性之一,它为游戏开发带来了极大的便利和灵活性。OOP 主要包含封装、继承、多态这几个概念。

封装,就像是给游戏中的各种元素加上了一个 “保护壳”。在游戏中,每个角色都有自己的生命值、攻击力、防御力等属性,以及移动、攻击、防御等行为。通过封装,我们可以将这些属性和行为组合在一起,形成一个类。以《英雄联盟》为例,英雄 “艾克” 就是一个类的实例,他的生命值、攻击力等属性被封装在这个类中,而他的技能 “时间卷曲器”“相位俯冲” 等行为也通过类的成员函数来实现。外部代码不能直接访问这些属性,只能通过类提供的公共方法来操作,这就保证了数据的安全性和一致性。比如,其他玩家不能直接修改 “艾克” 的生命值,只能通过攻击等合法的游戏行为来影响他的生命值,这样就避免了数据被随意篡改,保证了游戏的公平性和稳定性。

继承,则是实现代码复用的重要手段。在游戏中,有很多相似的对象,比如不同类型的怪物,它们可能都有一些共同的属性和行为,如生命值、攻击力、移动等。我们可以创建一个基类,包含这些共同的属性和行为,然后让不同类型的怪物类继承这个基类。以《暗黑破坏神》系列游戏为例,游戏中有各种恶魔和怪物,它们都继承自一个 “怪物” 基类。“沉沦魔” 类继承自 “怪物” 基类,它不仅拥有 “怪物” 基类的基本属性和行为,还可以有自己特有的属性和行为,比如更灵活的移动方式、特殊的攻击技能等。通过继承,我们可以减少代码的重复编写,提高开发效率。当我们需要修改怪物的一些基本属性时,只需要在基类中进行修改,所有继承自这个基类的怪物类都会自动继承这些修改,大大方便了代码的维护和扩展。

多态,是指同一个操作作用于不同的对象,可以产生不同的结果。在游戏中,多态的应用非常广泛。以《鬼泣》系列游戏为例,游戏中的角色 “但丁” 可以使用不同的武器,如大剑、双枪等。每个武器都有自己的攻击方式和效果,但是我们可以通过一个统一的接口来调用这些武器的攻击方法。当 “但丁” 使用大剑时,调用的是大剑的攻击方法,产生大剑的攻击效果;当他使用双枪时,调用的是双枪的攻击方法,产生双枪的攻击效果。这就是多态的体现,它使得代码更加灵活和可扩展。当我们需要添加新的武器时,只需要创建一个新的武器类,实现统一的攻击接口,就可以轻松地将新武器融入游戏中,而不需要大量修改现有的代码。

内存管理

在 C++ 游戏开发中,内存管理是一个至关重要的环节,它直接影响着游戏的性能和稳定性。C++ 提供了两种主要的内存分配方式:堆栈内存和堆内存,它们各有特点和适用场景。

栈内存是一种自动分配和释放的内存区域,它的分配和释放速度非常快,就像在一个栈中放入和取出物品一样简单高效。函数的局部变量和函数调用信息通常存储在栈上。当函数被调用时,局部变量会在栈上自动分配内存空间;当函数执行结束时,这些局部变量所占用的内存会自动被释放。在一个简单的游戏函数中,比如计算角色移动距离的函数:

void calculateMoveDistance() {int speed = 5; // 局部变量speed存储在栈上int time = 10; // 局部变量time存储在栈上int distance = speed * time; // 局部变量distance存储在栈上// 函数执行结束,speed、time、distance所占用的栈内存自动释放
}

栈内存的优点是速度快、效率高,但是它的大小是有限的,并且变量的生命周期与函数的作用域紧密相关。如果在栈上分配过多的内存,或者在函数中创建了大型的局部数组,可能会导致栈溢出,从而使程序崩溃。

堆内存则是用于动态分配内存的区域,它由程序员手动控制内存的分配和释放。在游戏中,当我们需要创建一些动态的对象,如角色、道具等,并且这些对象的生命周期需要根据游戏的运行情况来动态管理时,就需要使用堆内存。以创建一个游戏角色为例:

class Character {
public:int health;int attackPower;// 其他属性和方法
};int main() {Character* character = new Character(); // 在堆上分配内存创建Character对象character->health = 100;character->attackPower = 20;// 使用character对象delete character; // 手动释放堆内存,避免内存泄漏return 0;
}

堆内存的优点是可以根据需要动态分配内存大小,灵活性高,但是它的分配和释放过程相对复杂,需要程序员手动操作,并且速度比栈内存慢。如果在堆上分配了内存,但是在使用完毕后没有及时释放,就会导致内存泄漏,随着游戏的运行,内存占用会越来越高,最终可能导致游戏卡顿甚至崩溃。

为了更好地管理堆内存,C++11 引入了智能指针(如std::shared_ptr、std::unique_ptr等)。智能指针能够自动跟踪对象的引用计数,当对象不再被使用时,自动释放其所占用的内存,有效地避免了内存泄漏的问题。以std::shared_ptr为例:

#include <memory>
#include <iostream>class Character {
public:int health;int attackPower;Character() : health(100), attackPower(20) {}~Character() { std::cout << "Character destroyed" << std::endl; }
};int main() {std::shared_ptr<Character> character = std::make_shared<Character>();// 使用character对象// 当character离开作用域时,其引用计数降为0,自动释放所指向的Character对象的内存return 0;
}

在这个例子中,std::shared_ptr会自动管理Character对象的生命周期,当character离开作用域时,它所指向的Character对象的内存会被自动释放,无需手动调用delete。智能指针的使用大大简化了内存管理,提高了代码的安全性和可维护性。

C++ 标准库(STL)

C++ 标准库(STL)是 C++ 编程中的强大工具集,它提供了丰富的容器和算法,在游戏开发中有着广泛的应用,能够大大提高开发效率。

STL 中的容器是存储和管理数据的重要工具,其中vector、list、map是比较常用的容器。vector是一个动态数组,它允许在运行时动态地调整大小,并且支持快速的随机访问。在游戏中,vector常用于存储游戏对象的集合,如游戏中的角色列表、道具列表等。以一个简单的射击游戏为例,我们可以使用vector来存储所有的敌人:

#include <vector>
#include <iostream>class Enemy {
public:int health;int attackPower;Enemy() : health(50), attackPower(10) {}
};int main() {std::vector<Enemy> enemies;for (int i = 0; i < 10; i++) {enemies.push_back(Enemy());}// 访问和操作enemies中的敌人for (size_t i = 0; i < enemies.size(); i++) {std::cout << "Enemy " << i << " health: " << enemies[i].health << std::endl;}return 0;
}

在这个例子中,vector可以方便地添加和访问敌人对象,并且在需要时自动调整大小,非常适合存储动态变化的游戏对象集合。

list是一个双向链表,它的特点是在链表的任何位置进行插入和删除操作都非常高效,但是不支持随机访问。在游戏中,当需要频繁地插入和删除元素时,list就派上了用场。比如在一个实时策略游戏中,单位的创建和销毁非常频繁,我们可以使用list来存储游戏中的单位:

#include <list>
#include <iostream>class Unit {
public:int health;int attackPower;Unit() : health(100), attackPower(20) {}
};int main() {std::list<Unit> units;units.push_back(Unit()); // 在链表尾部插入一个单位units.push_front(Unit()); // 在链表头部插入一个单位auto it = units.begin();++it; // 移动到第二个单位units.insert(it, Unit()); // 在第二个单位之前插入一个单位// 删除单位it = units.begin();units.erase(it); // 删除第一个单位// 遍历listfor (const auto& unit : units) {std::cout << "Unit health: " << unit.health << std::endl;}return 0;
}

在这个例子中,list的高效插入和删除操作使得它非常适合处理游戏中频繁变化的单位集合。

map是一个关联容器,它存储的是键值对,并且会根据键自动排序。在游戏中,map常用于存储需要根据某个键来查找对应值的数据,如游戏中的道具字典,我们可以使用道具的 ID 作为键,道具的详细信息作为值:

#include <map>
#include <string>
#include <iostream>class Item {
public:std::string name;int value;Item(const std::string& n, int v) : name(n), value(v) {}
};int main() {std::map<int, Item> items;items[1] = Item("Health Potion", 50); // 添加一个ID为1的道具items[2] = Item("Mana Potion", 30); // 添加一个ID为2的道具// 根据ID查找道具auto it = items.find(1);if (it!= items.end()) {std::cout << "Item name: " << it->second.name << ", value: " << it->second.value << std::endl;}return 0;
}

在这个例子中,map可以快速地根据道具 ID 查找到对应的道具信息,非常方便管理和查找游戏中的各种数据。

STL 中的算法也是游戏开发中不可或缺的工具,其中sort和find是比较常用的算法。sort算法用于对容器中的元素进行排序,在游戏中,经常需要对游戏对象进行排序,如根据角色的等级对角色进行排序,或者根据玩家的得分对玩家进行排名。以对玩家得分进行排序为例:

#include <vector>
#include <algorithm>
#include <iostream>struct Player {std::string name;int score;Player(const std::string& n, int s) : name(n), score(s) {}
};// 自定义比较函数,用于按得分从高到低排序
bool compareByScore(const Player& p1, const Player& p2) {return p1.score > p2.score;
}int main() {std::vector<Player> players;players.push_back(Player("Alice", 80));players.push_back(Player("Bob", 90));players.push_back(Player("Charlie", 70));// 对玩家按得分进行排序std::sort(players.begin(), players.end(), compareByScore);// 输出排序后的玩家列表for (const auto& player : players) {std::cout << "Player: " << player.name << ", Score: " << player.score << std::endl;}return 0;
}

在这个例子中,std::sort算法可以方便地对玩家列表进行排序,使得玩家按照得分从高到低排列。

find算法用于在容器中查找指定的元素,在游戏中,经常需要查找某个特定的游戏对象,如查找某个 ID 对应的角色,或者查找某个位置的道具。以查找某个 ID 对应的角色为例:

#include <vector>
#include <algorithm>
#include <iostream>class Character {
public:int id;std::string name;Character(int i, const std::string& n) : id(i), name(n) {}
};int main() {std::vector<Character> characters;characters.push_back(Character(1, "Warrior"));characters.push_back(Character(2, "Mage"));characters.push_back(Character(3, "Rogue"));// 查找ID为2的角色auto it = std::find_if(characters.begin(), characters.end(), [](const Character& c) {return c.id == 2;});if (it!= characters.end()) {std::cout << "Found Character: " << it->name << std::endl;} else {std::cout << "Character not found" << std::endl;}return 0;
}

在这个例子中,std::find_if算法可以在characters容器中查找 ID 为 2 的角色,如果找到则输出角色的名字,否则输出提示信息。

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

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

相关文章

可以称之为“yyds”的物联网开源框架有哪几个?

有了物联网的发展&#xff0c;我们的生活似乎也变得更加“鲜活”、有趣、便捷&#xff0c;包具有科技感的。在物联网&#xff08;IoT&#xff09;领域中&#xff0c;也有许多优秀的开源框架支持设备连接、数据处理、云服务等&#xff0c;成为被用户们广泛认可的存在。以下给大家…

Mybatis-plus 更新 Null 的策略踩坑记

一个bug 在一个管理页面&#xff0c;有一个非必填字段被设置成空了并提交更新&#xff0c;再次打开的时候&#xff0c;发现字段还在&#xff0c;并没有被更新成功。 使用的数据库映射框架是 Mybatis-plus &#xff0c;对于Mybatis 在更新字段的时候会对空进行校验&#xff0c;…

Linux第一讲--基本的命令操作

从今天开始&#xff0c;我将在csdn这个平台上和大家分享Linux的相关知识&#xff0c;欢迎大家一起讨论&#xff01; 零、基本操作 1.进入全屏&#xff1a; ALTENTER,退出也是这个 2.复制&#xff1a;ctrlinsert 3.粘贴&#xff1a;shiftinsert Linux中&#xff0c;cv是不好…

[CISCN2019 华东南赛区]Web41

进入题目页面如下 点击链接但发现 各种尝试无果 看了一个大佬的博客&#xff0c;链接如下 BUUCTF&#xff1a;[CISCN2019 华东南赛区]Web4-CSDN博客 给了很大的提示&#xff0c;大佬尝试了file:///etc/passwd无果&#xff0c;猜测Flask&#xff0c;尝试local_file:///读取文…

make controller vibrate and 判断是否grab

我自己的例子&#xff0c;新建cube上挂载oculus交互的代码&#xff0c;如下 然后加载自己写的代码到cube上就可以了 using Oculus.Interaction.HandGrab; using System.Collections; using System.Collections.Generic; using UnityEngine;public class Vibtation : MonoBehav…

基于C++的DPU医疗领域编程初探

一、大型医院数据处理困境与 DPU 的崛起 在数字化浪潮的席卷下,医疗行业正经历着深刻变革,大型医院作为医疗服务的核心枢纽,积累了海量的数据,涵盖患者的基本信息、诊断记录、检验报告、影像资料等多个维度。这些数据不仅规模庞大,而且增长速度迅猛,传统的中央处理器(C…

【记录】日常|从零散记录到博客之星Top300的成长之路

文章目录 shandianchengzi 2024 年度盘点概述写作风格简介2024年的创作内容总结 shandianchengzi 2024 年度盘点 概述 2024年及2025年至今我创作了786即84篇文章&#xff0c;加上这篇就是85篇。 很荣幸这次居然能够入选博客之星Top300&#xff0c;这个排名在我之前的所有年份…

详解最基本的数据顺序存储结构:顺序表

新的一年&#xff0c;我觉得这张图很合适&#xff01;有梦想&#xff0c;敢拼&#xff0c;马上就是除夕了&#xff0c;希望新的一年我们逢考必过&#xff0c;事事顺心&#xff0c;看见朝阳的你是不是嘴角微微上扬&#xff01; 本篇从0基础白话文讲述顺序表的概念、用法、注意事…

字节跳动发布UI-TARS,超越GPT-4o和Claude,能接管电脑完成复杂任务

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

移动光猫怎么自己改桥接模式?

环境&#xff1a; 型号H3-8s 问题描述&#xff1a; 家里宽带用的是H3-8s 光猫&#xff0c;想改桥接模式。 解决方案&#xff1a; 1.默认管理员账号和密码&#xff1a; 账号&#xff1a;CMCCAdmin 密码&#xff1a;aDm8H%MdAWEB页面我试了登陆不了&#xff0c;显示错误 …

【Java数据结构】排序

【Java数据结构】排序 一、排序1.1 排序的概念1.2 排序的稳定性1.3 内部排序和外部排序1.3.1 内部排序1.3.2 外部排序 二、插入排序2.1 直接插入排序2.2 希尔排序 三、选择排序3.1 选择排序3.2 堆排序 四、交换排序4.1 冒泡排序4.2 快速排序Hoare法&#xff1a;挖坑法&#xff…

Java数据结构 (链表反转(LinkedList----Leetcode206))

1. 链表的当前结构 每个方框代表一个节点&#xff0c;每个节点包含两个部分&#xff1a; 左侧的数字&#xff1a;节点存储的值&#xff0c;例如 45、34 等。右侧的地址&#xff08;如 0x90&#xff09;&#xff1a;表示该节点 next 指针指向的下一个节点的内存地址。 例子中&a…

Linux查看服务器的内外网地址

目录&#xff1a; 1、内网地址2、外网地址3、ping时显示地址与真实不一致 1、内网地址 ifconfig2、外网地址 curl ifconfig.me3、ping时显示地址与真实不一致 原因是dns缓存导致的&#xff0c;ping这种方法也是不准确的&#xff0c;有弊端不建议使用&#xff0c;只适用于测试…

微服务学习-服务调用组件 OpenFeign 实战

1. OpenFeign 接口方法编写规范 1.1. 在编写 OpenFeign 接口方法时&#xff0c;需要遵循以下规范 1.1.1.1. 接口中的方法必须使用 RequestMapping、GetMapping、PostMapping 等注解声明 HTTP 请求的类型。 1.1.1.2. 方法的参数可以使用 RequestParam、RequestHeader、PathVa…

基于C语言的数组从入门到精通

简介:本篇文章主要介绍了一维数组,二维数组,字符数组的定义,数组的应用,数组的核心代码解析,适用于0基础的初学者. C语言数组 1.一维数组 1.1定义 1.1.1声明 语法:数据类型 数组名[数组大小];示例:int arr[5]; 1.1.2初始化 a.静态初始化 完全初始化&#xff1a;int arr[5] {1…

音频入门(二):音频数据增强

本文介绍了一些常见的音频数据增强方法&#xff0c;并给出了代码实现。 目录 一、简介 二、代码 1. 安装必要的库 2. 代码 3. 各函数的介绍 4. 使用方法 参考&#xff1a; 一、简介 音频数据增强是机器学习和深度学习领域中用于改善模型性能和泛化能力的技术。 使用数据…

Go中new和make的区别对比

Go 中 new 和 make 的区别 在 Go 语言中&#xff0c;new 和 make 都用于分配内存&#xff0c;但它们的使用场景和行为有显著的区别。 1. new 定义 new 是 Go 语言中的一个内置函数&#xff0c;用于分配内存并返回指向该内存的指针。new 分配的内存会被初始化为零值。 作用…

消息队列篇--通信协议篇--AMOP(交换机,队列绑定,消息确认,AMOP实现实例,AMOP报文,帧,AMOP消息传递模式等)

AMQP&#xff08;Advanced Message Queuing Protocol&#xff0c;高级消息队列协议&#xff09;是一种开放的、跨平台的消息传递协议&#xff0c;旨在提供一种标准化的方式在不同的消息代理和客户端之间进行消息传递。AMQP不仅定义了消息格式和路由机制&#xff0c;还规定了如何…

LLaMA-Factory 微调LLaMA3

LoRA介绍 LoRA&#xff08;Low-Rank Adaptation&#xff09;是一种用于大模型微调的技术&#xff0c; 通过引入低秩矩阵来减少微调时的参数量。在预训练的模型中&#xff0c; LoRA通过添加两个小矩阵B和A来近似原始的大矩阵ΔW&#xff0c;从而减 少需要更新的参数数量。具体来…

【项目实战】—— 高并发内存池设计与实现

目录 一&#xff0c;项目介绍 1.1 关于高并发内存池 1.2 关于池化技术 1.3 关于malloc 二&#xff0c;定长内存池实现 2.1 实现详情 ​2.2 完整代码 三&#xff0c;高并发内存池整体设计 四&#xff0c;threadcache设计 4.1 整体设计 4.2 哈希桶映射对齐规则 4.3 …