Search code examples
pythonmergepygamepython-modulepygame-surface

How can I set conditions for an inputting textbox module on pygame?


I'm a beginner in python and am currently using pygame. I'm making a game which requires user input. I have an algorithm called "Typing_Questions" and it has conditions on what the score and lives for the user are if they make mistakes. This algorithm runs correctly. It runs the script on the bottom of pygame so it doesn't load a separate screen.

Typing_Questions:

Score = 0
Lives = 3
Question_4 = "Code print"
Answer = "print"
print(T_Question_4)
user_input = input("Enter: ")

if user_input == Answer:
   Lives = Lives
   Score = Score + 1
   print(Lives)
   print(Score)
   print("Well Done!")

while user_input != Answer:
   user_input = input()
   if user_input == Answer:
       Lives = Lives
       Score = Score + 1
       print(Lives)
       print(Score)
       print("Well Done!")
   else:
       Lives = Lives - 1
       Score = Score - 1
       print(Lives)
       if Score == -1:
          Score = 0
          print(Score)
       if Lives == 0:
          print("Game Over")
          quit()
       else:
          print("Try again.")
          print(T_Question_4)

I also have an algorithm for the input text box. This lets me type anything and loads a separate screen. This also works correctly.

Textbox:

import pygame as pg
def main():
    screen = pg.display.set_mode((1275, 775))
    font = pg.font.Font(None, 32)
    clock = pg.time.Clock()
    input_box = pg.Rect(400, 300, 142, 32)
    color_inactive = pg.Color('lighskyblue3')
    color_active = pg.Color('dodgerblue2')
    color = color_inactive
    active = False
    text = ''
    done = False

   while not done:
      for event in pg.event.get():
          if event.type == pg.QUIT:
             done = True
          if event.type == pg.MOUSEBUTTONDOWN:
             if input_box.collidepoint(event.pos):
                 active = not active
             else:
                 active = False
             color = color_active if active else color_inactive
          if event.type == pg.KEYDOWN:
             if active:
                if event.key == pg.K_RETURN:
                   print(text)
                   text = ''
                elif event.key == pg.K_BACKSPACE:
                   text = text[:-1]
                else:
                   text += event.unicode

       screen.fill(250, 250, 250)
       txt_surface = font.render(text, True, color)
       width = max(200, txt_surface.get_width()+10)
       input_box.w = width
       screen.blit(txt_surface, (input_box.x + 5, input_box.y + 5))
       pg.draw.rect(screen, color, input_box, 2)

       pg.display.flip()
       clock.tick(30)

if __name__ == '__main__':
   pg.init()
   main()
   pg.quit()

My aim is to merge these two modules together. I tried importing the other into one's module but only the Typing_Questions will run and the screen won't load for the textbox module and vice versa.

I want the textbox screen to display so the user can enter their answer from there. When they answer it in the box, I want the program to follow the script from the Typing_Questions algorithm (so it will only accept the answer or it will decrease a life or end the program if necessary).

Is there a way to do this? Thank you.


Solution

  • Use the example in the answer to How to create a text input box with pygame? ss the basis for your application. The example contains a complete class that implements a text input box.
    You have to implement an application loop. For more information on implementing an application loop, see the answer to Why is my PyGame application not running at all?.

    The typical PyGame application loop has to:

    Make a list of questions and a list of answers to the questions. Specify variables for the score, lives and current_question. For instance:

    questions = ["question 1", "question 2", "question 3"]
    answer = ["answer 1", "answer 2", "answer 3"]
    current_question = 0 
    lives = 3
    score = 0
    

    Use the application loop to get input from the text entry field. Evaluate the result and change the variables for score, lives and current_question accordingly:

    while run:
        # [...]`
    
        if lives > 0 and current_question < len(questions): 
            group.update(event_list)
            if not text_input_box.active:
                if text_input_box.text == answer[current_question]:
                    score += 1
                    current_question += 1
                else:
                    lives -= 1
                text_input_box.reset()
    

    See Python display text with font & color? and generate text output. For input:

    game_over_surf = font100.render("Game Over", True, (255, 255, 255))
    window.blit(game_over_surf, game_over_surf.get_rect(center = window.get_rect().center))
    

    Complete example:

    import pygame
    
    class TextInputBox(pygame.sprite.Sprite):
        def __init__(self, x, y, w, font):
            super().__init__()
            self.color = (255, 255, 255)
            self.backcolor = None
            self.pos = (x, y) 
            self.width = w
            self.font = font
            self.active = True
            self.text = ""
            self.render_text()
    
        def render_text(self):
            t_surf = self.font.render(self.text, True, self.color, self.backcolor)
            self.image = pygame.Surface((max(self.width, t_surf.get_width()+10), t_surf.get_height()+10), pygame.SRCALPHA)
            if self.backcolor:
                self.image.fill(self.backcolor)
            self.image.blit(t_surf, (5, 5))
            pygame.draw.rect(self.image, self.color, self.image.get_rect().inflate(-2, -2), 2)
            self.rect = self.image.get_rect(topleft = self.pos)
    
        def reset(self):
            self.text = ""
            self.active = True
            self.render_text()
    
        def update(self, event_list):
            for event in event_list:
                if event.type == pygame.KEYDOWN and self.active:
                    if event.key == pygame.K_RETURN:
                        self.active = False
                    elif event.key == pygame.K_BACKSPACE:
                        self.text = self.text[:-1]
                    else:
                        self.text += event.unicode
                    self.render_text()
    
    questions = ["question 1", "question 2", "question 3"]
    answer = ["answer 1", "answer 2", "answer 3"]
    current_question = 0 
    lives = 3
    score = 0
    
    pygame.init()
    window = pygame.display.set_mode((500, 500))
    clock = pygame.time.Clock()
    font100 = pygame.font.SysFont(None, 100)
    font50 = pygame.font.SysFont(None, 50)
    
    text_input_box = TextInputBox(20, 170, 460, font100)
    group = pygame.sprite.Group(text_input_box)
    
    run = True
    while run:
        clock.tick(60)
        event_list = pygame.event.get()
        for event in event_list:
            if event.type == pygame.QUIT:
                run = False
    
        if lives > 0 and current_question < len(questions): 
            group.update(event_list)
            if not text_input_box.active:
                if text_input_box.text == answer[current_question]:
                    score += 1
                    current_question += 1
                else:
                    lives -= 1
                text_input_box.reset()
    
        window.fill(0)
        
        if lives == 0:
            game_over_surf = font100.render("Game Over", True, (255, 255, 255))
            window.blit(game_over_surf, game_over_surf.get_rect(center = window.get_rect().center))
        elif current_question < len(questions): 
            question_surf = font100.render(questions[current_question], True, (255, 255, 255))
            window.blit(question_surf, (20, 50))
            group.draw(window)
        else:
            well_done_surf = font100.render("Well Done!", True, (255, 255, 255))
            window.blit(well_done_surf, well_done_surf.get_rect(center = window.get_rect().center))
    
        score_surf = font50.render("score: " + str(score), True, (255, 255, 255))
        window.blit(score_surf, (20, 400))
        lives_surf = font50.render("lives: " + str(lives), True, (255, 255, 255))
        window.blit(lives_surf, (300, 400))
    
        pygame.display.flip()
    
    pygame.quit()
    exit()