1

I went back to the first game I made in pygame and wanted to add sprites so I went into three different classes and changed the code to have them be sprites not blocks. Now whenever I run the code I get an error on the line all_sprites.draw(screen) with the error argument 1 must be pygame.Surface, not str I think I have incorrect syntax somewhere but most of it was copied from other working games. I have put the full code here and any help is appreciated. Thanks.

import pygame
import os
import random
import time

big_Jump = 1
small_Jump = 1

game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, "images")

class Player(pygame.sprite.Sprite):
    #How to make a player class
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join(img_folder, "ghost_sprite_right.png"))
        self.rect = pygame.Rect(50,630,50,50)
        all_sprites.add(self)

    def update(self):
        pass

    def move(self,dx,dy):
        if dx != 0:
            self.move_single_axis(dx,0)
            if dx >0:
                self.image = pygame.image.load(os.path.join(img_folder, "ghost_sprite_right.png"))
            if dx <0:
                self.image = pygame.image.load(os.path.join(img_folder, "ghost_sprite_left.png"))
        if dy != 0:
            self.move_single_axis(0,dy)

    def move_single_axis(self,dx,dy):

        self.rect.x += dx
        self.rect.y += dy
        for wall in walls:
            if self.rect.colliderect(wall.rect):
                global big_Jump
                global small_Jump
                #big_Jump = 1
                #small_Jump = 1
                #print("Big Jump :",big_Jump,"\n"+"Small Jump :",small_Jump)
                if dx>0:
                    self.rect.right = wall.rect.left
                    big_Jump = 1
                    small_Jump = 1
                if dx<0:
                    self.rect.left = wall.rect.right
                    big_Jump = 1
                    small_Jump = 1
                if dy>0:
                    self.rect.bottom = wall.rect.top
                    big_Jump = 1
                    small_Jump = 1
                if dy<0:
                    self.rect.top = wall.rect.bottom
                    #big_Jump = 1
                    #small_Jump = 1



class Wall(pygame.sprite.Sprite):
    def __init__(self,wx,wy):
        pygame.sprite.Sprite.__init__(self)
        self.image = os.path.join(img_folder,"brick_wall.png")
        self.rect = pygame.Rect(wx,wy,30,30)
        walls.append(self)
        all_sprites.add(self)
    def update(self):
        pass

class DBlock(pygame.sprite.Sprite):
    def __init__(self,wx,wy):
        pygame.sprite.Sprite.__init__(self)
        self.image = os.path.join(img_folder,"spike.jpg")
        self.rect = pygame.Rect(wx,wy,30,30)
        DBlocks.append(self)
        all_sprites.add(self)
    def update(self):
        pass

class RandomBlock(object):
    def __init__(self,wx,wy):
        RBlocks.append(self)
        self.rect = pygame.Rect(wx,wy,30,30)

class WhiteFlag(object):
    def __init__(self,wx,wy):
        WFlags.append(self)
        self.rect = pygame.Rect(wx,wy,30,30)

class BlackFlag(object):
    def __init__(self,wx,wy):
        BFlags.append(self)
        self.rect = pygame.Rect(wx,wy,30,30)

def text_objects(text,font):
    textSurface = font.render(text,True,(0,0,0))
    return textSurface, textSurface.get_rect()

def message_display(text,top,left,size):
    my_text = pygame.font.Font("freesansbold.ttf",size)
    text_surface,text_rect = text_objects(text,my_text)
    text_rect.center = ((top),(left))
    screen.blit(text_surface,text_rect)





#Start pygame
os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()

#Adding music
#pygame.mixer.music.load("Sounds/background_music.mp3")
#pygame.mixer.music.play(-1)
#Set up the display
WIDTH = 840
HEIGHT = 720

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("A Sqaure on a Mission") #Title of the window
all_sprites = pygame.sprite.Group()

clock = pygame.time.Clock()

walls = []
DBlocks = []
RBlocks = []
BFlags = []
WFlags = []
playBlock = 60
player = Player() #Create a player object using the class
colour = (0,128,255)



#In this level W means wall, D mean death block, C means coin and E means exit

