如何在PyGame塔防游戏中实现单塔攻击冷却(不暂停全局)
实现塔的独立攻击冷却机制
你当前通过两个塔对象(可见塔+透明塔)扩大碰撞范围,要实现单塔攻击冷却(攻击后等待一段时间再攻击,不暂停全局游戏),可以按以下方式修改代码:
核心修改思路
- 合并塔类:将
Tower和Tower2合并为一个Tower类,同时管理显示图像和攻击范围矩形,避免维护两个独立对象 - 添加冷却属性:给每个塔实例添加攻击间隔、上次攻击时间的属性,实现独立冷却
- 冷却判断逻辑:在检测到敌人进入范围时,判断当前时间是否满足冷却条件,满足才执行攻击并更新冷却计时
修改后的完整代码
import pygame import sys # 补充原代码缺失的常量定义 WIDTH = 800 HEIGHT = 600 BLACK = (0, 0, 0) WHITE = (255, 255, 255) GREEN = (0, 255, 0) LGREEN = (0, 200, 0) RED = (255, 0, 0) LRED = (200, 0, 0) BLUE = (0, 0, 255) LBLUE = (0, 0, 200) CYAN = (0, 255, 255) PURPLE = (128, 0, 128) LPURPLE = (150, 50, 150) COLORS = {} pygame.init() Mainclock = pygame.time.Clock() class Tower: def __init__(self, x, y, display_width=64, display_height=64, attack_range=150): # 显示用的图像与矩形 self.image = pygame.image.load("goku.png").convert_alpha() self.image = pygame.transform.smoothscale(self.image, (display_width, display_height)) self.display_rect = self.image.get_rect() self.display_rect.center = (x, y) # 攻击范围矩形(替代原Tower2的功能) self.attack_rect = pygame.Rect(0, 0, attack_range, attack_range) self.attack_rect.center = (x, y) # 冷却相关属性 self.attack_cooldown = 1000 # 攻击间隔,单位:毫秒(可自行调整) self.last_attack_time = 0 # 上次攻击的时间戳 def get_attack_rect(self): """获取攻击范围矩形的副本""" return self.attack_rect.copy() def can_attack(self): """判断当前是否可以发起攻击""" current_time = pygame.time.get_ticks() return current_time - self.last_attack_time >= self.attack_cooldown def update_attack_time(self): """更新上次攻击时间为当前时间""" self.last_attack_time = pygame.time.get_ticks() 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 = 500 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 self.rect.colliderect(other_rect) def get_rect(self): """获取自身矩形的副本""" 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)) # 加载背景图 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) self.mouse = pygame.mouse.get_pos() self.action_box_image = pygame.Surface((30,30)) # 占位,替换为实际图像 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, self.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 # 强制启动第一波敌人 while True: Mainclock.tick(60) self.mouse = pygame.mouse.get_pos() # 更新鼠标位置 for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() elif event.type == pygame.MOUSEBUTTONUP: # 创建单个塔对象,同时包含显示和攻击范围 mouse = pygame.mouse.get_pos() self.tower.append(Tower(mouse[0], mouse[1])) if self.startwave and len(self.enemy)==0: self.wave(10, 20, 8) self.startwave = False for i in range(len(self.enemy)-1, -1, -1): 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) 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(self.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.display_rect) button_text("Start next wave", 0, 600, WIDTH, 100, PURPLE, LPURPLE, self.wave) for tower in self.tower: for enemy in self.enemy: # 用攻击范围矩形检测碰撞,同时判断冷却是否完成 if enemy.collidesWith(tower.get_attack_rect()) and tower.can_attack(): print("COLLIDES WITH TOWER - ATTACKING") if enemy.health > 0: enemy.health -= 1 tower.update_attack_time() # 更新冷却计时 else: enemy.die() for i in range(len(self.enemy)-1, -1, -1): if self.enemy[i].isDead(): del(self.enemy[i]) pygame.display.update() def wave(self, quantity, size, distance): for i in range(quantity): saiba = Enemy(800 + (distance + size)*i, 100 - size/2, size, size) self.enemy.append(saiba) if __name__ == "__main__": MainWindow = Main() MainWindow.Intro()
关键修改说明
- 塔类合并:
Tower类现在同时管理显示图像和攻击范围矩形,创建塔时只需添加一个对象,简化了对象管理逻辑 - 冷却逻辑:每个塔拥有独立的冷却计时,
can_attack()方法判断是否满足攻击条件,攻击后调用update_attack_time()重置计时,实现单塔独立冷却 - 攻击检测:用塔的攻击范围矩形检测敌人,只有满足冷却条件时才会发起攻击,不会影响其他塔和游戏全局循环
内容的提问来源于stack exchange,提问作者omzy54
相关产品推荐
相关产品推荐

