Bounding box ============ Here is the code I have to keep the paddle in:: def keep_paddle_in(): if paddle.x < 0: paddle.x = 0 elif paddle.x + paddle.width > canvas.width: paddle.x = canvas.width - paddle.width def handle_keydown_events(ev): global pause, _id if ev.keyCode == 37: # left arrow paddle.dx = - abs(paddle.dx) paddle.move() keep_paddle_in() if ev.keyCode == 39: # right arrow paddle.dx = abs(paddle.dx) paddle.move() keep_paddle_in() # more code ... I think that the code for ``keep_paddle_in`` is simple enough that I do not need to explain to you how it works. Some observations: #. The function ``keep_paddle_in`` is **much** simpler than ``stay_in_world`` that is used to keep the ball inside. Perhaps there is a lesson there ... let's keep this in mind. #. There is something *not quite right* about having 3 instructions specific to the paddle inside each ``if`` statement for the function ``handle_keydown_events()``. However, since it works, I will leave it as is for now. .. topic:: Your turn Look at the code and consider the above observations. Can you think of a different way of writing the code that could make things better? Bouncing the ball off the paddle -------------------------------- We want the ball to bounce up from the paddle when it hits it. But what do we mean by "hit"? Let's draw some rectangles on the screen so that we can discuss this in details. .. topic:: Draw this Add the following code anywhere (outside of a function) to your game code and run it. Do not start the animation! .. code-block:: py3 ctx.fillStyle = "red" ctx.fillRect(10, 10, 100, 90) ctx.fillStyle = "yellow" ctx.fillRect(120, 20, 120, 110) ctx.fillStyle = "green" ctx.fillRect(200, 210, 130, 140) ctx.fillStyle = "rgba(0, 0, 255, 0.5)" # transparent blue ctx.fillRect(20, 110, 150, 160) ctx.fillStyle = "orange" ctx.fillRect(320, 5, 170, 180) .. note:: In addition so specifying colours by their "name", we can specify them using various formats. Have a look at `this brief 5 "page" introduction ` for more details. So, we have various rectangles on the screen and only two overlap: the yellow one and the transparent blue one. Let's see how we can figure this out from the numerical values. The format for rectangles is ``fillRect(x, y, width, height)``. A rectangle will have its ``x`` coordinate start at ``x`` and end at ``x+width``. Thus, the red rectangle ``x`` cordinate starts at ``10`` and end at ``10 + 100=110``. So, the **maximum** value of the ``x`` coordinate for the red rectangle is ``110``. The **minimum** value of the ``x`` coordinate for the yellow rectangle is ``120``. This minimum value is less than the maximum value for the red rectangle: these two rectangles do not overlap. You can do the same analysis for all ``x`` and ``y`` coordinates of the non-overlapping rectangle: you will always find that the **minimal value** from **one** rectangle (we don't know which one) will be greater than the **maximum value** of the other. Let's look at the overlapping rectangles. The minimum value of the ``x`` coordinate for the yellow rectangle is ``x_min = 120`` and its maximum value is ``x_max = 240``. Similarly, the minimum value of its ``y`` coordinate is ``y_min = 20`` and ``y_max = 130``. For the transparent blue rectangle, we have ``X_min = 20``, ``X_max = 170``, ``Y_min = 110`` and ``Y_max = 270``, where I used upper case ``X`` and ``Y`` to distinguish from the corresponding variables for the yellow rectangle. Notice how we have: ``X_min < x_min < X_max``: the yellow rectangle starts (horizontally) between the beginning and the end of where the transparent blue rectangle starts. We also have ``y_min < Y_min < y_max``: the blue rectangle starts (horizontally) between the beginning and the end of where the yellow rectangle starts. So, as long as one of them starts (either vertically or horizontally) in the range where the other one is present, there is a possibility of overlap. Let's start rewriting this in code:: if (x_min < X_min < x_max) or (X_min < x_min < X_max): print("horizontal overlap exists.") if (y_min < Y_min < y_max) or (Y_min < y_min < Y_max): print("vertical overlap exists.") We can combine the two statements and simply write:: if ( ((x_min < X_min < x_max) or (X_min < x_min < X_max)) and ((y_min < Y_min < y_max) or (Y_min < y_min < Y_max)) ): print("overlap exists.") If we work with objects, we can define an overlap method that returns ``True`` if the object (``self``) overlap with an other as follows:: def overlap(self, other): if ( ((self.x_min < other.x_min < self.x_max) or (other.x_min < self.x_min < other.x_max)) and ((self.y_min < other.y_min < self.y_max) or (other.y_min < self.y_min < other.y_max)) ): return True return False You may find that I have formatted the code a bit strangely, adding extra spaces and putting things on different lines even though they could have been put on the same line. The reason I have done this is that I find it easier to see the pattern which should make it easier to spot any error. Remember from the beginner's tutorial: .. important:: **Rule # 2** Write your computer programs to make them easy for **people** to read and understand.