You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 11:24:03