【问题标题】:I dont know how to stop my tower from attacking in a tower defence game, someone helped me with a functions canAttack and attack, but i dont know how我不知道如何在塔防游戏中阻止我的塔攻击,有人帮我提供了可以攻击和攻击的功能,但我不知道如何
【发布时间】:2022-10-13 08:46:26
【问题描述】:

目的是实现一个冷却系统,这样我的塔就不会在不停止整个程序的情况下尽可能多地攻击,正如我所说的 canAttack 和攻击功能是别人给我的,但我不知道如何使用它们在我的课程中,为了修复冷却时间,我没有任何射弹,只是碰撞触发了攻击,对于长代码感到抱歉,但这都是必要的。我尝试过但失败了,我的尝试仍然存在。

import sys
import pygame
import threading

WIDTH = 800
HEIGHT= 600


RED = (150, 0, 0)
LRED = (255, 0, 0)
GREEN = (0, 150, 0)
LGREEN = (0, 255, 0)
BLUE = (0, 0, 150)
LBLUE = (0, 0, 255)
CYAN=(0x00, 0xff, 0xff)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
PURPLE = (150, 0, 150)
LPURPLE = (255, 0, 255)
COLORS = [RED, LRED, GREEN, LGREEN, BLUE, LBLUE, WHITE, PURPLE, LPURPLE]

pygame.init()
Mainclock = pygame.time.Clock()


action_box_image = pygame.image.load('goku.png')
fantower_image = pygame.image.load('saibaman1.png')

class Tower:
    def __init__(self, x, y, width, height):
        self.image = pygame.image.load( "goku.png" ).convert_alpha()
        self.image = pygame.transform.smoothscale( self.image, ( width, height  ) )
        self.rect = self.image.get_rect()
        self.rect.center = ( x, y )
        self.next_attack_time = 0

    COOLDOWN = 1200

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

    def canAttack( self ):
        """ Has the attack cooldown-period expired """
        time_now = pygame.time.get_ticks()
        if ( time_now > self.next_attack_time ):
            return True
        else:
            return False

    def attack( self, opponent ):
        """ The tower is attacking the opponent """
        if ( self.canAttack() ):
            self.next_attack_time = pygame.time.get_ticks() + Tower.COOLDOWN
            ### TODO: Whatever needs to be done for an attack
            ### Maybe create and return a projectile, change the Tower image, etc.
            return True  # New projectile, whatever
        else:
            return None  # Cooldown is still running; no attack


    

class Tower2:
    def __init__(self, x, y, width, height):
        self.image = pygame.image.load( "invis.png" )
        self.image = pygame.transform.smoothscale( self.image, ( width, height  ) )
        self.rect = self.image.get_rect()
        self.rect.center = ( x, y )
        self.next_attack_time = 0

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

    def canAttack( self ):
        """ Has the attack cooldown-period expired """
        time_now = pygame.time.get_ticks()
        if ( time_now > self.next_attack_time ):
            return True
        else:
            return False

    def attack( self, opponent ):
        """ The tower is attacking the opponent """
        if ( self.canAttack() ):
            self.next_attack_time = pygame.time.get_ticks() + Tower.COOLDOWN
            ### TODO: Whatever needs to be done for an attack
            ### Maybe create and return a projectile, change the Tower image, etc.
            return True  # New projectile, whatever
        else:
            return None  # Cooldown is still running; no attack

    
class Enemy:
    def __init__(self, x, y, width, height):
        self.dead = False
        self.dir = 4
        self.movement = [(810, 100, 2), (810, 350, 4), (620, 350, 8), (620, 275, 4), (410, 275, 2), (410, 350, 4), (298, 350, 2), (298, 450, 4), (80, 450, 8), (80, 350, 4)]
        self.image = pygame.image.load( "saibaman1.png" ).convert_alpha()
        self.image = pygame.transform.smoothscale( self.image, ( width, height ) )
        self.rect = self.image.get_rect()
        self.rect.topleft = ( x, y )
        self.health = 50

     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]

    def die( self, action=True ):
        self.dead = action

    def isDead( self ):
        return self.dead

    def collidesWith( self, other_rect ):
        """ Return true, if other_rect overlaps my rect """
        return self.rect.colliderect( other_rect )

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

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 text_objects(text, font):
    textSurface = font.render(text, True, WHITE)
    return textSurface, textSurface.get_rect()

