LearnOpenGL

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

Levels.html (27862B)


      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">Levels</h1>
    319 <h1 id="content-url" style='display:none;'>In-Practice/2D-Game/Levels</h1>
    320 <p>
    321   Breakout is unfortunately not just about a single happy green face, but contains complete levels with a lot of playfully colored bricks. We want these levels to be configurable such that they can support any number of rows and/or columns, we want the levels to have solid bricks (that cannot be destroyed), we want the levels to support multiple brick colors, and we want them to be stored externally in (text) files.
    322 </p>
    323 
    324 <p>
    325   In this chapter we'll briefly walk through the code of a game level object that is used to manage a large amount of bricks. We first have to define what an actual <def>brick</def> is though.
    326 </p>
    327 
    328 <p>
    329   We create a component called a <def>game object</def> that acts as the base representation of an object inside the game. Such a game object holds state data like its position, size, and velocity. It holds a color, a rotation component, whether it is solid and/or destroyed, and it also stores a <fun>Texture2D</fun> variable as its sprite. 
    330 </p>
    331 
    332 <p>
    333   Each object in the game is represented as a <fun>GameObject</fun> or a derivative of this class. You can find the code of the <fun>GameObject</fun> class below:
    334 </p>
    335 
    336 <ul>
    337   <li><strong>GameObject</strong>: <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/game_object.h" target="_blank">header</a>, <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/game_object.cpp" target="_blank">code</a> </li>
    338 </ul>
    339 
    340 <p>
    341   A level in Breakout consists entirely of bricks so we can represent a level by exactly that: a collection of bricks. Because a brick requires the same state as a game object, we're going to represent each brick of the level as a <fun>GameObject</fun>. The declaration of the <fun>GameLevel</fun> class then looks as follows:
    342 </p>
    343 
    344 <pre><code>
    345 class GameLevel
    346 {
    347 public:
    348     // level state
    349     std::vector&lt;GameObject&gt; Bricks;
    350     // constructor
    351     GameLevel() { }
    352     // loads level from file
    353     void Load(const char *file, unsigned int levelWidth, unsigned int levelHeight);
    354     // render level
    355     void Draw(SpriteRenderer &renderer);
    356     // check if the level is completed (all non-solid tiles are destroyed)
    357     bool IsCompleted();
    358 private:
    359     // initialize level from tile data
    360     void init(std::vector&lt;std::vector&lt;unsigned int&gt;&gt; tileData, 
    361               unsigned int levelWidth, unsigned int levelHeight);
    362 };  
    363 </code></pre>
    364 
    365 <p>
    366   Since a level is loaded from an external (text) file, we need to propose some kind of level structure. Here is an example of what a game level may look like in a text file:
    367 </p>
    368 
    369 <pre><code>
    370 1 1 1 1 1 1 
    371 2 2 0 0 2 2
    372 3 3 4 4 3 3
    373 </code></pre>
    374 
    375 <p>
    376   A level is stored in a matrix-like structure where each number represents a type of brick, each one separated by a space. Within the level code we can then assign what each number represents. We have chosen the following representation:
    377 </p>
    378 
    379 <ul>
    380   <li>A number of 0: no brick, an empty space within the level.</li>
    381   <li>A number of 1: a solid brick, a brick that cannot be destroyed.</li>
    382   <li>A number higher than 1: a destroyable brick; each subsequent number only differs in color.</li>
    383 </ul>
    384 
    385 <p>
    386   The example level listed above would, after being processed by <fun>GameLevel</fun>, look like this:
    387 </p>
    388 
    389 <img src="/img/in-practice/breakout/levels-example.png" class="clean" alt="Example of a level using the Breakout GameLevel class"/>
    390   
    391 <p>
    392   The <fun>GameLevel</fun> class uses two functions to generate a level from file. It first loads all the numbers in a two-dimensional vector within its <fun>Load</fun> function that then processes these numbers (to create all game objects) in its <fun>init</fun> function.
    393 </p>
    394 
    395 
    396 <pre><code>
    397 void GameLevel::Load(const char *file, unsigned int levelWidth, unsigned int levelHeight)
    398 {
    399     // clear old data
    400     this-&gt;Bricks.clear();
    401     // load from file
    402     unsigned int tileCode;
    403     GameLevel level;
    404     std::string line;
    405     std::ifstream fstream(file);
    406     std::vector&lt;std::vector&lt;unsigned int&gt;&gt; tileData;
    407     if (fstream)
    408     {
    409         while (std::getline(fstream, line)) // read each line from level file
    410         {
    411             std::istringstream sstream(line);
    412             std::vector&lt;unsigned int&gt; row;
    413             while (sstream &gt;&gt; tileCode) // read each word separated by spaces
    414                 row.push_back(tileCode);
    415             tileData.push_back(row);
    416         }
    417         if (tileData.size() &gt; 0)
    418             this-&gt;init(tileData, levelWidth, levelHeight);
    419     }
    420 } 
    421 </code></pre>
    422 
    423 <p>
    424   The loaded <var>tileData</var> is then passed to the game level's <fun>init</fun> function:
    425 </p>
    426 
    427 <pre><code>
    428 void GameLevel::init(std::vector&lt;std::vector&lt;unsigned int&gt;&gt; tileData, 
    429                      unsigned int lvlWidth, unsigned int lvlHeight)
    430 {
    431     // calculate dimensions
    432     unsigned int height = tileData.size();
    433     unsigned int width  = tileData[0].size();
    434     float unit_width    = lvlWidth / static_cast&lt;float&gt;(width);
    435     float unit_height   = lvlHeight / height;
    436     // initialize level tiles based on tileData		
    437     for (unsigned int y = 0; y &lt; height; ++y)
    438     {
    439         for (unsigned int x = 0; x &lt; width; ++x)
    440         {
    441             // check block type from level data (2D level array)
    442             if (tileData[y][x] == 1) // solid
    443             {
    444                 glm::vec2 pos(unit_width * x, unit_height * y);
    445                 glm::vec2 size(unit_width, unit_height);
    446                 GameObject obj(pos, size, 
    447                     ResourceManager::GetTexture("block_solid"), 
    448                     glm::vec3(0.8f, 0.8f, 0.7f)
    449                 );
    450                 obj.IsSolid = true;
    451                 this-&gt;Bricks.push_back(obj);
    452             }
    453             else if (tileData[y][x] &gt; 1)	
    454             {
    455                 glm::vec3 color = glm::vec3(1.0f); // original: white
    456                 if (tileData[y][x] == 2)
    457                     color = glm::vec3(0.2f, 0.6f, 1.0f);
    458                 else if (tileData[y][x] == 3)
    459                     color = glm::vec3(0.0f, 0.7f, 0.0f);
    460                 else if (tileData[y][x] == 4)
    461                     color = glm::vec3(0.8f, 0.8f, 0.4f);
    462                 else if (tileData[y][x] == 5)
    463                     color = glm::vec3(1.0f, 0.5f, 0.0f);
    464 
    465                 glm::vec2 pos(unit_width * x, unit_height * y);
    466                 glm::vec2 size(unit_width, unit_height);
    467                 this-&gt;Bricks.push_back(
    468                     GameObject(pos, size, ResourceManager::GetTexture("block"), color)
    469                 );
    470             }
    471         }
    472     }  
    473 }
    474 </code></pre>
    475 
    476 <p>
    477   The <fun>init</fun> function iterates through each of the loaded numbers and adds a <fun>GameObject</fun> to the level's <var>Bricks</var> vector based on the processed number. The size of each brick is automatically calculated (<var>unit_width</var> and <var>unit_height</var>) based on the total number of bricks so that each brick perfectly fits within the screen bounds. 
    478 </p>
    479 
    480 <p>
    481   Here we load the game objects with two new textures, a <a href="/img/in-practice/breakout/textures/block.png" target="_blank">block</a> texture and a <a href="/img/in-practice/breakout/textures/block_solid.png" target="_blank">solid block</a> texture.
    482 </p>
    483 
    484 <img src="/img/in-practice/breakout/block-textures.png" alt="Image of two types of block textures"/>
    485 
    486 <p>
    487   A nice little trick here is that these textures are completely in gray-scale. The effect is that we can neatly manipulate their colors within the game-code by multiplying their grayscale colors with a defined color vector; exactly as we did within the <fun>SpriteRenderer</fun>. This way, customizing the appearance of their colors doesn't look too weird or unbalanced.
    488 </p>
    489 
    490 <p>
    491   The <fun>GameLevel</fun> class also houses a few other functions, like rendering all non-destroyed bricks, or validating if all non-solid bricks are destroyed. You can find the source code of the <fun>GameLevel</fun> class below:
    492 </p>
    493 
    494 <ul>
    495   <li><strong>GameLevel</strong>: <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/game_level.h" target="_blank">header</a>, <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/game_level.cpp" target="_blank">code</a> </li>
    496 </ul>
    497 
    498 <p>
    499   The game level class gives us a lot of flexibility since any amount of rows and columns are supported and a user could easily create his/her own levels by modifying the level files. 
    500 </p>
    501 
    502 <h2>Within the game</h2>
    503 <p>
    504   We would like to support multiple levels in the Breakout game so we'll have to extend the game class a little by adding a vector that holds variables of type <fun>GameLevel</fun>. We'll also store the currently active level while we're at it:
    505 </p>
    506 
    507 <pre><code>
    508 class Game
    509 {
    510     [...]
    511     std::vector&lt;GameLevel&gt; Levels;
    512     unsigned int           Level;
    513     [...]  
    514 };
    515 </code></pre>
    516 
    517 <p>
    518   This series' version of the Breakout game features a total of 4 levels:
    519 </p>
    520 
    521 <ul>
    522   <li><a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/levels/one.lvl" target="_blank">Standard</a></li>
    523   <li><a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/levels/two.lvl" target="_blank">A few small gaps</a></li>
    524   <li><a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/levels/three.lvl" target="_blank">Space invader</a></li>
    525   <li><a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/levels/four.lvl" target="_blank">Bounce galore</a></li>
    526 </ul>
    527 
    528 <p>
    529   Each of the textures and levels are then initialized within the game class's <fun>Init</fun> function:
    530 </p>
    531 
    532 <pre><code>
    533 void Game::Init()
    534 {
    535     [...]
    536     // load textures
    537     ResourceManager::LoadTexture("textures/background.jpg", false, "background");
    538     ResourceManager::LoadTexture("textures/awesomeface.png", true, "face");
    539     ResourceManager::LoadTexture("textures/block.png", false, "block");
    540     ResourceManager::LoadTexture("textures/block_solid.png", false, "block_solid");
    541     // load levels
    542     GameLevel one; one.Load("levels/one.lvl", this-&gt;Width, this-&gt;Height / 2);
    543     GameLevel two; two.Load("levels/two.lvl", this-&gt;Width, this-&gt;Height / 2);
    544     GameLevel three; three.Load("levels/three.lvl", this-&gt;Width, this-&gt;Height / 2);
    545     GameLevel four; four.Load("levels/four.lvl", this-&gt;Width, this-&gt;Height / 2);
    546     this-&gt;Levels.push_back(one);
    547     this-&gt;Levels.push_back(two);
    548     this-&gt;Levels.push_back(three);
    549     this-&gt;Levels.push_back(four);
    550     this-&gt;Level = 0;
    551 }  
    552 </code></pre>
    553 
    554 <p>
    555   Now all that is left to do, is actually render the level. We accomplish this by calling the currently active level's <fun>Draw</fun> function that in turn calls each <fun>GameObject</fun>'s <fun>Draw</fun> function using the given sprite renderer. Next to the level, we'll also render the scene with a nice <a href="/img/in-practice/breakout/textures/background.jpg" target="_blank">background image</a> (courtesy of Tenha):
    556 </p>
    557 
    558 <pre><code>
    559 void Game::Render()
    560 {
    561     if(this-&gt;State == GAME_ACTIVE)
    562     {
    563         // draw background
    564         Renderer-&gt;DrawSprite(ResourceManager::GetTexture("background"), 
    565             glm::vec2(0.0f, 0.0f), glm::vec2(this-&gt;Width, this-&gt;Height), 0.0f
    566         );
    567         // draw level
    568         this-&gt;Levels[this-&gt;Level].Draw(*Renderer);
    569     }
    570 }
    571 </code></pre>
    572 
    573 <p>
    574   The result is then a nicely rendered level that really starts to make the game feel more alive:
    575 </p>
    576 
    577 <img src="/img/in-practice/breakout/levels.png" class="clean" alt="Level in OpenGL breakout"/>
    578 
    579 <h3>The player paddle</h3>
    580 <p>
    581   While we're at it, we may just as well introduce a paddle at the bottom of the scene that is controlled by the player. The paddle only allows for horizontal movement and whenever it touches any of the scene's edges, its movement should halt. For the player paddle we're going to use the <a href="/img/in-practice/breakout/textures/paddle.png" target="_blank">following</a> texture:
    582 </p>
    583 
    584 <img src="/img/in-practice/breakout/textures/paddle.png" class="clean" style="width:256px;height:auto;" alt="Texture image if a paddle in OpenGL breakout"/>
    585 
    586 <p>
    587   A paddle object will have a position, a size, and a sprite texture, so it makes sense to define the paddle as a <fun>GameObject</fun> as well:
    588 </p>
    589 
    590 <pre><code>
    591 // Initial size of the player paddle
    592 const glm::vec2 PLAYER_SIZE(100.0f, 20.0f);
    593 // Initial velocity of the player paddle
    594 const float PLAYER_VELOCITY(500.0f);
    595 
    596 GameObject      *Player;
    597   
    598 void Game::Init()
    599 {
    600     [...]    
    601     ResourceManager::LoadTexture("textures/paddle.png", true, "paddle");
    602     [...]
    603     glm::vec2 playerPos = glm::vec2(
    604         this-&gt;Width / 2.0f - PLAYER_SIZE.x / 2.0f, 
    605         this-&gt;Height - PLAYER_SIZE.y
    606     );
    607     Player = new GameObject(playerPos, PLAYER_SIZE, ResourceManager::GetTexture("paddle"));
    608 }
    609 </code></pre>
    610 
    611 <p>
    612   Here we defined several constant values that define the paddle's size and speed. Within the Game's <fun>Init</fun> function we calculate the starting position of the paddle within the scene. We make sure the player paddle's center is aligned with the horizontal center of the scene.
    613 </p>
    614 
    615 <p>
    616   With the player paddle initialized, we also need to add a statement to the Game's <fun>Render</fun> function:
    617 </p>
    618 
    619 <pre><code>
    620 Player-&gt;Draw(*Renderer);  
    621 </code></pre>
    622 
    623 <p>
    624   If you'd start the game now, you would not only see the level, but also a fancy player paddle aligned to the bottom edge of the scene. As of now, it doesn't really do anything so we're going to delve into the Game's <fun>ProcessInput</fun> function to horizontally move the paddle whenever the user presses the <var>A</var> or <var>D</var> key:
    625 </p>
    626 
    627 <pre><code>
    628 void Game::ProcessInput(float dt)
    629 {
    630     if (this-&gt;State == GAME_ACTIVE)
    631     {
    632         float velocity = PLAYER_VELOCITY * dt;
    633         // move playerboard
    634         if (this-&gt;Keys[GLFW_KEY_A])
    635         {
    636             if (Player-&gt;Position.x &gt;= 0.0f)
    637                 Player-&gt;Position.x -= velocity;
    638         }
    639         if (this-&gt;Keys[GLFW_KEY_D])
    640         {
    641             if (Player-&gt;Position.x &lt;= this-&gt;Width - Player-&gt;Size.x)
    642                 Player-&gt;Position.x += velocity;
    643         }
    644     }
    645 } 
    646 </code></pre>
    647 
    648 <p>
    649   Here we move the player paddle either in the left or right direction based on which key the user pressed (note how we multiply the velocity with the <def>deltatime</def> variable). If the paddle's <code>x</code> value would be less than <code>0</code> it would've moved outside the left edge, so we only move the paddle to the left if the paddle's <code>x</code> value is higher than the left edge's <code>x</code> position (<code>0.0</code>). We do the same for when the paddle breaches the right edge, but we have to compare the right edge's position with the right edge of the paddle (subtract the paddle's width from the right edge's <code>x</code> position).
    650 </p>
    651 
    652 <p>
    653   Now running the game gives us a player paddle that we can move all across the bottom edge:
    654 </p>
    655 
    656 <img src="/img/in-practice/breakout/levels-player.png" class="clean" alt="Image of OpenGL breakout now with player paddle"/>
    657 
    658 <p>
    659   You can find the updated code of the Game class here:
    660 </p>
    661 
    662 <ul>
    663   <li><strong>Game</strong>: <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/progress/4.game.h" target="_blank">header</a>, <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/progress/4.game.cpp" target="_blank">code</a> </li>
    664 </ul>       
    665 
    666     </div>
    667     
    668     <div id="hover">
    669         HI
    670     </div>
    671    <!-- 728x90/320x50 sticky footer -->
    672 <div id="waldo-tag-6196"></div>
    673 
    674    <div id="disqus_thread"></div>
    675 
    676     
    677 
    678 
    679 </div> <!-- container div -->
    680 
    681 
    682 </div> <!-- super container div -->
    683 </body>
    684 </html>
    685 	</main>
    686 </body>
    687 </html>