ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

C语言桌球游戏课设:碰撞检测与Easy_X实现全解析

C语言桌球游戏课设:碰撞检测与Easy_X实现全解析 简介C语言编写的桌球游戏完整源代码基于Easy_X图形库开发运行环境为VS2013适合正在学习C语言编程的大学生、需要完成课程设计或程序设计大作业的读者参考。代码按函数模块划分包括init初始化、show画面显示、refreshWithInput输入刷新、refreshWithoutInput无输入刷新等结构清晰便于阅读和二次开发。碰撞模型以动量定理为基础假设所有球质量相等两球碰撞后交换速度并根据矢量合成交换x、y方向速度分量碰墙后速度反向同时更新小球坐标防止移出边界。资源共84个文件压缩包28.82MB涵盖cpp源程序、exe可执行文件、pptx答辩演示文稿、docx程序设计文档以及png、jpg图片素材与mp3、gif多媒体资源还包含sln、vcxproj等工程配置文件解压即可运行。目前已有1152人学习下载配套的程序设计文档和答辩PPT可帮助快速理解实现思路并准备课程展示。1. C语言桌球游戏源码、文档、PPT、可执行文件配齐的完整课设桌球游戏是C语言课程设计里出镜率极高的题目难点不在画一张台球桌而在碰撞模型的编排。这份叫“魔王勇者桌球大乱斗”的资源把VS2013 Easy_X的完整源代码、程序设计文档、答辩PPT和编译好的可执行文件都打包了。解压后你可以先双击Release目录下的exe看看成品效果再决定是直接用它交作业还是改造成自己的版本。它适合正在找C语言大作业方向的在校生也适合想研究等质量弹性碰撞在2D游戏里怎么落地的人。2. 先摸清文件结构再动手解决方案、源码与中间文件的区分这份资源不是零散代码而是一个完整的VS解决方案。解压billiards-games-master-c.zip之后你会看到解决方案文件“魔王勇者桌球大乱斗.sln”、工程文件“魔王勇者桌球大乱斗.vcxproj”、唯一的源文件main.cpp以及resourse资源目录。后面还跟着一长串.pdb、.obj、.ilk、.sdf文件——这些是编译产物和IDE缓存不是源码平时可以忽略。但能把它们分清楚能避免你误把中间文件当代码去改。很多新手拿到工程第一反应是逐个打开文件看到.sdf动辄几百兆直接蒙了。实际上你真正要动的只有main.cpp要跑的是Release目录下的exe。2.1 文件清单哪些是源码、哪些是编译临时文件先对照解决方案目录逐一说清楚。.sln是解决方案文件VS双击它就能打开整个项目.vcxproj是工程文件记录了编译选项、源文件列表和依赖库.vcxproj.user是当前用户的本地配置在别人机器上可能不存在.filters管的是源码在IDE里的虚拟目录显示删了不影响编译。readme.md是作者写的项目说明建议第一个打开里面通常写了运行配置和操作方式。main.cpp是整个C语言项目里唯一的源代码文件界面逻辑、碰撞检测、绘制都在这里。resourse目录放的是球桌、球、球杆的图片和音效资源运行时必须与exe保持相对路径一致。C语言程序设计大作业文档.docx和C语言答辩PPT.pptx是给老师看的不是给编译器看的各自对应课的设文档模板和答辩演示。剩下的.v12.suo、.sdf、vc120.pdb、vc120.idb、main.obj、.ilk、.tlog这类文件分别是IDE用户选项、IntelliSense数据库、调试符号、编译中间目标文件。它们会在每次编译后自动重新生成不用手动处理。值得注意vc120这个前缀VS2013对应的工具集版本就是v120如果你的机器装了更高版本的VS打开工程时一般会提示做一次工具集升级确认后能编译但个别API的兼容行为可能有差异。2.2 四个核心模块init、show、refreshWithInput、refreshWithoutInput项目正文里已经把模块划分写得很清楚init负责初始化show负责游戏画面显示refreshWithInput负责与输入有关的刷新refreshWithoutInput负责与输入无关的刷新。这种划分方式对课设答辩非常友好因为它天然对应了“程序有哪些功能、各自怎么协作”这个问题。init里常见做法是设置窗口大小、加载resourse里的资源图片、把球的初始坐标和速度清零再准备好全局变量。show负责把球、球桌、指针画到屏幕上配合Easy_X的绘图函数使用。refreshWithInput负责读鼠标或键盘比如按下方向键调整击球角度、按空格蓄力或者用鼠标拖拽拉出力度条。refreshWithoutInput则是每帧都要做的物理更新——球的位移、两球碰撞、碰墙反弹这些计算全都放在这里。一个典型的帧循环长这样int running 1; while (running) { refreshWithInput(); // 处理用户输入修改击球参数 refreshWithoutInput(); // 物理更新位移、碰撞、碰墙 show(); // 把最新状态画到屏幕上 }这段代码不是从压缩包里原样截取的但这类结构几乎都是这个骨架。它说明了一个关键设计输入、物理逻辑、渲染三层分离。input层只改参数比如记录当前击球角度和力度withoutInput层只算新坐标show层只负责画。这样改一处不会牵连另一处答辩时老师问“如果我想加暂停功能改哪里”直接指refreshWithInput里的按键分支就行。2.3 工程文件里的隐藏信息v120、Release、Debug打开.vcxproj或者直接看文件名也能读出不少信息。v120是VS2013的内部工具集编号Debug目录下的vc120.pdb说明这个工程用v120工具集编译过且带调试符号。资源包里同时有Release和Debug两个目录Release目录里有可执行文件说明作者保留的是正式编译结果而不是带调试信息的版本。Debug与Release的区别值得多说两句Debug版编译选项偏向调试体验不优化代码、保留完整符号体积大、运行偏慢Release版做了优化运行快适合直接交付。如果你下载后自己重新编译默认活动配置一般是Debug想发布给别人用就切到Release再生成一次。切错配置不一定报错但exe体积和运行表现会差很多这是很多新手第一个翻车点。这份资源里的可执行文件、程序设计文档、答辩PPT是配套的PPT里的模块说明和工程截图能对得上。真要改动源码记得文档里的模块划分描述也要跟着微调否则答辩时老师拿文档和代码一对比问题就露馅了。3. 碰撞模型拆解等质量弹性碰撞的速度交换与边界处理桌球游戏的核心不在画图在碰撞。项目正文里对碰撞模型的描述很精炼“假设所有球质量相等根据动量定理一个球碰撞一个静止的小球或者两个运动的球相撞两个球交换速度根据矢量合成两球交换x y上的速度判断碰墙碰墙后速度反向。更新小球坐标防止小球出边界。”这三句话信息密度很高需要逐句拆开。逆推回来实现约等于球与球之间是等质量完全弹性碰撞碰撞瞬间沿两球连心线方向交换速度分量球与桌面边界是速度取反每次更新坐标后做范围钳制。3.1 碰撞条件两球距离阈值与边界阈值项目里说的“球移动到边界或者两球的距离小于阈值”是两类触发条件。边界条件好理解球的坐标加上半径超出桌面四边形区域就算碰墙。两球碰撞条件一般取球心距离小于等于两球半径之和也就是阈值等于2R。写代码时常见做法是直接比较平方距离省去开方运算#define BALL_RADIUS 10.0f #define BALL_DIAMETER (2 * BALL_RADIUS) // 两球圆心距离的平方小于直径平方判定为碰撞 float dx b.x - a.x; float dy b.y - a.y; if (dx * dx dy * dy BALL_DIAMETER * BALL_DIAMETER) { // 进入碰撞处理 }用平方距离比较是这里最常见的优化sqrt是相对昂贵的运算每帧每对球都调用一次很亏。课设规模下性能不是瓶颈但这个写法在答辩时可以主动讲出来属于加分项。容易写错的是阈值用了半径平方而不是直径平方如果漏掉系数球还没接触就提前触发碰撞表现就是球与球“隔空弹开”。3.2 为什么等质量碰撞可以“交换速度”动量守恒加能量守恒是推导的起点。两个质量相等的小球发生一维正碰时碰撞后两球速度完全交换运动的球停下来静止的球以同样速度出去。二维斜碰不能直接交换x和y的整体速度否则球会朝莫名其妙的方向飞。正确做法是把两球的速度沿碰撞法线也就是两球连心线方向和切线方向分解法线方向套用一维交换公式切线方向保持不变。很多实现只在x、y分量上做简单交换看起来球也弹开了但斜碰角度是错的。这份资源的描述提到“根据矢量合成两球交换x y上的速度”具体实现会有多种写法我见过不少作业用的是“法线方向交换分量”这个严谨版本这也是答辩时最不容易被追问倒的版本。3.3 碰撞处理的C代码骨架这个处理函数是这类项目的核心我给出一个完整可读的骨架void collideBalls(Ball* a, Ball* b) { float dx b-x - a-x; float dy b-y - a-y; float dist sqrtf(dx * dx dy * dy); if (dist 0.0f) return; // 完全重合跳过本次 if (dist BALL_DIAMETER) return; // 未接触 // 归一化法向量从球a指向球b float nx dx / dist; float ny dy / dist; // 相对速度在法向方向上的分量 float va_n a-vx * nx a-vy * ny; float vb_n b-vx * nx b-vy * ny; // 等质量弹性碰撞法向分量交换 float va_n_new vb_n; float vb_n_new va_n; // 换回x、y分量 a-vx a-vx - va_n * nx va_n_new * nx; a-vy a-vy - va_n * ny va_n_new * ny; b-vx b-vx - vb_n * nx vb_n_new * nx; b-vy b-vy - vb_n * ny vb_n_new * ny; // 位置分离防止两球重叠后反复触发碰撞 float overlap BALL_DIAMETER - dist; a-x - overlap * 0.5f * nx; a-y - overlap * 0.5f * ny; b-x overlap * 0.5f * nx; b-y overlap * 0.5f * ny; }逻辑说明先计算两球连心线方向的单位向量这个方向就是碰撞法线。然后把每个球的速度投影到法线上得到法向分量va_n、vb_n。等质量碰撞下这两个法向分量直接交换。交换完成后再把新的法向分量乘回法向量叠加到原速度上得到碰撞后的x、y速度。最后一步位置分离很关键——如果不把重叠的两球推开下一帧距离依然小于阈值碰撞会被反复触发出现“粘球”。参数说明BALL_RADIUS是球的半径取值按桌面视觉比例定常见做法是8到12像素dist是两球心距离va_n、vb_n是标量不是向量理解这一点是看懂整个函数的关键。这里交换的是法向分量切向分量从头到尾没动所以两球在相切方向上的速度保持原样斜碰效果才自然。主循环里对所有球做两两配对依次调用这个函数就完成了所有球之间的碰撞处理。3.4 碰墙反向与出界钳制防止球飞出桌面碰墙逻辑比球碰球简单。水平墙只翻转y方向速度垂直墙只翻转x方向速度。但光翻转速度不够如果球已经嵌入墙壁要把它推回界内否则下一帧还在墙外速度又被翻转一次看起来像球在墙边抽搐。常见做法是判断越界后立即修正坐标到边界内void collideWall(Ball* ball, float left, float right, float top, float bottom) { if (ball-x - BALL_RADIUS left) { ball-x left BALL_RADIUS; ball-vx -ball-vx; // 左墙水平速度反向 } if (ball-x BALL_RADIUS right) { ball-x right - BALL_RADIUS; ball-vx -ball-vx; } if (ball-y - BALL_RADIUS top) { ball-y top BALL_RADIUS; ball-vy -ball-vy; // 上墙垂直速度反向 } if (ball-y BALL_RADIUS bottom) { ball-y bottom - BALL_RADIUS; ball-vy -ball-vy; } }这段代码里的四个边界值来自桌面的绘制坐标在init里初始化。修正坐标放在速度反向之后没有问题只要保证同一帧内完成“检测→反向→归位”三步就行。容易踩的坑是只反向速度不归位球速度越大出界越深表现就越像穿越。4. 从源码到可运行画面VS2013编译、Easy_X配置与Release运行拿到代码到看见台球桌中间隔着环境配置这一步。这套资源基于VS2013和Easy_X图形库能把这一步走顺后面改代码才有意义。先双击“魔王勇者桌球大乱斗.sln”如果你的VS版本比2013新会弹出工具集升级提示直接确认就行一般不会出问题。4.1 打开 .sln 之后的三个动作第一件事看活动配置。VS顶部工具栏的解决方案配置默认可能是Debug如果是课设演示建议切到Release。第二件事确认平台是x86还是x64Easy_X的早期版本和一些链接问题都跟平台位数有关这份工程大概率是x86平台编译的新机器上也优先选x86避免出现无法解析的外部符号之类的链接错误。第三件事是重新生成解决方案快捷键CtrlShiftB然后看输出窗口的错误列表。如果编译直接通过说明机器上的Easy_X环境是好的。如果报错90%是头文件路径问题具体处理放下一章。编译成功后exe会生成在当前活动配置对应的目录里文件名和工程名一致魔王勇者桌球大乱斗.exe。Debug和Release的exe不要混用课件演示前确认活动配置是Release。4.2 Easy_X图形库安装与包含目录配置Easy_X是C/C的简易绘图库Windows下常见的安装方式是下载安装包后运行它会自动把include和lib配置给Visual Studio。有的教程写成EasyX指的是同一个库不用纠结。安装完成后在工程里包含头文件#include graphics.h // Easy_X 绘图函数与窗口管理 #include conio.h // _getch() 等控制台输入函数这两个头文件几乎每个用Easy_X的C语言项目都会出现。graphics.h提供initgraph、closegraph、loadimage、putimage、setfillcolor等绘图函数conio.h在接收按键时用到。如果安装后依然找不到头文件手动把Easy_X安装目录下的include路径加到项目属性→VC目录→包含目录lib路径加到库目录这个操作对VS2013和更高版本都适用。画布刷新还涉及一个容易忽略的点Easy_X默认是直接绘图到窗口球多的时候会闪烁。常见做法是用BeginBatchDraw和EndBatchDraw包住show函数里的绘图部分先把所有图元画到内存缓冲再一次提交到屏幕。这份资源里如果已经这么做画面会很平滑如果没有自己加这两行也能立刻改善闪烁。答辩时主动提“用了双缓冲避免闪烁”是比“我调用了绘图函数”高一个段位的回答。4.3 直接运行Release里的可执行文件不想折腾编译环境直接进Release目录双击exe也可以。这里有个前提exe要找得到resourse目录里的图片资源。如果只把exe复制到桌面单独运行大概率黑屏或闪退因为相对路径找不到素材。正确姿势是保持Release目录完整或者把整个项目目录一起带走。文件清单可以对照下面这张表这是这组资源里最需要记的一张表标注了哪些文件运行必需哪些只是编译痕迹文件作用是否必需魔王勇者桌球大乱斗.sln解决方案文件VS双击打开项目编译必需main.cpp全部源代码编译必需resourse 目录图片/音效资源运行期加载运行必需Release/魔王勇者桌球大乱斗.exe编译好的程序直接运行必需C语言程序设计大作业文档.docx课设说明书交文档需要C语言答辩PPT.pptx答辩演示答辩需要.suo/.sdf/.obj/.ilk/.pdbIDE缓存、中间文件可以忽略单个文件看起来不复杂但它们的关系决定了交付时文件夹里该保留哪些。常见做法是把Release整个目录作为演示版工程源码和文档单独建文件夹。把Debug目录当成果交上去是最常见的失误Debug里的exe只是编译验证启动慢、体积大换一台没装调试符号的机器反而跑不起来。提示Release目录里的exe如果提示缺少VC运行库组件把项目属性里的运行库改成多线程静态链接也就是/MT重新编译一次exe就不依赖目标机器安装运行库了。5. 踩坑集合编译报错、闪退、穿模与答辩追问这部分是这类项目最容易被卡住的四关每一条都是真实出现过的翻车记录按现象、原因、解决三个步骤写能对上哪条就处理哪条。5.1 现象编译报错“无法打开包括文件 graphics.h”原因电脑上没装Easy_X图形库或者装了但VS没把include路径指过去。graphics.h不是C语言标准头文件也不是Windows SDK自带的它随Easy_X一起安装。解决先装Easy_X装完重新打开工程再生成。如果还报错在项目属性→VC目录→包含目录里手动加进Easy_X的include路径。两步都做了仍然报错检查安装的Easy_X位数和工程平台是否一致x86工程配x64库库会出现典型的头文件找不到或链接失败。5.2 现象双击Release里的exe闪退或黑屏原因闪退多半是exe所在目录没有resourse资源文件夹代码用相对路径加载图片时找不到文件init阶段就退出了。黑屏是窗口创建成功但图片没加载或刷新循环没有跑起来。解决保持Release目录完整exe和resourse必须在同一级目录下再双击。从VS里F5启动还黑屏检查show是否被调用以及initgraph和loadimage的调用顺序。我一般在init里先initgraph再loadimage顺序反过来容易出一段时间黑屏后才出图的现象。用Release时双击exe用Debug时从IDE启动不要混用。5.3 现象球速一调大就穿模两球还会粘在一起原因位置更新是每帧先移动再检测碰撞球速高时一帧内位移超过球半径两球可能从“未碰撞”直接跳到“互相穿透”检测条件被跳过这就是常说的隧穿。粘球则是碰撞后没做位置分离重叠状态下每帧都触发碰撞法向分量来回交换表现就是球粘住了。解决第一步把球速上限限制在单帧位移不超过球半径的范围比如半径10像素时每帧位移不超过8像素。第二步补上3.3节的位置分离代码碰撞后立即把球心推到刚好接触的位置。第三部如果还不够把一帧的物理更新拆成多个子步进比如1/2或1/4步长相当于提高采样率。按性价比排序位置分离必须做速度上限最直接子步进留给追求效果的人。5.4 现象答辩时碰撞模型被老师追问到卡壳原因PPT里写了“动量守恒、交换速度”但没准备二维斜碰更深入的推导。老师常问“两个球质量一样碰撞后为什么速度交换”也常问“斜着碰和正着碰有什么区别”。解决把3.2节的法向分量交换理解到位。正碰时连心线与速度方向重合法向分量就是速度本身交换法向分量等于交换整个速度斜碰时连心线与速度方向有夹角必须先分解到法线和切线方向只有法向分量交换。回答时先画一条连心线再写交换公式。这是答辩现场最能体现水平的几秒钟也是对这份资源里碰撞值不值钱的关键验证。5.5 现象换一台电脑双击exe提示缺少DLL或运行时组件原因程序用的是VS2013的VC运行库编译目标机器上可能没有对应版本运行库或缺少Easy_X依赖的动态库。解决把项目属性→C/C→代码生成→运行库改成多线程静态链接对应/MT重编后exe自带运行库不再依赖系统里装没装VC Redistributable。同时把Release目录里出现的dll文件与exe一并拷走。这个是课设交接时最常见的隐藏问题也是我看过最多人在答辩现场栽跟头的地方提前处理能省一晚上折腾。6. 进阶改法进球判定与双人计分的落地拿到能跑的源码只是第一步答辩想站住脚至少要有功能改动。两个方向性价比最高进球检测和双人对战。6.1 加进球检测在桌面四角和两边中间定义球袋坐标球心与袋口圆心距离小于袋口半径就算进球。放在refreshWithoutInput里每个球位移后查一次。int isPocketed(Ball* ball, Pocket* pockets, int pocketCount) { for (int i 0; i pocketCount; i) { float dx ball-x - pockets[i].x; float dy ball-y - pockets[i].y; if (dx * dx dy * dy pockets[i].radius * pockets[i].radius) { return 1; } } return 0; }说明Pocket结构体里放袋口圆心坐标和半径半径一般比球半径大两三个像素这样进球手感不刁钻。比较用平方形式避免每帧调用sqrt。进袋后的球要标记为不可见并停止参与两两碰撞检测否则一个已经“消失”的球还在桌面里挡路体验很怪。6.2 改成双人计分对战击球权用全局变量turn记录0和1交替。每次击球完成后turn取反进袋加分后比分显示用Easy_X的outtextxy绘制文字即可。这样改完演示时就有了“我打一下、你打一下”的互动感比单机演示耐看答辩时也让老师有参与体验。我自己改这个资源时最受用的习惯是每次改完代码先跑Release里的旧exe对比行为再跑自己编译的新exe两边手感差多少一目了然。答辩前把Release作为演示版本调试版本留在工程里。这套流程走顺基本两小时能出一版能跑、能讲、能答的课设。从那以后我每次跑这套工程都强制走一遍“Release旧版对比→新版冒烟→PPT核对代码”的流程避免在讲台上当着老师的面翻车。希望帮到你。本文还有配套的精品资源点击获取
返回列表