当前位置: 首页 > news >正文

关于C语言的模拟物理模型

声明:本文全部代码效果基于C语言easyx图形界面库。

引言

关于很多游戏和模型的开发,都需要模拟真实的物理模型

比如:基本矢量运动模型(位移,速度,加速度),重力模型,碰撞模型,万有引力模型。

本文我会一一介绍这几种模型的开发。

既然是模拟显示物理模型,那么引入的现实物理公式也是必要的。

本文所需要引用的公式有:其中TIKME_STEP是每帧变化的量,来弥补时间效果和逐帧效果的差

最后的总物理模型的话,可以选择性给出每个球的状态情况,比如每个方向的初速度,初加速度,以及是否受重力和球之间的万有引力,对偏心碰撞,边框碰撞。

代码

位移公式 : ▲x = v * t  

程序内使用:x += vx  y+= vy (逐帧使用)
void move()//移动
{for (int i = 0; i <= 20; i++) {if (a[i].live) {a[i].x += a[i].vx * TIME_STEP;a[i].y += a[i].vy * TIME_STEP;}}
}

速度公式 :▲v = a * t 

程序内使用  vx += ax  vy += ay (逐帧使用)
void speed()//速度变化
{for (int i = 0; i <= 20; i++) {if (a[i].live) {a[i].vx += a[i].ax * TIME_STEP;a[i].vy += a[i].ay * TIME_STEP;}}
}

加速度公式:a = F / m

程序内使用 (Fx+Fx1+Fx2...) / m = ax  (Fy+Fy1+Fy2...) / m = ay
void Fa()//受力
{for (int i = 0; i <= 20; i++) {if (a[i].live) {a[i].ax = (a[i].Fx + a[i].Fwx) / a[i].m;a[i].ay = (a[i].Fy + a[i].GN + a[i].Fwy) / a[i].m;}}
}

重力公式: G = mg

程序内使用 G = m*g  (g预定义数值) 然后G 是Fy的组成元素a[i].GN = a[i].m * g;

碰撞前后的动量守恒和能量守恒

m1*v1 + m2*v2 = m1*v3+m2*v4;

0.5*m1*v1*v1 + 0.5*m2*v2*v2 = 0.5*m1*v3*v3 + 0.5*m2*v3*v4;

然后再考虑是否对心碰撞分析左右偏移向量

