Spaces:
Runtime error
Runtime error
| import pygame | |
| import sys | |
| from levels import * | |
| class Game: | |
| def __init__(self, screen): | |
| self.screen = screen | |
| self.clock = pygame.time.Clock() | |
| # Load fonts - try to use more playful fonts if available | |
| try: | |
| self.font = pygame.font.SysFont('Comic Sans MS', 32) | |
| self.small_font = pygame.font.SysFont('Comic Sans MS', 24) | |
| self.title_font = pygame.font.SysFont('Comic Sans MS', 48) | |
| except: | |
| self.font = pygame.font.SysFont('Arial', 32) | |
| self.small_font = pygame.font.SysFont('Arial', 24) | |
| self.title_font = pygame.font.SysFont('Arial', 48) | |
| # Enhanced color palette | |
| self.WHITE = (255, 255, 255) | |
| self.BLACK = (0, 0, 0) | |
| self.GREEN = (76, 175, 80) | |
| self.RED = (244, 67, 54) | |
| self.BLUE = (33, 150, 243) | |
| self.PURPLE = (156, 39, 176) | |
| self.BACKGROUND_TOP = (179, 229, 252) # Light blue | |
| self.BACKGROUND_BOTTOM = (255, 255, 255) | |
| self.GOLD = (255, 193, 7) | |
| # Game state | |
| self.current_grade = 1 | |
| self.score = 0 | |
| self.lives = 3 | |
| self.answer_input = "" | |
| self.feedback = "" | |
| self.feedback_color = self.BLACK | |
| self.feedback_scale = 1.0 # For animation | |
| # Load heart image for lives or create a heart shape | |
| self.heart_points = [ | |
| (0, -4), (2, -2), (4, -4), (4, -2), (2, 4), (0, 2), | |
| (-2, 4), (-4, -2), (-4, -4), (-2, -2) | |
| ] | |
| self.heart_points = [(x * 3 + 20, y * 3 + 80) for x, y in self.heart_points] | |
| # Initialize first problem | |
| self.new_problem() | |
| def new_problem(self): | |
| """Generate a new math problem based on current grade""" | |
| self.problem = generate_problem(self.current_grade) | |
| self.answer_input = "" | |
| self.feedback = "" | |
| def handle_events(self): | |
| """Handle user input events""" | |
| for event in pygame.event.get(): | |
| if event.type == pygame.QUIT: | |
| pygame.quit() | |
| sys.exit() | |
| if event.type == pygame.KEYDOWN: | |
| if event.key == pygame.K_RETURN and self.answer_input: | |
| self.check_answer() | |
| elif event.key == pygame.K_BACKSPACE: | |
| self.answer_input = self.answer_input[:-1] | |
| elif event.unicode.isnumeric() or event.unicode == '-': | |
| self.answer_input += event.unicode | |
| def check_answer(self): | |
| """Check if the provided answer is correct""" | |
| try: | |
| user_answer = int(self.answer_input) | |
| if user_answer == self.problem.answer: | |
| self.score += 10 * self.current_grade | |
| self.feedback = "Correct!" | |
| self.feedback_color = self.GREEN | |
| self.feedback_scale = 1.5 # Start larger for "pop" effect | |
| # Increase grade if score threshold reached | |
| if self.score >= self.current_grade * 100 and self.current_grade < 5: | |
| self.current_grade += 1 | |
| self.feedback = f"Level Up! Now at Grade {self.current_grade}" | |
| self.feedback_color = self.GOLD | |
| self.feedback_scale = 2.0 # Even bigger for level up | |
| else: | |
| self.lives -= 1 | |
| self.feedback = "Wrong answer!" | |
| self.feedback_color = self.RED | |
| self.feedback_scale = 1.3 # Slightly larger for wrong answer | |
| if self.lives <= 0: | |
| self.game_over() | |
| # Draw one frame with the current feedback | |
| self.draw() | |
| pygame.display.flip() | |
| pygame.time.wait(500) # Show feedback for half a second | |
| self.new_problem() | |
| except ValueError: | |
| self.feedback = "Please enter a valid number" | |
| self.feedback_color = self.RED | |
| self.feedback_scale = 1.2 | |
| def game_over(self): | |
| """Handle game over state""" | |
| waiting = True | |
| alpha = 0 | |
| fade_surface = pygame.Surface((self.screen.get_width(), self.screen.get_height())) | |
| fade_surface.fill(self.BLACK) | |
| while alpha < 128: # Fade to semi-transparent black | |
| self.draw() # Draw the game screen underneath | |
| fade_surface.set_alpha(alpha) | |
| self.screen.blit(fade_surface, (0, 0)) | |
| pygame.display.flip() | |
| alpha += 2 | |
| pygame.time.wait(5) | |
| # Create game over panel | |
| panel_width = 400 | |
| panel_height = 300 | |
| panel_x = (self.screen.get_width() - panel_width) // 2 | |
| panel_y = (self.screen.get_height() - panel_height) // 2 | |
| while waiting: | |
| # Draw the base game screen and fade overlay | |
| self.draw() | |
| fade_surface.set_alpha(128) | |
| self.screen.blit(fade_surface, (0, 0)) | |
| # Draw game over panel | |
| pygame.draw.rect(self.screen, self.WHITE, | |
| (panel_x, panel_y, panel_width, panel_height)) | |
| pygame.draw.rect(self.screen, self.BLUE, | |
| (panel_x, panel_y, panel_width, panel_height), 4) | |
| # Draw game over text | |
| game_over_text = self.title_font.render("Game Over!", True, self.RED) | |
| score_text = self.font.render(f"Final Score: {self.score}", True, self.BLACK) | |
| grade_text = self.font.render(f"Reached Grade: {self.current_grade}", True, self.BLUE) | |
| restart_text = self.small_font.render("Press R to restart or Q to quit", True, self.PURPLE) | |
| # Center all text in the panel | |
| self.screen.blit(game_over_text, | |
| game_over_text.get_rect(centerx=panel_x + panel_width // 2, | |
| top=panel_y + 40)) | |
| self.screen.blit(score_text, | |
| score_text.get_rect(centerx=panel_x + panel_width // 2, | |
| top=panel_y + 120)) | |
| self.screen.blit(grade_text, | |
| grade_text.get_rect(centerx=panel_x + panel_width // 2, | |
| top=panel_y + 170)) | |
| self.screen.blit(restart_text, | |
| restart_text.get_rect(centerx=panel_x + panel_width // 2, | |
| top=panel_y + 220)) | |
| pygame.display.flip() | |
| for event in pygame.event.get(): | |
| if event.type == pygame.QUIT: | |
| pygame.quit() | |
| sys.exit() | |
| if event.type == pygame.KEYDOWN: | |
| if event.key == pygame.K_r: | |
| self.__init__(self.screen) | |
| waiting = False | |
| elif event.key == pygame.K_q: | |
| pygame.quit() | |
| sys.exit() | |
| def update(self): | |
| """Update game state""" | |
| self.clock.tick(60) | |
| def draw_gradient_background(self): | |
| """Draw a gradient background""" | |
| height = self.screen.get_height() | |
| for i in range(height): | |
| progress = i / height | |
| color = [int(self.BACKGROUND_TOP[j] * (1 - progress) + self.BACKGROUND_BOTTOM[j] * progress) | |
| for j in range(3)] | |
| pygame.draw.line(self.screen, color, (0, i), (self.screen.get_width(), i)) | |
| def draw_heart(self, x, y, filled=True): | |
| """Draw a heart shape at the specified position""" | |
| points = [(px + x - 20, py - 80 + y) for px, py in self.heart_points] | |
| if filled: | |
| pygame.draw.polygon(self.screen, self.RED, points) | |
| pygame.draw.polygon(self.screen, (200, 0, 0), points, 2) | |
| def draw(self): | |
| """Draw the game screen""" | |
| # Draw gradient background | |
| self.draw_gradient_background() | |
| # Draw decorative header | |
| pygame.draw.rect(self.screen, self.BLUE, (0, 0, self.screen.get_width(), 120)) | |
| pygame.draw.rect(self.screen, self.PURPLE, (0, 115, self.screen.get_width(), 10)) | |
| # Draw grade and score with enhanced styling | |
| grade_text = self.small_font.render(f"Grade: {self.current_grade}", True, self.WHITE) | |
| score_text = self.small_font.render(f"Score: {self.score}", True, self.WHITE) | |
| self.screen.blit(grade_text, (20, 20)) | |
| self.screen.blit(score_text, (20, 50)) | |
| # Draw lives as hearts | |
| for i in range(3): | |
| self.draw_heart(60 + i * 30, 80, i < self.lives) | |
| # Draw problem with a background panel | |
| panel_rect = pygame.Rect(250, 150, 300, 250) | |
| pygame.draw.rect(self.screen, self.WHITE, panel_rect) | |
| pygame.draw.rect(self.screen, self.BLUE, panel_rect, 3) | |
| # Draw problem text | |
| problem_text = self.font.render(str(self.problem), True, self.BLACK) | |
| problem_rect = problem_text.get_rect(centerx=panel_rect.centerx, top=panel_rect.top + 30) | |
| self.screen.blit(problem_text, problem_rect) | |
| # Draw answer input with a box | |
| input_rect = pygame.Rect(panel_rect.left + 20, problem_rect.bottom + 20, | |
| panel_rect.width - 40, 40) | |
| pygame.draw.rect(self.screen, self.WHITE, input_rect) | |
| pygame.draw.rect(self.screen, self.BLACK, input_rect, 2) | |
| answer_text = self.font.render(f"Answer: {self.answer_input}", True, self.BLACK) | |
| answer_rect = answer_text.get_rect(centerx=input_rect.centerx, centery=input_rect.centery) | |
| self.screen.blit(answer_text, answer_rect) | |
| # Draw feedback with animation | |
| if self.feedback: | |
| feedback_text = self.font.render(self.feedback, True, self.feedback_color) | |
| feedback_rect = feedback_text.get_rect(centerx=panel_rect.centerx, | |
| top=input_rect.bottom + 20) | |
| # Apply scale animation | |
| scaled_surface = pygame.transform.scale( | |
| feedback_text, | |
| (int(feedback_text.get_width() * self.feedback_scale), | |
| int(feedback_text.get_height() * self.feedback_scale)) | |
| ) | |
| scaled_rect = scaled_surface.get_rect(center=feedback_rect.center) | |
| self.screen.blit(scaled_surface, scaled_rect) | |
| # Update scale for animation | |
| target_scale = 1.0 | |
| self.feedback_scale += (target_scale - self.feedback_scale) * 0.1 | |
| if abs(self.feedback_scale - target_scale) < 0.01: | |
| self.feedback_scale = target_scale |