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) { static void contact_callback(void *data, dGeomID g1, dGeomID g2) {
uint16_t e1 = (uintptr_t) dGeomGetData(g1); uint16_t e1 = (uintptr_t) dGeomGetData(g1);
uint16_t e2 = (uintptr_t) dGeomGetData(g2); 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}; vec3 n = {0, 1, 0};
glm_quat_rotatev(q, n, n); 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) { if(glm_vec3_dot(contact[i].geom.normal, n) >= 0.7) {
struct CMovement *m = game_getcomponent(e1, movement); struct CMovement *m = game_getcomponent(e1, movement);
if(m) { if(m) {
if(m->holding != ENT_ID_INVALID && m->holding == e2) { if(m->holding != ENT_ID_INVALID && m->holding == e2) {
ghost = 1; ghost = 1;
} }
m->canJump = 1;
break; break;
} }
} }
} }*/
if(c->trigger != TRIGGER_INVALID) { if(c->trigger != TRIGGER_INVALID) {
Game.triggers[c->trigger - 1](c->trigger, e1, e2, triggerType); 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}; vec3 n = {0, -1, 0};
glm_quat_rotatev(q, n, n); 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) { if(glm_vec3_dot(contact[i].geom.normal, n) >= 0.7) {
struct CMovement *m = game_getcomponent(e2, movement); struct CMovement *m = game_getcomponent(e2, movement);
if(m) { if(m) {
if(m->holding != ENT_ID_INVALID && m->holding == e1) { if(m->holding != ENT_ID_INVALID && m->holding == e1) {
ghost = 1; ghost = 1;
} }
m->canJump = 1;
break;
} }
} }
} }*/
if(c->trigger != TRIGGER_INVALID) { if(c->trigger != TRIGGER_INVALID) {
Game.triggers[c->trigger - 1](c->trigger, e2, e1, triggerType); 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() { void game_update() {
game_character_controller_raycast();
for(size_t i = 0; i < Game.entities.playerctrlCount; i++) { for(size_t i = 0; i < Game.entities.playerctrlCount; i++) {
struct CPlayerCtrl *cc = &Game.entities.playerctrl[i]; struct CPlayerCtrl *cc = &Game.entities.playerctrl[i];
@ -528,6 +607,8 @@ void game_update() {
if(glm_vec3_norm(wishvel) > 3) { if(glm_vec3_norm(wishvel) > 3) {
glm_vec3_scale_as(wishvel, 3, wishvel); 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)); float currentspeed = glm_vec3_dot(wishvel, dBodyGetLinearVel(bid));

View File

@ -88,6 +88,7 @@ struct CMovement {
vec3 dir; vec3 dir;
float pointing; float pointing;
char jump, canJump; char jump, canJump;
vec3 groundNormal;
uint16_t holding; uint16_t holding;
}; };

View File

@ -227,6 +227,7 @@ static int eng_init() {
GameWnd = glfwCreateWindow(START_WIDTH, START_HEIGHT, START_TITLE, NULL, NULL); GameWnd = glfwCreateWindow(START_WIDTH, START_HEIGHT, START_TITLE, NULL, NULL);
} }
// Attempt compatibility
if(!GameWnd) { if(!GameWnd) {
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE);
@ -299,7 +300,7 @@ static void fix_resol() {
} }
static void eng_ui_init() { static void eng_ui_init() {
set_ui_mode(1); set_ui_mode(!!UiActive);
} }
static void fps_counter_step(double newDT) { static void fps_counter_step(double newDT) {
@ -338,6 +339,7 @@ static int gr_shadowmap_init() {
"!!ARBfp1.0\n" "!!ARBfp1.0\n"
"TEMP col;\n" "TEMP col;\n"
"TEX col, fragment.texcoord, texture[0], 2D;\n" "TEX col, fragment.texcoord, texture[0], 2D;\n"
"MOV result.color, col;\n"
"MAD col.xyz, -col, 29.9, 30.1;\n" "MAD col.xyz, -col, 29.9, 30.1;\n"
"RCP col.x, col.x;\n" "RCP col.x, col.x;\n"
"RCP col.y, col.y;\n" "RCP col.y, col.y;\n"
@ -393,7 +395,6 @@ int main(int argc_, char **argv_) {
argv = argv_; argv = argv_;
eng_init(); eng_init();
eng_ui_init();
gr_shadowmap_init(); gr_shadowmap_init();
gr_bloom_init(); gr_bloom_init();
@ -413,6 +414,8 @@ int main(int argc_, char **argv_) {
luaapi_load(k4_get_arg("script") ? k4_get_arg("script") : "init"); luaapi_load(k4_get_arg("script") ? k4_get_arg("script") : "init");
// //
eng_ui_init();
LuaapiStartTime = glfwGetTime(); LuaapiStartTime = glfwGetTime();
LastTime = glfwGetTime(); LastTime = glfwGetTime();