Jack Hanson
Jack Hanson

Reputation: 321

Spawning multiple instances of a class at different x position pygame

I'm making a Pong clone in pygame, but I'm having trouble spawning the paddles. My paddle class looks like this:

class Paddle(pygame.sprite.Sprite, x_pos):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((20,70))
        self.image.fill(colors["WHITE"])
        self.rect = self.image.get_rect()
        self.rect.x = x_pos
        self.rect.y = SCREEN_HEIGHT/2
        self.y_speed = 0

And I try to spawn two of them at opposite sides of the screen with

player1 = Paddle(SCREEN_WIDTH - self.image.get_width() - 10) # Adjust for paddle width and border
player2 = Paddle(10)

But I get the error

Traceback (most recent call last):
  File "pypong.py", line 19, in <module>
    class Paddle(pygame.sprite.Sprite, x_pos):
NameError: name 'x_pos' is not defined

I tried replacing self.rect.x = x_pos with self.rect.x_pos = self.x_pos but I still get the same error. I thought I was getting the hang of OOP but this threw me for a loop. Can anybody help? Thanks in advance.

Upvotes: 2

Views: 232

Answers (1)

Ari Cooper-Davis
Ari Cooper-Davis

Reputation: 3485

So the class that you've defined has some issues, and I think it's worth going over some of the basics first and then having a look at your class second. I've split the answer up into those two sections, so you can skip ahead if you must.


A python class can "see" the variables that are passed to it or defined within it. We do that passing and defining in the __init__ method:

class Paddle:
    def __init__(self, x_pos):
        ...

Note that the class itself doesn't take any arguments (it doesn't even have brackets!). Instead we pass all of the arguments that we want to use in our class to the __init__ method! A class can be defined with brackets, but that's only when its a class that's based on another class, which is called a derived class:

class pygame.sprite.Sprite:
    def __init__(self, ...):
        ...

class Paddle(pygame.sprite.Sprite):
    def __init__(self, ...):
        ...

Next, we've seen that we can pass variables to classes via their __init__ methods, but how do we store them in the class as attributes and use them in the class methods (functions)? We do that by prepending class attributes with self. like so:

class Paddle(pygame.sprite.Sprite):
    def __init__(self, x_pos):
        ...
        self.x_position = x_pos

Now we can use that attribute in other methods in the class, not just in the __init__ method:

class Paddle(pygame.sprite.Sprite):
    def __init__(self, x_pos):
        ...
        self.x_position = x_pos

    def x_add_1(self):
        self.x_position += 1

The stuff inside the x_add_1() method knows about the x_position attribute because we passed self to the method, which is where the x_position attribute is stored (because we defined it as self.x_position).

So now we have a class, with an attribute (self.x_position) and a method (x_add_1), let's use it by creating an instance of the class:

class Paddle(pygame.sprite.Sprite):
    def __init__(self, x_pos):
        ...
        self.x_position = x_pos

    def x_add_1(self):
        self.x_position += 1

player_1 = Paddle(5)
print(player1.x_position)
> 5
player1.x_add_1()
print(player1.x_position)
> 6

Now you can see how we made an instance of the Paddle class, and passed it the x_pos value of 5. We then accessed the x_position attribute of our player_1 instance, and used the x_add_1 method too.


Now let's see where you've run into some trouble:

class Paddle(pygame.sprite.Sprite, x_pos):
    def __init__(self):
    ...

First of all, you've made Paddle a derived class of pygame.sprite.Sprite. This seems reasonable. But you've also passed it x_pos, which should be passed to the __init__ method, which you haven't passed anything! This is why you get your error that the x_pos isn't defined, because the __init__ method has been told to use it but hasn't been passed it.

But once we've fixed that we're still in trouble:

class Paddle(pygame.sprite.Sprite):
    def __init__(self, x_pos):
        ...
        self.image.fill(colors["WHITE"])
        self.rect.y = SCREEN_HEIGHT/2

Your class hasn't been told about a dictionary called colors, nor an integer called SCREEN_HEIGHT. To be able to use those it would have to be passed them when the class is being instantiated.

class Paddle(pygame.sprite.Sprite):
    def __init__(self, x_pos, colors, SCREEN_HEIGHT):
        ...
        self.image.fill(colors["WHITE"])
        self.rect.y = SCREEN_HEIGHT/2

You don't have to store those new variables as class attributes if you don't think that you'll use them outside of the __init__ method, but you could. For example you may want to make the paddle red when the ball hits it, in which case you will need to do make an attribute to store the colors dictionary:

class Paddle(pygame.sprite.Sprite):
    def __init__(self, x_pos, colors, SCREEN_HEIGHT):
        self.colors = colors
        ...
        self.image.fill(self.colors["WHITE"])
        self.rect.y = SCREEN_HEIGHT/2

    def paddle_hit(self):
        ...
        self.image.fill(self.colors["RED"])
        ...

That's probably all that you need to know to be able to fix your class. I haven't given you anything that you can copy and paste I'm afraid, but I've highlighted all of the problems that I can see (I think) and described how to fix them!

Upvotes: 2

Related Questions