news 2026/6/25 15:26:17

纯C写的横版闯关游戏源码,VS直接打开就能跑的超级玛丽风格工程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
纯C写的横版闯关游戏源码,VS直接打开就能跑的超级玛丽风格工程

本文还有配套的精品资源,点击获取

简介:用标准C语言从零实现的超级玛丽类横版动作游戏,不依赖C++、不调用OpenGL或SDL等图形库,所有渲染基于简易字符/像素绘图逻辑。项目包含完整的Visual Studio解决方案文件(.sln和.suo),开箱即用,支持VS2015及以上版本一键编译运行。代码结构清晰,分模块实现角色移动与跳跃、左右卷轴地图加载、蘑菇道具拾取、碰撞检测判定、音效占位接口等核心机制。附带‘源码的重要性.txt’说明文档,指出关键函数入口、数据结构组织方式和学习切入点,适合刚学完C语法、想动手做小项目的初学者。整个工程严格控制在ANSI C范围内,无系统API硬编码,移植到嵌入式平台或教学演示环境时修改成本低。资源包内无图片、音频等外部依赖文件,所有素材以数组或ASCII形式内嵌,目录干净,只有必要源码和配置文件。

1. 项目概述:为什么一个“纯C写的超级玛丽”值得你花30分钟认真看一遍

我第一次在嵌入式实验室的老旧Windows 7工控机上跑通这个工程时,盯着控制台里那个用@符号拼出来的跳跃小人,在ASCII地图上左右横跳、踩扁蘑菇、撞出金币——不是靠SDL贴图,不是靠OpenGL着色器,甚至没调用一句Win32 GDI——就只是printfgetch()memset()和一堆二维数组。那一刻我意识到:这不是玩具代码,而是一份被严重低估的C语言底层能力教科书。

它精准踩中了三个真实痛点:初学者学完语法却写不出完整程序教学场景需要零依赖可演示案例嵌入式/单片机开发者苦于图形逻辑无从下手。关键词里“C语言游戏”“超级玛丽源码”“VS工程”“横版闯关”“纯C实现”,每一个都不是虚词——它真正在用ANSI C89兼容语法,把游戏开发最核心的5个骨架模块全部拆解成可读、可改、可移植的C函数:角色状态机、卷轴地图索引、碰撞判定矩阵、道具拾取协议、音效占位回调。没有宏定义堆砌的“伪面向对象”,没有隐藏在头文件背后的黑盒API,所有逻辑都摊开在.c文件里,连main()函数入口都只做了三件事:初始化、主循环、清理。我试过把它直接复制进Keil MDK的裸机工程里,删掉conio.h相关输入部分,替换成串口按键扫描,再把draw_map()重定向到LCD驱动缓冲区——不到2小时,就在STM32F407开发板上跑出了带卷轴效果的字符版马里奥。这说明什么?它不是“能跑就行”的Demo,而是经过真实约束锤炼过的架构样本。

适合谁?如果你刚啃完《C Primer Plus》第12章指针数组,正对着“如何管理多个游戏角色状态”发懵;如果你是高校教师,需要一份不装环境、不配驱动、插U盘就能在教室电脑上演示“游戏循环本质”的课件;如果你在做国产MCU教育套件,想找一个既能讲内存布局又能讲状态迁移的参考实现——那它就是你现在该打开的工程。别被“超级玛丽”名字吓住,它没实现火焰花、无敌星或水下关卡,但把“按A键加速、空格跳跃、碰到敌人头顶反杀”这些机制,用不超过200行核心逻辑代码讲得比任何教材都透。接下来我会带你一层层剥开它的源码结构,告诉你每个.c文件里藏着什么关键设计,为什么player.c里要用联合体(union)存跳跃状态,为什么map.c的关卡数据必须用const unsigned char二维数组硬编码,以及——最重要的是,当你想加个新道具时,到底该动哪三行代码、改哪两个结构体、测试哪五个边界条件。

2. 整体架构与设计思路:为什么不用图形库,反而让逻辑更清晰

