|
import pygame |
|
import random |
|
import time |
|
import math |
|
|
|
class HighQualityTurtleGame: |
|
def __init__(self): |
|
# Initialize Pygame |
|
pygame.init() |
|
pygame.mixer.init() |
|
|
|
# Constants |
|
self.SCREEN_WIDTH = 1200 |
|
self.SCREEN_HEIGHT = 800 |
|
self.FPS = 60 |
|
self.PLAYER_SPEED = 5 |
|
self.FOOD_SIZE = 20 |
|
self.PLAYER_SIZE = 40 |
|
|
|
# Colors |
|
self.BLACK = (0, 0, 0) |
|
self.WHITE = (255, 255, 255) |
|
self.GREEN = (0, 255, 0) |
|
self.RED = (255, 0, 0) |
|
self.GOLD = (255, 215, 0) |
|
self.BLUE = (0, 100, 255) |
|
self.PURPLE = (128, 0, 128) |
|
self.ORANGE = (255, 165, 0) |
|
self.PINK = (255, 192, 203) |
|
self.CYAN = (0, 255, 255) |
|
self.YELLOW = (255, 255, 0) |
|
self.LIME = (50, 205, 50) |
|
|
|
# Game state |
|
self.score = 0 |
|
self.high_score = 0 |
|
self.level = 1 |
|
self.lives = 3 |
|
self.power_mode = False |
|
self.power_time = 0 |
|
self.running = True |
|
self.paused = False |
|
|
|
# Player state |
|
self.player_x = self.SCREEN_WIDTH // 2 |
|
self.player_y = self.SCREEN_HEIGHT // 2 |
|
self.player_angle = 0 |
|
self.player_vel_x = 0 |
|
self.player_vel_y = 0 |
|
|
|
# Food lists |
|
self.regular_foods = [] |
|
self.power_foods = [] |
|
self.food_colors = [self.RED, self.ORANGE, self.YELLOW, self.PINK, self.PURPLE, self.CYAN] |
|
|
|
# Timing |
|
self.last_food_spawn = time.time() |
|
self.last_power_spawn = time.time() |
|
|
|
# Particles for effects |
|
self.particles = [] |
|
|
|
# Setup display |
|
self.screen = pygame.display.set_mode((self.SCREEN_WIDTH, self.SCREEN_HEIGHT)) |
|
pygame.display.set_caption("๐ข High-Quality Turtle Catch Game") |
|
self.clock = pygame.time.Clock() |
|
self.font = pygame.font.Font(None, 36) |
|
self.small_font = pygame.font.Font(None, 24) |
|
self.large_font = pygame.font.Font(None, 48) |
|
|
|
# Generate simple sound effects |
|
self.create_sounds() |
|
|
|
# Spawn initial foods |
|
self.spawn_food() |
|
|
|
def create_sounds(self): |
|
"""Create simple sound effects using pygame""" |
|
try: |
|
# Create eat sound |
|
duration = 0.1 |
|
sample_rate = 22050 |
|
frames = int(duration * sample_rate) |
|
|
|
# Simple beep for eating food |
|
eat_sound = [] |
|
for i in range(frames): |
|
wave = 4096 * math.sin(2 * math.pi * 800 * i / sample_rate) |
|
eat_sound.append([int(wave), int(wave)]) |
|
|
|
self.eat_sound = pygame.sndarray.make_sound(pygame.array.array('i', eat_sound)) |
|
self.eat_sound.set_volume(0.3) |
|
|
|
# Power up sound |
|
power_sound = [] |
|
for i in range(frames * 2): |
|
freq = 400 + (i / frames) * 400 |
|
wave = 4096 * math.sin(2 * math.pi * freq * i / sample_rate) |
|
power_sound.append([int(wave), int(wave)]) |
|
|
|
self.power_sound = pygame.sndarray.make_sound(pygame.array.array('i', power_sound)) |
|
self.power_sound.set_volume(0.5) |
|
|
|
except: |
|
# Fallback if sound creation fails |
|
self.eat_sound = None |
|
self.power_sound = None |
|
|
|
def draw_turtle(self, x, y, angle, size, color, power_mode=False): |
|
"""Draw a realistic turtle that faces the direction it's moving""" |
|
# Calculate turtle parts based on angle |
|
head_offset = 25 |
|
head_x = x + math.cos(math.radians(angle)) * head_offset |
|
head_y = y + math.sin(math.radians(angle)) * head_offset |
|
|
|
# Draw shell (main body) |
|
shell_color = color if not power_mode else self.GOLD |
|
body_color = tuple(max(0, c - 50) for c in shell_color) |
|
|
|
# Shell segments for realistic look |
|
pygame.draw.circle(self.screen, body_color, (int(x), int(y)), size) |
|
pygame.draw.circle(self.screen, shell_color, (int(x), int(y)), size - 5) |
|
|
|
# Shell pattern |
|
for i in range(6): |
|
angle_offset = i * 60 |
|
pattern_angle = math.radians(angle_offset) |
|
pattern_x = x + math.cos(pattern_angle) * (size - 15) |
|
pattern_y = y + math.sin(pattern_angle) * (size - 15) |
|
pygame.draw.circle(self.screen, body_color, (int(pattern_x), int(pattern_y)), 5) |
|
|
|
# Draw legs (4 legs) |
|
leg_length = 15 |
|
leg_angles = [angle + 45, angle + 135, angle + 225, angle + 315] |
|
for leg_angle in leg_angles: |
|
leg_x = x + math.cos(math.radians(leg_angle)) * leg_length |
|
leg_y = y + math.sin(math.radians(leg_angle)) * leg_length |
|
pygame.draw.circle(self.screen, body_color, (int(leg_x), int(leg_y)), 6) |
|
|
|
# Draw head (pointing in movement direction) |
|
head_size = 12 |
|
pygame.draw.circle(self.screen, shell_color, (int(head_x), int(head_y)), head_size) |
|
|
|
# Draw eyes |
|
eye_offset = 8 |
|
eye_angle1 = angle + 20 |
|
eye_angle2 = angle - 20 |
|
eye1_x = head_x + math.cos(math.radians(eye_angle1)) * eye_offset |
|
eye1_y = head_y + math.sin(math.radians(eye_angle1)) * eye_offset |
|
eye2_x = head_x + math.cos(math.radians(eye_angle2)) * eye_offset |
|
eye2_y = head_y + math.sin(math.radians(eye_angle2)) * eye_offset |
|
|
|
pygame.draw.circle(self.screen, self.WHITE, (int(eye1_x), int(eye1_y)), 3) |
|
pygame.draw.circle(self.screen, self.WHITE, (int(eye2_x), int(eye2_y)), 3) |
|
pygame.draw.circle(self.screen, self.BLACK, (int(eye1_x), int(eye1_y)), 1) |
|
pygame.draw.circle(self.screen, self.BLACK, (int(eye2_x), int(eye2_y)), 1) |
|
|
|
# Power mode glow effect |
|
if power_mode: |
|
for i in range(3): |
|
glow_radius = size + 10 + i * 5 |
|
glow_color = (*self.GOLD, 50 - i * 15) |
|
glow_surface = pygame.Surface((glow_radius * 2, glow_radius * 2), pygame.SRCALPHA) |
|
pygame.draw.circle(glow_surface, glow_color, (glow_radius, glow_radius), glow_radius) |
|
self.screen.blit(glow_surface, (x - glow_radius, y - glow_radius)) |
|
|
|
def create_particle(self, x, y, color): |
|
"""Create particle effect""" |
|
for _ in range(5): |
|
particle = { |
|
'x': x + random.randint(-10, 10), |
|
'y': y + random.randint(-10, 10), |
|
'vx': random.uniform(-3, 3), |
|
'vy': random.uniform(-3, 3), |
|
'life': 30, |
|
'color': color, |
|
'size': random.randint(2, 5) |
|
} |
|
self.particles.append(particle) |
|
|
|
def update_particles(self): |
|
"""Update particle effects""" |
|
for particle in self.particles[:]: |
|
particle['x'] += particle['vx'] |
|
particle['y'] += particle['vy'] |
|
particle['life'] -= 1 |
|
particle['size'] = max(1, particle['size'] - 0.1) |
|
|
|
if particle['life'] <= 0: |
|
self.particles.remove(particle) |
|
|
|
def draw_particles(self): |
|
"""Draw particle effects""" |
|
for particle in self.particles: |
|
alpha = min(255, particle['life'] * 8) |
|
color = (*particle['color'], alpha) |
|
particle_surface = pygame.Surface((particle['size'] * 2, particle['size'] * 2), pygame.SRCALPHA) |
|
pygame.draw.circle(particle_surface, color, (particle['size'], particle['size']), particle['size']) |
|
self.screen.blit(particle_surface, (particle['x'] - particle['size'], particle['y'] - particle['size'])) |
|
|
|
def handle_input(self): |
|
"""Handle keyboard input with smooth movement""" |
|
keys = pygame.key.get_pressed() |
|
|
|
# Reset velocity |
|
self.player_vel_x = 0 |
|
self.player_vel_y = 0 |
|
|
|
# Movement with WASD and Arrow keys |
|
if keys[pygame.K_w] or keys[pygame.K_UP]: |
|
self.player_vel_y = -self.PLAYER_SPEED |
|
if keys[pygame.K_s] or keys[pygame.K_DOWN]: |
|
self.player_vel_y = self.PLAYER_SPEED |
|
if keys[pygame.K_a] or keys[pygame.K_LEFT]: |
|
self.player_vel_x = -self.PLAYER_SPEED |
|
if keys[pygame.K_d] or keys[pygame.K_RIGHT]: |
|
self.player_vel_x = self.PLAYER_SPEED |
|
|
|
# Diagonal movement normalization |
|
if self.player_vel_x != 0 and self.player_vel_y != 0: |
|
self.player_vel_x *= 0.707 # 1/sqrt(2) |
|
self.player_vel_y *= 0.707 |
|
|
|
# Update player position |
|
new_x = self.player_x + self.player_vel_x |
|
new_y = self.player_y + self.player_vel_y |
|
|
|
# Boundary checking with padding |
|
padding = self.PLAYER_SIZE |
|
if padding <= new_x <= self.SCREEN_WIDTH - padding: |
|
self.player_x = new_x |
|
if padding <= new_y <= self.SCREEN_HEIGHT - padding: |
|
self.player_y = new_y |
|
|
|
# Update turtle head angle based on movement direction |
|
if self.player_vel_x != 0 or self.player_vel_y != 0: |
|
target_angle = math.degrees(math.atan2(self.player_vel_y, self.player_vel_x)) |
|
# Smooth angle transition |
|
angle_diff = target_angle - self.player_angle |
|
# Handle angle wrapping |
|
if angle_diff > 180: |
|
angle_diff -= 360 |
|
elif angle_diff < -180: |
|
angle_diff += 360 |
|
self.player_angle += angle_diff * 0.2 # Smooth rotation |
|
|
|
def spawn_food(self): |
|
"""Spawn regular food""" |
|
if len(self.regular_foods) < 3 + self.level: |
|
food = { |
|
'x': random.randint(self.FOOD_SIZE, self.SCREEN_WIDTH - self.FOOD_SIZE), |
|
'y': random.randint(self.FOOD_SIZE, self.SCREEN_HEIGHT - self.FOOD_SIZE), |
|
'color': random.choice(self.food_colors), |
|
'pulse': random.uniform(0, math.pi * 2), |
|
'points': 10 |
|
} |
|
self.regular_foods.append(food) |
|
|
|
def spawn_power_food(self): |
|
"""Spawn power food""" |
|
if len(self.power_foods) == 0 and random.random() < 0.3: |
|
power_food = { |
|
'x': random.randint(self.FOOD_SIZE, self.SCREEN_WIDTH - self.FOOD_SIZE), |
|
'y': random.randint(self.FOOD_SIZE, self.SCREEN_HEIGHT - self.FOOD_SIZE), |
|
'color': self.GOLD, |
|
'pulse': 0, |
|
'points': 50, |
|
'rotation': 0 |
|
} |
|
self.power_foods.append(power_food) |
|
|
|
def draw_food(self, food, is_power=False): |
|
"""Draw animated food""" |
|
# Pulsing effect |
|
pulse_size = self.FOOD_SIZE + math.sin(food['pulse']) * 3 |
|
food['pulse'] += 0.2 |
|
|
|
if is_power: |
|
# Rotating star for power food |
|
food['rotation'] += 5 |
|
self.draw_star(food['x'], food['y'], pulse_size, food['color'], food['rotation']) |
|
else: |
|
# Regular circular food with glow |
|
# Outer glow |
|
for i in range(3): |
|
glow_size = pulse_size + i * 3 |
|
glow_alpha = 100 - i * 30 |
|
glow_color = (*food['color'], glow_alpha) |
|
glow_surface = pygame.Surface((glow_size * 2, glow_size * 2), pygame.SRCALPHA) |
|
pygame.draw.circle(glow_surface, glow_color, (int(glow_size), int(glow_size)), int(glow_size)) |
|
self.screen.blit(glow_surface, (food['x'] - glow_size, food['y'] - glow_size)) |
|
|
|
# Main food |
|
pygame.draw.circle(self.screen, food['color'], (int(food['x']), int(food['y'])), int(pulse_size)) |
|
pygame.draw.circle(self.screen, self.WHITE, (int(food['x']), int(food['y'])), int(pulse_size), 2) |
|
|
|
def draw_star(self, x, y, size, color, rotation): |
|
"""Draw a rotating star shape""" |
|
points = [] |
|
for i in range(10): |
|
angle = math.radians(rotation + i * 36) |
|
if i % 2 == 0: |
|
radius = size |
|
else: |
|
radius = size * 0.5 |
|
point_x = x + math.cos(angle) * radius |
|
point_y = y + math.sin(angle) * radius |
|
points.append((point_x, point_y)) |
|
|
|
pygame.draw.polygon(self.screen, color, points) |
|
pygame.draw.polygon(self.screen, self.WHITE, points, 2) |
|
|
|
def check_collisions(self): |
|
"""Check for food collisions""" |
|
# Regular foods |
|
for food in self.regular_foods[:]: |
|
distance = math.sqrt((self.player_x - food['x'])**2 + (self.player_y - food['y'])**2) |
|
if distance < self.PLAYER_SIZE // 2 + self.FOOD_SIZE: |
|
points = food['points'] * self.level |
|
if self.power_mode: |
|
points *= 2 |
|
self.score += points |
|
self.create_particle(food['x'], food['y'], food['color']) |
|
self.regular_foods.remove(food) |
|
if self.eat_sound: |
|
self.eat_sound.play() |
|
|
|
# Power foods |
|
for food in self.power_foods[:]: |
|
distance = math.sqrt((self.player_x - food['x'])**2 + (self.player_y - food['y'])**2) |
|
if distance < self.PLAYER_SIZE // 2 + self.FOOD_SIZE: |
|
self.score += food['points'] * self.level |
|
self.power_mode = True |
|
self.power_time = time.time() |
|
self.create_particle(food['x'], food['y'], food['color']) |
|
self.power_foods.remove(food) |
|
if self.power_sound: |
|
self.power_sound.play() |
|
|
|
def update_game_state(self): |
|
"""Update game state""" |
|
current_time = time.time() |
|
|
|
# Spawn foods |
|
if current_time - self.last_food_spawn > 2.0 / self.level: |
|
self.spawn_food() |
|
self.last_food_spawn = current_time |
|
|
|
if current_time - self.last_power_spawn > 8.0: |
|
self.spawn_power_food() |
|
self.last_power_spawn = current_time |
|
|
|
# Update power mode |
|
if self.power_mode and current_time - self.power_time > 5.0: |
|
self.power_mode = False |
|
|
|
# Level up |
|
if self.score > self.level * 500: |
|
self.level += 1 |
|
|
|
# Update high score |
|
if self.score > self.high_score: |
|
self.high_score = self.score |
|
|
|
def draw_ui(self): |
|
"""Draw user interface""" |
|
# Background gradient effect |
|
for y in range(0, 100, 2): |
|
alpha = 255 - (y * 2) |
|
color = (0, 0, 50, alpha) |
|
ui_surface = pygame.Surface((self.SCREEN_WIDTH, 2), pygame.SRCALPHA) |
|
ui_surface.fill(color) |
|
self.screen.blit(ui_surface, (0, y)) |
|
|
|
# Score |
|
score_text = self.font.render(f"Score: {self.score:,}", True, self.WHITE) |
|
self.screen.blit(score_text, (20, 20)) |
|
|
|
# Level |
|
level_text = self.small_font.render(f"Level: {self.level}", True, self.CYAN) |
|
self.screen.blit(level_text, (20, 60)) |
|
|
|
# High Score |
|
high_score_text = self.small_font.render(f"High Score: {self.high_score:,}", True, self.YELLOW) |
|
self.screen.blit(high_score_text, (20, 85)) |
|
|
|
# Power mode indicator |
|
if self.power_mode: |
|
remaining = 5.0 - (time.time() - self.power_time) |
|
if remaining > 0: |
|
power_text = self.font.render(f"POWER MODE: {remaining:.1f}s", True, self.GOLD) |
|
text_rect = power_text.get_rect(center=(self.SCREEN_WIDTH // 2, 40)) |
|
self.screen.blit(power_text, text_rect) |
|
|
|
# Controls |
|
controls = [ |
|
"WASD / Arrow Keys: Move", |
|
"P: Pause", |
|
"ESC: Quit" |
|
] |
|
for i, control in enumerate(controls): |
|
text = self.small_font.render(control, True, self.WHITE) |
|
self.screen.blit(text, (self.SCREEN_WIDTH - 200, 20 + i * 25)) |
|
|
|
# Pause overlay |
|
if self.paused: |
|
overlay = pygame.Surface((self.SCREEN_WIDTH, self.SCREEN_HEIGHT), pygame.SRCALPHA) |
|
overlay.fill((0, 0, 0, 128)) |
|
self.screen.blit(overlay, (0, 0)) |
|
|
|
pause_text = self.large_font.render("PAUSED", True, self.WHITE) |
|
text_rect = pause_text.get_rect(center=(self.SCREEN_WIDTH // 2, self.SCREEN_HEIGHT // 2)) |
|
self.screen.blit(pause_text, text_rect) |
|
|
|
continue_text = self.font.render("Press P to continue", True, self.WHITE) |
|
continue_rect = continue_text.get_rect(center=(self.SCREEN_WIDTH // 2, self.SCREEN_HEIGHT // 2 + 60)) |
|
self.screen.blit(continue_text, continue_rect) |
|
|
|
def run(self): |
|
"""Main game loop""" |
|
print("๐ข High-Quality Turtle Game Started!") |
|
print("Use WASD or Arrow Keys to move") |
|
print("Catch food to score points!") |
|
|
|
while self.running: |
|
# Handle events |
|
for event in pygame.event.get(): |
|
if event.type == pygame.QUIT: |
|
self.running = False |
|
elif event.type == pygame.KEYDOWN: |
|
if event.key == pygame.K_ESCAPE: |
|
self.running = False |
|
elif event.key == pygame.K_p: |
|
self.paused = not self.paused |
|
|
|
if not self.paused: |
|
# Game logic |
|
self.handle_input() |
|
self.check_collisions() |
|
self.update_game_state() |
|
self.update_particles() |
|
|
|
# Drawing |
|
# Gradient background |
|
for y in range(0, self.SCREEN_HEIGHT, 4): |
|
color_intensity = int(20 + (y / self.SCREEN_HEIGHT) * 30) |
|
color = (color_intensity // 3, color_intensity // 2, color_intensity) |
|
pygame.draw.rect(self.screen, color, (0, y, self.SCREEN_WIDTH, 4)) |
|
|
|
# Draw foods |
|
for food in self.regular_foods: |
|
self.draw_food(food) |
|
for food in self.power_foods: |
|
self.draw_food(food, True) |
|
|
|
# Draw particles |
|
self.draw_particles() |
|
|
|
# Draw player turtle |
|
self.draw_turtle(self.player_x, self.player_y, self.player_angle, |
|
self.PLAYER_SIZE // 2, self.LIME, self.power_mode) |
|
|
|
# Draw UI |
|
self.draw_ui() |
|
|
|
# Update display |
|
pygame.display.flip() |
|
self.clock.tick(self.FPS) |
|
|
|
print(f"\n๐ฎ Final Score: {self.score:,}") |
|
print(f"๐ High Score: {self.high_score:,}") |
|
print(f"๐ Level Reached: {self.level}") |
|
|
|
pygame.quit() |
|
|
|
# Start the game |
|
if __name__ == "__main__": |
|
game = HighQualityTurtleGame() |
|
game.run() |