0
\$\begingroup\$

I'm making my first game of Pygame. I'm going to create groups for making collisions but when I add an object to the group, I get an error in sprite.py (Pygame's Files)

AttributeError: 'pygame.Surface' object has no attribute 'add_internal'

Why I get this error?
There is a simplest way to make collisions?

There is my code:

import pygame
from pygame.locals import *
import sys
import os
import time
width = 950
height = 500
Game = False
GameOver = False
keyboard = pygame.key.get_pressed()[K_UP]
def main():
    pygame.init()
    screen = pygame.display.set_mode((width, height))
    pygame.display.set_caption('Flappy Dog')
    background = pygame.image.load(os.path.join("Images", "Background_00.png")).convert()
    FlappyDog = pygame.image.load(os.path.join("Images", "Flappy.png")).convert_alpha()
    Play = pygame.image.load(os.path.join("Images", "Play.png")).convert_alpha()
    Dog0 = pygame.image.load(os.path.join("Images", "Dog0.png")).convert_alpha()
    Dog1 = pygame.image.load(os.path.join("Images", "Dog1.png")).convert_alpha()
    SpikeUp0 = pygame.image.load(os.path.join("Images", "SpikeUp0.png")).convert_alpha()
    SpikeUp1 = pygame.image.load(os.path.join("Images", "SpikeUp1.png")).convert_alpha()
    SpikeDown0 = pygame.image.load(os.path.join("Images", "SpikeDown0.png")).convert_alpha()
    SpikeDown1 = pygame.image.load(os.path.join("Images", "SpikeDown1.png")).convert_alpha()
    GameOver = pygame.image.load(os.path.join("Images", "Game-Over.png")).convert_alpha()
    Replay = pygame.image.load(os.path.join("Images", "Replay.png")).convert_alpha()
    Bone = pygame.image.load(os.path.join("Images", "Bone.png")).convert_alpha()

    Game = True
    Dog1_pos_x = 100
    Dog1_pos_y = 100
    screen.blit(background, (0, 0))
    screen.blit(FlappyDog, (0, 0))
    screen.blit(Bone, (550, 100))
    screen.blit(Play, (600, 350))
    screen.blit(Dog0, (5, 240))
    bones = pygame.sprite.Group()
    bones.add(Bone) # <-- Error here
    Dog = pygame.sprite.Group()
    Dog.add(Dog1)
    pygame.display.update()


    while True:
        if GameOver == true:
            screen.blit(background, (0, 0))
            screen.blit(GameOver, (20, 50))
        if pygame.sprite.gropucollide(Dog, Bones, True, True):
            Game = False
            GameOver = True
        while Game == True:
            pygame.event.pump()
            if pygame.key.get_pressed()[K_UP]:
                for i in range(10): # Up
                    Dog1_pos_y = Dog1_pos_y -1
                    screen.blit(background, (0, 0))
                    screen.blit(Dog1, (Dog1_pos_x, Dog1_pos_y))
                    screen.blit(SpikeDown0, (0, 436))
                    screen.blit(SpikeUp0, (0, 0))
                    pygame.display.update()
                    pygame.time.delay(1)
            else: # Down
                Dog1_pos_y = Dog1_pos_y +1
                screen.blit(background, (0, 0))
                screen.blit(Dog1, (Dog1_pos_x, Dog1_pos_y))
                screen.blit(SpikeDown0, (0, 436))
                screen.blit(SpikeUp0, (0, 0))
                pygame.display.update()
                pygame.time.delay(1)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
                pygame.display.update()



if __name__ == "__main__":
    main()
\$\endgroup\$
  • \$\begingroup\$ Did you search for existing Q&A discussing similar errors? How have you tried applying these existing answers to your case? \$\endgroup\$ – DMGregory Mar 18 '19 at 18:42
  • \$\begingroup\$ Yes, In the first URL, in the code that is "fine", i'ts exactly the same, only that change the object name. I don't know why I obtain the error. \$\endgroup\$ – ArnauBG Mar 18 '19 at 19:50
  • \$\begingroup\$ So, like in the answer at the first link, you tried creating a Sprite object to add each image to, then add your sprites to the group? Where did this go wrong for you? \$\endgroup\$ – DMGregory Mar 18 '19 at 20:01
  • \$\begingroup\$ I dont know. Pygame says that the error is here bonesSpikes.add (SpikeDown0) and in a pygame file (Sprite.py) \$\endgroup\$ – ArnauBG Mar 18 '19 at 20:26
  • \$\begingroup\$ Right, because SpikeDown0 is a Surface, and you're trying to add it to a group made to contain Sprite objects. Did you follow the linked answer and try something like SpikeDown0Sprite = pygame.sprite.Sprite() SpikeDown0Sprite.image = SpikeDown0 ... boneSpikes.add(SpikeDown0Sprite)? \$\endgroup\$ – DMGregory Mar 18 '19 at 21:31
0
\$\begingroup\$

Programming languages like Python have types, which determine what you can do with which piece of data. Using each variable in a way that's appropriate to its type is like putting a round peg in a round hole, or a square peg into a square hole.

When you try to do an operation that expects one type, but you give it a different, incompatible type, that's trying to shove a square peg into a round hole. The computer won't be able to make sense of the operation and it will throw an error.

That's what you have happening here. bones = pygame.sprite.Group() tells the computer "bones is a group that holds Sprite objects" (ie. it's a round hole to put round pegs into)

