272 lines
7.8 KiB
C++
272 lines
7.8 KiB
C++
#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 <btBulletDynamicsCommon.h>
|
|
#include <chrono>
|
|
#include <random>
|
|
#include <raylib.h>
|
|
#include <stdio.h>
|
|
#include <vector>
|
|
|
|
// 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<Color> colors = {MAROON, PINK, VIOLET,
|
|
DARKBLUE, DARKPURPLE, SKYBLUE};
|
|
|
|
btDefaultCollisionConfiguration *collision_configuration;
|
|
btCollisionDispatcher *dispatcher;
|
|
btBroadphaseInterface *overlappping_pair_cache;
|
|
btSequentialImpulseConstraintSolver *solver;
|
|
btDiscreteDynamicsWorld *dynamics_world;
|
|
btAlignedObjectArray<btCollisionShape *> 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<PhysObj> 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<Color> 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;
|
|
} |