关于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.mzph.cn/diannao/79351.shtml

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

相关文章

C++编译与链接:从源码到可执行文件的魔法之旅(Visual Studio实践)

文章目录 **C++编译与链接:从源码到可执行文件的魔法之旅(Visual Studio实践)****一、C++编译器的工作流程****二、Visual Studio环境配置实战****三、示例项目:Hello World全流程解析****四、高级技巧与工具链****五、总结与参考资料**C++编译与链接:从源码到可执行文件的…

现代C++的范式演进与工程实践深度解析(本文序号不知道怎么整的,有点问题)

引言:C++的复兴时代 在经历了"已死语言"的质疑后,现代C++正迎来前所未有的复兴。据2024年TIOBE指数显示,C++以8.33%的占比稳居第三,较2020年上升2.1个百分点。这种复兴并非偶然——随着C++20标准的全面落地和C++23特性的逐步实现,这门已有40年历史的语言正在系…

通过gird布局实现div的响应式分布排列

目标&#xff1a;实现对于固定宽度的div盒子在页面中自适应排布&#xff0c;并且最后一行的div盒子可以与前面的盒子对齐。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" con…

WSL2-Ubuntu22.04安装URSim5.21.3

WSL2-Ubuntu22.04安装URSim5.21.3 准备安装启动 准备 名称版本WSL2Ubuntu22.04URSim5.21.3VcXsrvNaN WSL2安装与可视化请见这篇:WSL2-Ubuntu22.04-配置。 安装 我们是wsl2-ubuntu22.04&#xff0c;所以安装Linux版本的URSim&#xff0c;下载之前需要注册一下&#xff0c;即…

产品研发项目管理6大痛点

在产品研发项目管理实践中&#xff0c;企业普遍面临六大系统性挑战&#x1f937;‍♀️&#xff0c;直接影响研发效能与战略目标达成&#x1f514;&#xff0c;具体表现为&#xff1a; ① 产品需求管理不完善&#xff1a;需求与市场脱节&#xff0c;需求不明确、需求变更频繁…

计算机网络基础概论

计算机网络基础概论 目录 一、网络基本概念 1.1. 网络 1.2 互联网 1.3 ip地址 1.3.1 作用 1.3.2 分类 1.4 MAC地址 1.4.1 MAC地址与 IP 地址的关系 1.5 网络协议 二、网络分层模型 2.1 物理层 2.2 数据链路层 2.3 网络层 2.4 传输层 2.5 会话层 2.6 表示层 2.7…

Windows下导入文件中的环境变量

在Windows批处理脚本&#xff08;.bat&#xff09;中&#xff0c;通过文件获取并设置环境变量通常涉及逐行读取文件内容并动态赋值给变量。以下是具体实现方法及示例&#xff1a; 一、从文件读取变量并设置到环境变量 假设有一个配置文件&#xff08;如env_config.txt&#xf…

WebSocket 实现数据实时推送原理

WebSocket 实现数据实时推送的核心机制在于其全双工通信能力和持久的连接特性。以下是其工作原理的详细步骤&#xff1a; 1. 握手阶段&#xff08;HTTP 升级协议&#xff09; 客户端发起请求&#xff1a;通过发送一个带有特殊头部的 HTTP 请求&#xff0c;请求协议升级。 GET …

Linux操作系统学习之---进程状态

目录 明确进程的概念: Linux下的进程状态: 虚拟终端的概念: 见一见现象: 用途之一 : 结合指令来监控进程的状态: 和进程强相关的系统调用函数接口: getpid()和getppid(): fork(): fork函数创建子进程的分流逻辑: 进程之间具有独立性: 进程中存在的写时拷贝: 见一见进程状态…

何小鹏在得意的笑

"小鹏汽车率先迈出了造车新势力出海一大步" 作者 | 魏强 编辑 | 卢旭成 4月15日&#xff0c;小鹏汽车在香港举行小鹏全球热爱之夜和2025首款全球旗舰小鹏X9上市发布会。 当小鹏汽车创始人何小鹏把香车X9交付给香港首批车主的时候&#xff0c;脸上露出经典的笑脸。…