Bone = pygame.image.load(os.path.join("Images", "Bone.png")).convert_alpha() tells the computer "Bone is a Surface object loaded from an image like so..." (ie. it's a square peg to put into a square hole)

bones.add(Bone) says "take that square peg (Surface) and shove it into that round hole (group of Sprite objects)"

So the computer errors-out and tells you that the Bone variable's type, pygame.Surface, does not have the shape that the bones variable's type, pygame.sprite.Group needs for its add method. It wants a Sprite that has an add_internal attribute, but you gave it a Surface which doesn't have that attribute.

AttributeError: 'pygame.Surface' object has no attribute 'add_internal'

So, first you need to make Sprite objects from the Surface objects you loaded from your images - think of it like an adapter to turn the square peg into a round peg - like so:

boneSprite = pygame.sprite.Sprite()
boneSprite.image = Bone
boneSprite.rect = Bone.get_rect()

Now that you have a Sprite that uses the Bone image, you can add it to your group like so:

bones.add(boneSprite)

This will not generate errors, because we're putting a round peg into a round hole now.

As described in the comments, this is all explained in existing answers, so please take the time to search for existing documentation and read it thoroughly to solve your problems faster in future.

\$\endgroup\$
  • \$\begingroup\$ Ok, thanks. But now says that 'Sprite' Object has no attribute 'get_rect' \$\endgroup\$ – ArnauBG Mar 24 '19 at 16:40
  • \$\begingroup\$ What exact line is throwing the error? \$\endgroup\$ – DMGregory Mar 24 '19 at 16:43
  • \$\begingroup\$ The line that produces the error is Bone.rect = Bone.image.get_rect() \$\endgroup\$ – ArnauBG Mar 24 '19 at 16:50
  • \$\begingroup\$ You're mixing types again. See how the object on the left in my example is called boneSprite? That's to help you keep track of the fact that it's a sprite, not the original Bone surface. You want something that looks like (some Sprite).rect = (some Surface).get_rect(). See how the object on the left and object on the right are two different types? So you can't use the same Bone variable in both places. \$\endgroup\$ – DMGregory Mar 24 '19 at 16:53
  • \$\begingroup\$ Ok, but now how can I blit it to the screen. Because says that I can't blit and sprite. Sorry for inconvenences \$\endgroup\$ – ArnauBG Mar 24 '19 at 17:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.