# Example file showing a basic pygame "game loop" import pygame from pygame.math import Vector2 from time import time class FloatingSign(pygame.sprite.Sprite): # Constructor. Pass in the color of the block, # and its x and y position def __init__(self, image: pygame.Surface): # Call the parent class (Sprite) constructor pygame.sprite.Sprite.__init__(self) # Create an image of the block, and fill it with a color. # This could also be an image loaded from the disk. self.image = image self.width, self.height = image.get_size() # Fetch the rectangle object that has the dimensions of the image # Update the position of this object by setting the values of rect.x and rect.y self.rect = self.image.get_rect() self.pos = Vector2(0, 0) self.hits = 0 self.corner_hits = 0 self.last_hit = Vector2(0, 0) self.last_corner_hit = 0 self.font = pygame.font.SysFont('Noto Sans', 40, True) self.text_surfaces = [ self.font.render(f'Hits: {self.hits}', False, (255, 255, 255)), self.font.render(f'Corner hits: {self.corner_hits}', False, (255, 255, 255)), None ] def move(self, delta: float):# -> pygame.Rect: sw, sh = pygame.display.get_window_size() before = self.pos hit_x = False hit_y = False movement = self.velocity * delta self.pos += movement if self.pos.x < 0: hit_x = True self.pos.x *= -1 elif self.pos.y < 0: hit_y = True self.pos.y *= -1 elif self.pos.x > sw - self.width: hit_x = True self.pos.x -= self.pos.x + self.width - sw elif self.pos.y > sh - self.height: hit_y = True self.pos.y -= self.pos.y + self.height - sh if hit_x or hit_y: if hit_x: self.velocity.x *= -1 else: self.velocity.y *= -1 self.hits += 1 hit_distance = self.pos.distance_to(self.last_hit) self.last_hit = self.pos.copy() if hit_distance < 10: self.corner_hits += 1 self.last_corner_hit = time() self.text_surfaces[1] = self.font.render(f'Corner hits: {self.corner_hits}', False, (255, 255, 255)) self.text_surfaces[0] = self.font.render(f'Hits: {self.hits}', False, (255, 255, 255)) self.rect.topleft = self.pos #return pygame.Rect(min_x, min_y, max_x - min_x, max_y - min_y) def lazy_update(self, delta: float): secs = time() - self.last_corner_hit if secs < 3600: fmtd = (str(secs // 1) + 's') if secs < 60 else (str(secs // 60) + 'm') self.text_surfaces[2] = self.font.render(f'Last corner hit: {fmtd}', False, (255, 255, 255)) else: self.text_surfaces[2] = None def main(screen_size: tuple[int], background: str, image_path: str, initial_velocity: Vector2): # pygame setup pygame.init() screen = pygame.display.set_mode(screen_size, flags=pygame.RESIZABLE, vsync=1) clock = pygame.time.Clock() running = True image = pygame.image.load(image_path) floating_sign = FloatingSign(image) floating_sign.velocity = initial_velocity screen.fill(background) pygame.display.flip() lu = 0 while running: delta = clock.tick() lu += delta # poll for events # pygame.QUIT event means the user clicked X to close your window for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # fill the screen with a color to wipe away anything from last frame screen.fill(background) movement_swept = floating_sign.move(delta / 1000) if lu > 1: floating_sign.lazy_update(lu) lu = 0 for i in range(len(floating_sign.text_surfaces)): if floating_sign.text_surfaces[i] is not None: screen.blit(floating_sign.text_surfaces[i], (20, 10 + 40 * i)) screen.blit(floating_sign.image, floating_sign.rect) # flip() the display to put your work on screen pygame.display.flip() #pygame.display.update(movement_swept) pygame.quit() if __name__ == "__main__": main(screen_size=(1280, 720), background="#3b3b3b", image_path="Untitled.png", initial_velocity=Vector2(200, 127))