import pygame import random import math import os # Initialization pygame.init() WIDTH, HEIGHT = 640, 480 screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("Hopple - Run from the Snake!") clock = pygame.time.Clock() font = pygame.font.SysFont("Arial", 28) # Colors & constants WHITE = (255, 255, 255) BLUE = (64, 164, 223) TITLE, PLAYING, GAME_OVER = "title", "playing", "game_over" GRAVITY = 0.8 JUMP_FORCE = 12 PLATFORM_WIDTH = 700 HIGH_SCORE_FILE = "highscore.txt" # Load assets def load_and_scale(img, size): return pygame.transform.scale(pygame.image.load(img).convert_alpha(), size) skier_imgs = [ load_and_scale("skier1.png", (30, 50)), load_and_scale("skier2.png", (30, 50)), load_and_scale("skier3.png", (30, 50)), ] skier_jump = load_and_scale("skier_jump.png", (30, 50)) leaf_image = load_and_scale("leaf.png", (40, 40)) tree_image_raw = pygame.image.load("tree.png").convert_alpha() title_bg = load_and_scale("HOPPLE.jpg", (WIDTH, HEIGHT)) # Game state game_state = TITLE high_score = 0 level = 1 # High score functions def read_high_score(): if os.path.exists(HIGH_SCORE_FILE): with open(HIGH_SCORE_FILE, "r") as f: return int(f.read()) return 0 def write_high_score(score): with open(HIGH_SCORE_FILE, "w") as f: f.write(str(score)) # Player setup player = pygame.Rect(160, 340, 30, 50) velocity_y = 0 on_ground = False current_skier_image = skier_imgs[0] ski_frame_index = 0 ski_frame_timer = 0 ski_frame_delay = 8 cash = 0 # Game environment floor_tiles = [pygame.Rect(0, HEIGHT - 140, PLATFORM_WIDTH, 140)] floating_platforms = [] leaves = [] trees = [] speed = 5 tiles_passed = 0 scrolling = True start_time = pygame.time.get_ticks() cycle_time = 0 cycle_duration = 3000 cycle_speed = 1 / cycle_duration # Snow effect snowflakes = [{"x": random.randint(0, WIDTH), "y": random.randint(0, HEIGHT), "radius": random.randint(1, 3), "speed": random.uniform(1, 3)} for _ in range(100)] # Reset game state def reset_game(): global player, velocity_y, on_ground, floor_tiles, leaves, trees, floating_platforms, tiles_passed, scrolling global start_time, cash, level player.x, player.y = 160, 340 velocity_y = 0 on_ground = False floor_tiles = [pygame.Rect(0, HEIGHT - 140, PLATFORM_WIDTH, 140)] floating_platforms.clear() leaves.clear() trees.clear() tiles_passed = 0 scrolling = True start_time = pygame.time.get_ticks() cash = 0 level = 1 # Day-night color blending def get_day_night_colors(cycle): t = (math.sin(cycle * math.pi * 2 - math.pi / 2) + 1) / 2 sky_day, sky_night = (137, 207, 240), (10, 10, 40) ground_day, ground_night = (217, 217, 217), (128, 128, 128) blend = lambda c1, c2: tuple(int(c1[i] * t + c2[i] * (1 - t)) for i in range(3)) return blend(sky_day, sky_night), blend(ground_day, ground_night) # Draw entire scene def draw_world(): global cycle_time cycle_time += cycle_speed sky_color, ground_color = get_day_night_colors(cycle_time) screen.fill(sky_color) for flake in snowflakes: pygame.draw.circle(screen, WHITE, (int(flake["x"]), int(flake["y"])), flake["radius"]) for tree in trees: tree_img = pygame.transform.scale(tree_image_raw, (int(tree["scale"] * 60), int(tree["scale"] * 100))) tree_img.set_alpha(tree["alpha"]) screen.blit(tree_img, (tree["x"], tree["y"] - tree_img.get_height())) for tile in floor_tiles: pygame.draw.rect(screen, ground_color, tile) for platform in floating_platforms: pygame.draw.rect(screen, (160, 82, 45), platform) for tile in floor_tiles: if tile.height < 60: pygame.draw.rect(screen, BLUE, tile) for leaf in leaves: screen.blit(leaf_image, (leaf.x, leaf.y)) screen.blit(current_skier_image, (player.x, player.y)) elapsed_time = (pygame.time.get_ticks() - start_time) // 1000 hud_y = HEIGHT - 40 screen.blit(font.render(f"Speed: {speed}", True, WHITE), (10, hud_y)) screen.blit(font.render(f"Time: {elapsed_time}s", True, WHITE), (220, hud_y)) screen.blit(leaf_image, (570, hud_y - 6)) screen.blit(font.render(f"${cash}", True, WHITE), (615, hud_y)) # Get platform height at player's position def get_current_platform_height(x): for tile in floor_tiles: if tile.x <= x <= tile.x + tile.width: return HEIGHT - tile.height for platform in floating_platforms: if platform.x <= x <= platform.x + platform.width: return platform.top return HEIGHT # Check player collisions with terrain def check_collisions(): global on_ground, velocity_y, game_state, scrolling, high_score for tile in floor_tiles: if player.colliderect(tile) and player.right > tile.left and player.left < tile.right: if player.bottom > tile.top: if tile.height == 30: # Water tile hit scrolling = False if cash > high_score: high_score = cash write_high_score(high_score) game_state = GAME_OVER return False player.bottom = tile.top velocity_y = 0 on_ground = True break for platform in floating_platforms: if player.colliderect(platform) and player.right > platform.left and player.left < platform.right: if player.bottom > platform.top: player.bottom = platform.top velocity_y = 0 on_ground = True break return on_ground # Move player vertically def move_player(): global velocity_y, on_ground velocity_y += GRAVITY player.y += velocity_y on_ground = check_collisions() if not on_ground: on_ground = False # Generate terrain and objects def add_platforms(): global floor_tiles, floating_platforms MIN_HEIGHT_DIFF = 30 MAX_HEIGHT_DIFF = 80 if len(floor_tiles) < 3: last = floor_tiles[-1] last_top = last.top if random.random() < 0.3: left_tile_height = random.randint(HEIGHT - 180, HEIGHT - 100) left_tile = pygame.Rect(last.x + PLATFORM_WIDTH, left_tile_height, PLATFORM_WIDTH, HEIGHT - left_tile_height) floor_tiles.append(left_tile) water_width = PLATFORM_WIDTH water_tile = pygame.Rect(left_tile.x + PLATFORM_WIDTH, HEIGHT - 30, water_width, 30) floor_tiles.append(water_tile) right_tile_height = random.randint(HEIGHT - 180, HEIGHT - 100) right_tile = pygame.Rect(water_tile.x + water_width, right_tile_height, PLATFORM_WIDTH, HEIGHT - right_tile_height) floor_tiles.append(right_tile) for i in range(2): plat_x = water_tile.x + 100 + i * 300 platform = pygame.Rect(plat_x, HEIGHT - 200, 100, 20) floating_platforms.append(platform) else: attempt = 0 while True: attempt += 1 proposed_top = random.randint(HEIGHT - 200, HEIGHT - 80) height_diff = abs(proposed_top - last_top) if MIN_HEIGHT_DIFF <= height_diff <= MAX_HEIGHT_DIFF or attempt > 10: break new_tile = pygame.Rect(last.x + PLATFORM_WIDTH, proposed_top, PLATFORM_WIDTH, HEIGHT - proposed_top) floor_tiles.append(new_tile) if random.random() < 0.7: leaf_rect = pygame.Rect(new_tile.x + random.randint(50, 600), new_tile.y - 40, 40, 40) leaves.append(leaf_rect) for _ in range(random.randint(1, 3)): scale = random.uniform(0.5, 1.2) alpha = int(255 * (0.3 + (scale - 0.5) / 0.7)) trees.append({ "x": new_tile.x + random.randint(0, new_tile.width), "y": new_tile.y, "scale": scale, "alpha": min(255, max(80, alpha)) }) # Clean up offscreen objects def clean_world(): global tiles_passed, speed, level for tile in floor_tiles[:]: if tile.x + tile.width < 0: floor_tiles.remove(tile) tiles_passed += 1 if tiles_passed % 3 == 0: speed += 1 level += 1 leaves[:] = [leaf for leaf in leaves if leaf.right >= 0] trees[:] = [tree for tree in trees if tree["x"] >= -100] floating_platforms[:] = [p for p in floating_platforms if p.right >= 0] # Move environment def move_world(): for tile in floor_tiles: tile.x -= speed for leaf in leaves: leaf.x -= speed for tree in trees: tree["x"] -= speed for platform in floating_platforms: platform.x -= speed # Check if player hits wall def check_side_collision(): for tile in floor_tiles: if player.colliderect(tile) and player.right > tile.left and player.left < tile.left and player.bottom > tile.top: return True return False # Display centered text def draw_text_center(text, y): surface = font.render(text, True, WHITE) rect = surface.get_rect(center=(WIDTH // 2, y)) screen.blit(surface, rect) # Main loop high_score = read_high_score() running = True while running: clock.tick(60) keys = pygame.key.get_pressed() for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if game_state == TITLE: screen.blit(title_bg, (0, 0)) padding_x, padding_y = 20, 80 bottom_y = HEIGHT - padding_y screen.blit(font.render(f"High Score: ${high_score}", True, WHITE), (padding_x, bottom_y)) screen.blit(font.render("Press 1 (easy), 2, or 3 (hard) to Start", True, WHITE), (padding_x, bottom_y + 35)) pygame.display.flip() if keys[pygame.K_1]: reset_game() speed = 5 game_state = PLAYING elif keys[pygame.K_2]: reset_game() speed = 10 game_state = PLAYING elif keys[pygame.K_3]: reset_game() speed = 15 game_state = PLAYING elif game_state == PLAYING: if keys[pygame.K_SPACE] and on_ground: velocity_y = -JUMP_FORCE on_ground = False if scrolling: move_world() clean_world() add_platforms() move_player() for leaf in leaves[:]: if player.colliderect(leaf): leaves.remove(leaf) cash += 1 if check_side_collision() or player.top > HEIGHT: scrolling = False if cash > high_score: high_score = cash write_high_score(high_score) game_state = GAME_OVER else: current_skier_image = skier_imgs[ski_frame_index] if on_ground else skier_jump if on_ground: ski_frame_timer += 1 if ski_frame_timer >= ski_frame_delay: ski_frame_index = (ski_frame_index + 1) % len(skier_imgs) ski_frame_timer = 0 draw_world() pygame.display.flip() elif game_state == GAME_OVER: screen.fill((50, 0, 0)) draw_text_center("GAME OVER", 160) draw_text_center(f"Score: ${cash}", 220) draw_text_center(f"High Score: ${high_score}", 260) draw_text_center("Press SPACE to Restart", 320) pygame.display.flip() if keys[pygame.K_SPACE]: game_state = TITLE pygame.quit()