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

Pygame技术问题:如何将PNG纹理1:1映射到矩形

Pygame Flappy Bird管道纹理映射问题

我是Pygame新手,正在制作Flappy Bird克隆作为首个Pygame项目。目前已有基础框架,但为矩形添加纹理时遇到问题:用两个矩形表示上下管道,仅显示矩形时尺寸位置符合预期,但添加PNG管道纹理后,纹理无法与矩形正确映射。

我的代码如下:

import pygame
import random

pygame.init()

screen = pygame.display.set_mode((250,500))
clock = pygame.time.Clock()
run = True

background = pygame.image.load('graphics/background-day.png')
ground = pygame.image.load('graphics/base.png')

birdRec = pygame.Rect(0, 0, 30, 24)
birdRec.center = (100,300)


bottomPipeHeight = random.randrange(50, 350)

pipeRecBottom = pygame.Rect(0,0, 50, bottomPipeHeight)
pipeRecBottom.midbottom = (150, 450)


pipeRecTop = pygame.Rect(0,0,50,500)
pipeRecTop.midbottom = pipeRecBottom.midtop
pipeRecTop.y -= 100

gravity = 0


pipeBottomTexture = pygame.image.load("graphics/pipe-green.png").convert_alpha()



while run:
    #poll for events
    #pygame.QUIT event means the user clicked x
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    gravity += .1
    birdRec.y += gravity

    keys = pygame.key.get_pressed()
    if keys[pygame.K_w]:
        birdRec.y -= 7
        gravity = 0
    if keys[pygame.K_s]:
        birdRec.y += 2
    if keys[pygame.K_d]:
        birdRec.x += 2
    if keys[pygame.K_a]:
        birdRec.x -= 2

    pipeRecBottom.x -= 1
    pipeRecTop.x -= 1

    if(birdRec.colliderect(pipeRecTop) or birdRec.colliderect(pipeRecBottom)):
        print("Collision")
        

    # RENDER GAME
    screen.blit(background,(0,0))
    screen.blit(ground,(0,450))

    #PROBLOMATIC AREA BEGIN

    pygame.draw.rect(screen, "Black", pipeRecBottom)  
    #screen.blit(pipeBottomTexture, pipeRecBottom)

    #PROBLOMATIC AREA END

    pygame.draw.rect(screen, "Green", pipeRecTop)     
    pygame.draw.rect(screen, "Red", birdRec)

    if pipeRecBottom.right < -30: 
        pipeRecBottom.height = random.randrange(50,350)
        pipeRecBottom.bottomleft = (280,450)
    
    if pipeRecTop.right < -30: 
        pipeRecTop.midbottom = pipeRecBottom.midtop
        pipeRecTop.y -= 100



    pygame.display.flip()
    

    clock.tick(60)

pygame.quit()

我尝试注释掉问题区域的第一行,仅保留第二行,原本以为可将纹理直接贴在计算好位置的矩形上,但纹理出现偏移,底部管道会穿入地面。我认为底部管道的顶部映射位置正确,希望解决纹理穿入地面的问题。

正确效果:
正确效果

错误效果:
错误效果

两者的高度差异是因为管道高度随机生成,即使固定高度,仍存在穿入问题。


解决方法

问题根源是你定义的管道矩形尺寸和管道PNG的原始尺寸不匹配,直接用blit(纹理, 矩形)时,Pygame会把纹理左上角对齐矩形左上角,但不会缩放纹理适配矩形大小,导致纹理实际尺寸和你预期的矩形尺寸不符,底部管道就会因为纹理过高穿入地面。

步骤1:初始化时缩放并翻转纹理

# 加载并处理底部管道纹理
pipeBottomTexture = pygame.image.load("graphics/pipe-green.png").convert_alpha()
pipeBottomTexture = pygame.transform.scale(pipeBottomTexture, (pipeRecBottom.width, pipeRecBottom.height))

# 加载并处理顶部管道纹理(需要垂直翻转)
pipeTopTexture = pygame.image.load("graphics/pipe-green.png").convert_alpha()
pipeTopTexture = pygame.transform.flip(pipeTopTexture, False, True)  # 垂直翻转
pipeTopTexture = pygame.transform.scale(pipeTopTexture, (pipeRecTop.width, pipeRecTop.height))

步骤2:绘制时使用矩形位置绘制缩放后的纹理

替换问题区域的代码:

# PROBLOMATIC AREA BEGIN
screen.blit(pipeBottomTexture, pipeRecBottom.topleft)
# PROBLOMATIC AREA END
screen.blit(pipeTopTexture, pipeRecTop.topleft)

步骤3:管道重置时重新缩放纹理

因为每次管道高度会随机变化,所以重置管道后要重新适配纹理尺寸:

if pipeRecBottom.right < -30: 
    pipeRecBottom.height = random.randrange(50,350)
    pipeRecBottom.bottomleft = (280,450)
    # 重新缩放底部管道纹理
    pipeBottomTexture = pygame.transform.scale(pipeBottomTexture, (pipeRecBottom.width, pipeRecBottom.height))

if pipeRecTop.right < -30: 
    pipeRecTop.midbottom = pipeRecBottom.midtop
    pipeRecTop.y -= 100
    # 重新缩放顶部管道纹理
    pipeTopTexture = pygame.transform.scale(pipeTopTexture, (pipeRecTop.width, pipeRecTop.height))

这样处理后,纹理就会完全适配你定义的管道矩形尺寸,不会出现穿入地面的问题了。


内容的提问来源于stack exchange,提问作者ZacharyyK

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 16:20:24