import pygame import random import os import sys # 获取当前脚本的目录 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 初始化Pygame pygame.init() # 游戏常量设置 SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 FPS = 60 PLAYER_SPEED = 8 BULLET_SPEED = 15 ALIEN_COUNT = 8 PLAYER_SIZE = (50, 50) ALIEN_SIZE = (50, 50) BULLET_SIZE = (20, 40) # 颜色定义 BACKGROUND_COLOR = (25, 62, 11) TEXT_COLOR = (255, 0, 255) SCORE_COLOR = (255, 0, 0) # 创建游戏窗口 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("外星人大战") # 字体设置 def load_chinese_font(size=48): """尝试多种方式加载中文字体""" font_paths = [ "c:/Windows/Fonts/simhei.ttf", "c:/Windows/Fonts/msyh.ttc", "c:/Windows/Fonts/simsun.ttc", "/System/Library/Fonts/PingFang.ttc", "/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf", ] for path in font_paths: try: if os.path.exists(path): return pygame.font.Font(path, size) except: continue try: return pygame.font.SysFont('simhei', size) except: pass print("警告: 无法加载中文字体,将使用默认字体") return pygame.font.Font(None, size) # 加载字体 chinese_font_large = load_chinese_font(48) chinese_font_medium = load_chinese_font(36) # 创建默认图像 def create_default_image(size, color): """创建一个默认图像,带有透明背景""" image = pygame.Surface(size, pygame.SRCALPHA) pygame.draw.circle(image, color, (size[0] // 2, size[1] // 2), min(size[0], size[1]) // 2) return image # 创建默认玩家图像(蓝色飞船) def create_default_player(): image = pygame.Surface(PLAYER_SIZE, pygame.SRCALPHA) # 飞船主体(三角形) pygame.draw.polygon(image, (30, 144, 255), [ (PLAYER_SIZE[0] // 2, 0), # 顶点 (0, PLAYER_SIZE[1]), # 左下 (PLAYER_SIZE[0], PLAYER_SIZE[1]) # 右下 ]) # 飞船窗口(小圆) pygame.draw.circle(image, (200, 200, 255), (PLAYER_SIZE[0] // 2, PLAYER_SIZE[1] // 3), PLAYER_SIZE[0] // 6) return image # 创建默认外星人图像(绿色UFO) def create_default_alien(): image = pygame.Surface(ALIEN_SIZE, pygame.SRCALPHA) # UFO主体(椭圆) pygame.draw.ellipse(image, (50, 205, 50), (0, ALIEN_SIZE[1] // 4, ALIEN_SIZE[0], ALIEN_SIZE[1] // 2)) # UFO顶部(半圆) pygame.draw.circle(image, (180, 230, 180), (ALIEN_SIZE[0] // 2, ALIEN_SIZE[1] // 2), ALIEN_SIZE[0] // 3) return image # 创建默认子弹图像(红色激光) def create_default_bullet(): image = pygame.Surface(BULLET_SIZE, pygame.SRCALPHA) # 激光束 pygame.draw.line(image, (255, 0, 0), (BULLET_SIZE[0] // 2, 0), (BULLET_SIZE[0] // 2, BULLET_SIZE[1]), 3) # 激光光晕 pygame.draw.circle(image, (255, 100, 100, 128), (BULLET_SIZE[0] // 2, BULLET_SIZE[1] // 2), BULLET_SIZE[0] // 2) return image # 加载图片并处理可能的错误 def load_image(filename, size, default_creator=None): """加载并缩放图片,处理可能的错误""" try: path = os.path.join(BASE_DIR, filename) if os.path.exists(path): image = pygame.image.load(path).convert_alpha() # 使用convert_alpha()支持透明度 return pygame.transform.scale(image, size) except Exception as e: print(f"无法加载图片 {filename}: {e}") # 如果无法加载图片,使用默认创建器或创建彩色占位符 if default_creator: return default_creator() else: return create_default_image(size, (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))) # 加载游戏图片 player_img = load_image('player.png', PLAYER_SIZE, create_default_player) alien_img = load_image('alien.png', ALIEN_SIZE, create_default_alien) bullet_img = load_image('bullet.png', BULLET_SIZE, create_default_bullet) # 玩家类 class Player(pygame.sprite.Sprite): def __init__(self): """初始化玩家对象""" super().__init__() self.image = player_img self.rect = self.image.get_rect() self.rect.centerx = SCREEN_WIDTH // 2 self.rect.bottom = SCREEN_HEIGHT - 10 self.speed = PLAYER_SPEED self.last_shot = pygame.time.get_ticks() self.shoot_delay = 250 def update(self): """更新玩家位置""" keys = pygame.key.get_pressed() if keys[pygame.K_LEFT] and self.rect.left > 0: self.rect.x -= self.speed if keys[pygame.K_RIGHT] and self.rect.right < SCREEN_WIDTH: self.rect.x += self.speed # 自动射击功能 now = pygame.time.get_ticks() if keys[pygame.K_SPACE] and now - self.last_shot > self.shoot_delay: self.shoot() self.last_shot = now def shoot(self): """创建一个新子弹""" bullet = Bullet(self.rect.centerx, self.rect.top) all_sprites.add(bullet) bullets.add(bullet) # 外星人类 class Alien(pygame.sprite.Sprite): def __init__(self): """初始化外星人对象""" super().__init__() self.image = alien_img self.rect = self.image.get_rect() self.reset_position() def reset_position(self): """重置外星人位置和速度""" self.rect.x = random.randint(0, SCREEN_WIDTH - self.rect.width) self.rect.y = random.randint(-150, -40) self.speed = random.randint(2, 5) def update(self): """更新外星人位置""" self.rect.y += self.speed if self.rect.top > SCREEN_HEIGHT: self.reset_position() # 子弹类 class Bullet(pygame.sprite.Sprite): def __init__(self, x, y): """初始化子弹对象""" super().__init__() self.image = bullet_img self.rect = self.image.get_rect() self.rect.centerx = x self.rect.bottom = y self.speed = BULLET_SPEED def update(self): """更新子弹位置""" self.rect.y -= self.speed if self.rect.bottom < 0: self.kill() # 爆炸效果类 class Explosion(pygame.sprite.Sprite): def __init__(self, center, size): super().__init__() self.size = size self.frame = 0 self.image = self.create_explosion_frame(self.frame, self.size) self.rect = self.image.get_rect() self.rect.center = center self.last_update = pygame.time.get_ticks() self.frame_rate = 50 # 爆炸动画帧率 def create_explosion_frame(self, frame, size): """创建爆炸动画的一帧""" # 根据帧数创建不同大小的爆炸圆圈 image = pygame.Surface((size, size), pygame.SRCALPHA) max_radius = size // 2 if frame < 5: # 爆炸扩大阶段 radius = max_radius * (frame + 1) // 5 alpha = 255 else: # 爆炸消失阶段 radius = max_radius alpha = 255 * (10 - frame) // 5 # 绘制爆炸圆圈 pygame.draw.circle(image, (255, 200, 50, alpha), (size // 2, size // 2), radius) pygame.draw.circle(image, (255, 120, 0, alpha), (size // 2, size // 2), radius * 3 // 4) pygame.draw.circle(image, (255, 255, 255, alpha), (size // 2, size // 2), radius // 2) return image def update(self): now = pygame.time.get_ticks() if now - self.last_update > self.frame_rate: self.last_update = now self.frame += 1 if self.frame < 10: # 总共10帧动画 self.image = self.create_explosion_frame(self.frame, self.size) else: self.kill() # 动画结束后删除精灵 # 游戏状态类 class GameState: def __init__(self): """初始化游戏状态""" self.score = 0 self.game_over = False self.reset_game() def reset_game(self): """重置游戏状态和精灵组""" global all_sprites, aliens, bullets, player, explosions # 创建精灵组 all_sprites = pygame.sprite.Group() aliens = pygame.sprite.Group() bullets = pygame.sprite.Group() explosions = pygame.sprite.Group() # 创建玩家实例并添加到精灵组 player = Player() all_sprites.add(player) # 创建多个外星人实例并添加到精灵组 for i in range(ALIEN_COUNT): alien = Alien() all_sprites.add(alien) aliens.add(alien) # 重置游戏状态 self.score = 0 self.game_over = False # 创建游戏状态实例 game_state = GameState() # 预渲染文本 try: game_over_text = chinese_font_large.render("游戏结束", True, SCORE_COLOR) restart_text = chinese_font_medium.render("按 R 键重新开始", True, SCORE_COLOR) score_label = chinese_font_medium.render("得分: ", True, SCORE_COLOR) except: game_over_text = pygame.font.Font(None, 48).render("GAME OVER", True, SCORE_COLOR) restart_text = pygame.font.Font(None, 36).render("Press R to Restart", True, SCORE_COLOR) score_label = pygame.font.Font(None, 36).render("Score: ", True, SCORE_COLOR) # 游戏主循环 clock = pygame.time.Clock() running = True while running: # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: running = False elif event.key == pygame.K_r and game_state.game_over: game_state.reset_game() elif event.key == pygame.K_SPACE and not game_state.game_over: player.shoot() # 更新游戏状态 if not game_state.game_over: # 更新所有精灵 all_sprites.update() # 检查子弹和外星人的碰撞 hits = pygame.sprite.groupcollide(bullets, aliens, True, True) for hit in hits: game_state.score += 10 # 创建爆炸效果 explosion = Explosion(hit.rect.center, 50) all_sprites.add(explosion) explosions.add(explosion) # 创建新的外星人 alien = Alien() all_sprites.add(alien) aliens.add(alien) # 检查玩家和外星人的碰撞 hits = pygame.sprite.spritecollide(player, aliens, True) if hits: # 创建大爆炸效果 explosion = Explosion(player.rect.center, 100) all_sprites.add(explosion) explosions.add(explosion) game_state.game_over = True # 绘制 screen.fill(BACKGROUND_COLOR) all_sprites.draw(screen) # 显示得分 screen.blit(score_label, (10, 10)) try: score_value = chinese_font_medium.render(str(game_state.score), True, SCORE_COLOR) except: score_value = pygame.font.Font(None, 36).render(str(game_state.score), True, SCORE_COLOR) screen.blit(score_value, (10 + score_label.get_width(), 10)) # 游戏结束逻辑 if game_state.game_over: # 绘制半透明覆盖层 overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA) overlay.fill((0, 0, 0, 128)) screen.blit(overlay, (0, 0)) # 显示游戏结束文本 screen.blit(game_over_text, (SCREEN_WIDTH // 2 - game_over_text.get_width() // 2, SCREEN_HEIGHT // 2 - game_over_text.get_height() // 2)) # 显示重新开始提示 screen.blit(restart_text, (SCREEN_WIDTH // 2 - restart_text.get_width() // 2, SCREEN_HEIGHT // 2 + game_over_text.get_height())) # 更新屏幕 pygame.display.flip() # 控制帧率 clock.tick(FPS) # 退出Pygame pygame.quit() sys.exit()