- 音乐播放器
py
- @ 2026-1-18 12:24:00
import pygame import sys import random import os
初始化Pygame
pygame.init()
-------------------------- 游戏常量配置 --------------------------
屏幕设置
SCREEN_WIDTH = 800 SCREEN_HEIGHT = 400 FPS = 60 GRAVITY = 0.8 JUMP_FORCE = -18 CROUCH_SPEED = 0.5
颜色定义
WHITE = (255, 255, 255) BLACK = (0, 0, 0) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) GRAY = (200, 200, 200)
游戏状态枚举
class GameState: MENU = 0 PLAYING = 1 PAUSED = 2 GAME_OVER = 3
-------------------------- 资源加载(提前创建文件夹) --------------------------
创建必要的文件夹
if not os.path.exists("assets"): os.makedirs("assets") os.makedirs("assets/sounds")
尝试加载音效(如果没有音效文件则跳过)
try: # 跳跃音效 jump_sound = pygame.mixer.Sound("assets/sounds/jump.wav") # 碰撞音效 hit_sound = pygame.mixer.Sound("assets/sounds/hit.wav") # 计分音效 score_sound = pygame.mixer.Sound("assets/sounds/score.wav") except: # 没有音效文件时使用空函数替代 class DummySound: def play(self): pass jump_sound = DummySound() hit_sound = DummySound() score_sound = DummySound()
-------------------------- 玩家类 --------------------------
class Player(pygame.sprite.Sprite): def init(self): super().init() # 角色尺寸(正常/下蹲状态) self.normal_size = (60, 80) self.crouch_size = (60, 40)
# 创建简易角色图形(替代图片)
self.normal_image = pygame.Surface(self.normal_size)
self.normal_image.fill(BLUE)
# 绘制面部特征
pygame.draw.circle(self.normal_image, WHITE, (30, 30), 15) # 脸
pygame.draw.circle(self.normal_image, BLACK, (25, 25), 3) # 左眼
pygame.draw.circle(self.normal_image, BLACK, (35, 25), 3) # 右眼
pygame.draw.arc(self.normal_image, BLACK, (25, 35, 10, 5), 0, 3.14, 2) # 嘴
self.crouch_image = pygame.Surface(self.crouch_size)
self.crouch_image.fill(BLUE)
# 下蹲状态的面部
pygame.draw.circle(self.crouch_image, WHITE, (30, 20), 10)
pygame.draw.circle(self.crouch_image, BLACK, (25, 18), 2)
pygame.draw.circle(self.crouch_image, BLACK, (35, 18), 2)
self.image = self.normal_image
self.rect = self.image.get_rect()
self.rect.x = 100
self.rect.y = SCREEN_HEIGHT - self.normal_size[1] - 20
# 物理属性
self.velocity_y = 0
self.on_ground = True
self.is_crouching = False
self.crouch_timer = 0
def update(self):
# 应用重力
self.velocity_y += GRAVITY
self.rect.y += self.velocity_y
# 地面碰撞检测
ground_level = SCREEN_HEIGHT - self.normal_size[1] - 20
if self.rect.y >= ground_level:
self.rect.y = ground_level
self.velocity_y = 0
self.on_ground = True
# 处理下蹲逻辑
if self.is_crouching:
self.crouch_timer += 1
if self.crouch_timer > FPS * 0.5: # 最多下蹲0.5秒
self.stand_up()
else:
self.crouch_timer = 0
def jump(self):
"""玩家跳跃"""
if self.on_ground and not self.is_crouching:
self.velocity_y = JUMP_FORCE
self.on_ground = False
jump_sound.play()
def crouch(self):
"""玩家下蹲"""
if self.on_ground and not self.is_crouching:
self.is_crouching = True
self.image = self.crouch_image
# 调整位置避免穿地
self.rect.y = SCREEN_HEIGHT - self.crouch_size[1] - 20
def stand_up(self):
"""玩家站起"""
if self.is_crouching:
self.is_crouching = False
self.image = self.normal_image
self.rect.y = SCREEN_HEIGHT - self.normal_size[1] - 20
-------------------------- 障碍物类 --------------------------
class Obstacle(pygame.sprite.Sprite): def init(self): super().init() # 随机生成不同类型的障碍物 self.obstacle_type = random.choice(["small", "medium", "tall"])
if self.obstacle_type == "small":
self.size = (40, 40)
elif self.obstacle_type == "medium":
self.size = (50, 60)
else: # tall
self.size = (30, 80)
# 创建障碍物图形
self.image = pygame.Surface(self.size)
self.image.fill(RED)
# 添加纹理
for i in range(0, self.size[0], 10):
pygame.draw.line(self.image, BLACK, (i, 0), (i, self.size[1]), 2)
self.rect = self.image.get_rect()
self.rect.x = SCREEN_WIDTH
self.rect.y = SCREEN_HEIGHT - self.size[1] - 20
# 随机速度(增加游戏难度)
self.speed = random.randint(8, 12)
def update(self):
"""更新障碍物位置"""
self.rect.x -= self.speed
# 移除超出屏幕的障碍物
if self.rect.right < 0:
self.kill()
-------------------------- 背景类 --------------------------
class Background: def init(self): self.layers = [] # 创建多层背景(视差效果) for i in range(3): layer = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT)) layer.fill((135 + i20, 206 + i10, 235 + i5)) # 渐变天空蓝 # 添加云朵 for j in range(5 + i): cloud = pygame.Surface((80 - i10, 40 - i5), pygame.SRCALPHA) pygame.draw.ellipse(cloud, WHITE, (0, 0, 80 - i10, 40 - i5)) cloud_x = random.randint(0, SCREEN_WIDTH) cloud_y = random.randint(50, 150 - i30) layer.blit(cloud, (cloud_x, cloud_y)) self.layers.append({ "surface": layer, "x": 0, "speed": 1 + i*0.5 # 不同层不同速度 })
# 创建地面
self.ground = pygame.Surface((SCREEN_WIDTH, 20))
self.ground.fill(GREEN)
# 添加地面纹理
for i in range(0, SCREEN_WIDTH, 20):
pygame.draw.rect(self.ground, (0, 150, 0), (i, 0, 10, 20))
def update(self):
"""更新背景位置(滚动效果)"""
for layer in self.layers:
layer["x"] -= layer["speed"]
if layer["x"] <= -SCREEN_WIDTH:
layer["x"] = 0
def draw(self, screen):
"""绘制背景"""
for layer in self.layers:
screen.blit(layer["surface"], (layer["x"], 0))
screen.blit(layer["surface"], (layer["x"] + SCREEN_WIDTH, 0))
# 绘制地面
screen.blit(self.ground, (0, SCREEN_HEIGHT - 20))
-------------------------- 游戏主类 --------------------------
class ParkourGame: def init(self): # 创建游戏窗口 self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("高级跑酷游戏")
# 游戏时钟
self.clock = pygame.time.Clock()
# 初始化游戏状态
self.game_state = GameState.MENU
self.score = 0
self.high_score = 0
self.last_score_time = pygame.time.get_ticks()
# 加载高分记录
self.load_high_score()
# 创建游戏对象
self.background = Background()
self.all_sprites = pygame.sprite.Group()
self.obstacles = pygame.sprite.Group()
# 创建玩家
self.player = Player()
self.all_sprites.add(self.player)
# 障碍物生成计时器
self.obstacle_timer = 0
self.min_obstacle_interval = 800 # 最小生成间隔(毫秒)
# 字体设置
self.font_large = pygame.font.Font(None, 72)
self.font_medium = pygame.font.Font(None, 48)
self.font_small = pygame.font.Font(None, 36)
def load_high_score(self):
"""加载高分记录"""
try:
with open("high_score.txt", "r") as f:
self.high_score = int(f.read())
except:
self.high_score = 0
def save_high_score(self):
"""保存高分记录"""
if self.score > self.high_score:
self.high_score = self.score
with open("high_score.txt", "w") as f:
f.write(str(self.high_score))
def spawn_obstacle(self):
"""生成新的障碍物"""
current_time = pygame.time.get_ticks()
if current_time - self.obstacle_timer > self.min_obstacle_interval:
obstacle = Obstacle()
self.all_sprites.add(obstacle)
self.obstacles.add(obstacle)
self.obstacle_timer = current_time
# 随着游戏进行,减小生成间隔(增加难度)
self.min_obstacle_interval = max(300, self.min_obstacle_interval - 5)
def reset_game(self):
"""重置游戏状态"""
# 保存高分
self.save_high_score()
# 重置分数和计时器
self.score = 0
self.obstacle_timer = 0
self.min_obstacle_interval = 800
self.last_score_time = pygame.time.get_ticks()
# 清除所有障碍物
for obstacle in self.obstacles:
obstacle.kill()
# 重置玩家位置
self.player.rect.x = 100
self.player.rect.y = SCREEN_HEIGHT - self.player.normal_size[1] - 20
self.player.velocity_y = 0
self.player.on_ground = True
self.player.is_crouching = False
# 设置游戏状态为运行中
self.game_state = GameState.PLAYING
def handle_events(self):
"""处理游戏事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.save_high_score()
pygame.quit()
sys.exit()
# 键盘事件
if event.type == pygame.KEYDOWN:
# ESC键暂停/继续
if event.key == pygame.K_ESCAPE:
if self.game_state == GameState.PLAYING:
self.game_state = GameState.PAUSED
elif self.game_state == GameState.PAUSED:
self.game_state = GameState.PLAYING
# R键重启游戏
if event.key == pygame.K_r:
self.reset_game()
# 空格键跳跃
if event.key == pygame.K_SPACE and self.game_state == GameState.PLAYING:
self.player.jump()
# 下方向键下蹲
if event.key == pygame.K_DOWN and self.game_state == GameState.PLAYING:
self.player.crouch()
# 回车键开始游戏(菜单界面)
if event.key == pygame.K_RETURN and self.game_state == GameState.MENU:
self.reset_game()
# 释放下蹲键
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
self.player.stand_up()
def update_game(self):
"""更新游戏逻辑"""
if self.game_state == GameState.PLAYING:
# 更新背景
self.background.update()
# 更新所有精灵
self.all_sprites.update()
# 生成障碍物
self.spawn_obstacle()
# 计分逻辑(每0.5秒加1分)
current_time = pygame.time.get_ticks()
if current_time - self.last_score_time > 500:
self.score += 1
self.last_score_time = current_time
if self.score % 10 == 0: # 每10分播放一次计分音效
score_sound.play()
# 碰撞检测
if pygame.sprite.spritecollide(self.player, self.obstacles, False):
hit_sound.play()
self.game_state = GameState.GAME_OVER
# 菜单和结束界面不需要更新游戏逻辑
def draw_game(self):
"""绘制游戏画面"""
# 绘制背景
self.background.draw(self.screen)
if self.game_state == GameState.PLAYING:
# 绘制所有精灵
self.all_sprites.draw(self.screen)
# 绘制分数
score_text = self.font_medium.render(f"分数: {self.score}", True, BLACK)
self.screen.blit(score_text, (20, 20))
# 绘制高分
high_score_text = self.font_small.render(f"最高分: {self.high_score}", True, BLACK)
self.screen.blit(high_score_text, (20, 70))
elif self.game_state == GameState.MENU:
# 绘制开始菜单
title_text = self.font_large.render("PYTHON 跑酷游戏", True, BLACK)
start_text = self.font_medium.render("按 ENTER 开始游戏", True, BLACK)
instruction_text = self.font_small.render("空格跳跃 | 下方向键下蹲 | ESC暂停 | R重启", True, BLACK)
self.screen.blit(title_text, (SCREEN_WIDTH//2 - title_text.get_width()//2, 100))
self.screen.blit(start_text, (SCREEN_WIDTH//2 - start_text.get_width()//2, 200))
self.screen.blit(instruction_text, (SCREEN_WIDTH//2 - instruction_text.get_width()//2, 300))
elif self.game_state == GameState.PAUSED:
# 绘制暂停界面
pause_text = self.font_large.render("游戏暂停", True, BLACK)
resume_text = self.font_medium.render("按 ESC 继续 | 按 R 重启", True, BLACK)
# 半透明遮罩
mask = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
mask.fill(WHITE)
mask.set_alpha(128)
self.screen.blit(mask, (0, 0))
self.screen.blit(pause_text, (SCREEN_WIDTH//2 - pause_text.get_width()//2, 150))
self.screen.blit(resume_text, (SCREEN_WIDTH//2 - resume_text.get_width()//2, 250))
elif self.game_state == GameState.GAME_OVER:
# 绘制游戏结束界面
game_over_text = self.font_large.render("游戏结束", True, RED)
score_text = self.font_medium.render(f"最终分数: {self.score}", True, BLACK)
high_score_text = self.font_medium.render(f"最高分: {self.high_score}", True, BLACK)
restart_text = self.font_small.render("按 R 重新开始 | 按 ESC 返回菜单", True, BLACK)
# 半透明遮罩
mask = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
mask.fill(WHITE)
mask.set_alpha(128)
self.screen.blit(mask, (0, 0))
self.screen.blit(game_over_text, (SCREEN_WIDTH//2 - game_over_text.get_width()//2, 100))
self.screen.blit(score_text, (SCREEN_WIDTH//2 - score_text.get_width()//2, 200))
self.screen.blit(high_score_text, (SCREEN_WIDTH//2 - high_score_text.get_width()//2, 250))
self.screen.blit(restart_text, (SCREEN_WIDTH//2 - restart_text.get_width()//2, 300))
# 更新屏幕显示
pygame.display.flip()
def run(self):
"""游戏主循环"""
while True:
# 处理事件
self.handle_events()
# 更新游戏状态
self.update_game()
# 绘制游戏画面
self.draw_game()
# 控制帧率
self.clock.tick(FPS)
-------------------------- 启动游戏 --------------------------
if name == "main": game = ParkourGame() game.run()
1 条评论
-
吴佳陈 @ 2026-3-22 22:16:48这是何物
- 1