Summit Middle School classes for Andrew Busch
Andrew Busch - Summit
  • Home
  • Algebra 1
    • Alg 1B - Last Week
    • Alg1B 14 HW - Intro to Functions
    • Alg 1B 11 - Rational Expressions
    • Alg 1B 12 - Radical Expressions
    • Alg 1B 10 v2.0 - Quadratic Functions >
      • 10b Graphing with Pennies - Desmos Tutorial
      • 10i Snowboard Quadratic - Alg1B
      • 10 Quadratics Project
    • Alg 1B 10 Book - Factoring Quadratics
    • Alg 1B 9 - Exponential Functions
    • Alg 1B 8.5 - Representing Data
    • Alg 1B 13 - Inequalities
    • Alg 1B 8 - Best Fit Lines and Linear Regression
    • Alg 1B 7 - Linearity
  • Geometry
    • Geom Last Week
    • Geom 12 - Probability
    • Geom 11 - Circumference, Area, Volume
    • Geom 10-Circles
    • Geom 9 - Right Triangles and Trigonometry
    • Geom 8 - Similarity
    • Geom 7 - Quadrilaterals and Other Polygons
    • Geom 6 - Relationships Within Triangles
    • Geom 5 - Congruent Trianlges
    • Geom 4 - Transformations
    • Geometry 3.5 - Constructions
    • Geom 3 - Parallel and Perpendicular Lines
    • Geom 2 - Reasoning and Proofs
    • Geom 1 - Basics of Geometry
  • Programming
    • Directions for Sharing Programs with Me
    • Hour of Code
    • Intro to Python >
      • Installing and Using Portable Python
      • Introduction to Programming
      • Interactive Storyteller
      • Sophisticated Calculator
      • Getting Started with Games
      • Word Length Frequency
      • Substitution Cipher
      • Simple Game of Paddleball
      • Animating Many Objects
      • Accelerator
      • Applying Trigonometry
      • GIFs
      • Programmatic Art
      • Battleship
      • Pong
      • CodeCademy.com Suggested Work
      • Python Resources
    • Advanced Python >
      • Python Installation
      • Review of Intro to Programming
      • Objects and Classes >
        • More on Classes: Functions, Methods, Inheritance
        • Quadrilaterals
      • tkinter >
        • Paddle Ball
        • Light Bike
        • Frogger
        • Snake Game
        • Breakout
      • Reading and Writing Files
      • Directories and Importing Modules
      • Raspberry Pi
      • API's
      • Python Puzzles
  • Clubs
  • Graphing Calculator
  • PARCC Practice

A Simple Game of Paddleball

The resources on this page were originally created by Dr. Aaron Bradley of Summit Middle School. I've done some reformatting to add clarity but that is about it. Enjoy!
During this lesson, you will learn several Python tools:
  • How to create a program
  • How to access the properties of objects
  • How to build a game.
Video games are both fun and educational to create, as they involve a significant amount of math and physics.  In this exploration, we create a simple game of racquetball.  In the final version, a ball will fly around the window, bouncing off the sides and top.  The player will control the side-to-side motion of a paddle at the bottom of the window, against which the ball can bounce.  If the paddle is at the wrong place when the ball is at the bottom of the screen, the ball will fly off-screen and then be reset.
Let's get started!


Review: A Moving Ball

1. Create a new module named "paddleball.py."  Let's first review how to create motion.

2. In Getting Started with Games, you learned about the basic usage of the simple graphics (sgfx.py) module, including how to create a new window and how to add a circle to it.

     from sgfx import *
     w = Window(background="black", title="Paddleball")
     ball = w.circle(250, 400, 10, color="yellow")
     w.run()

The default window size is 500x500.  Coordinate (0, 0) is in the lower-left corner, and (500, 500) is in the upper-right corner.  Here, the yellow circle is placed in the center near the top, and the background is black.  Is that what you see?

3. Now let's make the ball move using animation.  We'll use variables vx and vy to hold its horizontal (vx) and vertical (vy) velocity components:

from sgfx import *

w = Window(background="black", title="Paddleball")

# Create the ball.
ball = w.circle(250, 400, 10, color="yellow")

# It initially moves right and downward.
vx = 3
vy = -5

def animate():
    # Move the ball vx units horizontally and vy units vertically.
    w.move(ball, vx, vy)

