剛體碰撞檢測與響應(C++實現)

本文實現一個經典的物理算法:剛體碰撞檢測與響應。這個算法用于檢測兩個剛體(如矩形或圓形)是否發生碰撞,并在碰撞時更新它們的速度和位置。我們將使用C++來實現這個算法,并結合**邊界框(Bounding Box)**數據結構來管理剛體的碰撞檢測。


1. 問題描述

剛體碰撞檢測與響應是物理引擎中的核心問題。我們將實現一個簡單的二維剛體碰撞系統,支持矩形和圓形剛體的碰撞檢測,并在碰撞時應用基本的物理響應(如動量守恒)。


2. 數據結構設計

  • 剛體(RigidBody):包含位置、速度、質量、形狀(矩形或圓形)等屬性。
  • 邊界框(BoundingBox):用于快速檢測剛體是否可能發生碰撞。
  • 系統(CollisionSystem):管理所有剛體,并檢測和處理碰撞。

3. 算法實現

#include <iostream>
#include <vector>
#include <cmath>// 定義二維向量
struct Vector2 {double x, y;Vector2(double x = 0, double y = 0) : x(x), y(y) {}Vector2 operator+(const Vector2& other) const {return Vector2(x + other.x, y + other.y);}Vector2 operator-(const Vector2& other) const {return Vector2(x - other.x, y - other.y);}Vector2 operator*(double scalar) const {return Vector2(x * scalar, y * scalar);}double length() const {return std::sqrt(x * x + y * y);}
};// 剛體形狀基類
struct Shape {virtual bool collidesWith(const Shape* other) const = 0;virtual ~Shape() = default;
};// 圓形剛體
struct Circle : Shape {double x, y; // 圓形的位置double radius;Circle(double x, double y, double r) : x(x), y(y), radius(r) {}bool collidesWith(const Shape* other) const override {if (const Circle* circle = dynamic_cast<const Circle*>(other)) {double distance = (Vector2(x, y) - Vector2(circle->x, circle->y)).length();return distance <= (radius + circle->radius);}return false;}
};// 矩形剛體
struct Rectangle : Shape {double x, y; // 矩形的位置double width, height;Rectangle(double x, double y, double w, double h) : x(x), y(y), width(w), height(h) {}bool collidesWith(const Shape* other) const override {if (const Rectangle* rect = dynamic_cast<const Rectangle*>(other)) {return !(x + width < rect->x || rect->x + rect->width < x ||y + height < rect->y || rect->y + rect->height < y);}return false;}
};// 剛體類
struct RigidBody {Vector2 position;Vector2 velocity;double mass;Shape* shape;RigidBody(Vector2 pos, Vector2 vel, double m, Shape* s): position(pos), velocity(vel), mass(m), shape(s) {// 更新形狀的位置if (Circle* circle = dynamic_cast<Circle*>(shape)) {circle->x = pos.x;circle->y = pos.y;} else if (Rectangle* rect = dynamic_cast<Rectangle*>(shape)) {rect->x = pos.x;rect->y = pos.y;}}void update(double dt) {position = position + velocity * dt;// 更新形狀的位置if (Circle* circle = dynamic_cast<Circle*>(shape)) {circle->x = position.x;circle->y = position.y;} else if (Rectangle* rect = dynamic_cast<Rectangle*>(shape)) {rect->x = position.x;rect->y = position.y;}}
};// 碰撞系統類
struct CollisionSystem {std::vector<RigidBody*> bodies;void addBody(RigidBody* body) {bodies.push_back(body);}void checkCollisions() {for (size_t i = 0; i < bodies.size(); ++i) {for (size_t j = i + 1; j < bodies.size(); ++j) {if (bodies[i]->shape->collidesWith(bodies[j]->shape)) {resolveCollision(bodies[i], bodies[j]);}}}}void resolveCollision(RigidBody* body1, RigidBody* body2) {// 簡單動量守恒碰撞響應Vector2 relativeVelocity = body2->velocity - body1->velocity;Vector2 normal = (body2->position - body1->position).length() > 0? (body2->position - body1->position) * (1.0 / (body2->position - body1->position).length()): Vector2(1, 0);double velocityAlongNormal = relativeVelocity.x * normal.x + relativeVelocity.y * normal.y;if (velocityAlongNormal > 0) return; // 已經分離,不需要處理double e = 1.0; // 恢復系數(完全彈性碰撞)double j = -(1 + e) * velocityAlongNormal;j /= (1 / body1->mass + 1 / body2->mass);Vector2 impulse = normal * j;body1->velocity = body1->velocity - impulse * (1 / body1->mass);body2->velocity = body2->velocity + impulse * (1 / body2->mass);}void update(double dt) {for (auto body : bodies) {body->update(dt);}checkCollisions();}
};int main() {// 創建碰撞系統CollisionSystem system;// 創建剛體RigidBody* body1 = new RigidBody(Vector2(0, 0), Vector2(1, 0), 1.0, new Circle(0, 0, 1.0));RigidBody* body2 = new RigidBody(Vector2(3, 0), Vector2(-1, 0), 1.0, new Circle(3, 0, 1.0));system.addBody(body1);system.addBody(body2);// 模擬double dt = 0.01;for (int i = 0; i < 100; i++) {system.update(dt);std::cout << "Body1 Position: (" << body1->position.x << ", " << body1->position.y << ")\n";std::cout << "Body2 Position: (" << body2->position.x << ", " << body2->position.y << ")\n";}// 釋放內存delete body1->shape;delete body2->shape;delete body1;delete body2;return 0;
}

4. 代碼解釋

