Home > Enterprise >  I am trying to get the rectangles in two different classes to collide but in pygame but it doesn
I am trying to get the rectangles in two different classes to collide but in pygame but it doesn

Time:09-09

My code works for the most part, but I don't know how to access the rectangles of the tower and enemy classes outside of these classes. Then I would like to use collisions as a way of deleting the enemy class, later I will change it to a health bar system. It is supposed to be a tower defense game. I have been trying to figure out how to do the collision for some time. Could anyone help me such that I can finally move on to a level system and health bars and login system. Any tips will be greatly appreciated. Thank you!

def wave(quantity, size, distance):
    global saiba
    hh = True
    for i in range(quantity):
        saiba = Enemy(800   (distance   size)*i, 100- size/2, size, size)
        MainWindow.enemy.append(saiba)

def button_tower(x, y, width, height, mouse, click, image, action = None):
    if x width > mouse[0] > x and y height > mouse[1] > y:
        if click[0] == 1 and action != None:
            MainWindow.action_box = action

def tower(width=30, height=30):
    global goku
    goku = Tower(MainWindow.mouse[0], MainWindow.mouse[1], width, height)
    MainWindow.tower.append(goku)

class Main:


    def __init__(self, width = WIDTH 100, height = HEIGHT   100):
        pygame.display.set_caption('DBZ Tower Defense')
        self.startwave = False
        self.width = width
        self.height = height
        self.Gamewindow = pygame.display.set_mode((self.width, self.height))

    def wave(self):
        self.startwave = True

    def Intro(self):
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()

            self.Gamewindow.fill(BLACK)
            largeText = pygame.font.Font('freesansbold.ttf', 30)
            TextSurf, TextRect = text_objects("simple tower defense game", largeText)
            TextRect = (100, 100)
            self.Gamewindow.blit(TextSurf, TextRect)


            button_text("New game", 100, 200, 400, 50, GREEN, LGREEN, MainWindow.MainLoop)
            button_text("Continue", 100, 300, 400, 50, RED, LRED)
            button_text("Exit", 100, 400, 400, 50, BLUE, LBLUE, quit)
            pygame.display.update()

    def MainLoop(self):
        self.enemy = []
        self.tower = []

        self.action_box = None
        while True:
            Mainclock.tick(60)

            self.mouse = pygame.mouse.get_pos()
            self.click = pygame.mouse.get_pressed()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()
                if event.type == pygame.KEYDOWN:
                    if event.key == ord('t'):
                        tower()
            
            if self.startwave == True and len(self.enemy)==0:
                wave(10, 20, 8)
                self.startwave = False
        
        
        
            **tt = self.enemy.rect.colliderect(self.tower.rect)
            if tt:
            del self.enemy[index]**
        
        

            for index,ene in enumerate(self.enemy):
            
                ene.update()
                ene.move()
                if ene.rect.left <= 0:
                    del self.enemy[index]
        
        

            self.Gamewindow.fill(CYAN)
            self.Gamewindow.blit(light_image_map1, background_rectangle)
            button_tower(800, 0, 50, 50, self.mouse, self.click, fantower_image, tower)

            if pygame.mouse.get_pressed()[0] == 1 and self.action_box != None:
                rectangle30 = pygame.Rect(self.mouse[0]-15, self.mouse[1]-15, 30, 30)
                self.Gamewindow.blit(action_box_image, rectangle30)
            elif self.action_box != None:
                self.action_box()
                self.action_box = None
            for object_enemy in self.enemy:
                self.Gamewindow.blit(fantower_image, object_enemy.rect)
            for object_tower in self.tower:
                self.Gamewindow.blit(object_tower.image, object_tower.rect)

            button_text("Start next wave", 0, 600, WIDTH, 100, PURPLE, LPURPLE, MainWindow.wave)
            pygame.display.update()


class Enemy:
    def __init__(self, x, y, width, height):
        self.rect = pygame.Rect(x, y, width, height)
        self.dir = 4
        self.movement = [(810, 100, 2), (810, 300, 4), (575, 300, 8), (575, 230, 4), (385, 230, 2), (385, 300, 4), (276, 300, 2), (276, 392, 4), (70, 392, 8), (70, 300, 4)]

   def move(self): 
       if self.dir == 8:
           self.rect.centery -= 1
        if self.dir == 4:
           self.rect.centerx -= 1
       if self.dir == 6:
           self.rect.centerx  = 1
       if self.dir == 2:
           self.rect.centery  = 1

    def update(self):
        for pos in self.movement:
             if self.rect.center == (pos[0], pos[1]):
                self.dir = pos[2]

    def color(self, colorid):
        return COLORS[colorid]




class Tower:
    def __init__(self, x, y, width, height):
        self.rect = pygame.Rect(x-15, y-15, width, height)
        self.image = pygame.transform.scale(tower1, (50, 50))

        def colliderec(self):
            if self.rect.collidedict(self.rect):
                print("true")

CodePudding user response:

There's a couple of issues, but let's start with the base question:

I don't know how to access the rectangles of the tower and enemy classes outside of the class

One of the important ideas of Objects is that you generally don't directly-access the internal items. It's more that you "hide" the internal operation, such that a set of similar objects can present a consistent interface to the outside code. For example the testCollision( a_rect ) function of a circular object might be different to that of a rectangular one, but the user of the functions only needs to know that you pass a rect, and get a boolean returned. The secrets of how the collision works is hidden.

Thinking about this, we can modify the Tower and Enemy objects the same:

class Enemy:
    # ...
    def collidesWith( self, other_rect ):
        """ Return true, if other_rect overlaps my rect """
        result = self.rect.colliderect( other_rect )

    def get_rect( self ):
        """ Get a copy of the rect, in PyGame style """
        return self.rect.copy()

We try not to access the internals of the object directly. The idea is to pass what's needed into member functions, and have it work on itself.

[...] use collisions as a way of deleting the enemy class

You already have a list of Tower and a list of Enemy, assuming that a collision of the two, results in the death of the Enemy. But currently there is no support for this, so lets add it:

class Enemy:
    def __init__( self ):
        # etc...
        self.dead = False   # not dead = alive

    # Is this enemy alive
    def die( self, action=True ):
        self.dead = action

    def isDead( self ):
        return self.dead

And now use it:

for tower in self.tower:
    tower_rect = tower.get_rect()
    for enemy in self.enemy:
        if ( enemy.collidesWith( tower_rect ) ):
            # Make enemy dead
            enemy.die()

This marks some elements of the self.enemy list as "dead". Then it's a simple loop to remove them:

for i in range( len( self.enemy ) - 1, -1, -1):   # note: loop backwards
    if ( self.enemy[i].isDead() ):
        del( self.enemy[i] )

Notice that we loop backwards. This is so we can delete items from the list while iterating. If the code uses an increasing iteration, it will skip items whenever something is deleted (and then crash at the end).

  • Related