# Register the function animate as the animation function.
w.animate(animate)
w.run()


4. Notice how all actions (creating the circle, moving it, adding the animation, running the animation) are done with respect to the window w.  The statement w.animate(animate) causes the function animate to be called 20 times per second. Thus, each 1/20 of a second, the ball is moved vx units horizontally and vy units vertically.  These discrete moves occur too fast for the human eye to see, and so we interpret what we see as smooth motion.

Running this program shows that the ball moves off-screen.  We would like it to bounce against the sides of the window.


A Bouncing Ball

1. In Python as an Interactive Storyteller, you first learned about conditional statements, that is, the use of if, elif, and else.  We'll now use conditional statements in a graphical setting to make the ball bounce.  In this section, we will only change the code in the animate function, which currently looks as follows:

def animate():
    # Move the ball vx units horizontally and vy units vertically.
    w.move(ball, vx, vy)

2. First, we need to find out where the ball is.  The sgfx module provides a way to obtain the Cartesian coordinates of a graphical object's upper-left corner and the lower-right corners.  In our case, the graphical object is a circle, which doesn't ordinarily have corners.  But we can picture a bounding square, which does have corners, around it---in geometric terms, an unseen square circumscribing the circle:

def animate():
    # Obtain the upper-left and lower-right corners of the ball's bounding square.
    bulx, buly = w.upperLeft(ball)
    blrx, blry = w.lowerRight(ball)
    # Move the ball vx units horizontally and vy units vertically.
    w.move(ball, vx, vy)


3. I named the variables in a descriptive way: bulx stands for "ball upper-left x-coordinate," and the others are named similarly.  Now that we know the ball's position, we can act on it:
  1. If the ball is too far left, it should switch to moving right.
  2. If the ball is too far right, it should switch to moving left.
  3. If the ball is too high, it should switch to moving down.
  4. If the ball is too low, it should switch to moving up.

We need to encode these conditions mathematically:
  1. too far left: bulx <= 0
  2. too far right: blrx >= 500
  3. too high: buly >= 500
  4. too low: blry <= 0

4. Actually, it's not a good idea to use hard-coded values like 500.  What if we decide to change the size of the window later?  The sgfx module provides the maximum x-coordinate as XMax and y-coordinate as YMax, allowing us to write instead:
  1. too far left: bulx <= 0
  2. too far right: blrx >= w.XMax
  3. too high: buly >= w.YMax
  4. too low: blry <= 0

5. The remaining question is how to change the ball's direction of motion.  Recall that it is moved vx units horizontally and vy units vertically every time that animate is run.  Thus, to change the direction of motion, we only need to change these two variables.  In particular, to "bounce," the value of the appropriate variable should be negated.

Putting these ideas together, we have the following:

def animate():
    # Because the variables vx and vy, created outside of this function,
    # are assigned to by this function, we must "declare" them.
    global vx, vy
    # Obtain the upper-left and lower-right corners of the ball's bounding square.
    bulx, buly = w.upperLeft(ball)
    blrx, blry = w.lowerRight(ball)
    # If the ball is too far left or right, negate its horizontal velocity.
    if bulx <= 0 or blrx >= w.XMax:
        vx = -vx
    # If the ball is too high or low, negate its vertical velocity.
    if buly >= w.YMax or blry <= 0:
        vy = -vy
    # Move the ball vx units horizontally and vy units vertically.
    w.move(ball, vx, vy)


The ball bounces!

Review: Making a User-Controlled Paddle

In Getting Started with Games, you learned how to associate actions with keys. 

1.
Let's put aside the bouncing ball for a moment---open a new module, and save it as "paddle.py." Before looking at the rest of this section, try to write a program that
  • creates a window with a black background;
  • creates a paddle at the bottom of the window, initially centered, modeled with a 50x10 red rectangle;
  • and associates a left movement of the paddle by 5 units with the 'j' key, and a right movement by 5 units with the 'l' key.
You may of course choose different colors, sizes, speeds, or keys.  Also, feel free to look at the previous sections of this exploration and Getting Started with Games.

2. Did you come up with something similar to the following?

     from sgfx import *

     w = Window(background="black", title="Paddle")
     paddle = w.rectangle(225, 10, 275, 0, color="red")

     def left():
         w.move(paddle, -5, 0)
     def right():
         w.move(paddle, 5, 0)

     w.on('j', left)
     w.on('l', right)
     w.run()