// 检测并处理小球碰撞
void collisionDetection()
{for (int i = 0; i < 20; i++) {if (a[i].live) {for (int j = i + 1; j <= 20; j++) {if (a[j].live) {double dx = a[i].x - a[j].x;double dy = a[i].y - a[j].y;double distance = sqrt(dx * dx + dy * dy);if (distance < 100) { // 两个小球半径之和为100double m1 = a[i].m;double m2 = a[j].m;double v1ix = a[i].vx;double v1iy = a[i].vy;double v2ix = a[j].vx;double v2iy = a[j].vy;// 计算碰撞法线方向的单位向量double n_x = dx / distance;double n_y = dy / distance;// 计算相对速度在法线方向和切线方向的分量double v1n = v1ix * n_x + v1iy * n_y;double v2n = v2ix * n_x + v2iy * n_y;double v1t = v1iy * n_x - v1ix * n_y;double v2t = v2iy * n_x - v2ix * n_y;// 应用动量守恒和恢复系数计算碰撞后的法向速度double v1nf = ((m1 - m2) * v1n + 2 * m2 * v2n + RESTITUTION_COEFFICIENT * m2 * (v2n - v1n)) / (m1 + m2);double v2nf = ((m2 - m1) * v2n + 2 * m1 * v1n + RESTITUTION_COEFFICIENT * m1 * (v1n - v2n)) / (m1 + m2);// 切线方向速度不变(假设无摩擦力)double v1tf = v1t;double v2tf = v2t;// 将法向和切向速度转换回笛卡尔坐标系a[i].vx = v1nf * n_x - v1tf * n_y;a[i].vy = v1nf * n_y + v1tf * n_x;a[j].vx = v2nf * n_x - v2tf * n_y;a[j].vy = v2nf * n_y + v2tf * n_x;}}}}}
}

边框碰撞模型

void peng()//碰撞影响一定放到位置更新之后
{for (int i = 0; i <= 20; i++) {if (a[i].live) {if (a[i].y - 50 < 0) {a[i].y = 50;  // 精确调整位置到边界a[i].vy = -a[i].vy;  // 确保速度反向}if (a[i].x - 50 < 0) {a[i].x = 50;a[i].vx = -a[i].vx;}if (a[i].y + 50 > high) {a[i].y = high - 50;a[i].vy = -a[i].vy;}if (a[i].x + 50 > width) {a[i].x = width - 50;a[i].vx = -a[i].vx;}}}
}

检测遇到边界后,改变水平或者垂直方向的速度方向相反,保持速度大小不变,

实现碰撞墙壁效果。

万有引力模型

F万 =  G*m1*m2/(x*x)


void F_allocation()
{double sin_w = (a[0].y - a[1].y) / sqrt((a[0].y - a[1].y) * (a[0].y - a[1].y) + (a[0].x - a[1].x) * (a[0].x - a[1].x));double cos_w = (a[0].x - a[1].x) / sqrt((a[0].y - a[1].y) * (a[0].y - a[1].y) + (a[0].x - a[1].x) * (a[0].x - a[1].x));double Fw = Gk * a[0].m * a[1].m / ((a[0].y - a[1].y) * (a[0].y - a[1].y) + (a[0].x - a[1].x) * (a[0].x - a[1].x));a[0].Fwx = -Fw * cos_w;a[0].Fwy = -Fw * sin_w;a[1].Fwx = -a[0].Fwx;a[1].Fwy = -a[0].Fwy;
}

关于运行前的准备

预编译和结构体

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <time.h>
#include <stdbool.h>
#include <math.h>#define g 98
#define width 1700
#define high 1000
#define TIME_STEP 0.05  // 固定时间步长
#define Gk 677770
#define RESTITUTION_COEFFICIENT 0.8 // 恢复系数,0 <= e <= 1,0为完全非弹性,1为完全弹性typedef struct stu {double x;double y;double ax;double ay;double vx;double vy;double Fx;double Fy;double Fwx;double Fwy;double m;double GN;bool live;
} G;

代码是集成的,每个作用都在,如果要研究其中某种模型,只需要调用该模型函数即可。

比如研究万有引力模型,需要将重力模型关掉,然后控制不要碰撞,这里数值我测出来了一个效果就是,用假设初速度完全满足万有引力提供向心力从而做圆周运动的模型,

我们需要将两个球的质量全设置为10,然后锁定右侧球,两球高度一致,赋予左球vy = 130便可以满足万有引力完全提供向心力的天体匀速圆周模型。

展示总函数

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <time.h>
#include <stdbool.h>
#include <math.h>#define g 98
#define width 1700
#define high 1000
#define TIME_STEP 0.05  // 固定时间步长
#define Gk 677770
#define RESTITUTION_COEFFICIENT 0.8 // 恢复系数,0 <= e <= 1,0为完全非弹性,1为完全弹性typedef struct stu {double x;double y;double ax;double ay;double vx;double vy;double Fx;double Fy;double Fwx;double Fwy;double m;double GN;bool live;
} G;G a[21];void Fa()//受力
{for (int i = 0; i <= 20; i++) {if (a[i].live) {a[i].ax = (a[i].Fx + a[i].Fwx) / a[i].m;a[i].ay = (a[i].Fy + a[i].GN + a[i].Fwy) / a[i].m;}}
}void speed()//速度变化
{for (int i = 0; i <= 20; i++) {if (a[i].live) {a[i].vx += a[i].ax * TIME_STEP;a[i].vy += a[i].ay * TIME_STEP;}}
}void move()//移动
{for (int i = 0; i <= 20; i++) {if (a[i].live) {a[i].x += a[i].vx * TIME_STEP;a[i].y += a[i].vy * TIME_STEP;}}
}void draw()
{for (int i = 0; i <= 20; i++) {if (a[i].live) {solidcircle((int)a[i].x, (int)a[i].y, 50);}}
}void peng()//碰撞影响一定放到位置更新之后
{for (int i = 0; i <= 20; i++) {if (a[i].live) {if (a[i].y - 50 < 0) {a[i].y = 50;  // 精确调整位置到边界a[i].vy = -a[i].vy;  // 确保速度反向}if (a[i].x - 50 < 0) {a[i].x = 50;a[i].vx = -a[i].vx;}if (a[i].y + 50 > high) {a[i].y = high - 50;a[i].vy = -a[i].vy;}if (a[i].x + 50 > width) {a[i].x = width - 50;a[i].vx = -a[i].vx;}}}
}void init()
{for (int i = 0; i <= 20; i++) {a[i].x = 0;a[i].y = 0;a[i].ax = 0;a[i].ay = 0;a[i].vx = 0;a[i].vy = 0;a[i].Fx = 0;a[i].Fy = 0;a[i].Fwx = 0;a[i].Fwy = 0;a[i].m = 10;a[i].live = false;a[i].GN = a[i].m * g;}
}void F_allocation()
{double sin_w = (a[0].y - a[1].y) / sqrt((a[0].y - a[1].y) * (a[0].y - a[1].y) + (a[0].x - a[1].x) * (a[0].x - a[1].x));double cos_w = (a[0].x - a[1].x) / sqrt((a[0].y - a[1].y) * (a[0].y - a[1].y) + (a[0].x - a[1].x) * (a[0].x - a[1].x));double Fw = Gk * a[0].m * a[1].m / ((a[0].y - a[1].y) * (a[0].y - a[1].y) + (a[0].x - a[1].x) * (a[0].x - a[1].x));a[0].Fwx = -Fw * cos_w;a[0].Fwy = -Fw * sin_w;//a[1].Fwx = -a[0].Fwx;//a[1].Fwy = -a[0].Fwy;
}// 检测并处理小球碰撞
void collisionDetection()
{for (int i = 0; i < 20; i++) {if (a[i].live) {for (int j = i + 1; j <= 20; j++) {if (a[j].live) {double dx = a[i].x - a[j].x;double dy = a[i].y - a[j].y;double distance = sqrt(dx * dx + dy * dy);if (distance < 100) { // 两个小球半径之和为100double m1 = a[i].m;double m2 = a[j].m;double v1ix = a[i].vx;double v1iy = a[i].vy;double v2ix = a[j].vx;double v2iy = a[j].vy;// 计算碰撞法线方向的单位向量double n_x = dx / distance;double n_y = dy / distance;// 计算相对速度在法线方向和切线方向的分量double v1n = v1ix * n_x + v1iy * n_y;double v2n = v2ix * n_x + v2iy * n_y;double v1t = v1iy * n_x - v1ix * n_y;double v2t = v2iy * n_x - v2ix * n_y;// 应用动量守恒和恢复系数计算碰撞后的法向速度double v1nf = ((m1 - m2) * v1n + 2 * m2 * v2n + RESTITUTION_COEFFICIENT * m2 * (v2n - v1n)) / (m1 + m2);double v2nf = ((m2 - m1) * v2n + 2 * m1 * v1n + RESTITUTION_COEFFICIENT * m1 * (v1n - v2n)) / (m1 + m2);// 切线方向速度不变(假设无摩擦力)double v1tf = v1t;double v2tf = v2t;// 将法向和切向速度转换回笛卡尔坐标系a[i].vx = v1nf * n_x - v1tf * n_y;a[i].vy = v1nf * n_y + v1tf * n_x;a[j].vx = v2nf * n_x - v2tf * n_y;a[j].vy = v2nf * n_y + v2tf * n_x;}}}}}
}int main()
{init();a[0].live = true;a[0].x = 200;a[0].y = 500;/*a[0].vx = 50;a[0].vy = 20;*/a[1].m = 10;a[1].live = true;a[1].x = 600;a[1].y = 500;/*a[1].vx = 30;a[1].vy = 20;*/// 初始化图形窗口,大小为 width x highinitgraph(width, high);// 设置填充颜色为绿色setfillcolor(GREEN);BeginBatchDraw();while (!_kbhit()) {cleardevice(); // 清除绘图// F_allocation();Fa();speed();move();peng();collisionDetection(); // 检测并处理碰撞draw();FlushBatchDraw();Sleep(8);}EndBatchDraw();// 关闭图形窗口closegraph();return 0;
}

本文展现的是集成的物理模型框架,感兴趣的可以尝试调试实现各种效果。

我自己测试的是

1,万有引力完全提供向心力的匀速圆周运动

2,对偏心碰撞的守恒

3,以及编写初期的重力测试,和碰撞测试,加速度测试。

至于运行效果,这博客也不好发视频,大家可以尝试敲一下代码运行试试。

当物理模型自己结合物理公式和编程写出来展现在眼前的物理运动时,是真的相信课本里说的天体运动,也是切身感受到了,还有碰撞问题,感觉可以写个桌球小游戏,不过这些交给大家发挥了,本文到此,感谢观看。

http://www.xdnf.cn/news/1297.html

相关文章:

  • vue3 el-dialog新增弹窗,不希望一进去就校验名称没有填写
  • SQL刷题记录贴
  • Oracle测试题目及笔记(单选)
  • 赛灵思 XCVU3P‑2FFVC1517I XilinxFPGA Virtex UltraScale+
  • AI在市场营销分析中的核心应用及价值,分场景详细说明
  • 【创新实训个人博客】前端实现
  • 【运维学习】lvs + keepalived + 主从dns 项目搭建
  • Valgrind的使用复习
  • 更换 CentOS 7.9 的系统源
  • 【软考-系统架构设计师】ATAM方法及效用树
  • 【python】pyCharm常用快捷键使用-(2)
  • C++入门基础:命名空间,缺省参数,函数重载,输入输出
  • blender 录课键位显示插件(图文傻瓜式安装)
  • .net core 项目快速接入Coze智能体-开箱即用-全局说明
  • 数据结构之BFS广度优先算法(腐烂的苹果)
  • ARINC818-1协议
  • visual Studio+Qt插件检查内存泄漏
  • Azure 私有端点和存储帐户用例
  • 基于springboot医药连锁店管理系统(源码+lw+部署文档+讲解),源码可白嫖!
  • 【论文精读】COLMAP-Free 3D Gaussian Splatting
  • vue入门:路由 router
  • [GESP202409 二级] 小杨的 N 字矩阵 题解
  • 《如何用 Function 实现动态配置驱动的处理器注册机制?》
  • Ubuntu多用户VNC远程桌面环境搭建:从零开始的完整指南
  • 多路由器通过三层交换机互相通讯(单臂路由+静态路由+默认路由版),通过三层交换机让pc端相互通讯
  • C++之类模板
  • 定制化突围:遨游防爆手机的差异化竞争策略
  • 实战|使用环信Flutter SDK构建鸿蒙HarmonyOS应用及推送配置
  • vue MarkdownIt标签多出了<p>标签导致高度变丑
  • 前端路由缓存实现