levels = [[
"WWWWWWWWWWWWWWWWWWWWWWWWWWWW",
"W           D      D     BwB",
"W           D      D     wBw",
"W           D            BwB",
"WW     W    D         WWWWWW",
"W      D          WWWWRRRRRW",
"W      D          DRRRRRRRRW",
"W      D          DRRRRRRRRW",
"W     WWWWWWWWWWWWWWWWWWWWWW",
"W                          W",
"W                          W",
"W                          W",
"WWWWWWW                   WW",
"WRRRRRD                    W",
"WRRRRRD                    W",
"WWWWWWDDDDDWWWWWWWD        W",
"W                          W",
"W                          W",
"W                          W",
"W     WWWWWW            WWWW",
"W                    WWWRRRW",
"W                  WWRRRRRRW",
"W                WWRRRRRRRRW",
"WWWWWWWWWDDDDWWWWWWWWWWWWWWW"
],[
"WWWWWWWWWWWWWWWWWWWWWWWWWWWW",
"                           W",
"                           W",
"                           W",
"WWWWW                 WWWWWW",
"WRRRRWW             WWRRRRRW",
"WRRRRRRWW         WWRRRRRRRW",
"WRRRRRRRRWW     WWRRRRRRRRRW",
"WRRRRRRRRRWW   WWRRRRRRRRRRW",
"WRRRRRRRRRRD   DRRRRRRRRRRRW",
"WRRRRRRRRRRD   DRRRRRRRRRRRW",
"WRRRRRRRRRRD   DRRRRRRRRRRRW",
"WRRRRRRRRRRD   DWWWWWWWWWWWW",
"WRRRRRRRRRRD               W",
"WRRRRRRRRRRD               W",
"WWWWWWWWWWWWWWWWWWWWW   DDDW",
"W           D              W",
"W           D              W",
"W                         DW",
"WDD    D         D       DDW",
"W      WWWWWWWWWWWWWWWWWWWWW",
"W           BwBwDRRRRRRRRRRW",
"W           wBwBDRRRRRRRRRRW",
"WWWWWWWWWWWWBwBwWWWWWWWWWWWW"
],[
"WWWWWWWWWWWWD  DWWWWWWWWWWWW",
"W          DD  DD          W",
"W                          W",
"W                          W",
"W          WWWWWW          W",
"W      DWWWRRRRRRWWWD      W",
"W     DDWRRRRRRRRRRWDD     W",
"W      DWWWWWWWWWWWWD      W",
"W            WD            W",
"W            DW            W",
"W            WD            W",
"WDDD         DW         DDDW",
"W         DDDWDDDD         W",
"W            DW            W",
"W            WD            W",
"W      DDWWWWDWWWWWDD      W",
"W            WD            W",
"W            DW            W",
"W            WD            W",
"WWWWD      DDDWDD      DWWWW",
"BwB          WD          wBw",
"wBw          DW          BwB",
"BwB          WD          wBw",
"WWWWWWWWWWWWWWWWWWWWWWWWWWWW"
],[
"WWWWWWWWWWWWWWWWWWWWWWWWWWWW",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"                           W",
"                           W",
"                           W",
"WWWWWWWWWWWWWWWWWWWWWWWWWWWW"
],[
],[
"WWWWWWWWWWWWWWWWWWWWWWWWWWWW",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                          W",
"W                           ",
"W                           ",
"W                           ",
"WWWWWWWWWWWWWWWWWWWWWWWWWWWW"
]]
screen.fill((0,0,0))
message_display("Hello, you're a Ghost and your on a mission,",380,300,20)
message_display("use the arrow keys and space bar for a big jump",380,330,20)
message_display("to get to the checkered flags.",400,360,20)
pygame.display.flip()
time.sleep(1)

#Start the gameplay
running = True

x=y=0
for row in levels[0]:
    for col in row:
        if col == "W":
            Wall(x,y)
        if col == "D":
            DBlock(x,y)
        if col == "R":
            RandomBlock(x,y)
        if col == "w":
            WhiteFlag(x,y)
        if col == "B":
            BlackFlag(x,y)
        x += 30
    y += 30
    x=0
