I am currently programming a Pong game in Python. For this, I am using the Python Turtle module. In the Pong game, the main idea is that there are two paddles (one on the left, one on the right) that hit a ball back and forth between them. This is the current state, which is running without any issues:
main.py:
from day22.game_screen import GameScreen
from day22.paddle import Paddle
game_screen = GameScreen()
screen = game_screen.get_screen()
right_paddle = Paddle((350, 0))
left_paddle = Paddle((-350, 0))
screen.listen()
screen.onkey(key="Up", fun=right_paddle.go_up)
screen.onkey(key="Down", fun=right_paddle.go_down)
screen.onkey(key="w", fun=left_paddle.go_up)
screen.onkey(key="s", fun=left_paddle.go_down)
game_is_on = True
while game_is_on:
screen.update()
screen.exitonclick()
paddle.py:
# some code to handle the initialization of the paddles...
game_screen.py:
from turtle import Screen
class GameScreen:
def __init__(self):
self.screen = Screen()
self.screen.bgcolor("black")
self.screen.setup(width=800, height=600)
self.screen.title("Pong")
self.screen.tracer(0)
def get_screen(self):
return self.screen
I wanted to refactor the code so that the GameScreen class inherits from the Screen class of the Turtle module. This would also make the get_screen()
method redundant. So, I did the following refactoring:
game_screen.py:
from turtle import Screen
class GameScreen(Screen):
def __init__(self):
super().__init__()
self.bgcolor("black")
self.setup(width=800, height=600)
self.title("Pong")
self.tracer(0)
main.py:
from day22.game_screen import GameScreen
from day22.paddle import Paddle
game_screen = GameScreen()
right_paddle = Paddle((350, 0))
left_paddle = Paddle((-350, 0))
game_screen.listen()
game_screen.onkey(key="Up", fun=right_paddle.go_up)
game_screen.onkey(key="Down", fun=right_paddle.go_down)
game_screen.onkey(key="w", fun=left_paddle.go_up)
game_screen.onkey(key="s", fun=left_paddle.go_down)
game_is_on = True
while game_is_on:
game_screen.update()
game_screen.exitonclick()
When I run this code now, I get the following error: TypeError: function() argument 'code' must be code, not str
. Is the reason for the error that the Screen class in the Turtle module is marked as a singleton and therefore cannot be inherited from, or am I making another mistake?
Using this code you can get path to source code
import turtle
print( turtle.__file__ )
And in source code you can see that Screen
is not class
but function
def Screen():
"""Return the singleton screen object.
If none exists at the moment, create a new one and return it,
else return the existing one."""
if Turtle._screen is None:
Turtle._screen = _Screen()
return Turtle._screen
and you can't use function
to create class
You may try to use class turtle._Screen
(not instances Turtle._screen
)
import turtle
class GameScreen(turtle._Screen):
But I don't know if it will work all time because it can have some mess in code - probably nobody expect that someone will try to create own class.
To work without error message I had to assign class to Turtle._screen
(like in function Screen()
)
class GameScreen(turtle._Screen):
def __init__(self):
super().__init__()
turtle.Turtle._screen = self
Full working code with other changes
I use onkeypress
and onkeyrelease
to set True/False
on variables move_up
and move_down
, and function move()
uses it to move turtle. And I run move()
in while game_is_on
.
This way it works better on my computer - because it doesn't have to wait for repeating (pressed) keys by system.
import time
import turtle
#print( turtle.__file__ )
# --- classes ---
class GameScreen(turtle._Screen):
def __init__(self):
super().__init__()
turtle.Turtle._screen = self
self.bgcolor("black")
self.setup(width=800, height=600)
self.title("Pong")
self.tracer(0)
class Paddle(turtle.Turtle):
def __init__(self, screen, pos, key1, key2, color='white'):
super().__init__()
self.screen = screen
self.shape('square')
self.penup()
self.left(90)
self.goto(pos)
self.color(color)
self.move_up = False
self.move_down = False
self.screen.onkeypress( key=key1, fun=lambda:self.set_move_up(True))
self.screen.onkeyrelease(key=key1, fun=lambda:self.set_move_up(False))
self.screen.onkeypress( key=key2, fun=lambda:self.set_move_down(True))
self.screen.onkeyrelease(key=key2, fun=lambda:self.set_move_down(False))
def set_move_up(self, value):
print('[DEBUG] set move up:', value)
self.move_up = value
def set_move_down(self, value):
print('[DEBUG] set move down:', value)
self.move_down = value
def move(self):
print('[DEBUG] move:', self.move_up, self.move_down)
if self.move_up and self.ycor() < 250:
print('[DEBUG] go up')
self.forward(10)
if self.move_down and self.ycor() > -250:
print('[DEBUG] go down')
self.backward(10)
# --- functions ---
def exit_game():
global game_is_on
print('[DEBUG] exit game')
game_is_on = False
# --- main code ---
game_screen = GameScreen()
right_paddle = Paddle(game_screen, ( 350, 0), 'Up', 'Down', 'red')
left_paddle = Paddle(game_screen, (-350, 0), 'w' ,'s', 'green')
game_screen.listen()
game_screen.onkey(key="Escape", fun=exit_game)
game_is_on = True
while game_is_on:
right_paddle.move()
left_paddle.move()
game_screen.update()
time.sleep(0.01) # use less CPU, and run with the same speed on different computers
#print('Click screen to exit')
turtle.color("white")
turtle.write('Click screen to exit', True, align="center", font=('Arial', 20, 'normal'))
game_screen.exitonclick()