Animation + User Control = Game

Now it's time to bring the bouncing ball and the paddle together. 

1.
Copy the necessary code from "paddle.py" to "paddleball.py" so that you have both the bouncing ball and the movable paddle in one window. 

It's not yet a game, but it's getting there.

2. What do we need to do to turn it into a game?  The main idea is to replace the bottom wall, against which the ball is currently bouncing, with the user-controlled paddle.  Only if the paddle is in the right place will the ball bounce. Otherwise, the ball will reset to its original position.

Once again, the main action is in the animate function.  We need to do the following:
  1. Remove the automatic bottom bounce.
  2. Obtain the current upper-left and lower-right coordinates of the paddle.
  3. Make the ball bounce off the paddle if the paddle is in the right location (based on the information obtained in Step 2).  Just as we used "or" for the conditions for bouncing, you will need to use "and" to describe this condition: the ball is to the right of the left side of the paddle and to the left of the right side. 
  4. If the paddle is not in the right location, make the ball go back to its initial position.  For this step, w.moveTo(ball, 250, 400) moves the ball so that it is centered at (250, 400).
Try to make these changes, based on how we obtained information about the ball, before reading on.  I will continue to use a variable naming scheme like the one for the ball, so that pulx will refer to the paddle's upper-left x-coordinate.


For Step 2, did you adapt the code for the ball to the paddle as follows?

     # Obtain the upper-left and lower-right corners of the paddle.
     pulx, puly = w.upperLeft(paddle)
     plrx, plry = w.lowerRight(paddle)


For Steps 3 and 4, you could use a conditional structure as follows:

     # If the ball is too low...
     if blry <= 10:
   
     # ... and the paddle is in the right place...
     if [your code here]:
        # ... then the ball bounces.
        vy = -vy
     else:
        # Otherwise, it resets.
       w.moveTo(ball, 250, 500)



Dr. Bradley's full implementation of animate is at the bottom of the page. You may check it if you are stuck.  Yours may differ and still be functional.

Extensions
  1. We made the conditions for bouncing use w.XMax and w.YMax, but the placements of the ball and the paddle are based on a 500x500 window.  Fix this problem so that the game will still work if the window's dimensions are changed.  For example, w = Window(width=700, height=700) creates a larger window.
  2. The ball only bounces if it is completely over the paddle, whereas it would be better if it bounced when at least half of it were over the paddle.  Make this change.  You may want to use w.center(ball), which returns the coordinates of the ball's center.
  3. Games are more fun with randomness.  Recall the use of the random module in Exploration: Substitution Cipher.  Read aboutrandom.randint(lower, upper) here.  Use the random number generator to set (and reset) the ball's velocity randomly.
  4. Implement vertical motion, so that the ball bounces in a parabolic fashion.
  5. Implement an energy function so that the ball loses energy with each bounce but gains energy based on how closely to the bounce that the player hits some button.
  6. Add interior walls.
  7. Implement levels so that, for example, the ball gains speed over time or (if you implemented idea 6) the interior walls change.
  8. Implement multiple balls.

Animate hint:
def animate():
    # Because the variables vx and vy, created outside of this function,
    # are assigned to by this function, we must "declare" them.
    global vx, vy
    # Obtain the upper-left and lower-right corners of the ball's bounding square.
    bulx, buly = w.upperLeft(ball)
    blrx, blry = w.lowerRight(ball)
    # If the ball is too far left or right, negate its horizontal velocity.
    if bulx <= 0 or blrx >= w.XMax:
        vx = -vx
    # If the ball is too high (ONLY too high), negate its vertical velocity.
    if buly >= w.YMax:
        vy = -vy
    # Obtain the upper-left and lower-right corners of the paddle.
    pulx, puly = w.upperLeft(paddle)
    plrx, plry = w.lowerRight(paddle)
    # If the ball is too low...
    if blry <= 10:
        # ... and the paddle is in the right place...
        if bulx >= pulx and blrx <= plrx:
            # ... then the ball bounces.
            vy = -vy
        else:
            # Otherwise, it resets.
            w.moveTo(ball, 250, 400)
    # Move the ball vx units horizontally and vy units vertically.
    w.move(ball, vx, vy)

Powered by Create your own unique website with customizable templates.