def button_text(msg, x, y, width, height, mouselse, mouseover, action = None, Text = True):
    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()

    if x+width > mouse[0] > x and y+height > mouse[1] > y:
        pygame.draw.rect(MainWindow.Gamewindow, mouseover,(x,y,width,height))
        if click[0] == 1 and action != None:
            action()
        else:
            pygame.draw.rect(MainWindow.Gamewindow, mouselse,(x,y,width,height))

    smallText = pygame.font.Font("freesansbold.ttf", 20)
    textSurf, textRect = text_objects(msg, smallText)
    textRect.center = ((x+(width/2)), (y+(height/2)))
    MainWindow.Gamewindow.blit(textSurf, textRect)


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))
        # Load images
        self.light_image_map1 = pygame.image.load( "Kami_lookout.png" ).convert_alpha() 
        self.light_image_map1 = pygame.transform.smoothscale( self.light_image_map1, ( width, height ) )
        self.background_rectangle = self.light_image_map1.get_rect()
        self.background_rectangle.topleft = (0,0)


    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

        self.startwave = True   # Don't have button code, force start

        while True:
            Mainclock.tick(60)
        
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()
                elif ( event.type == pygame.MOUSEBUTTONUP ):
                    # create a tower where the mouse was clicked
                    mouse = pygame.mouse.get_pos()
                    click = pygame.mouse.get_pressed()
                    self.tower.append( Tower( mouse[0], mouse[1], 64, 64 ) )
                    self.tower.append( Tower2( mouse[0], mouse[1], 150, 150 ) )
            
            if self.startwave == True and len(self.enemy)==0:
                self.wave(10, 20, 8) 
                self.startwave = False
        
            for i in range( len( self.enemy ) - 1, -1, -1):   # note: loop backwards
                self.enemy[i].update()
                self.enemy[i].move()
                if ( self.enemy[i].rect.left <= 0 ):
                    del( self.enemy[i] )
        
            self.Gamewindow.fill(CYAN)
            self.Gamewindow.blit(self.light_image_map1, self.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(object_enemy.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)
            ll = 0
        
            for tower in self.tower:
                for enemy in self.enemy:
                    if ( enemy.collidesWith( tower.get_rect() ) and Tower2.canAttack(self)):
                        # Make enemy dead
                        print("COLLIDES WITH TOWER")
                        #ll = ll + 1
                        #if ll > 2:
                        if enemy.health != 0:
                            enemy.health = enemy.health - 1
                        else: enemy.die()
                            #ll = 0
                        pp = pygame.time.get_ticks()
                        print(pp)
                    
                    
                    
                        
                    
        
            for i in range( len( self.enemy ) - 1, -1, -1):   # note: loop backwards
                if ( self.enemy[i].isDead() ):
                    del( self.enemy[i] )

            pygame.display.update()

    def wave( self, quantity, size, distance):    # <<-- Made member function of MainWindow
        global saiba
        hh = True
        for i in range(quantity):
            saiba = Enemy(800 + (distance + size)*i, 100- size/2, size, size)
            self.enemy.append(saiba)


# MAIN
MainWindow = Main()
MainWindow.MainLoop()

【问题讨论】:

    标签: python pygame


    【解决方案1】:

    目前 Tower 类中的 COOLDOWN 变量设置为 1200。由于 pygame.time.get_ticks() 使用毫秒,所以这个 1200 表示 1.2 秒。因此,如果您希望冷却时间更长,请增加 COOLDOWN 变量,看看是否有帮助。

    【讨论】:

    • 这个答案没有意义,我没有问如何增加冷却时间我问我如何才能让冷却时间起作用
    • @omzy54 你的塔现在多久攻击一次?比如每次攻击之间等待多少秒。
    • 它根本不等待,只要代码正在运行,它就会永远攻击,这就是我试图阻止的
    • @omzy54 我想知道它是否每秒都会持续发射。如果是这样,它本质上是在再次射击之前“停止”1 秒钟。这就是为什么我建议增加 1200 值以查看是否有帮助。当它实际上已经在使用 1 秒的“冷却时间”时,它可能看起来像是在永远攻击。
    • 它每秒触发多次
    【解决方案2】:

    所以有几个问题:

    首先是代码是针对 Tower 函数的“定义”(Tower2.canAttack())调用的,而不是在一个 Tower 的实例“实时副本”(tower.canAttack())上调用。

    for tower in self.tower:
        for enemy in self.enemy:
            if ( enemy.collidesWith( tower.get_rect() ) and Tower2.canAttack(self)):   # <<-- HERE
                # Make enemy dead
                print("COLLIDES WITH TOWER")
    

    用对象的实例替换它可以修复它:

    for tower in self.tower:
        for enemy in self.enemy:
            if ( enemy.collidesWith( tower.get_rect() ) and tower.canAttack()):   # <<-- HERE
                # Make enemy dead
                print("COLLIDES WITH TOWER")
    

    不同之处在于Tower2 就像对象的“模板”,您可以制作对象的“实时副本”——称为“实例”。这就是构造函数所做的(通过调用Tower2.__init__())~

    my_tower = Tower2( 10, 10, 64, 64 )
    

    在上述行中,my_tower实例Tower2。所以通常你使用my_tower 一旦它被构建。在某些情况下,您可能会在类定义上调用函数(“静态函数”),但这超出了此答案的范围。现在坚持使用您的 my_tower 实例。

    所以第二个问题是冷却是一个两步的过程。一旦您检查tower 是否可以使用tower.canAttack() 进行攻击,那么您需要注册攻击发生在tower.attack( enemy ) 上。将这个(和一些调试)添加到代码中可以使冷却工作。

                for tower in self.tower:
                    for enemy in self.enemy:
                        if ( enemy.collidesWith( tower.get_rect() ) ):
                            if ( tower.canAttack()):
                                tower.attack( enemy )        # <<-- HERE, note attack time
                                # Make enemy dead
                                print("COLLIDES WITH TOWER")
                                ### code omitted for brevity
                            else:
                                print( "tower can't attack (cooldown)" );
    

    调用.attack(enemy) 计算下一个允许的攻击时间,所以没有它,攻击总是有效的。

    import sys
    import pygame
    import threading
    
    WIDTH = 800
    HEIGHT= 600
    
    
    RED = (150, 0, 0)
    LRED = (255, 0, 0)
    GREEN = (0, 150, 0)
    LGREEN = (0, 255, 0)
    BLUE = (0, 0, 150)
    LBLUE = (0, 0, 255)
    CYAN=(0x00, 0xff, 0xff)
    WHITE = (255, 255, 255)
    BLACK = (0, 0, 0)
    PURPLE = (150, 0, 150)
    LPURPLE = (255, 0, 255)
    COLORS = [RED, LRED, GREEN, LGREEN, BLUE, LBLUE, WHITE, PURPLE, LPURPLE]
    
    pygame.init()
    Mainclock = pygame.time.Clock()
    
    
    action_box_image = pygame.image.load('tower1.png')
    fantower_image = pygame.image.load('tower2.png')
    
    class Tower:
        def __init__(self, x, y, width, height):
            self.image = pygame.image.load( "tower1.png" ).convert_alpha()
            self.image = pygame.transform.smoothscale( self.image, ( width, height  ) )
            self.rect = self.image.get_rect()
            self.rect.center = ( x, y )
            self.next_attack_time = 0
    
        COOLDOWN = 1200
    
        def get_rect( self ):
            """ Get a copy of the rect, in PyGame style """
            return self.rect.copy()
    
        def canAttack( self ):
            """ Has the attack cooldown-period expired """
            time_now = pygame.time.get_ticks()
            if ( time_now > self.next_attack_time ):
                return True
            else:
                return False
    
        def attack( self, opponent ):
            """ The tower is attacking the opponent """
            if ( self.canAttack() ):
                self.next_attack_time = pygame.time.get_ticks() + Tower.COOLDOWN
                ### TODO: Whatever needs to be done for an attack
                ### Maybe create and return a projectile, change the Tower image, etc.
                return True  # New projectile, whatever
            else:
                return None  # Cooldown is still running; no attack
    
    
        
    
    class Tower2:
        COOLDOWN = 1200
    
        def __init__(self, x, y, width, height):
            self.image = pygame.image.load( "Castle.png" )
            self.image = pygame.transform.smoothscale( self.image, ( width, height  ) )
            self.rect = self.image.get_rect()
            self.rect.center = ( x, y )
            self.next_attack_time = 0
    
        def get_rect( self ):
            """ Get a copy of the rect, in PyGame style """
            return self.rect.copy()
    
        def canAttack( self ):
            """ Has the attack cooldown-period expired """
            time_now = pygame.time.get_ticks()
            if ( time_now > self.next_attack_time ):
                return True
            else:
                return False
    
        def attack( self, opponent ):
            """ The tower is attacking the opponent """
            if ( self.canAttack() ):
                self.next_attack_time = pygame.time.get_ticks() + Tower.COOLDOWN
                ### TODO: Whatever needs to be done for an attack
                return True  # New projectile, whatever
            else:
                return False  # Cooldown is still running; no attack
    
        
    class Enemy:
        def __init__(self, x, y, width, height):
            self.dead = False
            self.dir = 4
            self.movement = [(810, 100, 2), (810, 350, 4), (620, 350, 8), (620, 275, 4), (410, 275, 2), (410, 350, 4), (298, 350, 2), (298, 450, 4), (80, 450, 8), (80, 350, 4)]
            self.image = pygame.image.load( "tower2.png" ).convert_alpha()
            self.image = pygame.transform.smoothscale( self.image, ( width, height ) )
            self.rect = self.image.get_rect()
            self.rect.topleft = ( x, y )
            self.health = 50
    
        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]
    
        def die( self, action=True ):
            self.dead = action
    
        def isDead( self ):
            return self.dead
    
        def collidesWith( self, other_rect ):
            """ Return true, if other_rect overlaps my rect """
            return self.rect.colliderect( other_rect )
    
        def get_rect( self ):
            """ Get a copy of the rect, in PyGame style """
            return self.rect.copy()
    
    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 text_objects(text, font):
        textSurface = font.render(text, True, WHITE)
        return textSurface, textSurface.get_rect()
    
    def button_text(msg, x, y, width, height, mouselse, mouseover, action = None, Text = True):
        mouse = pygame.mouse.get_pos()
        click = pygame.mouse.get_pressed()
    
        if x+width > mouse[0] > x and y+height > mouse[1] > y:
            pygame.draw.rect(MainWindow.Gamewindow, mouseover,(x,y,width,height))
            if click[0] == 1 and action != None:
                action()
            else:
                pygame.draw.rect(MainWindow.Gamewindow, mouselse,(x,y,width,height))
    
        smallText = pygame.font.Font("freesansbold.ttf", 20)
        textSurf, textRect = text_objects(msg, smallText)
        textRect.center = ((x+(width/2)), (y+(height/2)))
        MainWindow.Gamewindow.blit(textSurf, textRect)
    
    
    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))
            # Load images
            self.light_image_map1 = pygame.image.load( "background.png" ).convert_alpha() 
            self.light_image_map1 = pygame.transform.smoothscale( self.light_image_map1, ( width, height ) )
            self.background_rectangle = self.light_image_map1.get_rect()
            self.background_rectangle.topleft = (0,0)
    
    
        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
    
            self.startwave = True   # Don't have button code, force start
    
            while True:
                Mainclock.tick(60)
            
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        sys.exit()
                    elif ( event.type == pygame.MOUSEBUTTONUP ):
                        # create a tower where the mouse was clicked
                        mouse = pygame.mouse.get_pos()
                        click = pygame.mouse.get_pressed()
                        self.tower.append( Tower( mouse[0], mouse[1], 64, 64 ) )
                        self.tower.append( Tower2( mouse[0], mouse[1], 150, 150 ) )
                
                if self.startwave == True and len(self.enemy)==0:
                    self.wave(10, 20, 8) 
                    self.startwave = False
            
                for i in range( len( self.enemy ) - 1, -1, -1):   # note: loop backwards
                    self.enemy[i].update()
                    self.enemy[i].move()
                    if ( self.enemy[i].rect.left <= 0 ):
                        del( self.enemy[i] )
            
                self.Gamewindow.fill(CYAN)
                self.Gamewindow.blit(self.light_image_map1, self.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(object_enemy.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)
                ll = 0
            
                for tower in self.tower:
                    for enemy in self.enemy:
                        if ( enemy.collidesWith( tower.get_rect() ) ):
                            if ( tower.canAttack()):
                                tower.attack( enemy )
                                # Make enemy dead
                                print("COLLIDES WITH TOWER")
                                #ll = ll + 1
                                #if ll > 2:
                                if enemy.health != 0:
                                    enemy.health = enemy.health - 1
                                else: enemy.die()
                                    #ll = 0
                                pp = pygame.time.get_ticks()
                                print(pp)
                            else:
                                print( "tower can't attack (cooldown)" );
                            
                            
                        
                            
                        
            
                for i in range( len( self.enemy ) - 1, -1, -1):   # note: loop backwards
                    if ( self.enemy[i].isDead() ):
                        del( self.enemy[i] )
    
                pygame.display.update()
    
        def wave( self, quantity, size, distance):    # <<-- Made member function of MainWindow
            global saiba
            hh = True
            for i in range(quantity):
                saiba = Enemy(800 + (distance + size)*i, 100- size/2, size, size)
                self.enemy.append(saiba)
    
    
    # MAIN
    MainWindow = Main()
    MainWindow.MainLoop()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-09
      • 1970-01-01
      • 2017-03-31
      • 2021-11-03
      • 2021-10-13
      相关资源
      最近更新 更多