@Autowird 注解与存在多个相同类型对象的解方案

现有一个 Student 类&#xff0c;里面有两个属性&#xff0c;分别为 name 和 id&#xff1b;有一个 StuService 类&#xff0c;里面有两个方法&#xff0c;返回值均为类型为 Student 的对象&#xff1b;还有一个 StuController 类&#xff0c;里面有一个 Student 类型的属性&am…

黑马商城项目(三)微服务

一、单体架构 测试高并发软件 二、微服务 三、SpringCloud 四、微服务拆分 黑马商城模块&#xff1a; 服务拆分原则&#xff1a; 拆分服务&#xff1a; 独立project&#xff1a; maven聚合&#xff1a; 拆分案例&#xff1a; 远程调用&#xff1a; package com.hmall.cart.…

PyTorch:学习 CIFAR-10 分类

&#x1f50d; 开始你的图像分类之旅&#xff1a;一步一步学习 CIFAR-10 分类 图像分类是计算机视觉中最基础的任务之一&#xff0c;如果你是初学者&#xff0c;那么以 CIFAR-10 为训练场是一个不错的选择。本文一步一步带你从零开始&#xff0c;学习如何用深度学习模型实现图…

3.学习笔记--Spring-AOP总结(p39)-Spring事务简介(P40)-Spring事务角色(P41)-Spring事务属性(P42)

1.AOP总结&#xff1a;面向切面编程&#xff0c;在不惊动原始基础上为方法进行功能增强。 2.AOP核心概念&#xff1a; &#xff08;1&#xff09;代理&#xff1a;SpringAOP的核心是采用代理模式 &#xff08;2&#xff09;连接点&#xff1a;在SpringAOP中&#xff0c;理解为任…

数据库-day06

一、实验名称和性质 分类查询 验证 综合 设计 二、实验目的 1&#xff0e;掌握数据查询的Group by &#xff1b; 2&#xff0e; 掌握聚集函数的使用方法。 三、实验的软硬件环境要求 硬件环境要求&#xff1a; PC机(单机) 使用的软件名称、版本号以及模块&#xff1a; …

看门狗定时器(WDT)超时

一、问题 Arduino 程序使用<Ticker.h>包时&#xff0c;使用不当情况下&#xff0c;会导致“看门狗WDT超时” 1.1问题控制台报错 在串口监视器显示 --------------- CUT HERE FOR EXCEPTION DECODER ---------------Soft WDT resetException (4): epc10x402077cb epc2…

AI在多Agent协同领域的核心概念、技术方法、应用场景及挑战 的详细解析

以下是 AI在多Agent协同领域的核心概念、技术方法、应用场景及挑战 的详细解析&#xff1a; 1. 多Agent协同的定义与核心目标 多Agent系统&#xff08;MAS, Multi-Agent System&#xff09;&#xff1a; 由多个独立或协作的智能体&#xff08;Agent&#xff09;组成&#xff…

Wireshark TS | 异常 ACK 数据包处理

问题背景 来自于学习群里群友讨论的一个数据包跟踪文件&#xff0c;在其中涉及到两处数据包异常现象&#xff0c;而产生这些现象的实际原因是数据包乱序。由于这两处数据包异常&#xff0c;都有点特别&#xff0c;本篇也就其中一个异常现象单独展开说明。 问题信息 数据包跟…

【React】项目的搭建

create-react-app 搭建vite 搭建相关下载 在Vue中搭建项目的步骤&#xff1a;1.首先安装脚手架的环境&#xff0c;2.通过脚手架的指令创建项目 在React中有两种方式去搭建项目&#xff1a;1.和Vue一样&#xff0c;先安装脚手架然后通过脚手架指令搭建&#xff1b;2.npx create-…

深入浅出 NVIDIA CUDA 架构与并行计算技术

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《深度探秘&#xff1a;AI界的007》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、CUDA为何重要&#xff1a;并行计算的时代 2、NVIDIA在…