Pygame滑雪游戏tree精灵不显示问题排查及解决方案咨询
Pygame滑雪游戏树木不显示问题修复方案
核心问题清单
- 精灵组
tree_group和树木实例的作用域错误:原代码在draw_display函数内每次调用都重新创建空的tree_group,之前添加的树木会全部丢失,且函数内创建的Tree实例仅单次生效,无法实现持续的树木生成和移动效果 - 绘制逻辑顺序错误:先调用
tree_group.draw(display)再添加树木精灵,新增的树木永远不会被当前帧渲染,自然看不到显示 - 树木更新逻辑错误:在
main函数的循环内每次都创建新的Tree实例,仅更新单次创建的实例,没有对精灵组内所有树木做批量更新 - 变量作用域冲突:全局
score和main函数内的局部score重名,Tree类的update方法无法拿到正确的实时分数计算移动速度 - 生成判断逻辑错误:原代码用
tree.rect.x做垂直距离判断,实际应该判断树木的垂直Y轴位置来控制生成间隔
修复后完整代码
import pygame import sys import random import os import time from pygame.event import post # 初始化pygame库 pygame.init() pygame.font.init() pygame.mixer.init() FPS = 60 VEL = 5 # region | 主窗口属性与背景设置 WIDTH, HEIGHT = 800, 800 display = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("Ski Game") BACKGROUND = pygame.transform.scale(pygame.image.load(os.path.join("background.jpg")), (WIDTH, HEIGHT)) # endregion # region | 字体与颜色配置 SCORE_FONT = pygame.font.SysFont('comicsans', 40) GAME_OVER_FONT = pygame.font.SysFont('comicsans', 100) BLACK = (0, 0, 0) WHITE = (255, 255, 255) # endregion # region | 精灵资源加载与缩放 SKIER_WIDTH = 65 SKIER_HEIGHT = 105 SKIER = pygame.transform.scale(pygame.image.load( os.path.join("skier.png")), (SKIER_WIDTH, SKIER_HEIGHT)) # endregion # 全局树木精灵组,放在函数外保证数据持久化 tree_group = pygame.sprite.Group() # 记录上一棵树的生成位置,控制生成间隔 last_tree_y = 0 # 创建自定义事件 CRASH_TREE = pygame.USEREVENT + 1 def draw_display(score, skier): # 绘制背景 display.blit(BACKGROUND, (0, 0)) score_text = SCORE_FONT.render("Score: " + str(score), 1, BLACK) display.blit(score_text, (WIDTH / 2 - score_text.get_width()/2, 10)) # 绘制滑雪者 display.blit(SKIER, (skier.x, skier.y)) # 先更新所有树木,再绘制 tree_group.update(score) tree_group.draw(display) pygame.display.update() class Tree(pygame.sprite.Sprite): def __init__(self, score): super().__init__() self.TREE_WIDTH = 80 self.TREE_HEIGHT = 150 self.image = pygame.transform.scale(pygame.image.load(os.path.join("tree.png")), (self.TREE_WIDTH, self.TREE_HEIGHT)) self.rect = self.image.get_rect() self.rect.x = random.randrange(0, WIDTH - self.TREE_WIDTH) self.rect.y = -self.TREE_HEIGHT # 从屏幕顶部生成,向下移动更符合滑雪逻辑 def get_speed(self, score, base=2, interval=10, multiplier=0.05): return base + ((score//interval) * multiplier) def get_distance(self, score, base=100, interval=10, multiplier=5): return base + ((score//interval) * multiplier) # 增加score参数传入,避免全局变量问题 def update(self, score): self.rect.y += self.get_speed(score) # 树木移出屏幕底部后自动销毁,节省内存 if self.rect.y > HEIGHT: self.kill() def handle_skier_movement(keys_pressed, skier): if keys_pressed[pygame.K_LEFT] and skier.x - VEL > 0: # 向左移动 skier.x -= VEL if keys_pressed[pygame.K_RIGHT] and skier.x + VEL + skier.width < WIDTH: # 向右移动 skier.x += VEL if keys_pressed[pygame.K_UP] and skier.y - VEL > 0: # 向上移动 skier.y -= VEL if keys_pressed[pygame.K_DOWN] and skier.y + VEL + skier.height < HEIGHT: # 向下移动 skier.y += VEL def game_over(): game_over_text = GAME_OVER_FONT.render("GAME OVER", 1, BLACK) display.blit(game_over_text, (WIDTH/2 - game_over_text.get_width() / 2, HEIGHT/2 - game_over_text.get_height()/2)) pygame.display.update() pygame.time.delay(5000) def main(): global last_tree_y skier = pygame.Rect(700, 300, SKIER_WIDTH, SKIER_HEIGHT) score = 0 clock = pygame.time.Clock() run = True while run: clock.tick(FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False pygame.quit() sys.exit() if event.type == CRASH_TREE: game_over() # 重置游戏状态 score = 0 tree_group.empty() last_tree_y = 0 main() return keys_pressed = pygame.key.get_pressed() handle_skier_movement(keys_pressed, skier) # 控制树木生成逻辑 temp_tree = Tree(score) if abs(last_tree_y) > temp_tree.get_distance(score): new_tree = Tree(score) tree_group.add(new_tree) last_tree_y = 0 # 每生成一棵树分数加1,也可以按时间加分 score += 1 last_tree_y += temp_tree.get_speed(score) # 碰撞检测 if pygame.sprite.spritecollideany(skier, tree_group): post(pygame.event.Event(CRASH_TREE)) draw_display(score, skier) if __name__ == "__main__": main()
关键修改说明
- 把
tree_group移到全局作用域,所有生成的树木都会被持久保存在这个组里,不会每次渲染都丢失 - 调整绘制顺序:先调用
tree_group.update()批量更新所有树木的位置,再调用draw()渲染所有树木 - 优化生成逻辑:通过记录上一棵树的位置控制生成间隔,树木从屏幕顶部生成向下移动,更符合滑雪场景的视觉逻辑
- 修复变量作用域问题:把
score作为参数传入update方法,保证速度计算取到实时分数 - 增加自动销毁逻辑:树木移出屏幕后自动调用
kill()销毁,避免内存占用越来越高 - 补充碰撞检测逻辑:用
spritecollideany检测滑雪者和树木的碰撞,触发CRASH_TREE事件
内容的提问来源于stack exchange,提问作者user13391131
相关产品推荐
相关产品推荐

