Raycasting character controller

This commit is contained in:
mid
2025-06-11 10:14:56 +03:00
parent da59158fd1
commit 9478bca2ad
3 changed files with 96 additions and 11 deletions

View File

@@ -97,6 +97,15 @@ static void tick_pairs() {
}
}
static void vec3_project_to_plane(vec3 v, vec3 n, vec3 ret) {
float scale = glm_vec3_dot(v, n) / glm_vec3_dot(n, n);
vec3 n2;
glm_vec3_scale(n, scale, n2);
glm_vec3_sub(v, n2, ret);
}
static void contact_callback(void *data, dGeomID g1, dGeomID g2) {
uint16_t e1 = (uintptr_t) dGeomGetData(g1);
uint16_t e2 = (uintptr_t) dGeomGetData(g2);
@@ -197,19 +206,17 @@ static void contact_callback(void *data, dGeomID g1, dGeomID g2) {
vec3 n = {0, 1, 0};
glm_quat_rotatev(q, n, n);
if(!ghost) for(int i = 0; i < numc; i++) {
/*if(!ghost) for(int i = 0; i < numc; i++) {
if(glm_vec3_dot(contact[i].geom.normal, n) >= 0.7) {
struct CMovement *m = game_getcomponent(e1, movement);
if(m) {
if(m->holding != ENT_ID_INVALID && m->holding == e2) {
ghost = 1;
}
m->canJump = 1;
break;
}
}
}
}*/
if(c->trigger != TRIGGER_INVALID) {
Game.triggers[c->trigger - 1](c->trigger, e1, e2, triggerType);
@@ -238,19 +245,16 @@ static void contact_callback(void *data, dGeomID g1, dGeomID g2) {
vec3 n = {0, -1, 0};
glm_quat_rotatev(q, n, n);
if(!ghost) for(int i = 0; i < numc; i++) {
/*if(!ghost) for(int i = 0; i < numc; i++) {
if(glm_vec3_dot(contact[i].geom.normal, n) >= 0.7) {
struct CMovement *m = game_getcomponent(e2, movement);
if(m) {
if(m->holding != ENT_ID_INVALID && m->holding == e1) {
ghost = 1;
}
m->canJump = 1;
break;
}
}
}
}*/
if(c->trigger != TRIGGER_INVALID) {
Game.triggers[c->trigger - 1](c->trigger, e2, e1, triggerType);
@@ -349,7 +353,82 @@ void game_raycast(struct LocalRay *rays, size_t count) {
}
}
static void game_character_controller_raycast_handler(void *data, dGeomID g1, dGeomID g2) {
if(dGeomGetClass(g1) != dRayClass && dGeomGetClass(g2) != dRayClass) {
return;
}
dContact contact[1];
memset(contact, 0, sizeof(contact));
int numc = dCollide(g1, g2, 1, &contact[0].geom, sizeof(dContact));
uint16_t e1 = (uintptr_t) dGeomGetData(g1);
uint16_t e2 = (uintptr_t) dGeomGetData(g2);
if(numc) {
vec3 n = {0, -1, 0};
if(dGeomGetClass(g1) == dRayClass) {
struct CMovement *cm = &Game.entities.movement[(uintptr_t) dGeomGetData(g1)];
if(glm_vec3_dot(contact[0].geom.normal, n) <= -0.7) {
cm->canJump = 1;
glm_vec3_scale(contact[0].geom.normal, 1, cm->groundNormal);
}
return;
} else if(dGeomGetClass(g2) == dRayClass) {
struct CMovement *cm = &Game.entities.movement[(uintptr_t) dGeomGetData(g2)];
if(glm_vec3_dot(contact[0].geom.normal, n) <= -0.7) {
cm->canJump = 1;
glm_vec3_scale(contact[0].geom.normal, -1, cm->groundNormal);
}
return;
}
}
}
void game_character_controller_raycast() {
dGeomID rayGeoms[Game.entities.movementCount];
for(int i = 0; i < Game.entities.movementCount; i++) {
struct CPhysics *cp = game_getcomponent(Game.entities.movement[i].entity, physics);
if(!cp || !cp->geom || cp->type != CPHYSICS_CAPSULE) {
rayGeoms[i] = NULL;
continue;
}
rayGeoms[i] = dCreateRay(Game.space, 1);
dGeomSetData(rayGeoms[i], (void*) (uintptr_t) i);
dGeomSetCategoryBits(rayGeoms[i], CATEGORY_RAY);
dGeomSetCollideBits(rayGeoms[i], CATEGORY_STATIC | CATEGORY_ENTITY);
dBodyID bid = dGeomGetBody(cp->geom);
const float *position = dBodyGetPosition(bid);
dGeomRaySet(rayGeoms[i], position[0], position[1] - cp->capsule.length / 2 + 0.5, position[2], 0, -1, 0);
}
dSpaceCollide(Game.space, NULL, game_character_controller_raycast_handler);
for(int i = 0; i < Game.entities.movementCount; i++) {
if(rayGeoms[i]) {
dGeomDestroy(rayGeoms[i]);
}
}
}
void game_update() {
game_character_controller_raycast();
for(size_t i = 0; i < Game.entities.playerctrlCount; i++) {
struct CPlayerCtrl *cc = &Game.entities.playerctrl[i];
@@ -528,6 +607,8 @@ void game_update() {
if(glm_vec3_norm(wishvel) > 3) {
glm_vec3_scale_as(wishvel, 3, wishvel);
}
} else {
vec3_project_to_plane(wishvel, Game.entities.movement[mi].groundNormal, wishvel);
}
float currentspeed = glm_vec3_dot(wishvel, dBodyGetLinearVel(bid));