Red = random.randint(0,255)
Green = random.randint(0,255)
Blue = random.randint(0,255)
levelnum = 0
velocity = 5
while running:
    #print(player.rect.x,",",player.rect.y,",",velocity)
    #print(velocity)

    clock.tick(75)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False



        if(event.type == pygame.KEYDOWN) and (event.key == pygame.K_RETURN):
            if colour == (0,128,255):
                colour = (255,100,0)
            else:
                colour = (0,128,255)



    user_input = pygame.key.get_pressed()

    if user_input[pygame.K_UP] and player.rect.y > 0 and small_Jump == 1: #Adds borders
        velocity = -10
        small_Jump = 0


    if user_input[pygame.K_SPACE] and player.rect.y > 0 and big_Jump == 1 : #Adds borders
        velocity = -15
        big_Jump = 0


    if player.rect.y < (HEIGHT-playBlock)and velocity > -21 and velocity <=5:
        player.move(0,velocity)
        if velocity != 5:
            velocity += 1
        if player.rect.y > (HEIGHT-65):
            player.move(0,660-player.rect.y) #Makes sure it cant go past the bottom of  the screen

    if user_input[pygame.K_DOWN] and player.rect.y < (HEIGHT-playBlock):
        player.move(0,2)

    if user_input[pygame.K_LEFT] and player.rect.x >0:
        player.move(-5,0)


    if user_input[pygame.K_RIGHT] and player.rect.x<WIDTH-playBlock:
        player.move(5,0)

    for a in DBlocks:
        if player.rect.colliderect(a):
            small_Jump = 1
            big_Jump = 1
            if levelnum == 0:
                player.rect.x = 50
                player.rect.y = 625
            if levelnum == 1:
                player.rect.x = 10
                player.rect.y = 45
            if levelnum ==2:
                player.rect.x = 390
                player.rect.y = 60





    if player.rect.x >WIDTH-playBlock-1 or player.rect.y >720-playBlock-1:
        del walls[:]
        del DBlocks[:]
        del RBlocks[:]
        del WFlags[:]
        del BFlags[:]
        Red = random.randint(0,255)
        Green = random.randint(0,255)
        Blue = random.randint(0,255)
        x=y=0
        levelnum += 1
        #message_display("Level :"+str(levelnum),380,30,25)
        for row in levels[levelnum]:
            for col in row:
                if col == "W":
                    Wall(x,y)
                if col == "D":
                    DBlock(x,y)
                if col == "R":
                    RandomBlock(x,y)
                if col == "w":
                    WhiteFlag(x,y)
                if col == "B":
                    BlackFlag(x,y)
                x += 30
            y += 30
            x=0

        if levelnum ==4:
            screen.fill((0,0,0))
            message_display("Well done, you completed your mission Mr.Ghost!",380,350,30)
            pygame.display.flip()
            time.sleep(5)
            running = False
        elif levelnum == 1:
            player.rect.x = 10
            player.rect.y = 45
        elif levelnum == 2:
            player.rect.x = 390
            player.rect.y = 5


    #Draw the screen
    screen.fill((70,70,70))

    for wall in walls:
        pygame.draw.rect(screen,(200,200,200),wall.rect)
    for a in DBlocks:
        pygame.draw.rect(screen,(255,0,0),a.rect)
    for b in RBlocks:
        pygame.draw.rect(screen,(Red,Blue,Green),b.rect)
    for c in WFlags:
        pygame.draw.rect(screen,(255,255,255),c.rect)
    for d in BFlags:
        pygame.draw.rect(screen,(0,0,0),d.rect)
    pygame.draw.rect(screen,colour,player.rect)

    message_display(("Level "+str(levelnum+1)+" of 4"),380,20,25)

    all_sprites.update()
    all_sprites.draw(screen)
    pygame.display.flip()



pygame.quit()

Sam318
  • 63
  • 3
  • Can you please explain, if its to do with you not having the sprite .png files then you can use any or I can send you the ones I use. I cannot remove them from the code to make it work for anyone though as the sprites are what the problem is based around. – Sam318 Jun 05 '20 at 00:22

1 Answers1

0

Ok, that's a difficult bug to notice!

Traceback (most recent call last):
  File "./square_dash.py", line 429, in <module>
    all_sprites.draw(screen)
  File "/usr/lib/python3/dist-packages/pygame/sprite.py", line 476, in draw
    self.spritedict[spr] = surface_blit(spr.image, spr.rect)
TypeError: argument 1 must be pygame.Surface, not str

The bug is caused by your code when drawing all the sprites, but it doesn't actually trigger the error until inside the PyGame code.

So the issue is you've used a string for something that should be a surface. That, and it was triggered by calling Sprite.update() for all your sprites. This led me to start looking at the images you're loading into your various sprite.image member variables of all sprites.

The first couple were OK, but then there's this:

class Wall(pygame.sprite.Sprite):
    def __init__(self,wx,wy):
        global all_sprites
        pygame.sprite.Sprite.__init__(self)
        self.image = os.path.join(img_folder,"wall.png")   # <--HERE
        self.rect = pygame.Rect(wx,wy,30,30)
        walls.append(self)
        all_sprites.add(self)

Can you see the bug? You're not loading an image, just assigning self.image to be the string path to the image. You probably wanted:

self.image = pygame.image.load( os.path.join(img_folder, "wall.png" ) )

This exact same bug is present in DBlock too.

The self.image isn't used until that first Sprite.draw() is called, this is why the error doesn't come up until then. If you'd coded the typical self.rect = self.image.get_rect() it would have failed early in a very obvious place.

Kingsley
  • 14,398
  • 5
  • 31
  • 53
  • Yep you were exactly right and thanks so much. I see it now and thanks for explaining the problem as it makes a lot of sense now. I just made the adjustments you said and the game works! Thanks for all your help :) – Sam318 Jun 05 '20 at 10:57