Notes from 2016-11-26 – Revamping OpenBOR collision detection.
Currently coordinates (s_hitbox) exist as static sub-structures in s_collision_attack and s_collision_body. See below…
typedef struct { int x; int y; int width; int height; int z1; int z2; } s_hitbox; // s_collision_attack typedef struct { int attack_drop; // now be a knock-down factor, how many this attack will knock victim down int attack_force; int attack_type; // Reaction animation, death, etc. int blast; // Attack box active on hit opponent's fall animation. int blockflash; // Custom bflash for each animation, model id int blocksound; // Custom sound for when an attack is blocked s_hitbox coords; int counterattack; // Treat other attack boxes as body box. ...
This was done for simplicity, and with current logic wastes no memory as coordinates are always required for a collision box.
However, the addition of multiple collision box support has exposed the need to break collision detection down into smaller functions. This in turn requires a lot of passing around the entire s_hitbox structure. Given the rate this functionality is used (multiple collision evaluations on every entity on every animation frame @200 frames per second), efficiency is absolutely imperative. Replacing the static coords declaration with a pointer and using dynamic allocation will add some code complexity initially, but in the long term should simplify breaking down collision logic and save substantial resources.
The following are in progress logic functions, they will need reworking to accommodate new pointer.
// Caskey, Damon V. // 2016-11-25 // // Get 2D size and position of collision box. s_coords_box_2D collision_final_coords_2D(entity *entity, s_hitbox coords) { s_hitbox temp; s_coords_box_2D result; temp.z1 = 0; // If Z coords are reversed, let's correct them. // Otherwise we use if(coords.z2 > coords.z1) { temp.z1 = coords.z1 + (coords.z2 - coords.z1) / 2; } // Get entity positions with Z offset // included, and cast to integer. temp.x = (int)(entity->position.x); temp.y = (int)(temp.z1 - entity->position.y); // Use temporary positions to get final dimensions // for collision boxes. if(entity->direction == DIRECTION_LEFT) { result.position.x = temp.x - coords.width; result.size.x = temp.x - coords.x; } else { result.position.x = temp.x + coords.x; result.size.x = temp.x + coords.width; } result.position.y = temp.y + coords.y; result.size.y = temp.y + coords_owner.height; return result; } bool collision_check_contact_2D(s_coords_box_2D owner, s_coords_box_2D target) { // Compare the calculated boxes. If any one check // fails, then the boxes are not in contact. if(owner.position.x > target.size.x) { return FALSE; } if(target.position.x > target.size.x) { return FALSE; } if(owner.position.y > target.size.y) { return FALSE; } if(target.position.y > target.size.y) { return FALSE; } } bool collision_check_contact_Z(entity *owner, s_hitbox coords_owner, s_hitbox coords_target) { int Z_distance = 0; int z1 = 0; int z2 = 0; if(coords_owner.z2 > coords_owner.z1) { z1 += coords_owner.z1 + (coords_owner.z2 - coords_owner.z1) / 2; zdist = (coords_owner.z2 - coords_owner.z1) / 2; } else if(coords_owner.z1) { zdist += coords_owner.z1; } else { zdist += attacker->modeldata.grabdistance / 3 + 1; //temporay fix for integer to float conversion } if(coords_target.z2 > coords_target.z1) { z2 += coords_target.z1 + (coords_target.z2 - coords_target.z1) / 2; zdist += (coords_target.z2 - coords_target.z1) / 2; } else if(coords_target.z1) { zdist += coords_target.z1; } zdist++; // pass >= <= check if(diff(z1, z2) > zdist) { return FALSE; } return TRUE; } // Caskey, Damon V. // 2016-11-25 // // Compare collision boxes and return // TRUE if they are in contact. bool checkhit_collision(entity *owner, entity *target, s_hitbox coords_owner, s_hitbox coords_target) { s_coords_box_2D owner_final; s_coords_box_2D target_final; bool result; // First check Z contact. result = collision_check_contact_Z(owner, coords_owner, coords_target); // If result is TRUE, then run // 2D plane checks. if(result) { // Get final collision box 2D plane sizes. owner_final = collision_final_coords_2D(owner, coords_owner); target_final = collision_final_coords_2D(target, coords_target); // Compare the 2D boxes and get result. result = collision_check_contact_2D(owner_final, target_final); } // return final result. return result; } // Find center of attack area s_axis_f_2d collision_center() { leftleast = attack_pos_x; if(leftleast < detect_pos_x) { leftleast = detect_pos_x; } rightleast = attack_size_x; if(rightleast > detect_size_x) { rightleast = detect_size_x; } medx = (float)(leftleast + rightleast) / 2; }