{"id":6059,"date":"2016-11-26T11:01:32","date_gmt":"2016-11-26T16:01:32","guid":{"rendered":"https:\/\/www.caskeys.com\/dc\/?p=6059"},"modified":"2017-01-15T15:23:56","modified_gmt":"2017-01-15T20:23:56","slug":"code-snip-collision-checking","status":"publish","type":"post","link":"https:\/\/www.caskeys.com\/dc\/code-snip-collision-checking\/","title":{"rendered":"Code Snip &#8211; Collision Checking"},"content":{"rendered":"<p>Notes from 2016-11-26 &#8211; Revamping OpenBOR collision detection.<\/p>\n<figure id=\"attachment_6069\" aria-describedby=\"caption-attachment-6069\" style=\"width: 300px\" class=\"wp-caption alignright\"><a href=\"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2016\/11\/bor-0009.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-6069\" src=\"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2016\/11\/bor-0009-300x225.png\" alt=\"With the possibility of several dozen or more entities on screen, collision detection must be precise with minimal resource intensity.\" width=\"300\" height=\"225\" srcset=\"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2016\/11\/bor-0009-300x225.png 300w, https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2016\/11\/bor-0009.png 320w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><figcaption id=\"caption-attachment-6069\" class=\"wp-caption-text\">With the possibility of several dozen or more entities on screen, collision detection must be precise with minimal resource intensity.<\/figcaption><\/figure>\n<p>Currently coordinates (s_hitbox) exist as static sub-structures in <em>s_collision_attack<\/em> and <em>s_collision_body<\/em>. See below&#8230;<\/p>\n<pre class=\"brush: csharp; highlight: [20]; title: Code:; notranslate\" title=\"Code:\">\r\ntypedef struct\r\n{\r\n\tint x;\r\n\tint y;\r\n\tint width;\r\n\tint height;\r\n\tint z1;\r\n\tint z2;\r\n} s_hitbox;\r\n\r\n\/\/ s_collision_attack\r\ntypedef struct\r\n{\r\n    int                 attack_drop;        \/\/ now be a knock-down factor, how many this attack will knock victim down\r\n    int                 attack_force;\r\n    int                 attack_type;        \/\/ Reaction animation, death, etc.\r\n    int                 blast;              \/\/ Attack box active on hit opponent's fall animation.\r\n    int                 blockflash;         \/\/ Custom bflash for each animation, model id\r\n    int                 blocksound;         \/\/ Custom sound for when an attack is blocked\r\n    s_hitbox            coords;\r\n    int                 counterattack;      \/\/ Treat other attack boxes as body box.\r\n    ...\r\n<\/pre>\n<p>This was done for simplicity, and with current logic wastes no memory as coordinates are always required for a collision box.<\/p>\n<p>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 <em>s_hitbox<\/em> 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 <em>coords<\/em> 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.<\/p>\n<p>The following are in progress logic functions, they will need reworking to accommodate new pointer.<\/p>\n<pre class=\"brush: csharp; title: Code:; notranslate\" title=\"Code:\">\r\n\/\/ Caskey, Damon V.\r\n\/\/ 2016-11-25\r\n\/\/\r\n\/\/ Get 2D size and position of collision box.\r\ns_coords_box_2D collision_final_coords_2D(entity *entity, s_hitbox coords)\r\n{\r\n    s_hitbox        temp;\r\n    s_coords_box_2D result;\r\n\r\n    temp.z1 = 0;\r\n\r\n    \/\/ If Z coords are reversed, let's correct them.\r\n    \/\/ Otherwise we use\r\n    if(coords.z2 &amp;gt; coords.z1)\r\n    {\r\n        temp.z1 = coords.z1 + (coords.z2 - coords.z1) \/ 2;\r\n    }\r\n\r\n    \/\/ Get entity positions with Z offset\r\n    \/\/ included, and cast to integer.\r\n    temp.x    = (int)(entity-&amp;gt;position.x);\r\n    temp.y    = (int)(temp.z1 - entity-&amp;gt;position.y);\r\n\r\n    \/\/ Use temporary positions to get final dimensions\r\n    \/\/ for collision boxes.\r\n    if(entity-&amp;gt;direction == DIRECTION_LEFT)\r\n    {\r\n        result.position.x   = temp.x - coords.width;\r\n        result.size.x       = temp.x - coords.x;\r\n    }\r\n    else\r\n    {\r\n        result.position.x   = temp.x + coords.x;\r\n        result.size.x       = temp.x + coords.width;\r\n    }\r\n    result.position.y   = temp.y + coords.y;\r\n    result.size.y       = temp.y + coords_owner.height;\r\n\r\n    return result;\r\n}\r\n\r\nbool collision_check_contact_2D(s_coords_box_2D owner, s_coords_box_2D target)\r\n{\r\n    \/\/ Compare the calculated boxes. If any one check\r\n    \/\/ fails, then the boxes are not in contact.\r\n    if(owner.position.x &amp;gt; target.size.x)\r\n    {\r\n        return FALSE;\r\n    }\r\n    if(target.position.x &amp;gt; target.size.x)\r\n    {\r\n        return FALSE;\r\n    }\r\n    if(owner.position.y &amp;gt; target.size.y)\r\n    {\r\n        return FALSE;\r\n    }\r\n    if(target.position.y &amp;gt; target.size.y)\r\n    {\r\n        return FALSE;\r\n    }\r\n}\r\n\r\nbool collision_check_contact_Z(entity *owner, s_hitbox coords_owner, s_hitbox coords_target)\r\n{\r\n    int Z_distance = 0;\r\n    int z1 = 0;\r\n    int z2 = 0;\r\n\r\n    if(coords_owner.z2 &amp;gt; coords_owner.z1)\r\n    {\r\n        z1 += coords_owner.z1 + (coords_owner.z2 - coords_owner.z1) \/ 2;\r\n        zdist = (coords_owner.z2 - coords_owner.z1) \/ 2;\r\n    }\r\n    else if(coords_owner.z1)\r\n    {\r\n        zdist += coords_owner.z1;\r\n    }\r\n    else\r\n    {\r\n        zdist += attacker-&amp;gt;modeldata.grabdistance \/ 3 + 1;    \/\/temporay fix for integer to float conversion\r\n    }\r\n\r\n    if(coords_target.z2 &amp;gt; coords_target.z1)\r\n    {\r\n        z2 += coords_target.z1 + (coords_target.z2 - coords_target.z1) \/ 2;\r\n        zdist += (coords_target.z2 - coords_target.z1) \/ 2;\r\n    }\r\n    else if(coords_target.z1)\r\n    {\r\n        zdist += coords_target.z1;\r\n    }\r\n\r\n    zdist++; \/\/ pass &amp;gt;= &amp;lt;= check if(diff(z1, z2) &amp;gt; zdist)\r\n    {\r\n        return FALSE;\r\n    }\r\n    \r\n    return TRUE; \r\n}\r\n\r\n\/\/ Caskey, Damon V.\r\n\/\/ 2016-11-25\r\n\/\/\r\n\/\/ Compare collision boxes and return\r\n\/\/ TRUE if they are in contact.\r\nbool checkhit_collision(entity *owner, entity *target, s_hitbox coords_owner, s_hitbox coords_target)\r\n{\r\n    s_coords_box_2D owner_final;\r\n    s_coords_box_2D target_final;\r\n\r\n    bool result;\r\n    \r\n    \/\/ First check Z contact.\r\n    result = collision_check_contact_Z(owner, coords_owner, coords_target);    \r\n\r\n    \/\/ If result is TRUE, then run\r\n    \/\/ 2D plane checks.\r\n    if(result)\r\n    {\r\n        \/\/ Get final collision box 2D plane sizes.\r\n        owner_final     = collision_final_coords_2D(owner, coords_owner);\r\n        target_final    = collision_final_coords_2D(target, coords_target);\r\n        \r\n        \/\/ Compare the 2D boxes and get result.\r\n        result = collision_check_contact_2D(owner_final, target_final);\r\n    }\r\n    \r\n    \/\/ return final result.\r\n    return result;\r\n}\r\n\r\n\/\/ Find center of attack area\r\ns_axis_f_2d collision_center()\r\n{\r\n\r\n    leftleast = attack_pos_x;\r\n\r\n    if(leftleast &amp;lt; detect_pos_x) { leftleast = detect_pos_x; } rightleast = attack_size_x; if(rightleast &amp;gt; detect_size_x)\r\n    {\r\n        rightleast = detect_size_x;\r\n    }\r\n\r\n    medx = (float)(leftleast + rightleast) \/ 2;\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Notes from 2016-11-26 &#8211; Revamping OpenBOR collision detection. <\/p>\n","protected":false},"author":1,"featured_media":6215,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[71],"tags":[288,232,289],"class_list":["post-6059","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology-temerity","tag-coding-c","tag-applications-openbor","tag-coding-openbor-script"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/www.caskeys.com\/dc\/wp-content\/uploads\/2016\/11\/logo-openbor-3.png","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p5lNM5-1zJ","jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/posts\/6059","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/comments?post=6059"}],"version-history":[{"count":11,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/posts\/6059\/revisions"}],"predecessor-version":[{"id":6217,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/posts\/6059\/revisions\/6217"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/media\/6215"}],"wp:attachment":[{"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/media?parent=6059"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/categories?post=6059"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.caskeys.com\/dc\/wp-json\/wp\/v2\/tags?post=6059"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}