本文实现一个经典的物理算法:刚体碰撞检测与响应。这个算法用于检测两个刚体(如矩形或圆形)是否发生碰撞,并在碰撞时更新它们的速度和位置。我们将使用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. 代码解释
- Vector2:表示二维向量,支持加减乘等操作。
- Shape:刚体形状基类,支持圆形和矩形的碰撞检测。
- Circle 和 Rectangle:分别表示圆形和矩形刚体,实现碰撞检测逻辑。
- RigidBody:表示刚体,包含位置、速度、质量和形状。
- CollisionSystem:管理所有刚体,检测碰撞并应用碰撞响应。
- main函数:创建系统、刚体,并进行模拟。
5. 运行结果
程序会输出两个刚体的位置随时间的变化,模拟它们的碰撞和运动。