LearnOpenGL

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

Ball.html (7386B)


      1     <h1 id="content-title">Ball</h1>
      2 <h1 id="content-url" style='display:none;'>In-Practice/2D-Game/Collisions/Ball</h1>
      3 <p>
      4   At this point we have a level full of bricks and a movable player paddle. The only thing missing from the classic Breakout recipe is the ball. The objective is to let the ball collide with all the bricks until each of the destroyable bricks are destroyed, but this all within the condition that the ball is not allowed to reach the bottom edge of the screen.
      5 </p>
      6 
      7 <p>
      8   In addition to the general game object components, a ball has a radius, and an extra boolean value indicating whether the ball is <def>stuck</def> on the player paddle or it's allowed free movement. When the game starts, the ball is initially stuck on the player paddle until the player starts the game by pressing some arbitrary key.
      9 </p>
     10 
     11 <p>
     12   Because the ball is effectively a <fun>GameObject</fun> with a few extra properties it makes sense to create a <fun>BallObject</fun> class as a subclass of <fun>GameObject</fun>:
     13 </p>
     14 
     15 <pre><code>
     16 class BallObject : public GameObject
     17 {
     18     public:
     19         // ball state	
     20         float     Radius;
     21         bool      Stuck;
     22   
     23 
     24         BallObject();
     25         BallObject(glm::vec2 pos, float radius, glm::vec2 velocity, Texture2D sprite);
     26 
     27         glm::vec2 Move(float dt, unsigned int window_width);
     28         void      Reset(glm::vec2 position, glm::vec2 velocity);
     29 }; 
     30 </code></pre>
     31 
     32 <p>
     33   The constructor of <fun>BallObject</fun> initializes its own values, but also initializes the underlying <fun>GameObject</fun>. The <fun>BallObject</fun> class hosts a <fun>Move</fun> function that moves the ball based on its velocity. It also checks if it reaches any of the scene's edges and if so, reverses the ball's velocity:
     34 </p>
     35 
     36 <pre><code>
     37 glm::vec2 BallObject::Move(float dt, unsigned int window_width)
     38 {
     39     // if not stuck to player board
     40     if (!this-&gt;Stuck)
     41     { 
     42         // move the ball
     43         this-&gt;Position += this-&gt;Velocity * dt;
     44         // check if outside window bounds; if so, reverse velocity and restore at correct position
     45         if (this-&gt;Position.x &lt;= 0.0f)
     46         {
     47             this-&gt;Velocity.x = -this-&gt;Velocity.x;
     48             this-&gt;Position.x = 0.0f;
     49         }
     50         else if (this-&gt;Position.x + this-&gt;Size.x &gt;= window_width)
     51         {
     52             this-&gt;Velocity.x = -this-&gt;Velocity.x;
     53             this-&gt;Position.x = window_width - this-&gt;Size.x;
     54         }
     55         if (this-&gt;Position.y &lt;= 0.0f)
     56         {
     57             this-&gt;Velocity.y = -this-&gt;Velocity.y;
     58             this-&gt;Position.y = 0.0f;
     59         }
     60       
     61     }
     62     return this-&gt;Position;
     63 }  
     64 </code></pre>
     65 
     66 <p>
     67   In addition to reversing the ball's velocity, we also want relocate the ball back along the edge; the ball is only able to move if it isn't stuck. 
     68 </p>
     69 
     70 <note>
     71   Because the player is game over (or loses a life) if the ball reaches the bottom edge, there is no code to let the ball bounce of the bottom edge. We do need to later implement this logic somewhere in the game code though.
     72 </note>
     73 
     74 <p>
     75   You can find the code for the ball object below:
     76 </p>
     77 
     78 <ul>
     79   <li><strong>BallObject</strong>: <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/progress/5.1.ball_object_collisions.h" target="_blank">header</a>, <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/progress/5.1.ball_object_collisions.cpp" target="_blank">code</a></li>
     80 </ul>
     81 
     82 <p>
     83   First, let's add the ball to the game. Just like the player paddle, we create a <fun>BallObject</fun> and define two constants that we use to initialize the ball. As for the texture of the ball, we're going to use an image that makes perfect sense in a LearnOpenGL Breakout game: <a href="/img/textures/awesomeface.png" target="_blank">ball texture</a>.
     84 </p>
     85 
     86 <pre><code>
     87 // Initial velocity of the Ball
     88 const glm::vec2 INITIAL_BALL_VELOCITY(100.0f, -350.0f);
     89 // Radius of the ball object
     90 const float BALL_RADIUS = 12.5f;
     91   
     92 BallObject     *Ball; 
     93   
     94 void Game::Init()
     95 {
     96     [...]
     97     glm::vec2 ballPos = playerPos + glm::vec2(PLAYER_SIZE.x / 2.0f - BALL_RADIUS, 
     98                                               -BALL_RADIUS * 2.0f);
     99     Ball = new BallObject(ballPos, BALL_RADIUS, INITIAL_BALL_VELOCITY,
    100         ResourceManager::GetTexture("face"));
    101 }
    102 </code></pre>
    103 
    104 <p>
    105   Then we have to update the position of the ball each frame by calling its <fun>Move</fun> function within the game code's <fun>Update</fun> function:
    106 </p>
    107 
    108 <pre><code>
    109 void Game::Update(float dt)
    110 {
    111     Ball->Move(dt, this-&gt;Width);
    112 }  
    113 </code></pre>
    114 
    115 <p>
    116   Furthermore, because the ball is initially stuck to the paddle, we have to give the player the ability to remove it from its stuck position. We select the space key for freeing the ball from the paddle. This means we have to change the <fun>processInput</fun> function a little:
    117 </p> 
    118 
    119 <pre><code>
    120 void Game::ProcessInput(float dt)
    121 {
    122     if (this-&gt;State == GAME_ACTIVE)
    123     {
    124         float velocity = PLAYER_VELOCITY * dt;
    125         // move playerboard
    126         if (this-&gt;Keys[GLFW_KEY_A])
    127         {
    128             if (Player-&gt;Position.x &gt;= 0.0f)
    129             {
    130                 Player-&gt;Position.x -= velocity;
    131                 if (Ball-&gt;Stuck)
    132                     Ball-&gt;Position.x -= velocity;
    133             }
    134         }
    135         if (this-&gt;Keys[GLFW_KEY_D])
    136         {
    137             if (Player-&gt;Position.x &lt;= this-&gt;Width - Player-&gt;Size.x)
    138             {
    139                 Player-&gt;Position.x += velocity;
    140                 if (Ball-&gt;Stuck)
    141                     Ball-&gt;Position.x += velocity;
    142             }
    143         }
    144         if (this-&gt;Keys[GLFW_KEY_SPACE])
    145             Ball-&gt;Stuck = false;
    146     }
    147 }
    148 </code></pre>
    149 
    150 <p>
    151   Here, if the user presses the space bar, the ball's <var>Stuck</var> variable is set to <code>false</code>. Note that we also move the position of the ball alongside the paddle's position whenever the ball is stuck.
    152 </p>
    153 
    154 <p>
    155   Last, we need to render the ball which by now should be fairly obvious:
    156 </p>
    157 
    158 <pre><code>
    159 void Game::Render()
    160 {
    161     if (this->State == GAME_ACTIVE)
    162     {
    163         [...]
    164         Ball->Draw(*Renderer);
    165     }
    166 }  
    167 </code></pre>
    168 
    169 <p>
    170   The result is a ball that follows the paddle and roams freely whenever we press the spacebar. The ball also properly bounces of the left, right, and top edge, but it doesn't yet seem to collide with any of the bricks as we can see:
    171 </p>
    172 
    173 <div class="video paused" onclick="ClickVideo(this)">
    174   <video width="600" height="450" loop>
    175     <source src="/video/in-practice/breakout/no_collisions.mp4" type="video/mp4" />
    176     <img src="/img/in-practice/breakout/no_collisions.png" class="clean"/>
    177   </video>
    178 </div>
    179 
    180 <p>
    181   What we want is to create one or several function(s) that check if the ball object is colliding with any of the bricks in the level and if so, destroy the brick. These so called <def>collision detection</def> functions is what we'll focus on in the <a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Collision-detection" target="_blank">next</a> chapter.
    182 </p>       
    183 
    184     </div>
    185     
    186     <div id="hover">
    187         HI
    188     </div>
    189    <!-- 728x90/320x50 sticky footer -->
    190 <div id="waldo-tag-6196"></div>
    191 
    192    <div id="disqus_thread"></div>
    193 
    194     
    195 
    196 
    197 </div> <!-- container div -->
    198 
    199 
    200 </div> <!-- super container div -->
    201 </body>
    202 </html>