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.
Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.
Predict and Run 10 min · Investigate 15 min · Modify 10 min · Make 20 min
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.
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.
| What you will see | A question to ask | The fix |
|---|---|---|
| AttributeError: 'Star' object has no attribute ... | Was the value stored with self. in front, inside __init__? | self.speed = ..., not speed = .... |
| TypeError: __init__() missing 1 required positional argument. | How many values does __init__ need, and how many does Star(...) pass? | Pass one value for every parameter after self. |
| NameError: name 'self' is not defined. | Is the line inside a method of the class (indented under def)? | Use self only inside the class's methods; outside, use the object's name (star.speed). |
One possible solution for each task. Other correct programs are fine.
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, colour):
self.turtle = Turtle()
self.turtle.shape("circle")
self.turtle.color(colour)
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, "orange"))
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()
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 = random.randint(1, 3)
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()
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))
class Rock:
def __init__(self, x):
self.turtle = Turtle()
self.turtle.shape("square")
self.turtle.color("gray")
self.turtle.penup()
self.turtle.goto(x, 200)
self.turtle.setheading(270)
self.speed = random.randint(4, 8)
rocks = []
for i in range(2):
rocks.append(Rock(-100 + i * 200))
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)
for rock in rocks:
rock.turtle.forward(rock.speed)
if rock.turtle.distance(xcor(), ycor()) < 25:
score -= 3
rock.turtle.goto(random.randint(-200, 200), 200)
if rock.turtle.ycor() < -220:
rock.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()
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.
class Dog: def __init__(self, name): self.name = name. d = Dog("Rex"). What is d.name?
"Rex": __init__ stored it in d with self.name = name.
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.