Code Toolkit: Python, Fall 2025

Week 7 — Wednesday, October 8 — Class notes

  1. Review of Week 7: Timing, state & functions
  2. Review questions
    1. Adding text
    2. Implementing a moving object
    3. Implementing many moving objects
    4. Moving raster images
    5. Functions with arguments and return values
  3. That's it!

I. Review of Week 7: Timing, state & functions

We started today by reviewing the Week 7 class notes, in particular, we did a quick review of timing with millis(), then we discussed using state variables as a way to keep track of the phase or situation that your code is in, and finally we discussed using functions as a technique for organizing larger projects by increasing modularity and reusability.

One quick comment about this review. During our conversation I made a syntax mistake. I accidentally wrote that you could do something like this to toggle a Boolean variable value:

def keyPressed():
    global switchState
    if key == 'n':
        # Warning: this is wrong!
        switchState = ! switchState
The exclamation point is used as the symbol for the logical inverse operator in many programming languages, including Java and JavaScript. I got mixed up today and used this symbol. In Python, the logical inverse operator is not. So the proper way to write this in Python would be like this:
def keyPressed():
    global switchState
    if key == 'n':
        switchState = not switchState
Sorry for any confusion!

(jump back up to table of contents)

II. Review questions

For the rest of class I fielded review questions about topics from throughout the semester, mainly focused on questions people had about completing their midterm projects.

(jump back up to table of contents)

a. Adding text

This example illustrates all the basic principles of working with text in Python / Processing:

size(800,800)
background(0)

arialblack = loadFont("Arial-Black-48.vlw")
arial24 = createFont("Arial", 24)
georgia16 = createFont("Georgia", 128)

score = 42

textFont(arialblack)
fill(255,0,0)
textSize(128)
text("Hello", 100, 300)

textFont(arial24)
fill(0,255,255)
textSize(32)
text("Friends", 100, 350)

textFont(georgia16)
fill(0,255,255)
textSize(32)
text("Your score: "+str(score), 100, 450)

All the new commands here are documented in the Python Processing reference, in the Typography section.

You actually draw text to the screen with the text() command, which you can see illustrated on lines 13, 18, and 23. You can see that this command takes a string of text that you want to display (i.e., characters in between double-quotes, " "), and two arguments that correspond to the x and y location of this text on the screen.

If you want to render dynamic text onto the screen, use the str() variable to convert a variable value into a string, and concatenate two string values together using +. You can see this in action on line 23, which assumes that I have a variable called score, which has some numeric value. (In this case created on line 8.)

You can control what font to use to render this text by first creating or loading the font that you plan to work with. There are two ways to do this in Processing, illustrated on lines 4-6. Line 4 loads a predefined .vlw file which has to have been created already and saved into your sketch folder. You can create this file from the PDE menu by going to "Tools" > "Create Font...", specifying the font face and size you want, and clicking "OK".

If you would prefer, you can create the font dynamically at runtime using the createFont() command, as illustrated on lines 5 & 6. In this way, you can create the font when the program starts running, without having to create the .vlw file in advance. You specify the font face (which has to exist on your machine, exactly as typed here) and the size. I'm guessing there might be some performance cost to doing it this way because Processing has to create the font while your code is running. I am assuming you would not notice a different unless you were creating many fonts.

In either case, you either load or create the font, and assign it to a variable. Similar to the process of calling loadImage() and saving that image to a variable which you can then draw later. In this case, you can use any of these font variables later on when you are trying to write text.

You specify which font to use with the textFont() command, as you can see on lines 10, 15, and 20. This command works similarly to other commands that control how later things are drawn, like fill(), which I have also included here to show how they are similar. textFont() specifies the font that will be used to render any text that comes after with the text() command, and that will be the "active" font until you change it with another call to textFont().

You can see that I am also using textSize(). That specifies the size of the text that you are going to write. Ideally, this value should probably be the same as the value you used when you created or loaded the font. If you use a different value, you may get some digital distortion, as you can see this in action on line 4 in which I have created a font with size 48, and on lines 12 and 13 in which I am then using that font to draw text with size 128, giving some blurriness in the draw window. (If I change textSize() to 48, or if I create a new .vlw file with size 128, then this distortion goes away.)

Thanks, Brandon, for the question!

(jump back up to table of contents)

b. Implementing a moving object

Next we looked at how you can have the user initiate a projectile that flies across the screen. For discussion, we imagined this was a game like an arcade basketball throw, in which the player has a container with some number of balls that they can pick up and throw. The balls roll back down to the container and they can pick them up and throw again. We started out with just one ball. (Thanks, Bibi, for this question!)

My sample code is here:

x = -10
y = 400
speed = 0

def setup():
    size(800,800)

def draw():
    global x, speed
    background(255)

    fill(0)
    ellipse(x,y, 10,10)

    x = x + speed
    if x > width:
        x = -10
        speed = 0

def mousePressed():
    global x, y, speed
    if x < 0:
        x = 0
        y = mouseY
        speed = 10

