#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h" #include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h" #include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h" #include "LinearMath/btDefaultMotionState.h" #include "LinearMath/btVector3.h" #include #include #include #include #include #include // todo: untitled fighting game fr // - load player model // - code player movement left and right int randomInteger(int lbound, int ubound) { std::random_device rd; std::mt19937_64 rng(rd()); std::uniform_real_distribution<> dist(lbound, ubound); return dist(rng); } const std::vector colors = {MAROON, PINK, VIOLET, DARKBLUE, DARKPURPLE, SKYBLUE}; btDefaultCollisionConfiguration *collision_configuration; btCollisionDispatcher *dispatcher; btBroadphaseInterface *overlappping_pair_cache; btSequentialImpulseConstraintSolver *solver; btDiscreteDynamicsWorld *dynamics_world; btAlignedObjectArray collision_shapes; enum Shape { CUBE, SPHERE, }; enum PhysicsType { STATIC, DYNAMIC, KINEMATIC }; class PhysObj { private: btRigidBody *body; btCollisionShape *col_shape; Model model; public: Color color; PhysObj(Vector3 position = {0, 0, 0}, Vector3 rotation = {0, 0, 0}, Vector3 size = {1, 1, 1}, Shape shape = CUBE, PhysicsType type = STATIC, float mass = 0, Color color = WHITE) { this->color = color; if (shape == CUBE) { col_shape = new btBoxShape(btVector3( btScalar(size.x / 2), btScalar(size.y / 2), btScalar(size.z / 2))); model = LoadModelFromMesh(GenMeshCube(size.x, size.y, size.z)); } else if (shape == SPHERE) { col_shape = new btSphereShape(btScalar(size.x)); model = LoadModelFromMesh(GenMeshSphere(size.x, 16, 32)); } collision_shapes.push_back(col_shape); btTransform transform; transform.setIdentity(); transform.setOrigin(btVector3(position.x, position.y, position.z)); transform.setRotation(btQuaternion( btScalar(rotation.x), btScalar(rotation.y), btScalar(rotation.z))); btScalar object_mass(mass); btVector3 local_intertia(0, 0, 0); if (type == DYNAMIC || mass != 0.0) { col_shape->calculateLocalInertia(mass, local_intertia); } btDefaultMotionState *motion_state = new btDefaultMotionState(transform); btRigidBody::btRigidBodyConstructionInfo rb_info(object_mass, motion_state, col_shape, local_intertia); body = new btRigidBody(rb_info); dynamics_world->addRigidBody(body); } void render() { const float radian_scale = 57.296; btTransform trans; if (body && body->getMotionState()) { body->getMotionState()->getWorldTransform(trans); } else { return; } Vector3 pos = {float(trans.getOrigin().getX()), float(trans.getOrigin().getY()), float(trans.getOrigin().getZ())}; btQuaternion quat = trans.getRotation(); Vector3 axis = {float(quat.getAxis().getX()), float(quat.getAxis().getY()), float(quat.getAxis().getZ())}; float angle = float(quat.getAngle()) * radian_scale; DrawModelEx(model, pos, axis, angle, {1, 1, 1}, color); } void unload() { UnloadModel(model); } }; enum object_types { BOX, BALL }; class rObj { public: Vector3 posXYZ; Vector3 rotAxisXYZ; Vector3 scaleXYZ; float rotAngle; Color objColor; rObj(Vector3 position, Vector3 size, Vector3 scale, Vector3 rotAxis, float angle, Color color, object_types objType) { this->posXYZ = position; this->rotAxisXYZ = rotAxis; this->scaleXYZ = scale; this->rotAngle = angle; this->objColor = color; switch(objType) { case BOX: this->mesh = GenMeshCube(size.x,size.y,size.z); this->model = LoadModelFromMesh(mesh); break; case BALL: this->mesh = GenMeshSphere(size.x, 8,16); this->model = LoadModelFromMesh(mesh); break; } }; void render() { DrawModelEx(model, this->posXYZ, rotAxisXYZ, rotAngle, scaleXYZ, objColor); } private: Mesh mesh; Model model; }; int main() { InitWindow(800, 600, "raylib and bullet integration"); Camera3D cam = {0}; cam.position = (Vector3){10.f, 5.f, 10.f}; cam.target = (Vector3){0, 0, 0}; cam.up = (Vector3){0, 1, 0}; cam.fovy = 60.f; cam.projection = CAMERA_PERSPECTIVE; SetTargetFPS(60); Ray ray = {0}; RayCollision collision = {0}; collision_configuration = new btDefaultCollisionConfiguration(); dispatcher = new btCollisionDispatcher(collision_configuration); overlappping_pair_cache = new btDbvtBroadphase(); solver = new btSequentialImpulseConstraintSolver; dynamics_world = new btDiscreteDynamicsWorld( dispatcher, overlappping_pair_cache, solver, collision_configuration); dynamics_world->setGravity(btVector3(0, -10, 0)); std::vector physics_objects = { PhysObj({0, 0, 0}, {0, 0, 0}, {8, 0.5, 8}, CUBE, STATIC, 0.0, GRAY)}; for (size_t i = 0; i < 10; i++) { const std::vector colors = {MAROON, PINK, VIOLET, DARKBLUE, DARKPURPLE, SKYBLUE}; physics_objects.push_back( PhysObj({(float)randomInteger(-5, 5), (float)GetRandomValue(10, 15), (float)GetRandomValue(-5, 5)}, {(float)GetRandomValue(-3, 3), (float)GetRandomValue(-3, 3), (float)GetRandomValue(-3, 3)}, {1.0f, 1.0f, 1.0f}, CUBE, DYNAMIC, 1.0, colors[GetRandomValue(0, colors.size() - 1)])); } EnableCursor(); while (!WindowShouldClose()) { UpdateCamera(&cam, CAMERA_PERSPECTIVE); if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { if (!collision.hit) { // vec3(8f,0.5f,8f) is the size of the floor platform. ray = GetScreenToWorldRay(GetMousePosition(), cam); collision = GetRayCollisionBox( ray, {{-8 / 2, -0.5 / 2, -8 / 2}, {8 / 2, 0.5 / 2, 8 / 2}}); physics_objects.push_back(PhysObj( {collision.point.x, collision.point.y + 0.5f, collision.point.z}, {0, 0, 0}, {1, 1, 1}, CUBE, DYNAMIC, 1, colors[randomInteger(0, 5)])); } else collision.hit = false; } dynamics_world->stepSimulation(1.0 / float(60), 10); if (IsKeyPressed(KEY_SPACE)) { physics_objects.push_back(PhysObj({0, 10, 0}, {0, 0, 0}, {0.5, 0.5, 0.5}, SPHERE, DYNAMIC, 1, colors[randomInteger(0, 5)])); } // regular game logic and stuff BeginDrawing(); ClearBackground(BLACK); BeginMode3D(cam); for (auto &object : physics_objects) { object.render(); } DrawGrid(10, 1.0); EndMode3D(); DrawText("Left Click on the platform to create a cube", 16, 64, 20, GREEN); DrawText("Press Space to create a sphere", 16, 86, 20, GREEN); DrawFPS(16, 16); EndDrawing(); } for (int i = dynamics_world->getNumCollisionObjects() - 1; i >= 0; i--) { btCollisionObject *obj = dynamics_world->getCollisionObjectArray()[i]; btRigidBody *body = btRigidBody::upcast(obj); if (body && body->getMotionState()) { delete body->getMotionState(); } dynamics_world->removeCollisionObject(obj); delete obj; } for (int i = 0; i < collision_shapes.size(); i++) { btCollisionShape *shape = collision_shapes[i]; collision_shapes[i] = 0; delete shape; } for (auto &object : physics_objects) { object.unload(); } delete dynamics_world; delete solver; delete overlappping_pair_cache; delete dispatcher; delete collision_configuration; CloseWindow(); return 0x0; }