2.1 拒绝“便利性陷阱”:纯C实现的底层价值锚点

很多人看到“不用SDL/OpenGL”第一反应是“性能差”“画面丑”,但这个工程恰恰反其道而行之:它把所有渲染抽象成像素坐标映射+字符填充两步操作。比如绘制主角,不是调用SDL_RenderCopy()传纹理句柄,而是计算当前帧player.x,player.y对应的屏幕行列号,然后往全局screen_buffer[25][80]二维字符数组里填'@'。这种看似原始的方式,实则锁死了三个关键优势:

  • 内存行为完全可见:你能用调试器实时观察screen_buffer每行内容如何被draw_player()函数逐字节修改,清楚看到卷轴移动时哪几列被memmove()平移、哪几列被load_new_column()重载。我在教学生理解“帧缓冲区”概念时,让他们把screen_buffer声明改成volatile char screen_buffer[25][80],再单步执行draw_map(),立刻明白为什么嵌入式LCD驱动必须用volatile修饰显存地址。

  • 状态流转无隐式依赖:游戏主循环里update_player()只修改player.stateplayer.vel_y等字段,draw_player()只读取这些字段并写入screen_buffer,两者之间没有跨模块全局变量污染。对比某些用C++封装的教程项目,Player::Jump()里偷偷调用AudioManager::PlaySound(),导致初学者根本分不清“逻辑更新”和“表现渲染”的职责边界。

  • 移植成本趋近于零:整个工程只依赖stdio.hstdlib.hstring.hconio.h(仅用于getch()输入)和windows.h(仅用于Sleep()延时)。我把conio.h替换成Linux下的termios.h非阻塞读取,windows.hSleep()换成usleep(),其余代码一行未改,就在Ubuntu终端跑起来了。去年帮某职校移植到树莓派Pico时,只重写了draw_pixel()函数,把字符输出改成GPIO翻转模拟VGA信号,核心游戏逻辑.c文件全盘复用。

提示:工程里所有“图形”操作最终都归结为对screen_buffer的读写。这意味着你完全可以把它当成一个“虚拟显存”,后续想接OLED、TFT屏甚至LED点阵,只需重写flush_screen()函数——把screen_buffer数据打包发送给硬件即可。

2.2 模块化切分逻辑:五个.c文件如何构成游戏骨架

整个工程目录下只有5个核心.c文件,每个文件解决一个不可替代的问题,且接口极简:

  • main.c:主循环中枢,只包含init_game()game_loop()cleanup()三函数。game_loop()里严格遵循“输入→更新→渲染→延时”四步,没有一行业务逻辑。
  • player.c:角色控制器,暴露update_player()draw_player()。内部用状态机管理IDLE/RUNNING/JUMPING/FALLING,跳跃高度通过player.vel_y积分计算,落地检测依赖is_on_ground()函数。
  • map.c:关卡引擎,核心是load_map_section()scroll_map()。关卡数据以const unsigned char map_data[][MAP_WIDTH]形式硬编码在.c文件里,避免文件IO依赖。
  • collision.c:碰撞检测中心,提供check_collision()resolve_collision()。采用分离轴定理(SAT)简化版:只检测矩形包围盒(AABB),但针对斜坡做了特殊处理——当玩家y坐标落在斜坡区间时,强制修正player.y为斜坡高度值。
  • item.c:道具管理系统,负责蘑菇生成、拾取判定、计分更新。蘑菇用struct item链表管理,每个节点含x,y,type,lifetime字段,type区分红蘑菇(加分)、绿蘑菇(增命)、金币(计分)。

这种划分不是为了“看起来专业”,而是直击教学痛点。我让学生先删掉item.c,运行游戏——发现只剩空白关卡,但角色移动跳跃完全正常;再删掉collision.c,角色直接穿墙而过;最后只留main.cplayer.c,就能做出一个“会跳的方块”。这种渐进式剥离,比任何UML类图都更能让人理解模块耦合度。

