python外星人入侵游戏 报错invalid destination position for blit

import sys
import pygame
from pygame.sprite import Group
from setting import Setting
from ship import Ship
from bullet import Bullet
from allien import Allien


class AlienInvasion:
    #管理游戏资源和行为的类
    def __init__(self):
        pygame.init()
        self.setting = Setting()
        self.screen = pygame.display.set_mode((self.setting.screen_width,self.setting.screen_height))
        #设置背景色
        # 创建飞3
        self.ship = Ship(self)
        # 创建子弹的编组
        self.bullets =pygame.sprite.Group()
        self.bulelts_allowed = 5
        # 创建外星人的编组
        self.alliens = pygame.sprite.Group()
        pygame.display.set_caption("Alien Invasion")


    #开始游戏的主循环
    def run_game(self):
        while True:
            
            #监视键盘和鼠标的辅助方法
            self._check_event()
            # 创建外星人
            self.ship.update()
            # 控制子弹移动方法检查子弹是否达到最上面
            self.update_bullet()
            self.creat_fleet()
            #让最近绘制的屏幕可见的方法
            self.update_alliens()
            #让最近绘制的屏幕可见的方
            self._update_screen()
        
    def update_alliens(self):
        self._check_fleet_edges()
        self.alliens.update()

    def update_bullet(self):
        self.bullets.update( )
        for bullet in self.bullets.copy():
            if bullet.rect.bottom < 0:
                self.bullets.remove(bullet)
    

    # 创建外星人组
    def creat_fleet(self):
        # 创造一个外星人并计算一行可以容纳多少外星人
        # 外星人间距等于外星人宽度
        allien = Allien(self)
        allien_width = allien.rect.width
        available_space_x = self.setting.screen_width - (2 * allien_width)
        number_allien_x = available_space_x // (2 * allien_width)
        # 计算屏幕可以容纳多少行外星人
        allien_hegiht = allien.rect.height
        available_space_y = self.setting.screen_height - (3 * allien_hegiht)
        row_number = available_space_y // (2 * allien_hegiht)
        self.creat_allien(row_number,number_allien_x)

    def creat_allien(self,row_number,number_allien_x):
        for number_row in range(row_number - 1):
            for number_x in range(number_allien_x):
                allien = Allien(self)
                allien_width = allien.rect.width
                allien_height = allien.rect.height
                allien_width, allien_hegiht = allien.rect.size
                allien.x  = allien_width + (2 * allien_width * number_x)
                allien.y =  allien_height + (2 * allien_height * number_row)
                allien.rect.x = allien.x 
                allien.rect.y = allien.y
                self.alliens.add(allien)
    def _check_fleet_edges(self):
        for alien in self.alliens.sprites():
            if alien.check_edges():
                self._change_fleet_direction()
                break
    def _change_fleet_direction(self):
        for alien in self.aliens.sprites():
            allien.rect.y += self.setting.fleet_drop_speed
        self.setting.fleet_direction *= -1


    def _fire_bullet(self):
        if len(self.bullets) <=  self.bulelts_allowed:
            new_bullet = Bullet(self)
            self.bullets.add(new_bullet)

        # 响应事件的辅助方法 
    def _check_event(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            # 按下按键的操作
            elif event.type == pygame.KEYDOWN:
                self._check_event_keydown(event)
            # 松开按键的操作
            elif event.type == pygame.KEYUP:
                self._check_event_keyup(event)
                # 按下按键的操作
            elif event.type == pygame.KEYDOWN:
                self._check_event_keydown(event)
        
    def _check_event_keydown(self,event):
            if event.key == pygame.K_RIGHT:
                self.ship.moving_right = True
            elif event.key == pygame.K_LEFT:
                self.ship.moving_left = True
            elif event.key == pygame.K_SPACE:
                self._fire_bullet()
            elif event.key == pygame.K_q:
                sys.exit()
    
    def _check_event_keyup(self,event):    
            if event.key == pygame.K_RIGHT:
                self.ship.moving_right = False
            elif event.key == pygame.K_LEFT:
                self.ship.moving_left = False


        # 屏幕刷新的辅助方法
    def _update_screen(self):
        self.screen.fill(self.setting.bg_color)
        self.ship.blitme()
        for bullet in self.bullets.sprites():
            bullet.draw_bullet()
        self.alliens.draw(self.screen)
        pygame.display.flip()

    #创建游戏实例并开始游戏
if __name__ == '__main__':
    ai_game = AlienInvasion()
    ai_game.run_game()

import pygame
from pygame.sprite import Sprite
class Allien(Sprite):
    def __init__(self,ai_game):
        super().__init__()
        self.screen = ai_game.screen
        self.setting = ai_game.setting
        # 创建图像和其矩形
        self.image = pygame.image.load("image/alien.bmp")
        self.rect = self.image.get_rect()
    
        # 每个外星人都在左上角附件
        self.rect.x = self.rect.width
        self.rect.y = self.rect.height
        # 储存x的精确位置
        self.x  = float(self.rect.x)

    def update(self):
        self.x += (self.setting.allien_speed * self.setting.fleet_direction)
        self.rect = self.x 

    def check_edges(self):
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right or self.rect.left <=  screen_rect.left:
            return True


    
    #储存游戏中所有设置的类
class Setting:
    def __init__(self):
        #屏幕设置
        self.screen_width = 1200
        self.screen_height = 800
        self.bg_color = (230,230,230)
        # 飞船速度设置
        self.ship_speed = 1.5
        # 子弹设置
        self.bullet_speed = 1
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = (60,60,60)
        # 外星人设置
        self.allien_speed = 1.0
        self.fleet_drop_speed = 10
        # fleet_direction = 1 为1 表示右移,为-1表示左移
        self.fleet_direction = 1
        
import pygame
from pygame.sprite import Sprite

class Bullet(Sprite):
    # 子弹的类
    def __init__(self,ai_game):
        super().__init__()
        self.screen = ai_game.screen

        # 在(0,0)处先创建一个矩形,再移动到飞船
        self.rect = pygame.Rect(0,0,ai_game.setting.bullet_width,ai_game.setting.bullet_height)
        self.rect.centerx = ai_game.ship.rect.centerx
        self.rect.top = ai_game.ship.rect.top

        # 储存用小数表达的子弹的y
        self.y = float(self.rect.y)

        self.color = ai_game.setting.bullet_color
        self.speed = ai_game.setting.bullet_speed


    # 子弹的移动
    def update(self):
        #更新表示子弹位置的小数值
        self.y -= self.speed
        # 更新表示矩形y位置???
        self.rect.y = self.y

    def draw_bullet(self):
        # 在屏幕上绘制子弹
        pygame.draw.rect(self.screen,self.color,self.rect)


pygame 2.1.0 (SDL 2.0.16, Python 3.9.9)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
  File "D:\allien_work\allien_invasion.py", line 140, in <module>
    ai_game.run_game()
  File "D:\allien_work\allien_invasion.py", line 41, in run_game
    self._update_screen()
  File "D:\allien_work\allien_invasion.py", line 134, in _update_screen
    self.alliens.draw(self.screen)
  File "C:\Users\Lenovo\AppData\Roaming\Python\Python39\site-packages\pygame\sprite.py", line 546, in draw
    surface.blits((spr.image, spr.rect) for spr in sprites)
TypeError: invalid destination position for blit
[Finished in 2.5s]