You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PyGame塔防游戏中实现单塔攻击冷却(不暂停全局)

实现塔的独立攻击冷却机制

你当前通过两个塔对象(可见塔+透明塔)扩大碰撞范围,要实现单塔攻击冷却(攻击后等待一段时间再攻击,不暂停全局游戏),可以按以下方式修改代码:

核心修改思路

  1. 合并塔类:将Tower和Tower2合并为一个Tower类,同时管理显示图像和攻击范围矩形,避免维护两个独立对象
  2. 添加冷却属性:给每个塔实例添加攻击间隔、上次攻击时间的属性,实现独立冷却
  3. 冷却判断逻辑:在检测到敌人进入范围时,判断当前时间是否满足冷却条件,满足才执行攻击并更新冷却计时

修改后的完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 07:45:20