2.3 VS工程配置的细节玄机:为什么.sln文件比代码更重要

很多人忽略了一个事实:这个工程能在VS2015+一键编译,靠的不是代码多高级,而是.sln.vcxproj文件里埋了三处关键配置:

  1. 字符集设置为“使用多字节字符集”:避免宽字符wchar_t引发的printf乱码。我在VS2022上首次编译时出现中文注释变问号,就是因为默认启用了Unicode字符集,必须手动改回多字节。

  2. 预处理器定义_CRT_SECURE_NO_WARNINGS:禁用微软安全警告。否则strcpy()sprintf()等函数会报错,初学者容易误以为代码有bug。这个定义写在项目属性→C/C++→预处理器→预处理器定义里,而不是代码里#pragma,保证跨平台一致性。

  3. 链接器→系统→子系统设为“控制台”:这是最关键的一步。很多新手把游戏当成GUI程序,结果编译出黑窗口闪退。必须明确告诉链接器:“我要的是console application”,这样main()才能作为入口点被正确调用。

注意:.suo文件是VS用户选项缓存,包含断点、窗口布局等个人设置,绝对不要提交到Git。工程包里出现.suo,说明作者是在真实开发环境中导出的,不是网上拼凑的Demo。

3. 核心模块深度解析:从角色跳跃到卷轴地图的实现原理

3.1 角色控制器(player.c):用积分法实现物理感跳跃

主角跳跃不是简单地y -= 10,而是用经典运动学公式v = v0 + a*ts = s0 + v0*t + 0.5*a*t²离散化实现。player.c里定义了关键常量:

#define GRAVITY 0.5f // 重力加速度(像素/帧²) #define JUMP_FORCE -8.0f // 初始跳跃力(负值表示向上) #define MAX_FALL_SPEED 12.0f // 最大下落速度,防止穿底

update_player()函数中,跳跃状态更新逻辑如下:

