Untitled

Anonymous
plain_text
02/26/2026 6:43 AM
8.8 KB
14
Indexable
import pygame
import sys
import math

# =============================================
# Simple Hill Climbing Game for PC
# Inspired by Hill Climb Racing
# Controls: RIGHT ARROW = Accelerate
#           LEFT ARROW  = Brake / Reverse
#           R           = Restart after crash
# =============================================

pygame.init()

# Screen settings
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Hill Climbing Game")
clock = pygame.time.Clock()
font = pygame.font.SysFont("Arial", 36)
small_font = pygame.font.SysFont("Arial", 24)

# Colors
SKY = (100, 180, 255)
GROUND = (34, 139, 34)
DARK_GROUND = (20, 100, 20)
CAR_BODY = (220, 20, 20)
CAB = (180, 20, 20)

class Car:
    def __init__(self):
        self.screen_x = 280          # Fixed position on screen (car doesn't move left/right on screen)
        self.world_x = 100.0         # Starting world position
        self.speed = 3.0             # Starting speed (pixels per frame along slope)
        self.angle = 0.0

        # Create the car sprite (will be rotated later)
        self.base_surf = pygame.Surface((90, 55), pygame.SRCALPHA)
        
        # Main body
        pygame.draw.rect(self.base_surf, CAR_BODY, (8, 22, 74, 18))
        # Cabin
        pygame.draw.rect(self.base_surf, CAB, (35, 12, 38, 18))
        # Window
        pygame.draw.rect(self.base_surf, (200, 230, 255), (42, 16, 20, 10))
        
        # Wheels
        pygame.draw.circle(self.base_surf, (30, 30, 30), (20, 38), 11)
        pygame.draw.circle(self.base_surf, (30, 30, 30), (70, 38), 11)
        pygame.draw.circle(self.base_surf, (200, 200, 200), (20, 38), 6)
        pygame.draw.circle(self.base_surf, (200, 200, 200), (70, 38), 6)

    def get_y_and_angle(self):
        """Calculate car height and tilt based on terrain under the wheels"""
        wheel_base = 55
        rear_x = self.world_x - wheel_base / 2
        front_x = self.world_x + wheel_base / 2
        
        rear_h = get_terrain_height(rear_x)
        front_h = get_terrain_height(front_x)
        
        delta_h = front_h - rear_h
        self.angle = math.degrees(math.atan2(delta_h, wheel_base))
        
        # Car sits on the terrain (average height - offset)
        return (rear_h + front_h) / 2 - 32

def get_terrain_height(world_x):
    """Procedural hills using multiple sine waves"""
    return 430 + \
           85 * math.sin(world_x * 0.007) + \
           55 * math.sin(world_x * 0.018) + \
           35 * math.sin(world_x * 0.035) + \
           20 * math.sin(world_x * 0.09)

def draw_terrain(camera_x):
    points = []
    step = 6
    for sx in range(-20, WIDTH + 21, step):
        wx = camera_x + sx
        hy = get_terrain_height(wx)
        points.append((sx, hy))
    
    # Fill the ground
    poly = points[:] + [(WIDTH, HEIGHT), (0, HEIGHT)]
    pygame.draw.polygon(screen, GROUND, poly)
    
    # Darker top line for depth
    pygame.draw.lines(screen, DARK_GROUND, False, points, 8)

def main():
    car = Car()
    camera_x = 0.0
    score = 0
    game_over = False
    high_score = 0

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            
            if event.type == pygame.KEYDOWN and game_over:
                if event.key == pygame.K_r:
                    car = Car()
                    camera_x = 0.0
                    score = 0
                    game_over = False

        if not game_over:
            keys = pygame.key.get_pressed()
            
            # Controls
            if keys[pygame.K_RIGHT]:
                car.speed += 0.65
            if keys[pygame.K_LEFT]:
                car.speed -= 0.45
            
            # Get slope at current position
            dx = 8
            h1 = get_terrain_height(car.world_x - dx)
            h2 = get_terrain_height(car.world_x + dx)
            slope = (h2 - h1) / (2 * dx)
            slope_rad = math.atan(slope)
            
            # Gravity pulls you down the slope
            car.speed -= 0.22 * math.sin(slope_rad)
            
            # Natural drag
            car.speed *= 0.975
            
            # Speed limits
            car.speed = max(-7.5, min(car.speed, 16.0))
            
            # Move car in world space
            move_dx = car.speed * math.cos(slope_rad)
            car.world_x += move_dx
            
            # Camera follows the car (keeps car at fixed screen_x)
            camera_x = car.world_x - car.screen_x
            
            # Update score (distance traveled)
            score = int(car.world_x / 4)
            
            # Crash detection (too steep + slow speed = flip!)
            if abs(car.angle) > 47 or (abs(car.angle) > 32 and abs(car.speed) < 1.8):
                game_over = True
                if score > high_score:
                    high_score = score

        # === DRAWING ===
        screen.fill(SKY)
        
        draw_terrain(camera_x)
        
        # Draw the car
        car_y = car.get_y_and_angle()
        rotated = pygame.transform.rotate(car.base_surf, -car.angle)
        rect = rotated.get_rect(center=(car.screen_x, int(car_y)))
        screen.blit(rotated, rect.topleft)
        
        # HUD
        score_surf = font.render(f"DISTANCE: {score} m", True, (255, 255, 255))
        screen.blit(score_surf, (15, 15))
        
        high_surf = small_font.render(f"HIGH: {high_score} m", True, (255, 255, 200))
        screen.blit(high_surf, (15, 55))
        
        # Instructions
        if not game_over and score < 50:
            inst = small_font.render("← → ARROWS to drive  |  Don't flip!", True, (255, 255, 255))
            screen.blit(inst, (WIDTH//2 - 180, 15))
        
        if game_over:
            overlay = pygame.Surface((WIDTH, HEIGHT))
            overlay.set_alpha(180)
            overlay.fill((0, 0, 0))
            screen.blit(overlay, (0, 0))
            
            go1 = font.render("CRASHED!", True, (255, 50, 50))
            go2 = font.render(f"FINAL DISTANCE: {score} m", True, (255, 255, 255))
            go3 = small_font.render("Press R to try again", True, (200, 200, 200))
            
            screen.blit(go1, (WIDTH//2 - go1.get_width()//2, 180))
            screen.blit(go2, (WIDTH//2 - go2.get_width()//2, 250))
            screen.blit(go3, (WIDTH//2 - go3.get_width()//2, 320))
        
        pygame.display.flip()
        clock.tick(60)

if __name__ == "__main__":
    print("Starting Hill Climbing Game...")
    main()
Editor is loading...
Leave a Comment