QuarkPhysics

repository·master·Indexed 43 days ago

https://github.com/erayzesen/quarkphysics

A 2D physics engine for video games that provides a unified simulation environment for rigid and soft bodies using pixels as direct units. It features PBD (Position Based Dynamics) for soft bodies, SAP (Sweep and Prune) for broadphase collision, and support for kinematic and area bodies. The engine includes a dedicated Godot Engine integration and relies on SFML and nlohmann/json for rendering and data parsing.

Tokens
2.8K
Snippets
9
Records
14
Agent score
55%

What's inside QuarkPhysics

  1. Overview of QuarkPhysics features

    master

    QuarkPhysics is a 2D physics engine designed for video games. It provides a unified approach to simulating rigid bodies and soft bodies using a simple and consistent API. Key capabilities include:

    General Physics

    • Shapes & Properties: Supports primitive shapes (circle, polygon, rectangle, etc.) and physical properties like mass, area, and restitution.
    • Collision Management: Features raycasting, collision layer masks for filtering, and SAP (Sweep and Prune) for broadphase.
    • Performance: Supports sleeping islands to reduce CPU load.
    • Units: Uses pixels directly as the unit of measurement without additional abstractions.
    • Rendering Support: Supports UV mapping via QMesh for rendering operations.

    Rigid Bodies

    • Geometry: Supports convex polygons and unlimited shape-mesh support.
    • Connectivity: Supports joints to connect bodies.
    • Body Types: Includes Kinematic bodies (for controllable objects) and Area bodies (for collision detection/reporting).
    • Stability: Designed for reasonable stability when stacking objects.

    Soft Bodies

    • Models: Uses mass-spring and area-volume preserving models with PBD (Position Based Dynamics).
    • Connectivity: Uses springs to connect particles and supports internal springs/particles for complexity.
    • Features: Supports shape matching, self-collisions, and customizable constraints.
  2. Initialize and update a QWorld

    master

    A QWorld object manages all physics objects and handles the simulation steps. You must create a world instance first, configure its properties like gravity and iteration count, and then call Update() to progress the simulation.

    To configure the world:

    • Use SetGravity(QVector) to set the gravity vector.
    • Use SetIterationCount(int) to set the number of physics iterations per step.
    • Use Update() to advance the simulation.
    // Create a world
    QWorld *world = new QWorld(); 
    
    // Set the gravity value
    world->SetGravity(QVector(0.0f, 0.2f)); 
    
    // Set the iteration count per step of physics in the world
    world->SetIterationCount(4); 
    
    // Update the physics simulation of the world as a step
    world->Update();
  3. Create a Spring between particles

    master

    A QSpring applies distance constraints between two particles. This is used for internal soft body connections or for connecting independent bodies/particles.

    • Between two particles: Pass two particles (retrieved via body->GetParticleAt(index)) and a target length to the QSpring constructor.
    • Between a particle and a point in space: Create a QParticle, set its position in the world, and use it as one of the two particles in the QSpring constructor.

    Always add the spring to the world using QWorld::AddJoint() (or the appropriate spring method if available).

    // Create a Spring between two particles in a body
    float length = 32.0f;
    QSpring *spring = new QSpring(bodyA->GetParticleAt(2), bodyA->GetParticleAt(5), length);
    world->AddJoint(spring);
    
    // Create a Spring between a particle and a world position (via a particle)
    QParticle *mouseParticle = new QParticle();
    mouseParticle->SetPosition(mousePosition);
    QSpring *mouseSpring = new QSpring(bodyA->GetParticleAt(2), mouseParticle, 0.0f);
    world->AddJoint(mouseSpring);
  4. Create a Soft Body

    master

    Soft bodies are created similarly to rigid bodies but use the QSoftBody class. A QSoftBody requires a QMesh that defines its shape. For soft bodies, it is often necessary to use gridded meshes to provide internal particle connections and spring networks.

    // Create a Soft Body
    QSoftBody *body = new QSoftBody();
    
    // Create a Mesh  
    QMesh *polygonMesh = QMesh::CreateWithPolygon(radius, sideCount, QVector(centerPosX, centerPosY));
    
    // Add the Mesh to the Soft Body
    body->AddMesh(polygonMesh); 
    
    // Set the Body Position
    body->SetPosition(QVector(posX, posY));
    
    // Set the Body Rotation
    body->SetRotation(radAngle); // or body->SetRotationDegree(degreeAngle)
    
    // Add the Soft Body to the World
    world->AddBody(body);
  5. Build QuarkPhysics from source

    master

    To build the project, ensure you have SFML and CMake installed on your system. You can build using the provided shell scripts.

    Standard build: Navigate to the main project folder and run:

    ./build.sh -r

    Fast Linux build: If you are on Linux and want a faster compilation, run:

    ./run_linux_fast.sh -r
    #!/bin/bash
    ./build.sh -r
  6. Create a Joint to connect bodies

    master

    Use QJoint to connect two rigid bodies with constraints. You must add the joint to the world using QWorld::AddJoint().

    Connecting to a fixed point in space: To connect a body to a specific point in the world (rather than another body), pass nullptr as the second body in the QJoint constructor and provide the world anchor position.

    // Connect two bodies
    QJoint *joint = new QJoint(bodyA, anchorWorldPositionA, anchorWorldPositionB, bodyB);
    world->AddJoint(joint);
    
    // Connect a body to a point in space (e.g., for mouse interaction)
    QJoint *mouseJoint = new QJoint(bodyA, anchorWorldPositionA, mousePosition, nullptr);
    world->AddJoint(mouseJoint);
  7. Build and run examples

    master

    To build and run the included examples, you must first install SFML 2.x and CMake on your system.

    Using the build script

    From the main project folder, run:

    ./build.sh -r

    Fast Linux compilation

    If you are on Linux, you can compile the project directly via gcc using:

    ./run_linux_fast.sh -r
    # Using the build script
    ./build.sh -r
    
    # Fast Linux compilation
    ./run_linux_fast.sh -r
  8. Create a Rigid Body

    master

    To create a rigid body, follow these steps:

    1. Instantiate a QRigidBody object.
    2. Create a QMesh to define the shape (e.g., using QMesh::CreateWithRect).
    3. Attach the mesh to the body using AddMesh().
    4. Set the body's position with SetPosition() and rotation with SetRotation() (radians) or SetRotationDegree() (degrees).
    5. Add the body to the world using QWorld::AddBody().
    // Create a Rigid Body
    QRigidBody *body = new QRigidBody();
    
    // Create a Mesh  
    QMesh *rectMesh = QMesh::CreateWithRect(QVector(rectWidth, rectHeight), QVector(centerPosX, centerPosY));
    
    // Add the Mesh to the Rigid Body
    body->AddMesh(rectMesh); 
    
    // Set the Body Position
    body->SetPosition(QVector(posX, posY));
    
    // Set the Body Rotation
    body->SetRotation(radAngle); // or body->SetRotationDegree(degreeAngle)
    
    // Add the Rigid Body to the World
    world->AddBody(body);
  9. Create gridded meshes for Soft Bodies

    master

    To give soft bodies structural integrity, use QMesh methods that generate internal spring connections via grid networks.

    • Gridded Rectangle: Use QMesh::CreateWithRect and provide gridRowCount and gridColumnCount.
    • Gridded Polygon: Use QMesh::CreateWithPolygon and provide a polarGrid value.
    // Create a Gridded Rectangle Mesh
    int gridColumnCount = 3;
    int gridRowCount = 3;
    QMesh *griddedRectMesh = QMesh::CreateWithRect(QVector(width, height), QVector(centerX, centerY), QVector(gridRowCount, gridColumnCount));
    mySoftBody->AddMesh(griddedRectMesh);
    
    // Create a Gridded Polygon Mesh
    int polarGrid = 2;
    QMesh *griddedPolyMesh = QMesh::CreateWithPolygon(64, 12, QVector(centerX, centerY), polarGrid);
    mySoftBody->AddMesh(griddedPolyMesh);