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