Daniel
Daniel

Reputation: 15

Source object must be a surface

I am encountering a problem which says that the source object must be a surface. I asked this question before, and the answer worked, but now it's a different scenario. I looked at the previous question I had, and I couldn't figure out how to solve it.

Error Message:

Traceback (most recent call last):
File "C:\Users\Daniel\Desktop\Thing.py", line 22, in <module>
level.run()
File "C:\Users\Daniel\Desktop\level2.py", line 131, in run
self.clouds.draw(self.display_surface, self.world_shift)
File "C:\Users\Daniel\Desktop\decoration.py", line 67, in draw
self.cloud_sprites.draw(surface)
File "C:\Users\Daniel\AppData\Local\Programs\Python\Python310\lib\site- 
packages\pygame\sprite.py", line 551, in draw
self.spritedict.update(zip(sprites, surface.blits((spr.image, spr.rect) for 
spr in sprites)))
TypeError: Source objects must be a surface

Basically I am trying to blit things onto a surface, and the thing that confuses me the most is that it worked when I was trying to blit water onto the screen, it had the exact same code but instead of 'cloud' it had 'water', however the water blitting worked while the cloud did not.

Water Class:

class Water:
def __init__(self, top, level_width):
    water_start = -width
    water_tile_width = 192
    tile_x_amount = int((level_width + width) / water_tile_width)
    self.water_sprites = pygame.sprite.Group()

    for tile in range(tile_x_amount):
        x = tile * water_tile_width + water_start
        y = top
        sprite = AnimatedTile(192, x, y, (x, y), 
        'C:\\Desktop\\Game\\decoration\\water')
        self.water_sprites.add(sprite)


def draw(self, surface, shift):
    self.water_sprites.update(shift)
    self.water_sprites.draw(surface)

Cloud Class:

class Clouds:
def __init__(self, horizon, level_width, cloud_number):
    min_x = -width
    max_x = level_width + width 
    min_y = 0
    max_y = horizon
    cloud_surface_list = 'C:\\Desktop\\Game\\decoration\\clouds'
    self.cloud_sprites = pygame.sprite.Group()

    for cloud in range(cloud_number):
        cloud = choice(cloud_surface_list)
        x = randint(min_x, max_x)
        y = randint(min_y, max_y)
        sprite = StaticTile(0, x, y, (x, y), 
        'C:\\Desktop\\Game\\decoration\\clouds')
        self.cloud_sprites.add(sprite)

def draw(self, surface, shift):
    self.cloud_sprites.update(shift)
    self.cloud_sprites.draw(surface)

As you can see the draw method is the exact same code, pretty much. The only difference that I can spot that could be causing the problem would be the inheritance. Water inherits from a class called AnimatedTile while Clouds inherits from StaticTile. I will put the code for both of those here:

AnimatedTile:

class AnimatedTile(Tile):
def __init__(self, size, x, y, pos, path):
    super().__init__(size, x, y, (x, y))
    self.frames = import_folder(path)
    self.frame_index = 0
    self.image = self.frames[int(self.frame_index)]

def animate(self):
    self.frame_index += 0.15

    if self.frame_index >= 4:
        self.frame_index = 0

    self.image = self.frames[int(self.frame_index)]

def update(self, shift):
    self.animate()
    self.rect.x += shift

StaticTile:

class StaticTile(Tile):
def __init__(self, size, x, y, pos, surface):
    super().__init__(size, x, y, (x,y))
    self.image = surface
    self.surface = surface

Drawing and Updating:

self.clouds.draw(self.display_surface, 
self.world_shift)

*I know these are surfaces because I drew them the same exact way to blit the water onto the screen (self.water.draw(self.display_surface, self.world_shift) and it worked.

Other code:

class Level:
    def __init__(self, level_data, surface):

        self.display_surface = surface
        self.world_shift = -8

Tile:

class Tile(pygame.sprite.Sprite):
def __init__(self, size, x, y, pos):
    super().__init__()
    self.image = pygame.Surface((size, size))
    self.rect = self.image.get_rect(topleft = pos)

def update(self, shift):
    self.rect.x += shift

world_shift is basically how fast the level is moving (negative means right, positive means left)

I'm sorry if this sounds stupid and the answer is obvious.

Upvotes: 0

Views: 186

Answers (1)

Blckknght
Blckknght

Reputation: 104722

You're not correctly assigning to the image attribute of your StaticTile sprite in Clouds. I'm not sure if it's the caller (Clouds) or the tile class that is getting it wrong though, you'll have to decide what the API should be.

The mismatch is between your call, here:

sprite = StaticTile(0, x, y, (x, y), 
    'C:\\Desktop\\Game\\decoration\\clouds')

And the StaticTile.__init__ method, which is declared like this:

def __init__(self, size, x, y, pos, surface):
    super().__init__(size, x, y, (x,y))
    self.image = surface
    self.surface = surface

Note that the calling code is passing a string as the surface argument. That's similar to how AnimatedTile is initialized (with a path), but the StaticTile class expects a surface object to already be loaded.

Upvotes: 2

Related Questions