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