Search code examples
pythonpygamebuilder

Problems with builder pattern in Python


I want to create a User Fish and Enemy Fish from the same base class Fish. However, as I learned, with this code below when I try to change the Enemy Fish attributes, my User Fish attributes end up changing as well:

# base class
class Fish(object):
    def __init__(self, type="None", size=(1, 1), position=(1, 1), speed=1,
                 direction=1):
        self.type = type
        self.size = size
        self.position = position
        self.speed = speed
        self.direction = direction

    def draw(self):
        raise NotImplementedError

# user fish builder: generates new user fish
class Create_User_Fish(Fish):
    Fish.type = "User"
    Fish.size = (150, 100)
    Fish.position = (20, 200)

    def draw(self):
        pygame.draw.ellipse(DISPLAYSURF, BLUE, (Fish.position, Fish.size))

# enemy fish builder: generates new enemy fish
class Create_Enemy_Fish(Fish):
    Fish.type = "Enemy"
    Fish.size = (150, 100)
    Fish.position = (750, 200)

    def draw(self):
        pygame.draw.ellipse(DISPLAYSURF, BLUE, (Fish.position, Fish.size))

# snippet of calls I make before running my game
Player = Create_User_Fish()
Player.draw()

When I change the Fish.position under the class Create_Enemy_Fish, this changes the Fish.position of my User Fish too. Tips?


Solution

  • The attributes in the object Fish like self.type, self.size are instance attribute, but there are additional class attributes set to the class Fish like Fish.type, Fish.size, ... (The assignment of thes attributes is done in after class Create_User_Fish respectively class Create_Enemy_Fish). The class attributes exists only once in the class Fish, the 2nd writing overwrites the 1st one.

    You've to add a constructor to the classes Create_User_Fish respectively Create_Enemy_Fish and to do a super() call to the constructor of the inherited class Fish, to set the instance attributes. Us the instance attributes in the method draw:

    class Create_User_Fish(Fish):
    
        def __init__(self):
            super().__init__("User", (150, 100), (20, 200)) 
    
        def draw(self):
            pygame.draw.ellipse(DISPLAYSURF, BLUE, (self.position, self.size))
    
    class Create_Enemy_Fish(Fish):
    
        def __init__(self):
            super().__init__("Enemy", (150, 100), (750, 200)) 
    
        def draw(self):
            pygame.draw.ellipse(DISPLAYSURF, BLUE, (self.position, self.size))