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

Pygame报错TypeError: Invalid rect assignment,子弹定位问题求助

解决Pygame中子弹对齐的TypeError问题

我想让子弹的topright与飞船的topright对齐,于是在Bullet类的__init__方法中写了:

self.rect = self.image.get_rect(topright = (pos))

通过以下代码传入飞船的topright位置:

self.shoot.add(Bullet(self.rect.topright))

其中self是Spaceship类的实例,shoot是pygame精灵组,但运行时出现TypeError: Invalid rect assignment错误,尝试移除pos的括号、设置x=pos等操作都没解决,完整代码如下:

import pygame

# normal setup
pygame.init()
screen = pygame.display.set_mode((700, 700), pygame.RESIZABLE)
pygame.display.set_caption('ZAP!')
icon = pygame.image.load('download.jpg')
pygame.display.set_icon(icon)
clock = pygame.time.Clock()
running = True  # while loop running so after ending game i can still run

# bg
bg = pygame.image.load('ok_proper.jpg')
bg_pic = pygame.transform.scale(bg, (700, 700))


class Bullet(pygame.sprite.Sprite):
    def __init__(self,pos):
        super().__init__()
        self.image = pygame.transform.rotate(pygame.transform.scale(pygame.image.load('Graphics/yes.png'),(100,100)),90)
        self.rect = self.image.get_rect(topright = (pos))
        self.speed = 10
        self.rect.y -= self.speed
        if self.rect.y < 0:
            self.rect = self.image.get_rect(topright= (pos))



class Spaceship(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load('Graphics/spaceship.png')
        self.rect = self.image.get_rect(bottomleft=(250, 700))
        self.speed = 5
        self.laser_time = 0
        self.laser_cooldown = 600
        self.ready = True
        self.shoot = pygame.sprite.Group()

    def movement(self):
        keys = pygame.key.get_pressed()
        if (keys[pygame.K_RIGHT] or keys[pygame.K_d]) and self.rect.right + self.speed < 699:
            self.rect.x += self.speed
        elif (keys[pygame.K_LEFT] or keys[pygame.K_a]) and self.rect.x - self.speed > 0:
            self.rect.x -= self.speed
        elif keys[pygame.K_SPACE] and self.ready:
            self.shootlaser()
            self.ready = False
            self.laser_time = pygame.time.get_ticks()

    def shootlaser(self):
        if not self.ready:
            timeoflaser = pygame.time.get_ticks()
            if self.laser_time - timeoflaser == self.laser_cooldown:
                self.ready = True
        else:
            self.shoot.add(Bullet(self.rect.topright))



    def update(self):
        self.movement()
        self.shootlaser()

# spaceship
spaceship = Spaceship()
# spaceship = pygame.sprite.GroupSingle()
# spaceship.add(Spaceship())

# bullet
bullet = Bullet(spaceship)

while running:
    clock.tick(60)
    screen.blit(bg_pic, (0, 0))  # background
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    screen.blit(spaceship.image,spaceship.rect)
    screen.blit(bullet.image,bullet.rect)
    spaceship.update()
    # spaceship.draw(screen)
    pygame.display.update()

错误原因分析

  • 致命参数错误:代码中bullet = Bullet(spaceship)这行传入的是Spaceship实例,不是坐标元组,而get_rect的topright参数需要(x,y)格式的元组,直接传对象导致了Invalid rect assignment。
  • 逻辑位置错误:Bullet类的__init__里直接修改位置、判断越界,这部分移动逻辑应该放在update方法中,初始化只负责创建实例。
  • 冷却判断逻辑颠倒:shootlaser里的self.laser_time - timeoflaser == self.laser_cooldown写反了,应该是当前时间减上次发射时间,而且用==容易因帧率问题错过触发,改用>=更稳妥。
  • 精灵组未正确使用:创建了shoot精灵组却没在主循环更新、绘制,反而单独绘制了错误的bullet实例。

修正后的完整代码

import pygame

# 初始化设置
pygame.init()
screen = pygame.display.set_mode((700, 700), pygame.RESIZABLE)
pygame.display.set_caption('ZAP!')
icon = pygame.image.load('download.jpg')
pygame.display.set_icon(icon)
clock = pygame.time.Clock()
running = True  

# 背景设置
bg = pygame.image.load('ok_proper.jpg')
bg_pic = pygame.transform.scale(bg, (700, 700))


class Bullet(pygame.sprite.Sprite):
    def __init__(self, pos):
        super().__init__()
        # 加载并处理子弹图片
        self.image = pygame.transform.rotate(pygame.transform.scale(pygame.image.load('Graphics/yes.png'), (100, 100)), 90)
        # 直接用pos设置topright,self.rect.topright本身就是元组,无需额外加括号
        self.rect = self.image.get_rect(topright=pos)
        self.speed = 10

    def update(self):
        # 子弹向上移动
        self.rect.y -= self.speed
        # 超出屏幕顶部就销毁子弹
        if self.rect.bottom < 0:
            self.kill()


class Spaceship(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load('Graphics/spaceship.png')
        self.rect = self.image.get_rect(bottomleft=(250, 700))
        self.speed = 5
        self.laser_time = 0
        self.laser_cooldown = 600
        self.ready = True
        self.shoot = pygame.sprite.Group()

    def movement(self):
        keys = pygame.key.get_pressed()
        # 向右移动,边界判断改用屏幕宽度更灵活
        if (keys[pygame.K_RIGHT] or keys[pygame.K_d]) and self.rect.right + self.speed < screen.get_width():
            self.rect.x += self.speed
        # 向左移动
        elif (keys[pygame.K_LEFT] or keys[pygame.K_a]) and self.rect.x - self.speed > 0:
            self.rect.x -= self.speed
        # 发射子弹
        if keys[pygame.K_SPACE] and self.ready:
            self.shootlaser()
            self.ready = False
            self.laser_time = pygame.time.get_ticks()

    def shootlaser(self):
        # 冷却时间判断逻辑修正
        if not self.ready:
            time_now = pygame.time.get_ticks()
            if time_now - self.laser_time >= self.laser_cooldown:
                self.ready = True
        else:
            # 传入飞船的topright坐标创建子弹
            self.shoot.add(Bullet(self.rect.topright))

    def update(self):
        self.movement()
        # 更新子弹组的所有子弹
        self.shoot.update()


# 创建飞船实例
spaceship = Spaceship()

while running:
    clock.tick(60)
    screen.blit(bg_pic, (0, 0))  

    # 事件处理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # 更新飞船状态
    spaceship.update()
    # 绘制飞船
    screen.blit(spaceship.image, spaceship.rect)
    # 绘制所有子弹
    spaceship.shoot.draw(screen)

    pygame.display.update()

关键修改点

  1. 删除了错误的bullet = Bullet(spaceship)代码,不再创建无效的子弹实例。
  2. 将Bullet的移动、越界逻辑移到update方法,初始化只做基础设置。
  3. 修正冷却时间判断逻辑,确保冷却结束后能正确恢复发射状态。
  4. 主循环中通过spaceship.shoot.draw(screen)绘制所有子弹,利用精灵组统一管理。
  5. 简化了get_rect的参数写法,直接使用传入的pos元组。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:50:25