Table Of Contents

Previous topic

10. Keeping the paddle in

This Page

11. 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:

  1. 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.
  2. 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.

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?

11.1. 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.

Draw this

Add the following code anywhere (outside of a function) to your game code and run it. Do not start the animation!

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.