if (player.state == JUMPING || player.state == FALLING) { player.vel_y += GRAVITY; // 每帧增加向下的速度 if (player.vel_y > MAX_FALL_SPEED) player.vel_y = MAX_FALL_SPEED; player.y += player.vel_y; // 位置 = 旧位置 + 速度 * 时间(1帧) // 落地检测:检查脚下是否为实心砖块 if (is_on_ground(player.x, player.y + 1.0f)) { player.y = floorf(player.y); // 强制对齐到整数像素 player.vel_y = 0.0f; player.state = IDLE; } }

这里有两个易错点初学者常踩坑:
第一,player.yfloat类型存储,而非int。因为跳跃过程需要亚像素精度(如y=10.3),如果直接用整数,vel_y=0.5会导致y永远在10和11之间震荡,无法平滑上升。
第二,is_on_ground()检测时传入player.y + 1.0f,而非player.y——这是为了检测“脚底下一格”是否为地面,避免角色悬空。我在教学时让学生把+ 1.0f改成+ 0.1f,立刻看到角色在空中微距抖动,直观理解浮点精度对物理模拟的影响。

3.2 关卡地图系统(map.c):硬编码二维数组的工程智慧

关卡数据不是从文件加载,而是直接定义在map.c里的const数组:

const unsigned char level1_map[MAP_HEIGHT][MAP_WIDTH] = { {0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0}, {0,0,0,1,1,2,2,2,2,2,2,1,1,0,0,0}, {0,0,1,2,2,2,3,3,3,3,2,2,2,1,0,0}, // ... 更多行 };

其中数字含义:0=空白,1=普通砖块,2=问号砖块,3=云朵(装饰)。这种设计牺牲了关卡编辑便利性,却换来三大确定性:

  • 启动零延迟:无需fopen()fread()main()一运行地图数据已在内存只读段。
  • 内存占用可控MAP_HEIGHT*MAP_WIDTH字节即为最大内存占用,便于嵌入式RAM预算(如STM32F103只有20KB SRAM)。
  • 调试极度友好:在VS调试器里直接展开level1_map变量,能看到整个关卡的ASCII视图,修改某个数字后F5重启,立刻验证地形变化。

卷轴实现采用“双缓冲地图索引”技巧。map.c维护两个全局变量:

static int map_offset_x = 0; // 当前显示区域左上角X偏移 static unsigned char display_map[SCREEN_HEIGHT][SCREEN_WIDTH]; // 实际渲染用的局部地图副本

scroll_map()函数每次只更新display_map中“即将进入视野”的新列,而非整张地图重绘:

// 当玩家右移超过阈值,向右滚动一列 if (player.x > map_offset_x + SCREEN_WIDTH - 5) { map_offset_x++; // 把新列从level1_map拷贝到display_map最后一列 for (int i = 0; i < SCREEN_HEIGHT; i++) { display_map[i][SCREEN_WIDTH-1] = level1_map[i][map_offset_x + SCREEN_WIDTH - 1]; } // 其余列左移:memmove(display_map[0], display_map[0]+1, ...); }

这种“增量更新”策略让16MHz单片机也能维持30FPS卷轴,远比memcpy()整图高效。

3.3 碰撞检测(collision.c):从AABB到斜坡支持的演进

基础碰撞用AABB(轴对齐包围盒):

bool check_collision(float x1, float y1, float w1, float h1, float x2, float y2, float w2, float h2) { return !(x1 + w1 <= x2 || x2 + w2 <= x1 || y1 + h1 <= y2 || y2 + h2 <= y1); }

但超级玛丽有斜坡地形,纯AABB会卡在斜坡边缘。工程采用“高度场采样法”:在map.c中为斜坡区域额外定义高度映射表:

// 斜坡高度表:x偏移量 → y方向抬升高度 const float slope_heights[SLOPE_WIDTH] = {0.0f, 0.5f, 1.0f, 1.5f, 2.0f};

resolve_collision()检测到玩家与斜坡砖块碰撞时,不再简单阻止移动,而是:

if (is_slope_tile(tile_type)) { int slope_x = (int)(player.x - map_offset_x) % SLOPE_WIDTH; float target_y = map_base_y - slope_heights[slope_x]; if (player.y < target_y) { player.y = target_y; // 强制站在斜坡表面 player.vel_y = 0; // 清除垂直速度 } }

这个设计启示我们:游戏物理不必追求物理引擎级精度,而要服务于玩法体验。“站在斜坡上不下滑”比“精确计算摩擦力”重要得多。

3.4 道具系统(item.c):链表管理与生命周期控制

蘑菇道具用单向链表管理,每个节点结构体:

typedef struct item { float x, y; int type; // ITEM_MUSHROOM_RED, ITEM_COIN, etc. int lifetime; // 剩余存活帧数,-1表示永久存在 struct item* next; } Item;

生成蘑菇时调用spawn_item(x, y, type),内部执行:

Item* new_item = malloc(sizeof(Item)); new_item->x = x; new_item->y = y; new_item->type = type; new_item->lifetime = (type == ITEM_COIN) ? 180 : -1; // 金币3秒后消失 new_item->next = item_head; item_head = new_item;

拾取判定在update_player()末尾统一处理:

for (Item** p = &item_head; *p;) { if (check_collision(player.x, player.y, 1.0f, 1.5f, (*p)->x, (*p)->y, 1.0f, 1.0f)) { // 拾取逻辑:加分、增命、播放音效占位... Item* to_free = *p; *p = (*p)->next; free(to_free); score += 100; } else { if ((*p)->lifetime > 0 && --(*p)->lifetime == 0) { // 生命周期结束,删除节点 Item* to_free = *p; *p = (*p)->next; free(to_free); } else { p = &(*p)->next; } } }

这种手动内存管理虽繁琐,却是理解“资源生命周期”的最佳实践。我让学生把free()换成printf("Freed item at %p\n", to_free),然后观察控制台输出顺序,立刻明白链表删除时为何要用Item** p二级指针。

4. 实操指南:从VS编译到功能扩展的完整路径

4.1 VS2015+编译运行五步法(附常见错误速查)

步骤1:解压后直接双击Super mushrooms.sln
不要尝试用VS“打开文件夹”,必须用解决方案文件。若提示“项目已损坏”,右键.sln→用记事本打开,确认首行是Microsoft Visual Studio Solution File, Format Version 12.00(VS2015对应版本号)。

步骤2:配置项目属性(关键!)
右键项目→属性→配置属性:
- 常规→字符集:使用多字节字符集
- C/C++→预处理器→预处理器定义:添加_CRT_SECURE_NO_WARNINGS
- 链接器→系统→子系统:控制台 (/SUBSYSTEM:CONSOLE)

步骤3:设置工作目录
调试→工作目录:设为$(ProjectDir)(即.sln所在目录)。否则printf输出可能被VS后台进程吞掉。

步骤4:按Ctrl+F5运行(不调试)
首次运行会弹出黑窗口,按方向键移动,空格跳跃。若窗口一闪而逝,说明编译成功但main()执行完退出——检查game_loop()里是否有while(1)死循环(工程里有,放心)。

步骤5:调试技巧
- 在update_player()开头设断点,F10单步看player.vel_y如何变化
- 在draw_player()里把screen_buffer[y][x] = '@'改成screen_buffer[y][x] = 'X',立刻看到主角变成X
- 修改GRAVITY0.1f,感受慢动作跳跃

错误现象可能原因解决方案
黑窗口闪退工作目录未设或子系统错误检查步骤3、4
字符显示为方块/问号字符集设为Unicode改回“多字节字符集”
方向键无响应conio.h未找到确认VS安装了“桌面开发with C++”工作负载(即使纯C也需此组件)
跳跃高度异常GRAVITYJUMP_FORCE被意外修改检查player.c顶部常量定义

4.2 功能扩展实战:加一个“弹簧”道具只需改三处

想让玩家踩中弹簧后高高弹起?不需要重写引擎,只需三步:

第一步:定义新道具类型
item.h中添加:

#define ITEM_SPRING 4

第二步:修改碰撞响应逻辑
collision.cresolve_collision()里,找到玩家与道具碰撞分支,插入:

else if (item->type == ITEM_SPRING) { player.vel_y = -15.0f; // 向上猛推 player.state = JUMPING; // 播放音效占位(调用audio_placeholder()) }

第三步:在关卡数据里放置弹簧
打开map.c,找到level1_map数组,把某处0(空白)改成4

{0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0}, {0,0,0,1,1,2,2,2,2,2,2,1,1,0,0,0}, {0,0,1,2,2,2,3,3,3,3,2,2,2,1,0,0}, {0,0,1,2,2,2,4,4,4,4,2,2,2,1,0,0}, // 第四行第七列开始放弹簧(4)

编译运行,走到弹簧位置跳跃踩中,立刻获得二段跳效果。整个过程不碰main.c、不改渲染逻辑、不新增头文件——这就是模块化设计的力量。

4.3 嵌入式移植要点:从PC到MCU的最小改动清单

移植到STM32F407开发板(带ILI9341 LCD)只需四步:

  1. 替换输入模块:删掉conio.hgetch(),在main.c中接入HAL_GPIO_ReadPin()读取按键,映射为KEY_LEFT/KEY_RIGHT/KEY_JUMP枚举。

  2. 重写显示驱动:新建lcd_driver.c,实现void lcd_draw_pixel(int x, int y, uint16_t color),在draw_player()中把screen_buffer[y][x] = '@'改为lcd_draw_pixel(x, y, RED)

  3. 调整时间基准:删掉windows.hSleep(),用HAL_Delay(33)代替(33ms≈30FPS),或更优方案——用SysTick中断驱动游戏循环。

  4. 内存优化:将screen_buffer[25][80]改为uint8_t screen_buffer[240*320/8](按LCD分辨率压缩),draw_map()函数内做坐标映射转换。

我在某次嵌入式课程设计中,学生用此工程为基础,三天内做出了带触摸控制的掌上游戏机,核心代码复用率超90%。这证明:好的C语言设计,从来不是“越高级越好”,而是“越贴近硬件越有力”。

5. 学习价值与避坑指南:那些文档里不会写的实战经验

5.1 为什么“源码的重要性.txt”比代码本身更值得精读

这份看似简单的文本,实则是作者十年教学经验的结晶。它没讲语法,而是直指学习路径:

  • 第一阶段(1天):只看main.cplayer.c,用纸笔画出player.state状态转移图(IDLE→RUNNING→JUMPING→FALLING→IDLE),标出每个箭头触发条件(如“空格键按下”“is_on_ground()返回true”)。

  • 第二阶段(2天):打开map.c,找level1_map数组,用Excel把它转成彩色表格(0=白,1=灰,2=黄,3=蓝),亲手画出关卡地形,再对照游戏运行效果,理解map_offset_x如何决定视野。

  • 第三阶段(3天):在collision.c里给check_collision()printf("Collision at %d,%d\n", (int)x1, (int)y1),运行时观察控制台输出,建立“坐标系-视觉-逻辑”的三维映射。

我坚持让学生按此顺序学,因为跳过第一阶段直接改地图,90%的人会陷入“为什么改了数组值角色不动”的困惑;跳过第二阶段直接调参数,又容易变成“调参工程师”,不懂数值背后的物理意义。

5.2 初学者必踩的五个坑(附现场debug记录)

坑1:浮点数比较用==
现象:角色在斜坡上反复微跳。
debug:在is_on_ground()里打印player.yfloorf(player.y),发现player.y=10.000001floorf()返回10,但player.y == 10.0f为false。
解法:改用fabs(player.y - floorf(player.y)) < 0.01f判断是否接近整数。

坑2:数组越界访问地图
现象:向右走到关卡尽头,程序崩溃。
debug:在load_map_section()里加assert(map_x < MAP_WIDTH),触发断言失败。
解法:所有地图坐标访问前加边界检查,或用% MAP_WIDTH取模实现循环关卡。

坑3:忘记初始化结构体
现象:新道具出现位置随机。
debug:spawn_item()malloc()后未初始化x,y,内存残留垃圾值。
解法:Item* new_item = calloc(1, sizeof(Item)),或手动赋初值。

坑4:音效占位函数阻塞主线程
现象:播放音效时游戏卡顿。
debug:发现audio_placeholder()里用了Sleep(200)
解法:改为事件驱动——设全局bool audio_playing标志,主循环中检测并清零,不阻塞。

坑5:卷轴速度与玩家速度不同步
现象:玩家快速奔跑时,背景滚动滞后。
debug:scroll_map()只在玩家x坐标超阈值时才滚动,但阈值固定为SCREEN_WIDTH-5
解法:改为if (player.vel_x > 0 && player.x > map_offset_x + SCREEN_WIDTH - 5 - player.vel_x),让滚动提前量随速度动态调整。

5.3 进阶思考:这个工程能带你走多远?

它不是一个终点,而是一把钥匙。掌握它之后,你可以:

  • 向底层走:把screen_buffer映射到STM32的FSMC总线,直接驱动TFT屏,实现真正的裸机游戏;
  • 向算法走:把AABB碰撞换成分离轴定理(SAT),支持旋转矩形和多边形碰撞;
  • 向架构走:用函数指针数组重构player.state,实现状态模式(State Pattern),为后续加入更多角色铺路;
  • 向工程走:把硬编码关卡数据生成为Python脚本自动导出C数组,实现可视化关卡编辑器。

去年我带的学生团队,基于此工程开发了“汉字闯关”教育游戏:把砖块换成“一、二、三”等汉字,踩中后朗读拼音。他们只用了两周,核心代码95%复用,新增的只是draw_chinese()函数和拼音音频播放逻辑。这印证了一个事实:真正优秀的教学代码,不在于它实现了多少功能,而在于它为你预留了多少可生长的接口。

我个人在实际教学中发现,学生完成这个项目后,对指针、结构体、内存布局的理解深度,远超刷完一百道LeetCode题。因为它把抽象概念钉在了具体问题上:当你亲手把player.vel_y从0.0f调到-12.0f,看着角色飞过三块砖才落地时,牛顿第二定律就不再是课本上的公式,而是你键盘敲出的每一行代码。

本文还有配套的精品资源,点击获取

简介:用标准C语言从零实现的超级玛丽类横版动作游戏,不依赖C++、不调用OpenGL或SDL等图形库,所有渲染基于简易字符/像素绘图逻辑。项目包含完整的Visual Studio解决方案文件(.sln和.suo),开箱即用,支持VS2015及以上版本一键编译运行。代码结构清晰,分模块实现角色移动与跳跃、左右卷轴地图加载、蘑菇道具拾取、碰撞检测判定、音效占位接口等核心机制。附带‘源码的重要性.txt’说明文档,指出关键函数入口、数据结构组织方式和学习切入点,适合刚学完C语法、想动手做小项目的初学者。整个工程严格控制在ANSI C范围内,无系统API硬编码,移植到嵌入式平台或教学演示环境时修改成本低。资源包内无图片、音频等外部依赖文件,所有素材以数组或ASCII形式内嵌,目录干净,只有必要源码和配置文件。


本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 21:11:19

基于Docker快速部署OneAPI以及统一调用国产大模型

本文以DeepSeek厂商为例&#xff0c;介绍OneAPI如何统一调用大模型API&#xff0c;其他大模型厂商照葫芦画瓢。 一、参考资料 One API Docker 部署实战&#xff1a;从 0 搭建多模型统一接口管理平台 - 技术栈 OneAPI保姆级部署教程&#xff1a;Docker一键启动&#xff0c;支…

作者头像 李华
网站建设 2026/6/8 13:27:19

八大网盘全速下载神器:一键获取真实直链,彻底告别龟速时代

八大网盘全速下载神器&#xff1a;一键获取真实直链&#xff0c;彻底告别龟速时代 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国…

作者头像 李华
网站建设 2026/6/10 2:29:33

小学期作业

在观察其他同学的555方波输出后&#xff0c;临时改为单片机&#xff0c;通过改变单片机的PWM波来输出50%占空比的方波&#xff0c;更加稳定以及受影响较小&#xff0c;上图为低通滤波采用stm32作为主控&#xff0c;同时供电方面采用一个供电口&#xff0c;对板子进行输入5V的电…

作者头像 李华
网站建设 2026/6/10 2:29:14

3分钟解锁屏幕标注新姿势:告别传统白板的效率革命

3分钟解锁屏幕标注新姿势&#xff1a;告别传统白板的效率革命 【免费下载链接】gInk An easy to use on-screen annotation software inspired by Epic Pen. 项目地址: https://gitcode.com/gh_mirrors/gi/gInk 你是否曾经在视频会议中&#xff0c;为了解释一个复杂概念…

作者头像 李华
网站建设 2026/6/8 13:24:54

V/Hz闭环电机控制:从原理到嵌入式软件实现与调试

1. 项目概述&#xff1a;从零构建一个可靠的V/Hz闭环电机控制器 在工业自动化、家电和许多嵌入式系统中&#xff0c;三相交流感应电机&#xff08;ACIM&#xff09;因其结构简单、坚固耐用和成本效益高而广泛应用。要让这些“大力士”听话地按照我们期望的速度和扭矩运行&#…

作者头像 李华
网站建设 2026/6/9 17:41:37

基于DSP56F80x的永磁同步电机速度闭环控制实战解析

1. 项目概述与核心价值 在工业驱动和高端消费电子领域&#xff0c;永磁同步电机&#xff08;PMSM&#xff09;凭借其高效率、高功率密度和优异的动态性能&#xff0c;早已成为伺服系统、压缩机、风机泵类以及高端家电&#xff08;如变频空调、滚筒洗衣机&#xff09;的首选动力…

作者头像 李华