Lines 12 and 13 draw the ball at some x, y location. Then line 15 moves the ball with our basic "x = x + 1" pattern to increment a variable.

Lines 1 and 2 set the initial values of the ball location. Note that initially the x value is -10. This is so that the ball does not appear anywhere on the screen before the user throws it. Also, speed is set to 0 so that initially the ball is not moving.

After moving the ball on line 15, we use an if statement to check if the ball has moved off to the right of the screen, and if so, we reset its position back offscreen with -10 and set its speed back to 0.

Now for the user to initiate the throw, we use a def mousePressed block. In this event handling block, we want to set the xposition of the ball to 0, so it is now visible on the left of the screen, and set the speed to 10 so the ball moves across the screen. (We also decided that we would set the y value of the ball to be wherever the mouse was when the user clicked.) But! we put these three lines in an if statement block that checks if the x value of the ball is less than zero, because we only want the user to be able to throw the ball if its position has been reset back to -10, i.e. in our game concept, if the basketball has rolled back down and is in the container again.

(jump back up to table of contents)

c. Implementing many moving objects

After finishing the above example I showed how you might implement this same interactive example but with multiple balls. That code looks like this:

x = []
y = []
speed = []

num_balls = 3

current_ball = 0

def setup():
    size(800,800)
    
    i = 0
    while i < num_balls:
        x.append(-10)
        y.append(400)
        speed.append(0)
        i = i + 1

def draw():
    background(255)

    i = 0
    while i < num_balls:
        # draw each one:
        fill(0)
        ellipse( x[i],y[i], 10,10)

        # move each one:
        x[i] = x[i] + speed[i]
        
        # check each one:
        if x[i] > width:
            x[i] = -10
            speed[i] = 0

        i = i + 1

def mousePressed():
    global current_ball
    if x[current_ball] < 0:
        x[current_ball] = 0
        y[current_ball] = mouseY
        speed[current_ball] = 10
        current_ball = ( current_ball + 1 ) % num_balls

Notice now on lines 1 - 3 that the variables x, y, and speed are all lists.

I am using the variable num_balls to specify how many balls we are allowing the player to throw.

Then, in setup() on lines 12-17, we are looping over the number of balls, and using append() to add a value to each list for each ball — so an x value, a y value, and a speed value for each ball.

Next, in draw() I have a loop with the same values (starting at i = 0, running while i < num_balls, and incrementing by 1). Each iteration, we are doing the same actions as in the single-ball example, except that now we are using [i], and taking those actions once per ball. So for each ball, we are drawing it (lines 25-26), moving it (line 29), and checking if it has gone off the screen (lines 32-34).

Finally, in def mousePressed(), we are doing the same thing. Repeating the code from the single-ball example, but now operating on list values instead of single-valued variables. But wait! Which list item do we want to operate on here? We are not in a loop, because this is where the user throws a ball. So we only want to manipulate one. Which one should it be? For this, I have added a new variable called current_ball. This will keep track of the next ball that the user is going to throw. Notice that on line 7 I initially set this to 0. Now, in the mousePressed block, I'm going to use that as the index of my lists. So that the first time the user throws a ball, we manipulate all the first values of our three lists (i.e., the 0 indexed values). Then, at the end of def mousePressed, we increment this variable, so that the next time the user presses the mouse, we will manipulate the next ball values in our lists.

But wait again! There is one more issue here. If we keep incrementing this variable, eventually current_ball will become greater than num_balls and we will get an IndexError. The solution? Make sure that after you increment current_ball, you check to reset it to 0 if it has gotten too large. You could do that like this:

current_ball = current_ball + 1
if current_ball > num_balls:
    current_ball = 0
or, more concisely, you could write that like this:
    current_ball = ( current_ball + 1 ) % num_balls
For a refresher of the modulo operator, refer back to the Week 5 class notes, the review of that during Week 6, or another example using this from Week 6 on lists.

(jump back up to table of contents)

d. Moving raster images

Sarah asked how we can draw raster images and have them move around. Here is a code snippet to do that, presented without comment:

imgX = 100

def setup():
    global img
    size(800,800)
    img = loadImage( ... )

def draw():
    global imgX

    image(img,imgX,400)
    
    imgX = imgX + 1
    
    if imgX > width:
        imgX = 0
Thanks, Sarah, for asking!

(jump back up to table of contents)

e. Functions with arguments and return values

We also talked about how you can use functions with arguments and return values. I will share another code snippet without comment, because we didn't have time to talk about this in class today, but if you are curious about any of this code, please don't hesitate to ask! I would be happy to explain.

def setup():
    size(600,600)

def draw():
    my_function(5)
    my_function(7)
    
    print("The midpoint is: ", midpoint(10,20) )

def my_function(n):
    rect(n,10,10,10)

def midpoint(x,y):
    m = ( x + y ) / 2
    return m
Thanks, Lizzy, for asking about this! I wish we'd had time to get to it.

(jump back up to table of contents)

IV. That's it!

That's all, everyone. Good luck on the midterm! If you have any questions, don't hesitate to ask.