LearnOpenGL

Translation in progress of learnopengl.com.
git clone https://git.mtkn.jp/LearnOpenGL
Log | Files | Refs

Collision-resolution.html (29194B)


      1 <!DOCTYPE html>
      2 <html lang="ja"> 
      3 <head>
      4     <meta charset="utf-8"/>
      5     <title>LearnOpenGL</title>
      6     <link rel="shortcut icon" type="image/ico" href="/favicon.ico"  />
      7 	<link rel="stylesheet" href="../static/style.css" />
      8 	<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"> </script>
      9 	<script src="/static/functions.js"></script>
     10 </head>
     11 <body>
     12 	<nav>
     13 <ol>
     14 	<li id="Introduction">
     15 		<a href="https://learnopengl.com/Introduction">はじめに</a>
     16 	</li>
     17 	<li id="Getting-started">
     18 		<span class="closed">入門</span>
     19 		<ol>
     20 			<li id="Getting-started/OpenGL">
     21 				<a href="https://learnopengl.com/Getting-started/OpenGL">OpenGL </a>
     22 			</li>
     23 			<li id="Getting-started/Creating-a-window">
     24 				<a href="https://learnopengl.com/Getting-started/Creating-a-window">ウィンドウの作成</a>
     25 			</li>
     26 			<li id="Getting-started/Hello-Window">
     27 				<a href="https://learnopengl.com/Getting-started/Hello-Window">最初のウィンドウ</a>
     28 			</li>
     29 			<li id="Getting-started/Hello-Triangle">
     30 				<a href="https://learnopengl.com/Getting-started/Hello-Triangle">最初の三角形</a>
     31 			</li>
     32 			<li id="Getting-started/Shaders">
     33 				<a href="https://learnopengl.com/Getting-started/Shaders">シェーダー</a>
     34 			</li>
     35 			<li id="Getting-started/Textures">
     36 				<a href="https://learnopengl.com/Getting-started/Textures">テクスチャ</a>
     37 			</li>
     38 			<li id="Getting-started/Transformations">
     39 				<a href="https://learnopengl.com/Getting-started/Transformations">座標変換</a>
     40 			</li>
     41 			<li id="Getting-started/Coordinate-Systems">
     42 				<a href="https://learnopengl.com/Getting-started/Coordinate-Systems">座標系</a>
     43 			</li>
     44 			<li id="Getting-started/Camera">
     45 				<a href="https://learnopengl.com/Getting-started/Camera">カメラ</a>
     46 			</li>
     47 			<li id="Getting-started/Review">
     48 				<a href="https://learnopengl.com/Getting-started/Review">まとめ</a>
     49 			</li>
     50 		</ol>
     51 	</li>
     52 	<li id="Lighting">
     53 		<span class="closed">Lighting </span>
     54 		<ol>
     55 			<li id="Lighting/Colors">
     56 				<a href="https://learnopengl.com/Lighting/Colors">Colors </a>
     57 			</li>
     58 			<li id="Lighting/Basic-Lighting">
     59 				<a href="https://learnopengl.com/Lighting/Basic-Lighting">Basic Lighting </a>
     60 			</li>
     61 			<li id="Lighting/Materials">
     62 				<a href="https://learnopengl.com/Lighting/Materials">Materials </a>
     63 			</li>
     64 			<li id="Lighting/Lighting-maps">
     65 				<a href="https://learnopengl.com/Lighting/Lighting-maps">Lighting maps </a>
     66 			</li>
     67 			<li id="Lighting/Light-casters">
     68 				<a href="https://learnopengl.com/Lighting/Light-casters">Light casters </a>
     69 			</li>
     70 			<li id="Lighting/Multiple-lights">
     71 				<a href="https://learnopengl.com/Lighting/Multiple-lights">Multiple lights </a>
     72 			</li>
     73 			<li id="Lighting/Review">
     74 				<a href="https://learnopengl.com/Lighting/Review">Review </a>
     75 			</li>
     76 		</ol>
     77 	</li>
     78 	<li id="Model-Loading">
     79 		<span class="closed">Model Loading </span>
     80 		<ol>
     81 			<li id="Model-Loading/Assimp">
     82 				<a href="https://learnopengl.com/Model-Loading/Assimp">Assimp </a>
     83 			</li>
     84 			<li id="Model-Loading/Mesh">
     85 				<a href="https://learnopengl.com/Model-Loading/Mesh">Mesh </a>
     86 			</li>
     87 			<li id="Model-Loading/Model">
     88 				<a href="https://learnopengl.com/Model-Loading/Model">Model </a>
     89 			</li>
     90 		</ol>
     91 	</li>
     92 	<li id="Advanced-OpenGL">
     93 		<span class="closed">Advanced OpenGL </span>
     94 		<ol>
     95 			<li id="Advanced-OpenGL/Depth-testing">
     96 				<a href="https://learnopengl.com/Advanced-OpenGL/Depth-testing">Depth testing </a>
     97 			</li>
     98 			<li id="Advanced-OpenGL/Stencil-testing">
     99 				<a href="https://learnopengl.com/Advanced-OpenGL/Stencil-testing">Stencil testing </a>
    100 			</li>
    101 			<li id="Advanced-OpenGL/Blending">
    102 				<a href="https://learnopengl.com/Advanced-OpenGL/Blending">Blending </a>
    103 			</li>
    104 			<li id="Advanced-OpenGL/Face-culling">
    105 				<a href="https://learnopengl.cm/Advanced-OpenGL/Face-culling">Face culling </a>
    106 			</li>
    107 			<li id="Advanced-OpenGL/Framebuffers">
    108 				<a href="https://learnopengl.com/Advanced-OpenGL/Framebuffers">Framebuffers </a>
    109 			</li>
    110 			<li id="Advanced-OpenGL/Cubemaps">
    111 				<a href="https://learnopengl.com/Advanced-OpenGL/Cubemaps">Cubemaps </a>
    112 			</li>
    113 			<li id="Advanced-OpenGL/Advanced-Data">
    114 				<a href="https://learnopengl.com/Advanced-OpenGL/Advanced-Data">Advanced Data </a>
    115 			</li>
    116 			<li id="Advanced-OpenGL/Advanced-GLSL">
    117 				<a href="https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL">Advanced GLSL </a>
    118 			</li>
    119 			<li id="Advanced-OpenGL/Geometry-Shader">
    120 				<a href="https://learnopengl.com/Advanced-OpenGL/Geometry-Shader">Geometry Shader </a>
    121 			</li>
    122 			<li id="Advanced-OpenGL/Instancing">
    123 				<a href="https://learnopengl.com/Advanced-OpenGL/Instancing">Instancing </a>
    124 			</li>
    125 			<li id="Advanced-OpenGL/Anti-Aliasing">
    126 				<a href="https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing">Anti Aliasing </a>
    127 			</li>
    128 		</ol>
    129 	</li>
    130 	<li id="Advanced-Lighting">
    131 		<span class="closed">Advanced Lighting </span>
    132 		<ol>
    133 			<li id="Advanced-Lighting/Advanced-Lighting">
    134 				<a href="https://learnopengl.com/Advanced-Lighting/Advanced-Lighting">Advanced Lighting </a>
    135 			</li>
    136 			<li id="Advanced-Lighting/Gamma-Correction">
    137 				<a href="https://learnopengl.com/Advanced-Lighting/Gamma-Correction">Gamma Correction </a>
    138 			</li>
    139 			<li id="Advanced-Lighting/Shadows">
    140 				<span class="closed">Shadows </span>
    141 				<ol>
    142 					<li id="Advanced-Lighting/Shadows/Shadow-Mapping">
    143 						<a href="https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping">Shadow Mapping </a>
    144 					</li>
    145 					<li id="Advanced-Lighting/Shadows/Point-Shadows">
    146 						<a href="https://learnopengl.com/Advanced-Lighting/Shadows/Point-Shadows">Point Shadows </a>
    147 					</li>
    148 				</ol>
    149 			</li>
    150 			<li id="Advanced-Lighting/Normal-Mapping">
    151 				<a href="https://learnopengl.com/Advanced-Lighting/Normal-Mapping">Normal Mapping </a>
    152 			</li>
    153 			<li id="Advanced-Lighting/Parallax-Mapping">
    154 				<a href="https://learnopengl.com/Advanced-Lighting/Parallax-Mapping">Parallax Mapping </a>
    155 			</li>
    156 			<li id="Advanced-Lighting/HDR">
    157 				<a href="https://learnopengl.com/Advanced-Lighting/HDR">HDR </a>
    158 			</li>
    159 			<li id="Advanced-Lighting/Bloom">
    160 				<a href="https://learnopengl.com/Advanced-Lighting/Bloom">Bloom </a>
    161 			</li>
    162 			<li id="Advanced-Lighting/Deferred-Shading">
    163 				<a href="https://learnopengl.com/Advanced-Lighting/Deferred-Shading">Deferred Shading </a>
    164 			</li>
    165 			<li id="Advanced-Lighting/SSAO">
    166 				<a href="https://learnopengl.com/Advanced-Lighting/SSAO">SSAO </a>
    167 			</li>
    168 		</ol>
    169 	</li>
    170 	<li id="PBR">
    171 		<span class="closed">PBR </span>
    172 		<ol>
    173 			<li id="PBR/Theory">
    174 				<a href="https://learnopengl.com/PBR/Theory">Theory </a>
    175 			</li>
    176 			<li id="PBR/Lighting">
    177 				<a href="https://learnopengl.com/PBR/Lighting">Lighting </a>
    178 			</li>
    179 			<li id="PBR/IBL">
    180 				<span class="closed">IBL </span>
    181 				<ol>
    182 					<li id="PBR/IBL/Diffuse-irradiance">
    183 						<a href="https://learnopengl.com/PBR/IBL/Diffuse-irradiance">Diffuse irradiance </a>
    184 					</li>
    185 					<li id="PBR/IBL/Specular-IBL">
    186 						<a href="https://learnopengl.com/PBR/IBL/Specular-IBL">Specular IBL </a>
    187 					</li>
    188 				</ol>
    189 			</li>
    190 		</ol>
    191 	</li>
    192 	<li id="In-Practice">
    193 		<span class="closed">In Practice </span>
    194 		<ol>
    195 			<li id="In-Practice/Debugging">
    196 				<a href="https://learnopengl.com/In-Practice/Debugging">Debugging </a>
    197 			</li>
    198 			<li id="In-Practice/Text-Rendering">
    199 				<a href="https://learnopengl.com/In-Practice/Text-Rendering">Text Rendering </a>
    200 			</li>
    201 			<li id="In-Practice/2D-Game">
    202 				<span class="closed">2D Game </span>
    203 				<ol>
    204 					<li id="In-Practice/2D-Game/Breakout">
    205 						<a href="https://learnopengl.com/In-Practice/2D-Game/Breakout">Breakout </a>
    206 					</li>
    207 					<li id="In-Practice/2D-Game/Setting-up">
    208 						<a href="https://learnopengl.com/In-Practice/2D-Game/Setting-up">Setting up </a>
    209 					</li>
    210 					<li id="In-Practice/2D-Game/Rendering-Sprites">
    211 						<a href="https://learnopengl.com/In-Practice/2D-Game/Rendering-Sprites">Rendering Sprites </a>
    212 					</li>
    213 					<li id="In-Practice/2D-Game/Levels">
    214 						<a href="https://learnopengl.com/In-Practice/2D-Game/Levels">Levels </a>
    215 					</li>
    216 					<li id="In-Practice/2D-Game/Collisions">
    217 						<span class="closed">Collisions </span>
    218 						<ol>
    219 							<li id="In-Practice/2D-Game/Collisions/Ball">
    220 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Ball">Ball </a>
    221 							</li>
    222 							<li id="In-Practice/2D-Game/Collisions/Collision-detection">
    223 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Collision-detection">Collision detection </a>
    224 							</li>
    225 							<li id="In-Practice/2D-Game/Collisions/Collision-resolution">
    226 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Collision-resolution">Collision resolution </a>
    227 							</li>
    228 						</ol>
    229 					</li>
    230 					<li id="In-Practice/2D-Game/Particles">
    231 						<a href="https://learnopengl.com/In-Practice/2D-Game/Particles">Particles </a>
    232 					</li>
    233 					<li id="In-Practice/2D-Game/Postprocessing">
    234 						<a href="https://learnopengl.com/In-Practice/2D-Game/Postprocessing">Postprocessing </a>
    235 					</li>
    236 					<li id="In-Practice/2D-Game/Powerups">
    237 						<a href="https://learnopengl.com/In-Practice/2D-Game/Powerups">Powerups </a>
    238 					</li>
    239 					<li id="In-Practice/2D-Game/Audio">
    240 						<a href="https://learnopengl.com/In-Practice/2D-Game/Audio">Audio </a>
    241 					</li>
    242 					<li id="In-Practice/2D-Game/Render-text">
    243 						<a href="https://learnopengl.com/In-Practice/2D-Game/Render-text">Render text </a>
    244 					</li>
    245 					<li id="In-Practice/2D-Game/Final-thoughts">
    246 						<a href="https://learnopengl.com/In-Practice/2D-Game/Final-thoughts">Final thoughts </a>
    247 					</li>
    248 				</ol>
    249 			</li>
    250 		</ol>
    251 	</li>
    252 	<li id="Guest-Articles">
    253 		<span class="closed">Guest Articles </span>
    254 		<ol>
    255 			<li id="Guest-Articles/How-to-publish">
    256 				<a href="https://learnopengl.com/Guest-Articles/How-to-publish">How to publish </a>
    257 			</li>
    258 			<li id="Guest-Articles/2020">
    259 				<span class="closed">2020 </span>
    260 				<ol>
    261 					<li id="Guest-Articles/2020/OIT">
    262 						<span class="closed">OIT </span>
    263 						<ol>
    264 							<li id="Guest-Articles/2020/OIT/Introduction">
    265 								<a href="https://learnopengl.com/Guest-Articles/2020/OIT/Introduction">Introduction </a>
    266 							</li>
    267 							<li id="Guest-Articles/2020/OIT/Weighted-Blended">
    268 								<a href="https://learnopengl.com/Guest-Articles/2020/OIT/Weighted-Blended">Weighted Blended </a>
    269 							</li>
    270 						</ol>
    271 					</li>
    272 					<li id="Guest-Articles/2020/Skeletal-Animation">
    273 						<a href="https://learnopengl.com/Guest-Articles/2020/Skeletal-Animation">Skeletal Animation </a>
    274 					</li>
    275 				</ol>
    276 			</li>
    277 			<li id="Guest-Articles/2021">
    278 				<span class="closed">2021 </span>
    279 				<ol>
    280 					<li id="Guest-Articles/2021/CSM">
    281 						<a href="https://learnopengl.com/Guest-Articles/2021/CSM">CSM </a>
    282 					</li>
    283 					<li id="Guest-Articles/2021/Scene">
    284 						<span class="closed">Scene </span>
    285 						<ol>
    286 							<li id="Guest-Articles/2021/Scene/Scene-Graph">
    287 								<a href="https://learnopengl.com/Guest-Articles/2021/Scene/Scene-Graph">Scene Graph </a>
    288 							</li>
    289 							<li id="Guest-Articles/2021/Scene/Frustum-Culling">
    290 								<a href="https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling">Frustum Culling </a>
    291 							</li>
    292 						</ol>
    293 					</li>
    294 					<li id="Guest-Articles/2021/Tessellation">
    295 						<span class="closed">Tessellation </span>
    296 						<ol>
    297 							<li id="Guest-Articles/2021/Tessellation/Height-map">
    298 								<a href="https://learnopengl.com/Guest-Articles/2021/Tessellation/Height-map">Height map </a>
    299 							</li>
    300 						</ol>
    301 					</li>
    302 				</ol>
    303 			</li>
    304 		</ol>
    305 	</li>
    306 	<li id="Code-repository">
    307 		<a href="https://learnopengl.com/Code-repository">Code repository </a>
    308 	</li>
    309 	<li id="Translations">
    310 		<a href="https://learnopengl.com/Translations">Translations </a>
    311 	</li>
    312 	<li id="About">
    313 		<a href="https://learnopengl.com/About">About </a>
    314 	</li>
    315 </ol>
    316 	</nav>
    317 	<main>
    318     <h1 id="content-title">Collision resolution</h1>
    319 <h1 id="content-url" style='display:none;'>In-Practice/2D-Game/Collisions/Collision-resolution</h1>
    320 <p>
    321   At the end of the last chapter we had a working collision detection system. However, the ball does not react in any way to the detected collisions; it moves straight through all the bricks. We want the ball to <em>bounce</em> of the collided bricks. This chapter discusses how we can accomplish this so called <def>collision resolution</def> within the AABB - circle collision detection logic.
    322 </p>
    323 
    324 <p>
    325   Whenever a collision occurs we want two things to happen: we want to reposition the ball so it is no longer inside the other object and second, we want to change the direction of the ball's velocity so it looks like it's bouncing of the object.
    326 </p>
    327 
    328 <h3>Collision repositioning</h3>
    329 <p>
    330   To position the ball object outside the collided AABB we have to figure out the distance the ball penetrated the bounding box. For this we'll revisit the diagram from the previous chapter:
    331 </p>
    332 
    333 <img src="/img/in-practice/breakout/collisions_aabb_circle_resolution.png" class="clean" alt="Collision resolution between circle and AABB"/>
    334   
    335 <p>
    336   Here the ball moved slightly into the AABB and a collision was detected. We now want to move the ball out of the shape so that it merely touches the AABB as if no collision occurred. To figure out how much we need to move the ball out of the AABB we need to retrieve the vector \(\color{brown}{\bar{R}}\), which is the level of penetration into the AABB. To get this vector \(\color{brown}{\bar{R}}\), we subtract \(\color{green}{\bar{V}}\) from the ball's radius. Vector \(\color{green}{\bar{V}}\) is the difference between closest point \(\color{red}{\bar{P}}\) and the ball's center \(\color{blue}{\bar{C}}\).
    337 </p>
    338   
    339 <p>
    340   Knowing \(\color{brown}{\bar{R}}\), we offset the ball's position by \(\color{brown}{\bar{R}}\) positioning it directly against the AABB; the ball is now properly positioned.
    341 </p>
    342   
    343 <h3>Collision direction</h3>
    344 <p>
    345    Next we need to figure out how to update the ball's velocity after a collision. For Breakout we use the following rules to change the ball's velocity: 
    346 </p>
    347   
    348   <ol>
    349     <li>If the ball collides with the right or left side of an AABB, its horizontal velocity (<code>x</code>) is reversed.</li>
    350     <li>If the ball collides with the bottom or top side of an AABB, its vertical velocity (<code>y</code>) is reversed.</li>
    351   </ol>
    352   
    353 <p>
    354   But how do we figure out the direction the ball hit the AABB? There are several approaches to this problem. One of them is that, instead of 1 AABB, we use 4 AABBs for each brick that we each position at one of its edges. This way we can determine which AABB and thus which edge was hit. However, a simpler approach exists with the help of the dot product.
    355 </p>
    356   
    357 <p>
    358   You probably still remember from the <a href="https://learnopengl.com/Getting-started/Transformations" target="_blank">transformations</a> chapter that the dot product gives us the angle between two normalized vectors. What if we were to define four vectors pointing north, south, west, and east, and calculate the dot product between them and a given vector? The resulting dot product between these four direction vectors and the given vector that is highest (dot product's maximum value is <code>1.0f</code> which represents a <code>0</code> degree angle) is then the direction of the vector. 
    359 </p>
    360   
    361 <p>
    362   This procedure looks as follows in code:
    363 </p>
    364   
    365 <pre><code>
    366 Direction VectorDirection(glm::vec2 target)
    367 {
    368     glm::vec2 compass[] = {
    369         glm::vec2(0.0f, 1.0f),	// up
    370         glm::vec2(1.0f, 0.0f),	// right
    371         glm::vec2(0.0f, -1.0f),	// down
    372         glm::vec2(-1.0f, 0.0f)	// left
    373     };
    374     float max = 0.0f;
    375     unsigned int best_match = -1;
    376     for (unsigned int i = 0; i &lt; 4; i++)
    377     {
    378         float dot_product = glm::dot(glm::normalize(target), compass[i]);
    379         if (dot_product &gt; max)
    380         {
    381             max = dot_product;
    382             best_match = i;
    383         }
    384     }
    385     return (Direction)best_match;
    386 }    
    387 </code></pre>
    388 
    389 <p>
    390   The function compares <var>target</var> to each of the direction vectors in the <var>compass</var> array. The compass vector <var>target</var> is closest to in angle, is the direction returned to the function caller. Here <var>Direction</var> is part of an enum defined in the game class's header file:
    391 </p>
    392   
    393 <pre><code>
    394 enum Direction {
    395 	UP,
    396 	RIGHT,
    397 	DOWN,
    398 	LEFT
    399 };    
    400 </code></pre>
    401   
    402 <p>
    403    Now that we know how to get vector \(\color{brown}{\bar{R}}\) and how to determine the direction the ball hit the AABB, we can start writing the collision resolution code.
    404 </p>
    405   
    406 <h3>AABB - Circle collision resolution</h3>
    407 <p>
    408     To calculate the required values for collision resolution we need a bit more information from the collision function(s) than just a <code>true</code> or <code>false</code>. We're now going to return a <def>tuple</def> of information that tells us if a collision occurred, what direction it occurred, and the difference vector \(\color{brown}{\bar{R}}\). You can find the <code>tuple</code> container in the <code>&lt;tuple&gt;</code> header.
    409 </p>
    410   
    411 <p>
    412   To keep the code slightly more organized we'll typedef the collision relevant data as <fun>Collision</fun>:
    413 </p>
    414   
    415 <pre><code>
    416 typedef std::tuple&lt;bool, Direction, glm::vec2&gt; Collision;    
    417 </code></pre>
    418   
    419 <p>
    420   Then we change the code of the <fun>CheckCollision</fun> function to not only return <code>true</code> or <code>false</code>, but also the direction and difference vector:
    421 </p>
    422   
    423 <pre><code>
    424 Collision CheckCollision(BallObject &one, GameObject &two) // AABB - AABB collision
    425 {
    426     [...]
    427     if (glm::length(difference) &lt;= one.Radius)
    428         return std::make_tuple(true, VectorDirection(difference), difference);
    429     else
    430         return std::make_tuple(false, UP, glm::vec2(0.0f, 0.0f));
    431 }
    432 </code></pre>
    433   
    434 <p>
    435   The game's <fun>DoCollision</fun> function now doesn't just check if  a collision occurred, but also acts appropriately whenever a collision did occur. The function now calculates the level of penetration (as shown in the diagram at the start of this tutorial) and adds or subtracts it from the ball's position based on the direction of the collision.
    436 </p>
    437   
    438 <pre><code>
    439 void Game::DoCollisions()
    440 {
    441     for (GameObject &box : this-&gt;Levels[this-&gt;Level].Bricks)
    442     {
    443         if (!box.Destroyed)
    444         {
    445             Collision collision = CheckCollision(*Ball, box);
    446             if (std::get&lt;0&gt;(collision)) // if collision is true
    447             {
    448                 // destroy block if not solid
    449                 if (!box.IsSolid)
    450                     box.Destroyed = true;
    451                 // collision resolution
    452                 Direction dir = std::get&lt;1&gt;(collision);
    453                 glm::vec2 diff_vector = std::get&lt;2&gt;(collision);
    454                 if (dir == LEFT || dir == RIGHT) // horizontal collision
    455                 {
    456                     Ball-&gt;Velocity.x = -Ball-&gt;Velocity.x; // reverse horizontal velocity
    457                     // relocate
    458                     float penetration = Ball-&gt;Radius - std::abs(diff_vector.x);
    459                     if (dir == LEFT)
    460                         Ball-&gt;Position.x += penetration; // move ball to right
    461                     else
    462                         Ball-&gt;Position.x -= penetration; // move ball to left;
    463                 }
    464                 else // vertical collision
    465                 {
    466                     Ball-&gt;Velocity.y = -Ball-&gt;Velocity.y; // reverse vertical velocity
    467                     // relocate
    468                     float penetration = Ball-&gt;Radius - std::abs(diff_vector.y);
    469                     if (dir == UP)
    470                         Ball-&gt;Position.y -= penetration; // move ball back up
    471                     else
    472                         Ball-&gt;Position.y += penetration; // move ball back down
    473                 }
    474             }
    475         }
    476     }
    477 }    
    478 </code></pre>
    479   
    480 <p>
    481   Don't get too scared by the function's complexity since it is basically a direct translation of the concepts introduced so far. First we check for a collision and if so, we destroy the block if it is non-solid. Then we obtain the collision direction <var>dir</var> and the vector \(\color{green}{\bar{V}}\) as <var>diff_vector</var> from the tuple and finally do the collision resolution.
    482 </p>
    483   
    484 <p>
    485   We first check if the collision direction is either horizontal or vertical and then reverse the velocity accordingly. If horizontal, we calculate the penetration value \(\color{brown}R\) from the <var>diff_vector</var>'s x component and either add or subtract this from the ball's position. The same applies to the vertical collisions, but this time we operate on the <code>y</code> component of all the vectors.
    486 </p>
    487   
    488 <p>
    489  Running your application should now give you working collision resolution, but it's probably difficult to really see its effect since the ball will bounce towards the bottom edge as soon as you hit a single block and be lost forever. We can fix this by also handling player paddle collisions. 
    490 </p>
    491   
    492 <h2>Player - ball collisions</h2>
    493 <p>
    494   Collisions between the ball and the player is handled slightly different from what we've previously discussed, since this time the ball's horizontal velocity should be updated based on how far it hit the paddle from its center. The further the ball hits the paddle from its center, the stronger its horizontal velocity change should be.
    495 </p>
    496   
    497 <pre><code>
    498 void Game::DoCollisions()
    499 {
    500     [...]
    501     Collision result = CheckCollision(*Ball, *Player);
    502     if (!Ball-&gt;Stuck && std::get&lt;0&gt;(result))
    503     {
    504         // check where it hit the board, and change velocity based on where it hit the board
    505         float centerBoard = Player-&gt;Position.x + Player-&gt;Size.x / 2.0f;
    506         float distance = (Ball-&gt;Position.x + Ball-&gt;Radius) - centerBoard;
    507         float percentage = distance / (Player-&gt;Size.x / 2.0f);
    508         // then move accordingly
    509         float strength = 2.0f;
    510         glm::vec2 oldVelocity = Ball-&gt;Velocity;
    511         Ball-&gt;Velocity.x = INITIAL_BALL_VELOCITY.x * percentage * strength; 
    512         Ball-&gt;Velocity.y = -Ball-&gt;Velocity.y;
    513         Ball-&gt;Velocity = glm::normalize(Ball-&gt;Velocity) * glm::length(oldVelocity);
    514     } 
    515 }
    516   </code></pre>
    517   
    518 <p>
    519   After we checked collisions between the ball and each brick, we'll check if the ball collided with the player paddle. If so (and the ball is not stuck to the paddle) we calculate the percentage of how far the ball's center is moved from the paddle's center compared to the half-extent of the paddle. The horizontal velocity of the ball is then updated based on the distance it hit the paddle from its center. In addition to updating the horizontal velocity, we also have to reverse the y velocity.
    520 </p>
    521   
    522 <p>
    523   Note that the old velocity is stored as <var>oldVelocity</var>. The reason for storing the old velocity is that we update the horizontal velocity of the ball's velocity vector while keeping its <code>y</code> velocity constant. This would mean that the length of the vector constantly changes, which has the effect that the ball's velocity vector is much larger (and thus stronger) if the ball hit the edge of the paddle compared to if the ball would hit the center of the paddle. For this reason, the new velocity vector is normalized and multiplied by the length of the old velocity vector. This way, the velocity of the ball is always consistent, regardless of where it hits the paddle.
    524 </p>
    525   
    526 <h3>Sticky paddle</h3>
    527 <p>
    528   You may or may not have noticed it when you ran the code, but there is still a large issue with the  player and ball collision resolution. The following shows what may happen:
    529 </p>
    530   
    531 <div class="video paused" onclick="ClickVideo(this)">
    532   <video width="600" height="450" loop>
    533     <source src="/video/in-practice/breakout/collisions_sticky_paddle.mp4" type="video/mp4" />
    534     <img src="/img/in-practice/breakout/collisions_sticky_paddle.png" class="clean"/>
    535   </video>
    536 </div>
    537 
    538 <p>
    539   This issue is called the <def>sticky paddle</def> issue. This happens, because the player paddle moves with a high velocity towards the ball with the ball's center ending up inside the player paddle. Since we did not account for the case where the ball's center is inside an AABB, the game tries to continuously react to all the collisions. Once it finally breaks free, it will have reversed its <code>y</code> velocity so much that it's unsure whether to go up or down after breaking free.
    540 </p>
    541   
    542 <p>
    543   We can easily fix this behavior by introducing a small hack made possible by the fact that the we can always assume we have a collision at the top of the paddle. Instead of reversing the <code>y</code> velocity, we simply always return a positive <code>y</code> direction so whenever it does get stuck, it will immediately break free.
    544 </p>
    545   
    546 <pre><code>
    547  //Ball->Velocity.y = -Ball->Velocity.y;
    548 Ball->Velocity.y = -1.0f * abs(Ball->Velocity.y);  
    549 </code></pre>
    550 
    551 <p>
    552   If you try hard enough the effect is still noticeable, but I personally find it an acceptable trade-off. 
    553 </p>
    554   
    555 <h3>The bottom edge</h3>
    556 <p>
    557   The only thing that is still missing from the classic Breakout recipe is some loss condition that resets the level and the player. Within the game class's <fun>Update</fun> function we want to check if the ball reached the bottom edge, and if so, reset the game.
    558 </p>
    559   
    560 <pre><code>
    561 void Game::Update(float dt)
    562 {
    563     [...]
    564     if (Ball->Position.y >= this->Height) // did ball reach bottom edge?
    565     {
    566         this->ResetLevel();
    567         this->ResetPlayer();
    568     }
    569 }  
    570 </code></pre>
    571   
    572 <p>
    573   The <fun>ResetLevel</fun> and <fun>ResetPlayer</fun> functions re-load the level and reset the objects' values to their original starting values. The game should now look a bit like this:
    574 </p>
    575   
    576 <div class="video paused" onclick="ClickVideo(this)">
    577   <video width="600" height="450" loop>
    578     <source src="/video/in-practice/breakout/collisions_complete.mp4" type="video/mp4" />
    579   </video> 
    580 </div>
    581   
    582 <p>
    583   And there you have it, we just finished creating a clone of the classical Breakout game with similar mechanics. You can find the game class' source code here: <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/progress/5.game.h" target="_blank">header</a>, <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/progress/5.game.cpp" target="_blank">code</a>.
    584   </p>
    585   
    586 <h2>A few notes</h2>
    587 <p>
    588   Collision detection is a difficult topic of video game development and possibly its most challenging. Most collision detection and resolution schemes are combined with physics engines as found in most modern-day games. The collision scheme we used for the Breakout game is a very simple scheme and one specialized specifically for this type of game. 
    589   </p>
    590   
    591 <p>
    592  It should be stressed that this type of collision detection and resolution is not perfect. It calculates possible collisions only per frame and only for the positions exactly as they are at that timestep; this means that if an object would have such a velocity that it would pass over another object within a single frame, it would look like it never collided with this object. So if there are framedrops, or you reach high enough velocities, this collision detection scheme will not hold.  
    593 </p>
    594   
    595 <p>
    596     Several of the issues that can still occur:
    597 </p>
    598   
    599 <ul>
    600 	<li>If the ball goes too fast, it may skip over an object entirely within a single frame, not detecting any collisions.</li>
    601   <li>If the ball hits more than one object within a single frame, it will have detected two collisions and reversed its velocity twice; not affecting its original velocity.</li>
    602   <li>Hitting a corner of a brick could reverse the ball's velocity in the wrong direction since the distance it travels in a single frame could decide the difference between <fun>VectorDirection</fun> returning a vertical or horizontal direction.</li>
    603 </ul>
    604   
    605 <p>
    606   These chapters are however aimed to teach the readers the basics of several aspects of graphics and game-development. For this reason, this collision scheme serves its purpose; its understandable and works quite well in normal scenarios. Just keep in mind that there exist better (more complicated) collision schemes that work well in almost all scenarios (including movable objects) like the <def>separating axis theorem</def>.
    607 </p>
    608   
    609 <p>
    610   Thankfully, there exist large, practical, and often quite efficient physics engines (with timestep-independent collision schemes) for use in your own games. If you wish to delve further into such systems or need  more advanced physics and have trouble figuring out the mathematics, <a href="http://box2d.org/" target="_blank">Box2D</a> is a perfect 2D physics library for implementing physics and collision detection in your applications.
    611 </p>
    612        
    613 
    614     </div>
    615     
    616     <div id="hover">
    617         HI
    618     </div>
    619    <!-- 728x90/320x50 sticky footer -->
    620 <div id="waldo-tag-6196"></div>
    621 
    622    <div id="disqus_thread"></div>
    623 
    624     
    625 
    626 
    627 </div> <!-- container div -->
    628 
    629 
    630 </div> <!-- super container div -->
    631 </body>
    632 </html>
    633 	</main>
    634 </body>
    635 </html>