记录一个开源的物理引擎:Physac
1、Physac介绍
Physac是一个开源的物理引擎,所有代码实现在头文件中,仅仅有2100行代码,移植接口只需要一个画线函数,因此很容易移植到嵌入式设备等,GitHub地址为https://github.com/victorfisac/Physac
2、引擎接口
引擎具有以下特性:
- 可以动态创建\销毁三种控件:圆形、多边形、四边形
- 可以改变全局重力方向
- 可以给控件添加力、角度力
- 用爆炸力将多边形物理体破碎成小物理体
API接口如下:
// Initializes physics values, pointers and creates physics loop thread
void InitPhysics(void);
// Returns true if physics thread is currently enabled
bool IsPhysicsEnabled(void);
// Sets physics global gravity force
void SetPhysicsGravity(float x, float y);
// Creates a new circle physics body with generic parameters
PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density);
// Creates a new rectangle physics body with generic parameters
PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density);
// Creates a new polygon physics body with generic parameters
PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density);
// Adds a force to a physics body
void PhysicsAddForce(PhysicsBody body, Vector2 force);
// Adds a angular force to a physics body
void PhysicsAddTorque(PhysicsBody body, float amount);
// Shatters a polygon shape physics body to little physics bodies with explosion force
void PhysicsShatter(PhysicsBody body, Vector2 position, float force);
// Returns the current amount of created physics bodies
int GetPhysicsBodiesCount(void);
// Returns a physics body of the bodies pool at a specific index
PhysicsBody GetPhysicsBody(int index);
// Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON)
int GetPhysicsShapeType(int index);
// Returns the amount of vertices of a physics body shape
int GetPhysicsShapeVerticesCount(int index);
// Returns transformed position of a body shape (body position + vertex transformed position)
Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex);
// Sets physics body shape transform based on radians parameter
void SetPhysicsBodyRotation(PhysicsBody body, float radians);
// Unitializes and destroy a physics body
void DestroyPhysicsBody(PhysicsBody body);
// Unitializes physics pointers and closes physics loop thread
void ClosePhysics(void);
3、移植相关
正如上述所说,移植仅仅需要一个画线函数,就可以匹配所有的平台:X86、嵌入式等等,我制作了一个demo,具体表现为在屏幕上有一个旋转的长方块,随机落下圆形或者是随机多边形打在长方块上。
#include "physac.h"
InitPhysics();
PhysicsBody floor = CreatePhysicsBodyRectangle((Vector2){screenWidth / 2 , screenHeight / 2 + 50 }, screenWidth*0.75,screenHeight*0.1, 10);
floor->enabled = false;
while(true)
{
QThread::usleep(30);
if(flag1++>10)
{
flag1 = 0;
Vector2 temp;
temp.x = QRandomGenerator::global()->bounded(screenWidth/2-20,screenWidth/2+20);
temp.y = QRandomGenerator::global()->bounded(10,20);
CreatePhysicsBodyCircle(temp, QRandomGenerator::global()->bounded(10, 30), QRandomGenerator::global()->bounded(10, 30));
temp.x = QRandomGenerator::global()->bounded(screenWidth/2-20,screenWidth/2+20);
temp.y = QRandomGenerator::global()->bounded(10,20);
CreatePhysicsBodyPolygon(temp, QRandomGenerator::global()->bounded(10, 30), QRandomGenerator::global()->bounded(3,8),QRandomGenerator::global()->bounded(10, 30));
}
if(flag2++>3)
{
flag2 = 0;
angle++;
angle = angle % 360 ;
SetPhysicsBodyRotation((PhysicsBody)addr, angle*PHYSAC_DEG2RAD);
}
int bodiesCount = GetPhysicsBodiesCount();
for (int i = bodiesCount - 1; i >= 0; i--)
{
PhysicsBody body = GetPhysicsBody(i);
if ((body != NULL) && (body->position.y > screenHeight * 2))
DestroyPhysicsBody(body);
}
RunPhysicsStep();
bodiesCount = GetPhysicsBodiesCount();
image.fill(Qt::white);
for (int i = 0; i < bodiesCount; i++)
{
PhysicsBody body = GetPhysicsBody(i);
if (body != NULL)
{
int vertexCount = GetPhysicsShapeVerticesCount(i);
for (int j = 0; j < vertexCount; j++)
{
// Get physics bodies shape vertices to draw lines
// Note: GetPhysicsShapeVertex() already calculates rotation transformations
Vector2 vertexA = GetPhysicsShapeVertex(body, j);
int jj = (((j + 1) < vertexCount) ? (j + 1) : 0); // Get next vertex or first to close the shape
Vector2 vertexB = GetPhysicsShapeVertex(body, jj);
QLineF line(vertexA.x, vertexA.y, vertexB.x, vertexB.y);// Draw a line between two vertex positions
Painter.drawLine(line);
}
}
}
4、移植展示
QT5:
ESP32:
5、已知问题
代码简单也是有代价的,简单看了一下代码,计算复杂两是O(N^N),这就导致控件数量较多的时候,计算复杂度会大幅度上升(控件较多时,ESP32计算一帧甚至需要几十秒),并且涉及到大量的浮点运算,对单片机非常不友好!
文章目录
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。