Typing Tutor Game
Animation
The typical computer screen is constantly refreshing at about 60 hertz. And for an object that moves that, quickly, our human eye can't catch the image to recognise it.
So we need to slow down our game refresh rate by using the pygame.time.Clock()
Frame rate
For games, we want to control our fps (frame rate per second), which is how often we update the display:
class GamePlay():
def __init__(self, screen):
self.screen = screen
pygame.init()
self.disp_surf = pygame.Surface(self.screen.get_size()).convert()
self.width, self.height = screen.get_size()
self.font = pygame.font.Font('Consolas Bold.ttf', 16)
self.playing = True
self.game_objects = GameObjects(self.width, self.height)
self.key_hit = None
self.last_add = 0 # time of adding word
self.add_timeout = 2000 # 2 seconds
self.fps = 25
self.fps_clock = pygame.time.Clock()
And call the clock tick in our loop, to set delay:
def execute(self):
while self.playing:
self.check_events()
self.loop()
self.render()
self.fps_clock.tick(self.fps)
return
Move words downwards
To move the words down, we just need to adjust the y coordinate of the word. So let's add move methods to all game objects:
# word.py
def move(self, delta):
self._y += delta
return
# objects.py
def move(self, delta):
for word in self.game_words:
word.move(delta)
And initialise a y_delta at GamePlay() and move it on game loop():
class GamePlay():
def __init__(self, screen):
self.screen = screen
pygame.init()
self.disp_surf = pygame.Surface(self.screen.get_size()).convert()
self.width, self.height = screen.get_size()
self.font = pygame.font.Font('Consolas Bold.ttf', 16)
self.playing = True
self.game_objects = GameObjects(self.width, self.height)
self.key_hit = None
self.last_add = 0 # time of adding word
self.add_timeout = 2000 # 2 seconds
self.fps = 25
self.fps_clock = pygame.time.Clock()
self.y_delta = 1
.
.
.
def loop(self):
'''Game play loop'''
self.check_key_hit()
self.game_objects.move(self.y_delta)
self.add_word()
return
Boundary
Fairly simply, our next step is to move the words down the screen. Once we have fixed the x coordinate of the word, we just need to change the Y coordinate until it hits the bottom of the screen, which we can fixed at 40 pixels from bottom of screen.
Let us set this as bound_y in our objects.py :
class GameObjects:
def __init__(self, screen_width, screen_height):
self.screen_width = screen_width
self.screen_height = screen_height
self.word_list = self.init_words()
self.game_words = []
self.bound_y = screen_height - 40
And to remove the words, once it hits the boundary. We cannot remove the words within the loop, so we have to have a way to set it for removal.
We will use a flag to indicate this:
# word.py
# Dimensions
STARTY = 20
class Word:
def __init__(self, word, x):
self.text = word
self._len = len(self.text)
self._x = x
self._y = STARTY
self.typed_idx = -1 # index of typed characters '-2' to remove
And a set_remove()
method to set the flag:
# word.py
def set_remove(self):
'''Set flag to be removed'''
self.typed_idx = -2
return
And a clean_up
method to remove words with negative flagged typed_idx
, in objects.py :
# objects.py
def clean_up (self):
'''Check and remove any word in game that is flagged to be removed.'''
if not self.game_words:
return
# Remove words from game_words with word.typed_idx == -2
self.game_words = [w for w in self.game_words if w.typed_idx != -2]
return
And now we just need to add a check of the y coordinate for each word:
# objects
def move(self, delta):
removed = False
for word in self.game_words:
word.move(delta)
if word.get_y() >= self.bound_y:
word.set_remove()
removed = True
self.clean_up()
return removed