Give the Star class methods (move, restart, touches), so the game loop is short and a new kind of falling thing is one class.
In a game engine you never move every enemy by hand: you tell each enemy to update itself, and it knows how.
The game still moved and checked each star itself. A method is a function inside a class: star.move() asks a star to move itself. The game loop shrinks to a few lines, and the star's rules live with the star.
Make your prediction first. Help opens once you've locked it in.
class Counter:
def __init__(self):
self.count = 0
def add(self, n):
self.count = self.count + n
c = Counter()
c.add(2)
c.add(5)
print(c.count)
def add(self, n): inside the class is a method. c.add(2) runs it for c: self is c and n is 2. What does it print?
What number does it print?
The same game, now with methods: move, restart and touches. Read tick first: it only asks each star to move, and asks whether it touches you.
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
def move(self):
self.turtle.forward(self.speed)
if self.turtle.ycor() < -220:
self.restart()
def restart(self):
self.turtle.goto(random.randint(-200, 200), 200)
def touches(self, x, y):
return self.turtle.distance(x, y) < 25
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.move()
if star.touches(xcor(), ycor()):
score += star.points
star.restart()
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
def move(self):
self.turtle.forward(self.speed)
if self.turtle.ycor() < -220:
self.restart()
def restart(self):
self.turtle.goto(random.randint(-200, 200), 200)
def touches(self, x, y):
return self.turtle.distance(x, y) < 25
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.move()
if star.touches(xcor(), ycor()):
score += star.points
star.restart()
show_score()
ontimer(tick, 50)
onkey(go_left, "Left")
onkey(go_right, "Right")
listen()
show_score()
tick()
mainloop()
What each method call does.
A change to how every star behaves.
A method that forgot something.
Match each call with what it does.
This stops with TypeError: faster() takes 0 positional arguments but 1 was given. Click the line that causes it.
Add a method flash that turns a star orange, and call it when a star is caught.
Add def flash(self): inside the class, with self.turtle.color("orange") in it.
Call star.flash() in tick, where a star is caught.
Add a method level_up that makes a caught star worth one more point and a little faster.
A method can change the star's own values: self.points += 1 and self.speed += 1.
Call it when a star is caught.
Add a flash method that turns a star orange, and call it when the star is caught.
Run your program. This ticks when your code does all of the above.
Add a level_up method that makes a caught star worth more and faster.
Run your program. This ticks when your code does all of the above.
Add a Rock class with the same three methods as Star (move, restart, touches). Make two rocks, and in tick ask each rock to move and to check whether it touches you. A rock costs 3 points. How many lines in tick did the rocks need?
Add a Rock class with move, restart and touches methods, and two rocks that cost 3 points.
Run your program. This ticks when your code does all of the above.
You started with 11 lines per star. Now a star is one line, Star(x), and each kind of thing knows how to move itself. Game engines such as microStudio and MakeCode Arcade work this way: sprites are objects, and you write how they behave.
Students give the Star class methods (move, restart, touches), so the game loop asks each star to act, then add methods of their own and a Rock class with the same method names. About 55 minutes.
Open the teacher guide: answers, solutions, slides and a worksheet.
Read the unit primer first. A method is a function inside a class; its first parameter is self, the object it was called on. star.move() runs move with self as that star, which is why a method without self (the bug task) stops with "takes 0 positional arguments but 1 was given". Methods can call each other (self.restart()) and change the object's own values (self.points += 1). The Make task gives Rock the same method names as Star, so tick treats both the same way. That is the idea behind game engines, without the word polymorphism.
Remembering self in a method's def and inside it. Let the TypeError happen, then ask what Python hands to a method first.
Stretch: Add a Heart class that gives back a life, and a lives counter that ends the game at 0.
Support: Give students the Rock class with __init__ and move written, and ask them to add restart and touches by copying Star's.
This completes the course. microStudio's sprites and MakeCode Arcade's sprites are objects with their own values and behaviour. Apps with Gradio and Data detective use objects too (a Question class, a row of data).