You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

372 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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()