← Objects with turtles

A Star class

Make a new kind of object with class, set up each one in __init__, and store its values with self.

Game engines are full of classes: one Enemy class, a hundred enemies made from it, each with its own position and health.

A dictionary needed star["speed"]. A class lets you make your own kind of object: class Star describes what every star stores, and Star(100) makes one. Its values read like a turtle's: star.speed.

PredictRead the code and say what it will do before you run anything. A wrong guess is fine: it shows you what to look for.

Predict

stars.py
class Pet:
    def __init__(self, name, legs):
        self.name = name
        self.legs = legs

a = Pet("Rex", 4)
b = Pet("Tweety", 2)
print(a.name, b.legs)

class Pet: describes a new kind of object. __init__ (two underscores each side) runs every time one is made, and self.name = name stores the name in that pet. What does it print?

What does it print?

RunRun it and compare the result with your prediction.

Run

The same game, now with a Star class. Star(-150 + i * 100) makes a star at that x position, and __init__ sets up its turtle, speed and points. In tick, compare star.speed with last lesson's star["speed"].

stars.py
from turtle import *
import random

speed(0)
penup()
goto(0, -180)
left(90)
score = 0

pen = Turtle()
pen.hideturtle()
pen.penup()
pen.goto(-220, 200)

class Star:
    def __init__(self, x):
        self.turtle = Turtle()
        self.turtle.shape("circle")
        self.turtle.color("gold")
        self.turtle.penup()
        self.turtle.goto(x, 200)
        self.turtle.setheading(270)
        self.speed = random.randint(3, 7)
        self.points = 1

stars = []
for i in range(4):
    stars.append(Star(-150 + i * 100))

def show_score():
    pen.clear()
    pen.write("Score: " + str(score), False, "left", ("Arial", 16, "normal"))

def go_left():
    goto(xcor() - 25, ycor())

def go_right():
    goto(xcor() + 25, ycor())

def tick():
    global score
    for star in stars:
        star.turtle.forward(star.speed)
        if star.turtle.distance(xcor(), ycor()) < 25:
            score += star.points
            star.turtle.goto(random.randint(-200, 200), 200)
        if star.turtle.ycor() < -220:
            star.turtle.goto(random.randint(-200, 200), 200)
    show_score()
    ontimer(tick, 50)

onkey(go_left, "Left")
onkey(go_right, "Right")
listen()
show_score()
tick()
mainloop()
Try it yourselfYour edits are saved in this browser.

InvestigateTrace how each line of code connects to what you see.

Investigate

stars.py
from turtle import *
import random

speed(0)
penup()
goto(0, -180)
left(90)
score = 0

pen = Turtle()
pen.hideturtle()
pen.penup()
pen.goto(-220, 200)

class Star:
    def __init__(self, x):
        self.turtle = Turtle()
        self.turtle.shape("circle")
        self.turtle.color("gold")
        self.turtle.penup()
        self.turtle.goto(x, 200)
        self.turtle.setheading(270)
        self.speed = random.randint(3, 7)
        self.points = 1

stars = []
for i in range(4):
    stars.append(Star(-150 + i * 100))

def show_score():
    pen.clear()
    pen.write("Score: " + str(score), False, "left", ("Arial", 16, "normal"))

def go_left():
    goto(xcor() - 25, ycor())

def go_right():
    goto(xcor() + 25, ycor())

def tick():
    global score
    for star in stars:
        star.turtle.forward(star.speed)
        if star.turtle.distance(xcor(), ycor()) < 25:
            score += star.points
            star.turtle.goto(random.randint(-200, 200), 200)
        if star.turtle.ycor() < -220:
            star.turtle.goto(random.randint(-200, 200), 200)
    show_score()
    ontimer(tick, 50)

onkey(go_left, "Left")
onkey(go_right, "Right")
listen()
show_score()
tick()
mainloop()

What each part of the class does.

The word every line inside the class uses.

A value that was never stored in the star.

Match each line with what it does.

class Star:
def __init__(self, x):
self.speed = random.randint(3, 7)
Star(-150 + i * 100)

Inside __init__, what is self?

This stops with AttributeError: 'Star' object has no attribute 'speed'. Click the line that causes it.

ModifyChange the code on purpose and check the result.

Modify

Give __init__ a colour parameter, and pass a colour in where the stars are made.

Need a hint?

Add a colour parameter after x: def init(self, x, colour):

Another hint

Use it with self.turtle.color(colour), and pass a colour where the stars are made: Star(-150 + i * 100, "orange").

Give each star a random 1 to 3 points.

Need a hint?

self.points = 1 gives every star 1 point. Use random.randint(1, 3).

Try it yourselfYour edits are saved in this browser.

Give __init__ a colour parameter and use it.

    Run your program. This ticks when your code does all of the above.

    Give each star a random 1 to 3 points.

      Run your program. This ticks when your code does all of the above.

      MakeBuild something new using what you have learned. Expect a few tries; that is normal.

      Make a Rock class

      Add a Rock class: a grey square that falls, with its own speed. Make a list of two rocks, move them in tick like the stars, and take 3 points off when one touches you.

      Try it yourselfYour edits are saved in this browser.

      Add a Rock class and a list of rocks that cost 3 points when they touch you.

        Run your program. This ticks when your code does all of the above.

        Info

        Where this leads

        The stars and rocks still need the game to move them and check them one line at a time. Next lesson gives the class its own methods, so a star can move itself: star.move().

        In MakeCode Arcade or microStudio, each sprite has an x, a y and a speed. In Python words, what is each sprite?

        For teachers

        Students rebuild the stars game with a Star class, set up each star in __init__, store its values with self, and add a second class for rocks. About 55 minutes.

        Open the teacher guide: answers, solutions, slides and a worksheet.

        Students will be able to

        Before class

        Read the unit primer first. class Star: describes a new kind of object. __init__ (two underscores each side; say "init") runs every time Star(...) makes one, and self is the object being made. self.speed = 5 stores a value in that object; a plain speed = 5 only makes a variable that disappears when __init__ ends, which is the bug task (AttributeError later, when the game asks for s.speed). Values read as star.speed, like a turtle's own commands. No inheritance, getters or class diagrams in this course.

        Running the lesson

        1. Predict: make two cards labelled a and b on the board, and write name and legs on each as __init__ runs.
        2. Run: compare star.speed with last lesson's star["speed"]. Same idea, tidier.
        3. Investigate: self is the hardest word. 'The star being made right now' is enough for now.
        4. Bug task: speed = speed looks like it works. Ask where the value lives after __init__ ends.
        5. Make: the Rock class is the Star class's shape again. Ask what is the same and what differs.

        The hard part (on purpose)

        self: why values need it to stay with each star. Ask them to point to where each value is stored, and whether it has self. in front.

        When students get stuck

        Stretch and support

        Stretch: Give Star a size parameter and use shape() and points so bigger stars are worth more.

        Support: Give students the Rock class already written, and ask them to make the list of rocks and move them in tick.

        Where it leads

        Next lesson adds methods, so a star moves itself (star.move()) and adding a new kind of falling thing is one class. Every game engine is built from classes like these.

        What each step is for

        Now you can
        Next lesson5. Stars that move themselvesGive the Star class methods (move, restart, touches), so the game loop is short and a new kind of falling thing is one class.