  1. Vector2:表示二維向量,支持加減乘等操作。
  2. Shape:剛體形狀基類,支持圓形和矩形的碰撞檢測。
  3. CircleRectangle:分別表示圓形和矩形剛體,實現碰撞檢測邏輯。
  4. RigidBody:表示剛體,包含位置、速度、質量和形狀。
  5. CollisionSystem:管理所有剛體,檢測碰撞并應用碰撞響應。
  6. main函數:創建系統、剛體,并進行模擬。

5. 運行結果

程序會輸出兩個剛體的位置隨時間的變化,模擬它們的碰撞和運動。

在這里插入圖片描述


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/75053.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/75053.shtml
英文地址,請注明出處:http://en.pswp.cn/web/75053.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

常用的國內鏡像源

常見的 pip 鏡像源 阿里云鏡像&#xff1a;https://mirrors.aliyun.com/pypi/simple/ 清華大學鏡像&#xff1a;https://pypi.tuna.tsinghua.edu.cn/simple 中國科學技術大學鏡像&#xff1a;https://pypi.mirrors.ustc.edu.cn/simple/ 豆瓣鏡像&#xff1a;https://pypi.doub…

鴻蒙小案例-京東登錄

效果 代碼實現 Entry Component struct Index {build() {Column() {Row() {Image($r(app.media.jd_cancel)).width(20)Text(幫助).fontSize(16).fontColor(#666)}.width(100%).justifyContent(FlexAlign.SpaceBetween)Image($r(app.media.jd_logo)).height(250).width(250)// …

《 Scikit-learn與MySQL的深度協同:構建智能數據生態系統的架構哲學》

在機器學習工程實踐中&#xff0c;數據存儲與模型訓練的割裂始終是制約算法效能的關鍵瓶頸。Scikit-learn作為經典機器學習庫&#xff0c;其與MySQL的深度協同并非簡單的數據管道連接&#xff0c;而是構建了一個具備自組織能力的智能數據生態系統。這種集成突破了傳統ETL流程的…

華為AI-agent新作:使用自然語言生成工作流

論文標題 WorkTeam: Constructing Workflows from Natural Language with Multi-Agents 論文地址 https://arxiv.org/pdf/2503.22473 作者背景 華為&#xff0c;北京大學 動機 當下AI-agent產品百花齊放&#xff0c;盡管有ReAct、MCP等框架幫助大模型調用工具&#xff0…

關于軟件bug描述

軟件缺陷&#xff08;Defect&#xff09;&#xff0c;常常又被叫做Bug。 所謂軟件缺陷&#xff0c;即為計算機軟件或程序中存在的某種破壞正常運行能力的問題、錯誤&#xff0c;或者隱藏的功能缺陷。缺陷的存在會導致軟件產品在某種程度上不能滿足用戶的需要。IEEE729-1983對缺…

【元表 vs 元方法】

元表 vs 元方法 —— 就像“魔法書”和“咒語”的關系 1. 元表&#xff08;Metatable&#xff09;&#xff1a;魔法書 是什么&#xff1f; 元表是一本**“規則說明書”**&#xff0c;它本身是一個普通的 Lua 表&#xff0c;但可以綁定到其他表上&#xff0c;用來定義這個表應該…

Spring Boot 通過全局配置去除字符串類型參數的前后空格

1、問題 避免前端輸入的字符串參數兩端包含空格&#xff0c;通過統一處理的方式&#xff0c;trim掉空格 2、實現方式 /*** 去除字符串類型參數的前后空格* author yanlei* since 2022-06-14*/ Configuration AutoConfigureAfter(WebMvcAutoConfiguration.class) public clas…

C語言核心知識點整理:結構體對齊、預處理、文件操作與Makefile

目錄 結構體的字節對齊預處理指令詳解文件操作基礎Makefile自動化構建總結 1. 結構體的字節對齊 字節對齊原理 內存對齊&#xff1a;CPU訪問內存時&#xff0c;對齊的地址能提高效率。操作系統要求變量按類型大小對齊。對齊規則&#xff1a; 每個成員的起始地址必須是min(成…

VBA+BOS單據+插件,解決計劃任務跟蹤的問題之二:導入ERP

第二步&#xff0c;就是要將拆分好的任務導入ERP了 1、將建一個BOS單據叫“任務池”&#xff0c;大概是這樣的 然后在拆分工具中進行導數據&#xff0c;點擊“數據導出準備”&#xff0c;跳轉到“導入ERP”界面&#xff0c;然后點“獲取數據”&#xff0c;將拆分好的數據轉過來…

使用uglifyjs對靜態引入的js文件進行壓縮

前言 因為有時候js文件沒有npm包&#xff0c;或者需要修改&#xff0c;只能引入靜態的js&#xff0c;那么這個時候就可以對js進行壓縮了。我其實想通過vite、webpack等插件進行壓縮的&#xff0c;可是他都不能定位到public目錄下面的文件&#xff0c;所以我只能自己壓縮了。編…

藍橋杯 web 水果拼盤 (css3)

做題步驟&#xff1a; 看結構&#xff1a;html 、css 、f12 分析: f12 查看元素&#xff0c;你會發現水果的高度剛好和拼盤的高度一樣&#xff0c;每一種水果的盤子剛好把頁面填滿了&#xff0c;所以咱們就只要讓元素豎著排列&#xff0c;加上是豎著&#xff0c;排不下的換行…

差分音頻轉單端音頻單電源方案

TI LMV321介紹 TI的LMV321是單通道的低壓軌到軌輸出運算放大器&#xff0c;適用于需要低工作壓、節省空間和低成本的應用。 其中&#xff0c;芯片設計中的軌到軌輸出&#xff08;Rail-to-Rail Output&#xff09; 是指通過特定的電路設計&#xff0c;使芯片&#xff08;如運算…

Pandas 庫

Pandas 是一個開源的數據分析和數據處理庫&#xff0c;它是基于 Python 編程語言的。 Pandas 提供了易于使用的數據結構和數據分析工具&#xff0c;特別適用于處理結構化數據&#xff0c;如表格型數據 Pandas 是數據科學和分析領域中常用的工具之一&#xff0c;它使得用戶能夠…

Vue 3 的<Teleport>功能與用法

Vue 3 的 <Teleport> 功能與用法 1. 基本用法 <Teleport> 是 Vue 3 的一個內置組件&#xff0c;允許將組件的內容渲染到 DOM 中的任意位置&#xff0c;而不改變其邏輯結構。以下是基本用法&#xff1a; 定義目標 DOM 元素&#xff1a;<div id"teleport-…

MySQL隨機獲取記錄之方法(The Method of Randomly Obtaining Records in MySQL)

MySQL中如何隨機獲取一條記錄 隨機獲取一條記錄是在數據庫查詢中常見的需求&#xff0c;特別在需要展示隨機內容或者隨機推薦的場景下。在 MySQL 中&#xff0c;有多種方法可以實現隨機獲取一條記錄&#xff0c;每種方法都有其適用的情況和性能特點。在本文中&#xff0c;我們將…

synchronized鎖升級詳解

synchronized鎖升級詳解 synchronized是Java中實現線程同步的關鍵字&#xff0c;它在JVM內部實現了鎖的升級機制&#xff0c;從偏向鎖到輕量級鎖再到重量級鎖&#xff0c;這種優化是為了減少鎖操作帶來的性能開銷。 1. 鎖的四種狀態 Java對象頭中的Mark Word會記錄鎖的狀態&…

C++函數如何返回多個參數

在編程中&#xff0c;我們經常會遇到需要函數返回多個值的場景。雖然 C 函數不能直接返回多個參數&#xff0c;但通過一些間接的方法&#xff0c;我們可以輕松實現這一需求。本文將詳細介紹幾種常見的實現方式&#xff0c;并分析它們的優缺點和適用場景。 1. 引言 在 C 中&…

最新版PhpStorm超詳細圖文安裝教程,帶補丁包(2025最新版保姆級教程)

目錄 前言 一、PhpStorm最新版下載 二、PhpStorm安裝 三、PhpStorm補丁 四、運行PhpStorm 前言 PhpStorm 是 JetBrains 公司推出的 專業 PHP 集成開發環境&#xff08;IDE&#xff09;&#xff0c;專為提升 PHP 開發效率設計。其核心功能包括智能代碼補全、實時語法錯誤檢…

【雜談】Godot4.4導出到Android平臺(正式導出)

學博而后可約&#xff0c;事歷而后知要。 目錄 一、準備二、Gradle構建三、配置Java SDK四、配置Android SDK五、配置密鑰 一、準備 本文在前文【雜談】Godot4.4導出到安卓平臺&#xff08;調試導出&#xff09;的基礎上&#xff0c;進行正式導出。調試導出并不是真正的編譯導…

隔行換色總結

功能效果展示&#xff1a; 第一種思路&#xff1a; 使用數組&#xff0c;將數組的內容渲染到頁面上&#xff0c;序號也就是將數組的下標輸出到第一個td上&#xff0c;將數組的內容輸出到第二個td上&#xff0c;&#xff08;使用拼接字符串&#xff09; 具體操作&#xff1a; …