千家信息网

Python Pygame怎么实现塔防游戏

发表于:2024-10-23 作者:千家信息网编辑
千家信息网最后更新 2024年10月23日,这篇文章主要讲解了"Python Pygame怎么实现塔防游戏",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Python Pygame怎么实现塔防游戏
千家信息网最后更新 2024年10月23日Python Pygame怎么实现塔防游戏

这篇文章主要讲解了"Python Pygame怎么实现塔防游戏",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Python Pygame怎么实现塔防游戏"吧!

    一、环境要求

    windows系统,python3.6+

    安装模块

    pip install pyqt5pip install pygame

    二、游戏介绍

    1、游戏目标

    按照关卡,设计不同的塔防地图(博主只设计了三关,有兴趣的同学,学会之后,可以自己画地图),设置三种炮台,每种炮台发射不同的炮弹,每种炮弹对敌人杀伤力不一样,每种

    炮台的价格也不一样。玩家通过钱币购买炮台,并设有剪出炮台的操作(有点类似植物大战僵尸里的铲子)。敌人成功抵达塔楼,游戏结束。

    2、先上游戏效果图

    三、完整开发流程

    1、项目主结构

    首先,先整理一下项目的主结构,其实看一下主结构,基本就清晰了

    2、详细配置

    config.py

    配置文件中,需要引入os模块,并且配置打开游戏的屏幕大小,并将资源中引用到的图片、音频插入到合适的位置。

    因为我们的迷宫游戏,需要划开模块。

    '''配置文件'''import os  '''屏幕大小'''SCREENSIZE = (800, 600)'''图片路径'''IMAGEPATHS = {    'choice': {        'load_game': os.path.join(os.getcwd(), 'resources/images/choice/load_game.png'),        'map1': os.path.join(os.getcwd(), 'resources/images/choice/map1.png'),        'map1_black': os.path.join(os.getcwd(), 'resources/images/choice/map1_black.png'),        'map1_red': os.path.join(os.getcwd(), 'resources/images/choice/map1_red.png'),        'map2': os.path.join(os.getcwd(), 'resources/images/choice/map2.png'),        'map2_black': os.path.join(os.getcwd(), 'resources/images/choice/map2_black.png'),        'map2_red': os.path.join(os.getcwd(), 'resources/images/choice/map2_red.png'),        'map3': os.path.join(os.getcwd(), 'resources/images/choice/map3.png'),        'map3_black': os.path.join(os.getcwd(), 'resources/images/choice/map3_black.png'),        'map3_red': os.path.join(os.getcwd(), 'resources/images/choice/map3_red.png'),    },    'end': {        'gameover': os.path.join(os.getcwd(), 'resources/images/end/gameover.png'),        'continue_red': os.path.join(os.getcwd(), 'resources/images/end/continue_red.png'),        'continue_black': os.path.join(os.getcwd(), 'resources/images/end/continue_black.png'),    },    'game': {        'arrow1': os.path.join(os.getcwd(), 'resources/images/game/arrow1.png'),         'arrow2': os.path.join(os.getcwd(), 'resources/images/game/arrow2.png'),         'arrow3': os.path.join(os.getcwd(), 'resources/images/game/arrow3.png'),         'basic_tower': os.path.join(os.getcwd(), 'resources/images/game/basic_tower.png'),         'boulder': os.path.join(os.getcwd(), 'resources/images/game/boulder.png'),         'bush': os.path.join(os.getcwd(), 'resources/images/game/bush.png'),         'cave': os.path.join(os.getcwd(), 'resources/images/game/cave.png'),         'dirt': os.path.join(os.getcwd(), 'resources/images/game/dirt.png'),         'enemy_blue': os.path.join(os.getcwd(), 'resources/images/game/enemy_blue.png'),         'enemy_pink': os.path.join(os.getcwd(), 'resources/images/game/enemy_pink.png'),         'enemy_red': os.path.join(os.getcwd(), 'resources/images/game/enemy_red.png'),         'enemy_yellow': os.path.join(os.getcwd(), 'resources/images/game/enemy_yellow.png'),         'godark': os.path.join(os.getcwd(), 'resources/images/game/godark.png'),         'golight': os.path.join(os.getcwd(), 'resources/images/game/golight.png'),         'grass': os.path.join(os.getcwd(), 'resources/images/game/grass.png'),         'healthfont': os.path.join(os.getcwd(), 'resources/images/game/healthfont.png'),         'heavy_tower': os.path.join(os.getcwd(), 'resources/images/game/heavy_tower.png'),         'med_tower': os.path.join(os.getcwd(), 'resources/images/game/med_tower.png'),         'nexus': os.path.join(os.getcwd(), 'resources/images/game/nexus.png'),         'othergrass': os.path.join(os.getcwd(), 'resources/images/game/othergrass.png'),         'path': os.path.join(os.getcwd(), 'resources/images/game/path.png'),         'rock': os.path.join(os.getcwd(), 'resources/images/game/rock.png'),         'tiles': os.path.join(os.getcwd(), 'resources/images/game/tiles.png'),         'unitfont': os.path.join(os.getcwd(), 'resources/images/game/unitfont.png'),         'water': os.path.join(os.getcwd(), 'resources/images/game/water.png'),         'x': os.path.join(os.getcwd(), 'resources/images/game/x.png'),     },    'pause': {        'gamepaused': os.path.join(os.getcwd(), 'resources/images/pause/gamepaused.png'),         'resume_black': os.path.join(os.getcwd(), 'resources/images/pause/resume_black.png'),         'resume_red': os.path.join(os.getcwd(), 'resources/images/pause/resume_red.png'),     },    'start': {        'play_black': os.path.join(os.getcwd(), 'resources/images/start/play_black.png'),         'play_red': os.path.join(os.getcwd(), 'resources/images/start/play_red.png'),         'quit_black': os.path.join(os.getcwd(), 'resources/images/start/quit_black.png'),         'quit_red': os.path.join(os.getcwd(), 'resources/images/start/quit_red.png'),         'start_interface': os.path.join(os.getcwd(), 'resources/images/start/start_interface.png'),     },}'''地图路径'''MAPPATHS = {    '1': os.path.join(os.getcwd(), 'resources/maps/1.map'),    '2': os.path.join(os.getcwd(), 'resources/maps/2.map'),    '3': os.path.join(os.getcwd(), 'resources/maps/3.map'),}'''字体路径'''FONTPATHS = {    'Calibri': os.path.join(os.getcwd(), 'resources/fonts/Calibri.ttf'),    'm04': os.path.join(os.getcwd(), 'resources/fonts/m04.ttf'),    'Microsoft Sans Serif': os.path.join(os.getcwd(), 'resources/fonts/Microsoft Sans Serif.ttf'),}'''不同难度的settings'''DIFFICULTYPATHS = {    'easy': os.path.join(os.getcwd(), 'resources/difficulties/easy.json'),    'hard': os.path.join(os.getcwd(), 'resources/difficulties/hard.json'),    'medium': os.path.join(os.getcwd(), 'resources/difficulties/medium.json'),}'''音频路径'''AUDIOPATHS = {    'bgm': os.path.join(os.getcwd(), 'resources/audios/bgm.mp3'),}

    3、定义敌人、塔楼、子弹的类

    turrent.py 以炮塔类为例

    炮塔首先需要初始化,即init函数,另外需要有射击属性、以及重置属性(即我们可以将已经建好的炮塔删除,然后重新添加)

    import pygamefrom .arrow import Arrow  '''炮塔类'''class Turret(pygame.sprite.Sprite):    def __init__(self, turret_type, cfg):        assert turret_type in range(3)        pygame.sprite.Sprite.__init__(self)        self.cfg = cfg        self.turret_type = turret_type        self.imagepaths = [cfg.IMAGEPATHS['game']['basic_tower'], cfg.IMAGEPATHS['game']['med_tower'], cfg.IMAGEPATHS['game']['heavy_tower']]        self.image = pygame.image.load(self.imagepaths[turret_type])        self.rect = self.image.get_rect()        # 箭        self.arrow = Arrow(turret_type, cfg)        # 当前的位置        self.coord = 0, 0        self.position = 0, 0        self.rect.left, self.rect.top = self.position        self.reset()    '''射击'''    def shot(self, position, angle=None):        arrow = None        if not self.is_cooling:            arrow = Arrow(self.turret_type, self.cfg)            arrow.reset(position, angle)            self.is_cooling = True        if self.is_cooling:            self.cool_time -= 1            if self.cool_time == 0:                self.reset()        return arrow    '''重置'''    def reset(self):        if self.turret_type == 0:            # 价格            self.price = 500            # 射箭的冷却时间            self.cool_time = 30            # 是否在冷却期            self.is_cooling = False        elif self.turret_type == 1:            self.price = 1000            self.cool_time = 50            self.is_cooling = False        elif self.turret_type == 2:            self.price = 1500            self.cool_time = 100            self.is_cooling = False

    4、游戏开始:选择难度地图

    在这里我们把游戏主界面初始化,并把三个难度的地图列出来,让玩家选择。

    import sysimport pygame  '''游戏选择主界面'''class MainInterface(pygame.sprite.Sprite):    def __init__(self, cfg):        pygame.sprite.Sprite.__init__(self)        self.image = pygame.image.load(cfg.IMAGEPATHS['choice']['load_game']).convert()        self.rect = self.image.get_rect()        self.rect.topleft = (0, 0)    '''更新函数'''    def update(self):        pass  '''地图1'''class MapButton1(pygame.sprite.Sprite):    def __init__(self, cfg, position=(175, 240)):        pygame.sprite.Sprite.__init__(self)        self.image_1 = pygame.image.load(cfg.IMAGEPATHS['choice']['map1_black']).convert()        self.image_2 = pygame.image.load(cfg.IMAGEPATHS['choice']['map1_red']).convert()        self.image_3 = pygame.image.load(cfg.IMAGEPATHS['choice']['map1']).convert()        self.image = self.image_1        self.rect = self.image.get_rect()        self.rect.center = position    '''更新函数: 不断地更新检测鼠标是否在按钮上'''    def update(self):        mouse_pos = pygame.mouse.get_pos()        if self.rect.collidepoint(mouse_pos):            self.image = self.image_2        else:            self.image = self.image_1  '''地图2'''class MapButton2(pygame.sprite.Sprite):    def __init__(self, cfg, position=(400, 240)):        pygame.sprite.Sprite.__init__(self)        self.image_1 = pygame.image.load(cfg.IMAGEPATHS['choice']['map2_black']).convert()        self.image_2 = pygame.image.load(cfg.IMAGEPATHS['choice']['map2_red']).convert()        self.image_3 = pygame.image.load(cfg.IMAGEPATHS['choice']['map2']).convert()        self.image = self.image_1        self.rect = self.image.get_rect()        self.rect.center = position    '''更新函数: 不断地更新检测鼠标是否在按钮上'''    def update(self):        mouse_pos = pygame.mouse.get_pos()        if self.rect.collidepoint(mouse_pos):            self.image = self.image_2        else:            self.image = self.image_1  '''地图3'''class MapButton3(pygame.sprite.Sprite):    def __init__(self, cfg, position=(625, 240)):        pygame.sprite.Sprite.__init__(self)        self.image_1 = pygame.image.load(cfg.IMAGEPATHS['choice']['map3_black']).convert()        self.image_2 = pygame.image.load(cfg.IMAGEPATHS['choice']['map3_red']).convert()        self.image_3 = pygame.image.load(cfg.IMAGEPATHS['choice']['map3']).convert()        self.image = self.image_1        self.rect = self.image.get_rect()        self.rect.center = position    '''更新函数: 不断地更新检测鼠标是否在按钮上'''    def update(self):        mouse_pos = pygame.mouse.get_pos()        if self.rect.collidepoint(mouse_pos):            self.image = self.image_2        else:            self.image = self.image_1  '''信息显示框'''class InfoBox(pygame.sprite.Sprite):    def __init__(self, position=(400, 475)):        pygame.sprite.Sprite.__init__(self)        self.ori_image = pygame.Surface((625, 200))        self.ori_image.fill((255, 255, 255))        self.ori_image_front = pygame.Surface((621, 196))        self.ori_image_front.fill((0, 0, 0))        self.ori_image.blit(self.ori_image_front, (2, 2))        self.rect = self.ori_image.get_rect()        self.rect.center = position    '''更新函数'''    def update(self, btns):        self.image = self.ori_image        mouse_pos = pygame.mouse.get_pos()        for btn in btns:            if btn.rect.collidepoint(mouse_pos):                self.image.blit(btn.image_3, (225, 25))                break  '''简单难度按钮'''class EasyButton(pygame.sprite.Sprite):    def __init__(self, cfg, position=(400, 150)):        pygame.sprite.Sprite.__init__(self)        self.image_1 = pygame.Surface((285, 100))        self.image_1_front = pygame.Surface((281, 96))        self.image_1.fill((255, 255, 255))        self.image_1_front.fill((0, 0, 0))        self.image_1.blit(self.image_1_front, (2, 2))        self.image_2 = pygame.Surface((285, 100))        self.image_2_front = pygame.Surface((281, 96))        self.image_2.fill((255, 255, 255))        self.image_2_front.fill((24, 196, 40))        self.image_2.blit(self.image_2_front, (2, 2))        self.text = 'easy'        self.font = pygame.font.Font(cfg.FONTPATHS['m04'], 42)        self.text_render = self.font.render(self.text, 1, (255, 255, 255))        self.image_1.blit(self.text_render, (60, 29))        self.image_2.blit(self.text_render, (60, 29))        self.image = self.image_1        self.rect = self.image.get_rect()        self.rect.center = position    '''更新函数: 不断地更新检测鼠标是否在按钮上'''    def update(self):        mouse_pos = pygame.mouse.get_pos()        if self.rect.collidepoint(mouse_pos):            self.image = self.image_2        else:            self.image = self.image_1  '''中等难度按钮'''class MediumButton(pygame.sprite.Sprite):    def __init__(self, cfg, position=(400, 300)):        pygame.sprite.Sprite.__init__(self)        self.image_1 = pygame.Surface((285, 100))        self.image_1_front = pygame.Surface((281, 96))        self.image_1.fill((255, 255, 255))        self.image_1_front.fill((0, 0, 0))        self.image_1.blit(self.image_1_front, (2, 2))        self.image_2 = pygame.Surface((285, 100))        self.image_2_front = pygame.Surface((281, 96))        self.image_2.fill((255, 255, 255))        self.image_2_front.fill((24, 30, 196))        self.image_2.blit(self.image_2_front, (2, 2))        self.text = 'medium'        self.font = pygame.font.Font(cfg.FONTPATHS['m04'], 42)        self.text_render = self.font.render(self.text, 1, (255, 255, 255))        self.image_1.blit(self.text_render, (15, 29))        self.image_2.blit(self.text_render, (15, 29))        self.image = self.image_1        self.rect = self.image.get_rect()        self.rect.center = position    '''更新函数: 不断地更新检测鼠标是否在按钮上'''    def update(self):        mouse_pos = pygame.mouse.get_pos()        if self.rect.collidepoint(mouse_pos):            self.image = self.image_2        else:            self.image = self.image_1  '''困难难度按钮'''class HardButton(pygame.sprite.Sprite):    def __init__(self, cfg, position=(400, 450)):        pygame.sprite.Sprite.__init__(self)        self.image_1 = pygame.Surface((285, 100))        self.image_1_front = pygame.Surface((281, 96))        self.image_1.fill((255, 255, 255))        self.image_1_front.fill((0, 0, 0))        self.image_1.blit(self.image_1_front, (2, 2))        self.image_2 = pygame.Surface((285, 100))        self.image_2_front = pygame.Surface((281, 96))        self.image_2.fill((255, 255, 255))        self.image_2_front.fill((196, 24, 24))        self.image_2.blit(self.image_2_front, (2, 2))        self.text = 'hard'        self.font = pygame.font.Font(cfg.FONTPATHS['m04'], 42)        self.text_render = self.font.render(self.text, 1, (255, 255, 255))        self.image_1.blit(self.text_render, (60, 29))        self.image_2.blit(self.text_render, (60, 29))        self.image = self.image_1        self.rect = self.image.get_rect()        self.rect.center = position    '''更新函数: 不断地更新检测鼠标是否在按钮上'''    def update(self):        mouse_pos = pygame.mouse.get_pos()        if self.rect.collidepoint(mouse_pos):            self.image = self.image_2        else:            self.image = self.image_1  '''游戏地图和困难选择界面'''class ChoiceInterface():    def __init__(self, cfg):        # part1        self.main_interface = MainInterface(cfg)        self.map_btn1 = MapButton1(cfg)        self.map_btn2 = MapButton2(cfg)        self.map_btn3 = MapButton3(cfg)        self.info_box = InfoBox()        # part2        self.easy_btn = EasyButton(cfg)        self.medium_btn = MediumButton(cfg)        self.hard_btn = HardButton(cfg)    '''外部调用'''    def update(self, screen):        clock = pygame.time.Clock()        # part1        self.map_btns = pygame.sprite.Group(self.map_btn1, self.map_btn2, self.map_btn3)        map_choice, difficulty_choice = None, None        while True:            clock.tick(60)            self.main_interface.update()            self.map_btns.update()            self.info_box.update(self.map_btns)            screen.blit(self.main_interface.image, self.main_interface.rect)            self.map_btns.draw(screen)            screen.blit(self.info_box.image, self.info_box.rect)            pygame.display.flip()            for event in pygame.event.get():                if event.type == pygame.QUIT:                    pygame.quit()                    sys.exit(0)                if event.type == pygame.MOUSEBUTTONDOWN:                    if event.button == 1:                        mouse_pos = pygame.mouse.get_pos()                        idx = 0                        for btn in self.map_btns:                            idx += 1                            if btn.rect.collidepoint(mouse_pos):                                map_choice = idx            if map_choice:                break        # part2        self.difficulty_btns = pygame.sprite.Group(self.easy_btn, self.medium_btn, self.hard_btn)        while True:            clock.tick(60)            screen.fill((0, 0, 0))            self.difficulty_btns.update()            self.difficulty_btns.draw(screen)            pygame.display.flip()            for event in pygame.event.get():                if event.type == pygame.QUIT:                    pygame.quit()                    sys.exit(0)                if event.type == pygame.MOUSEBUTTONDOWN:                    if event.button == 1:                        mouse_pos = pygame.mouse.get_pos()                        idx = 0                        for btn in self.difficulty_btns:                            idx += 1                            if btn.rect.collidepoint(mouse_pos):                                difficulty_choice = btn.text            if difficulty_choice:                break        return map_choice, difficulty_choice

    5、游戏开始界面

    包括开始按钮,退出游戏等操作

    start.py

    import sysimport pygame  '''游戏开始主界面'''class MainInterface(pygame.sprite.Sprite):    def __init__(self, cfg):        pygame.sprite.Sprite.__init__(self)        self.image = pygame.image.load(cfg.IMAGEPATHS['start']['start_interface']).convert()        self.rect = self.image.get_rect()        self.rect.center = cfg.SCREENSIZE[0] / 2, cfg.SCREENSIZE[1] / 2    '''更新函数'''    def update(self):        pass  '''开始游戏按钮'''class PlayButton(pygame.sprite.Sprite):    def __init__(self, cfg, position=(220, 415)):        pygame.sprite.Sprite.__init__(self)        self.image_1 = pygame.image.load(cfg.IMAGEPATHS['start']['play_black']).convert()        self.image_2 = pygame.image.load(cfg.IMAGEPATHS['start']['play_red']).convert()        self.image = self.image_1        self.rect = self.image.get_rect()        self.rect.center = position    '''更新函数: 不断地更新检测鼠标是否在按钮上'''    def update(self):        mouse_pos = pygame.mouse.get_pos()        if self.rect.collidepoint(mouse_pos):            self.image = self.image_2        else:            self.image = self.image_1  '''结束游戏按钮'''class QuitButton(pygame.sprite.Sprite):    def __init__(self, cfg, position=(580, 415)):        pygame.sprite.Sprite.__init__(self)        self.image_1 = pygame.image.load(cfg.IMAGEPATHS['start']['quit_black']).convert()        self.image_2 = pygame.image.load(cfg.IMAGEPATHS['start']['quit_red']).convert()        self.image = self.image_1        self.rect = self.image.get_rect()        self.rect.center = position    '''更新函数: 不断地更新检测鼠标是否在按钮上'''    def update(self):        mouse_pos = pygame.mouse.get_pos()        if self.rect.collidepoint(mouse_pos):            self.image = self.image_2        else:            self.image = self.image_1  '''游戏开始界面'''class StartInterface():    def __init__(self, cfg):        self.main_interface = MainInterface(cfg)        self.play_btn = PlayButton(cfg)        self.quit_btn = QuitButton(cfg)        self.components = pygame.sprite.LayeredUpdates(self.main_interface, self.play_btn, self.quit_btn)    '''外部调用'''    def update(self, screen):        clock = pygame.time.Clock()        while True:            clock.tick(60)            self.components.update()            self.components.draw(screen)            pygame.display.flip()            for event in pygame.event.get():                if event.type == pygame.QUIT:                    pygame.quit()                    sys.exit(0)                elif event.type == pygame.MOUSEBUTTONDOWN:                    if event.button == 1:                        mouse_pos = pygame.mouse.get_pos()                        if self.play_btn.rect.collidepoint(mouse_pos):                            return True                        elif self.quit_btn.rect.collidepoint(mouse_pos):                            return False

    6、游戏运行

    gaming.py

    import sysimport jsonimport mathimport randomimport pygamefrom ..sprites import Enemyfrom ..sprites import Turretfrom .pause import PauseInterfacefrom collections import namedtuple  '''游戏进行中界面'''class GamingInterface():    def __init__(self, cfg):        self.cfg = cfg        # 游戏地图大小        map_w = self.cfg.SCREENSIZE[0]        map_h = 500        # 按钮大小和位置        button_w = 60        button_h = 60        button_y = 520        # 间隙        gap = 20        # 按钮放在工具栏, 工具栏两端各有一个信息显示框        toolbar_w = gap * 7 + button_w * 6        info_w = (self.cfg.SCREENSIZE[0] - toolbar_w) // 2        info_h = self.cfg.SCREENSIZE[1] - map_h        toolbar_h = self.cfg.SCREENSIZE[1] - map_h        # 界面布置        self.map_rect = pygame.Rect(0, 0, map_w, map_h)        self.map_surface = pygame.Surface((map_w, map_h))        self.leftinfo_rect = pygame.Rect(0, map_h, info_w, info_h)        self.rightinfo_rect = pygame.Rect(self.cfg.SCREENSIZE[0] - info_w, map_h, info_w, info_h)        self.toolbar_rect = pygame.Rect(info_w, map_h, toolbar_w, toolbar_h)        # 草        self.grass = pygame.image.load(cfg.IMAGEPATHS['game']['grass'])        # 岩石(铺路用的)        self.rock = pygame.image.load(cfg.IMAGEPATHS['game']['rock'])        # 污垢        self.dirt = pygame.image.load(cfg.IMAGEPATHS['game']['dirt'])        # 水        self.water = pygame.image.load(cfg.IMAGEPATHS['game']['water'])        # 灌木        self.bush = pygame.image.load(cfg.IMAGEPATHS['game']['bush'])        # 纽带        self.nexus = pygame.image.load(cfg.IMAGEPATHS['game']['nexus'])        # 洞穴        self.cave = pygame.image.load(cfg.IMAGEPATHS['game']['cave'])        # 获取地图元素的大小,请保证素材库里组成地图的元素图大小一致        self.element_size = int(self.grass.get_rect().width)        # 一些字体        self.info_font = pygame.font.Font(cfg.FONTPATHS['Calibri'], 14)        self.button_font = pygame.font.Font(cfg.FONTPATHS['Calibri'], 20)        # 可以放炮塔的地方        self.placeable = {0: self.grass}        # 地图元素字典(数字对应.map文件中的数字)        self.map_elements = {            0: self.grass,            1: self.rock,            2: self.dirt,            3: self.water,            4: self.bush,            5: self.nexus,            6: self.cave        }        # 用于记录地图中的道路        self.path_list = []        # 当前的地图,将地图导入到这里面        self.current_map = dict()        # 当前鼠标携带的图标(即选中道具) -> [道具名, 道具]        self.mouse_carried = []        # 在地图上建造好了的炮塔        self.built_turret_group = pygame.sprite.Group()        # 所有的敌人        self.enemies_group = pygame.sprite.Group()        # 所有射出的箭        self.arrows_group = pygame.sprite.Group()        # 玩家操作用的按钮        Button = namedtuple('Button', ['rect', 'text', 'onClick'])        self.buttons = [            Button(pygame.Rect((info_w + gap), button_y, button_w, button_h), 'T1', self.takeT1),            Button(pygame.Rect((info_w + gap * 2 + button_w), button_y, button_w, button_h), 'T2', self.takeT2),            Button(pygame.Rect((info_w + gap * 3 + button_w * 2), button_y, button_w, button_h), 'T3', self.takeT3),            Button(pygame.Rect((info_w + gap * 4 + button_w * 3), button_y, button_w, button_h), 'XXX', self.takeXXX),            Button(pygame.Rect((info_w + gap * 5 + button_w * 4), button_y, button_w, button_h), 'Pause', self.pauseGame),            Button(pygame.Rect((info_w + gap * 6 + button_w * 5), button_y, button_w, button_h), 'Quit', self.quitGame)        ]    '''开始游戏'''    def start(self, screen, map_path=None, difficulty_path=None):        # 读取游戏难度对应的参数        with open(difficulty_path, 'r') as f:            difficulty_dict = json.load(f)        self.money = difficulty_dict.get('money')        self.health = difficulty_dict.get('health')        self.max_health = difficulty_dict.get('health')        difficulty_dict = difficulty_dict.get('enemy')        # 每60s生成一波敌人        generate_enemies_event = pygame.constants.USEREVENT + 0        pygame.time.set_timer(generate_enemies_event, 60000)        # 生成敌人的flag和当前已生成敌人的总次数        generate_enemies_flag = False        num_generate_enemies = 0        # 每0.5秒出一个敌人        generate_enemy_event = pygame.constants.USEREVENT + 1        pygame.time.set_timer(generate_enemy_event, 500)        generate_enemy_flag = False        # 防止变量未定义        enemy_range = None        num_enemy = None        # 是否手动操作箭塔射击        manual_shot = False        has_control = False        # 游戏主循环        while True:            if self.health <= 0:                return            for event in pygame.event.get():                if event.type == pygame.QUIT:                    self.quitGame()                if event.type == pygame.MOUSEBUTTONUP:                    # --左键选物品                    if event.button == 1:                        # ----鼠标点击在地图上                        if self.map_rect.collidepoint(event.pos):                            if self.mouse_carried:                                if self.mouse_carried[0] == 'turret':                                    self.buildTurret(event.pos)                                elif self.mouse_carried[0] == 'XXX':                                    self.sellTurret(event.pos)                        # ----鼠标点击在工具栏                        elif self.toolbar_rect.collidepoint(event.pos):                            for button in self.buttons:                                if button.rect.collidepoint(event.pos):                                    if button.text == 'T1':                                        button.onClick()                                    elif button.text == 'T2':                                        button.onClick()                                    elif button.text == 'T3':                                        button.onClick()                                    elif button.text == 'XXX':                                        button.onClick()                                    elif button.text == 'Pause':                                        button.onClick(screen)                                    elif button.text == 'Quit':                                        button.onClick()                                    break                    # --右键释放物品                    if event.button == 3:                        self.mouse_carried = []                    # --按中间键手动控制炮塔射箭方向一次,否则自由射箭                    if event.button == 2:                        manual_shot = True                if event.type == generate_enemies_event:                    generate_enemies_flag = True                if event.type == generate_enemy_event:                    generate_enemy_flag = True            # --生成敌人, 生成的敌人随当前已生成敌人的总次数的增加而变强变多            if generate_enemies_flag:                generate_enemies_flag = False                num_generate_enemies += 1                idx = 0                for key, value in difficulty_dict.items():                    idx += 1                    if idx == len(difficulty_dict.keys()):                        enemy_range = value['enemy_range']                        num_enemy = value['num_enemy']                        break                    if num_generate_enemies <= int(key):                        enemy_range = value['enemy_range']                        num_enemy = value['num_enemy']                        break            if generate_enemy_flag and num_enemy:                generate_enemy_flag = False                num_enemy -= 1                enemy = Enemy(random.choice(range(enemy_range)), self.cfg)                self.enemies_group.add(enemy)            # --射箭            for turret in self.built_turret_group:                if not manual_shot:                    position = turret.position[0] + self.element_size // 2, turret.position[1]                    arrow = turret.shot(position)                else:                    position = turret.position[0] + self.element_size // 2, turret.position[1]                    mouse_pos = pygame.mouse.get_pos()                    angle = math.atan((mouse_pos[1] - position[1]) / (mouse_pos[0] - position[0] + 1e-6))                    arrow = turret.shot(position, angle)                    has_control = True                if arrow:                    self.arrows_group.add(arrow)                else:                    has_control = False            if has_control:                has_control = False                manual_shot = False            # --移动箭和碰撞检测            for arrow in self.arrows_group:                arrow.move()                points = [(arrow.rect.left, arrow.rect.top), (arrow.rect.left, arrow.rect.bottom), (arrow.rect.right, arrow.rect.top), (arrow.rect.right, arrow.rect.bottom)]                if (not self.map_rect.collidepoint(points[0])) and (not self.map_rect.collidepoint(points[1])) and \                   (not self.map_rect.collidepoint(points[2])) and (not self.map_rect.collidepoint(points[3])):                    self.arrows_group.remove(arrow)                    del arrow                    continue                for enemy in self.enemies_group:                    if pygame.sprite.collide_rect(arrow, enemy):                        enemy.life_value -= arrow.attack_power                        self.arrows_group.remove(arrow)                        del arrow                        break            self.draw(screen, map_path)    '''将场景画到游戏界面上'''    def draw(self, screen, map_path):        self.drawToolbar(screen)        self.loadMap(screen, map_path)        self.drawMouseCarried(screen)        self.drawBuiltTurret(screen)        self.drawEnemies(screen)        self.drawArrows(screen)        pygame.display.flip()    '''画出所有射出的箭'''    def drawArrows(self, screen):        for arrow in self.arrows_group:            screen.blit(arrow.image, arrow.rect)    '''画敌人'''    def drawEnemies(self, screen):        for enemy in self.enemies_group:            if enemy.life_value <= 0:                self.money += enemy.reward                self.enemies_group.remove(enemy)                del enemy                continue            res = enemy.move(self.element_size)            if res:                coord = self.find_next_path(enemy)                if coord:                    enemy.reached_path.append(enemy.coord)                    enemy.coord = coord                    enemy.position = self.coord2pos(coord)                    enemy.rect.left, enemy.rect.top = enemy.position                else:                    self.health -= enemy.damage                    self.enemies_group.remove(enemy)                    del enemy                    continue            # 画血条            green_len = max(0, enemy.life_value / enemy.max_life_value) * self.element_size            if green_len > 0:                pygame.draw.line(screen, (0, 255, 0), (enemy.position), (enemy.position[0] + green_len, enemy.position[1]), 1)            if green_len < self.element_size:                pygame.draw.line(screen, (255, 0, 0), (enemy.position[0] + green_len, enemy.position[1]), (enemy.position[0] + self.element_size, enemy.position[1]), 1)            screen.blit(enemy.image, enemy.rect)    '''画已经建造好的炮塔'''    def drawBuiltTurret(self, screen):        for turret in self.built_turret_group:            screen.blit(turret.image, turret.rect)    '''画鼠标携带物'''    def drawMouseCarried(self, screen):        if self.mouse_carried:            position = pygame.mouse.get_pos()            coord = self.pos2coord(position)            position = self.coord2pos(coord)            # 在地图里再画            if self.map_rect.collidepoint(position):                if self.mouse_carried[0] == 'turret':                    screen.blit(self.mouse_carried[1].image, position)                    self.mouse_carried[1].coord = coord                    self.mouse_carried[1].position = position                    self.mouse_carried[1].rect.left, self.mouse_carried[1].rect.top = position                else:                    screen.blit(self.mouse_carried[1], position)    '''画工具栏'''    def drawToolbar(self, screen):        # 信息显示框        info_color = (120, 20, 50)        # --左        pygame.draw.rect(screen, info_color, self.leftinfo_rect)        left_title = self.info_font.render('Player info:', True, (255, 255, 255))        money_info = self.info_font.render('Money: ' + str(self.money), True, (255, 255, 255))        health_info = self.info_font.render('Health: ' + str(self.health), True, (255, 255, 255))        screen.blit(left_title, (self.leftinfo_rect.left + 5, self.leftinfo_rect.top + 5))        screen.blit(money_info, (self.leftinfo_rect.left + 5, self.leftinfo_rect.top + 35))        screen.blit(health_info, (self.leftinfo_rect.left + 5, self.leftinfo_rect.top + 55))        # --右        pygame.draw.rect(screen, info_color, self.rightinfo_rect)        right_title = self.info_font.render('Selected info:', True, (255, 255, 255))        screen.blit(right_title, (self.rightinfo_rect.left + 5, self.rightinfo_rect.top + 5))        # 中间部分        pygame.draw.rect(screen, (127, 127, 127), self.toolbar_rect)        for button in self.buttons:            mouse_pos = pygame.mouse.get_pos()            if button.rect.collidepoint(mouse_pos):                self.showSelectedInfo(screen, button)                button_color = (0, 200, 0)            else:                button_color = (0, 100, 0)            pygame.draw.rect(screen, button_color, button.rect)            button_text = self.button_font.render(button.text, True, (255, 255, 255))            button_text_rect = button_text.get_rect()            button_text_rect.center = (button.rect.centerx, button.rect.centery)            screen.blit(button_text, button_text_rect)    '''显示被鼠标选中按钮的作用信息'''    def showSelectedInfo(self, screen, button):        if button.text in ['T1', 'T2', 'T3']:            turret = Turret({'T1': 0, 'T2': 1, 'T3': 2}[button.text], self.cfg)            selected_info1 = self.info_font.render('Cost: ' + str(turret.price), True, (255, 255, 255))            selected_info2 = self.info_font.render('Damage: ' + str(turret.arrow.attack_power), True, (255, 255, 255))            selected_info3 = self.info_font.render('Affordable: ' + str(self.money >= turret.price), True, (255, 255, 255))            screen.blit(selected_info1, (self.rightinfo_rect.left + 5, self.rightinfo_rect.top + 35))            screen.blit(selected_info2, (self.rightinfo_rect.left + 5, self.rightinfo_rect.top + 55))            screen.blit(selected_info3, (self.rightinfo_rect.left + 5, self.rightinfo_rect.top + 75))        elif button.text == 'XXX':            selected_info = self.info_font.render('Sell a turret', True, (255, 255, 255))            screen.blit(selected_info, (self.rightinfo_rect.left + 5, self.rightinfo_rect.top + 35))        elif button.text == 'Pause':            selected_info = self.info_font.render('Pause game', True, (255, 255, 255))            screen.blit(selected_info, (self.rightinfo_rect.left + 5, self.rightinfo_rect.top + 35))        elif button.text == 'Quit':            selected_info = self.info_font.render('Quit game', True, (255, 255, 255))            screen.blit(selected_info, (self.rightinfo_rect.left + 5, self.rightinfo_rect.top + 35))    '''出售炮塔(半价)'''    def sellTurret(self, position):        coord = self.pos2coord(position)        for turret in self.built_turret_group:            if coord == turret.coord:                self.built_turret_group.remove(turret)                self.money += int(turret.price * 0.5)                del turret                break    '''建造炮塔'''    def buildTurret(self, position):        turret = self.mouse_carried[1]        coord = self.pos2coord(position)        position = self.coord2pos(coord)        turret.position = position        turret.coord = coord        turret.rect.left, turret.rect.top = position        if self.money - turret.price >= 0:            if self.current_map.get(turret.coord) in self.placeable.keys():                self.money -= turret.price                self.built_turret_group.add(turret)                if self.mouse_carried[1].turret_type == 0:                    self.mouse_carried = []                    self.takeT1()                elif self.mouse_carried[1].turret_type == 1:                    self.mouse_carried = []                    self.takeT2()                elif self.mouse_carried[1].turret_type == 2:                    self.mouse_carried = []                    self.takeT3()    '''拿炮塔1'''    def takeT1(self):        T1 = Turret(0, self.cfg)        if self.money >= T1.price:            self.mouse_carried = ['turret', T1]    '''拿炮塔2'''    def takeT2(self):        T2 = Turret(1, self.cfg)        if self.money >= T2.price:            self.mouse_carried = ['turret', T2]    '''拿炮塔3'''    def takeT3(self):        T3 = Turret(2, self.cfg)        if self.money >= T3.price:            self.mouse_carried = ['turret', T3]    '''出售炮塔'''    def takeXXX(self):        XXX = pygame.image.load(self.cfg.IMAGEPATHS['game']['x'])        self.mouse_carried = ['XXX', XXX]    '''找下一个路径单元'''    def find_next_path(self, enemy):        x, y = enemy.coord        # 优先级: 下右左上        neighbours = [(x, y+1), (x+1, y), (x-1, y), (x, y-1)]        for neighbour in neighbours:            if (neighbour in self.path_list) and (neighbour not in enemy.reached_path):                return neighbour        return None    '''将真实坐标转为地图坐标, 20个单位长度的真实坐标=地图坐标'''    def pos2coord(self, position):        return (position[0] // self.element_size, position[1] // self.element_size)    '''将地图坐标转为真实坐标, 20个单位长度的真实坐标=地图坐标'''    def coord2pos(self, coord):        return (coord[0] * self.element_size, coord[1] * self.element_size)    '''导入地图'''    def loadMap(self, screen, map_path):        map_file = open(map_path, 'r')        idx_j = -1        for line in map_file.readlines():            line = line.strip()            if not line:                continue            idx_j += 1            idx_i = -1            for col in line:                try:                    element_type = int(col)                    element_img = self.map_elements.get(element_type)                    element_rect = element_img.get_rect()                    idx_i += 1                    element_rect.left, element_rect.top = self.element_size * idx_i, self.element_size * idx_j                    self.map_surface.blit(element_img, element_rect)                    self.current_map[idx_i, idx_j] = element_type                    # 把道路记下来                    if element_type == 1:                        self.path_list.append((idx_i, idx_j))                except:                    continue        # 放洞穴和大本营        self.map_surface.blit(self.cave, (0, 0))        self.map_surface.blit(self.nexus, (740, 400))        # 大本营的血条        nexus_width = self.nexus.get_rect().width        green_len = max(0, self.health / self.max_health) * nexus_width        if green_len > 0:            pygame.draw.line(self.map_surface, (0, 255, 0), (740, 400), (740 + green_len, 400), 3)        if green_len < nexus_width:            pygame.draw.line(self.map_surface, (255, 0, 0), (740 + green_len, 400), (740 + nexus_width, 400), 3)        screen.blit(self.map_surface, (0, 0))        map_file.close()    '''暂停游戏'''    def pauseGame(self, screen):        pause_interface = PauseInterface(self.cfg)        pause_interface.update(screen)    '''退出游戏'''    def quitGame(self):        pygame.quit()        sys.exit(0)

    7、游戏暂停

    import sysimport pygame  '''游戏暂停主界面'''class MainInterface(pygame.sprite.Sprite):    def __init__(self, cfg):        pygame.sprite.Sprite.__init__(self)        self.image = pygame.image.load(cfg.IMAGEPATHS['pause']['gamepaused']).convert()        self.rect = self.image.get_rect()        self.rect.center = cfg.SCREENSIZE[0] / 2, cfg.SCREENSIZE[1] / 2    '''更新函数'''    def update(self):        pass  '''恢复游戏按钮'''class ResumeButton(pygame.sprite.Sprite):    def __init__(self, cfg, position=(391, 380)):        pygame.sprite.Sprite.__init__(self)        self.image_1 = pygame.image.load(cfg.IMAGEPATHS['pause']['resume_black']).convert()        self.image_2 = pygame.image.load(cfg.IMAGEPATHS['pause']['resume_red']).convert()        self.image = self.image_1        self.rect = self.image.get_rect()        self.rect.center = position    '''更新函数: 不断地更新检测鼠标是否在按钮上'''    def update(self):        mouse_pos = pygame.mouse.get_pos()        if self.rect.collidepoint(mouse_pos):            self.image = self.image_2        else:            self.image = self.image_1  '''游戏暂停界面'''class PauseInterface():    def __init__(self, cfg):        self.main_interface = MainInterface(cfg)        self.resume_btn = ResumeButton(cfg)        self.components = pygame.sprite.LayeredUpdates(self.main_interface, self.resume_btn)    '''外部调用'''    def update(self, screen):        clock = pygame.time.Clock()        background = pygame.Surface(screen.get_size())        count = 0        flag = True        while True:            count += 1            clock.tick(60)            self.components.clear(screen, background)            self.components.update()            if count % 10 == 0:                count = 0                flag = not flag            if flag:                self.components.draw(screen)            else:                screen.blit(self.main_interface.image, self.main_interface.rect)            pygame.display.flip()            for event in pygame.event.get():                if event.type == pygame.QUIT:                    pygame.quit()                    sys.exit(0)                elif event.type == pygame.MOUSEBUTTONDOWN:                    if event.button == 1:                        mouse_pos = pygame.mouse.get_pos()                        if self.resume_btn.rect.collidepoint(mouse_pos):                            return True

    8、游戏结束及分数

    import sysimport pygame  '''游戏结束主界面'''class MainInterface(pygame.sprite.Sprite):    def __init__(self, cfg):        pygame.sprite.Sprite.__init__(self)        self.image = pygame.image.load(cfg.IMAGEPATHS['end']['gameover']).convert()        self.rect = self.image.get_rect()        self.rect.center = cfg.SCREENSIZE[0] / 2, cfg.SCREENSIZE[1] / 2    '''更新函数'''    def update(self):        pass  '''继续游戏按钮'''class ContinueButton(pygame.sprite.Sprite):    def __init__(self, cfg, position=(400, 409)):        pygame.sprite.Sprite.__init__(self)        self.image_1 = pygame.image.load(cfg.IMAGEPATHS['end']['continue_black']).convert()        self.image_2 = pygame.image.load(cfg.IMAGEPATHS['end']['continue_red']).convert()        self.image = self.image_1        self.rect = self.image.get_rect()        self.rect.center = position    '''更新函数: 不断地更新检测鼠标是否在按钮上'''    def update(self):        mouse_pos = pygame.mouse.get_pos()        if self.rect.collidepoint(mouse_pos):            self.image = self.image_2        else:            self.image = self.image_1  '''游戏结束类'''class EndInterface():    def __init__(self, cfg):        self.main_interface = MainInterface(cfg)        self.continue_btn = ContinueButton(cfg)        self.components = pygame.sprite.LayeredUpdates(self.main_interface, self.continue_btn)    '''外部调用'''    def update(self, screen):        clock = pygame.time.Clock()        background = pygame.Surface(screen.get_size())        count = 0        flag = True        while True:            count += 1            clock.tick(60)            self.components.clear(screen, background)            self.components.update()            if count % 10 == 0:                count = 0                flag = not flag            if flag:                self.components.draw(screen)            else:                screen.blit(self.main_interface.image, self.main_interface.rect)            pygame.display.flip()            for event in pygame.event.get():                if event.type == pygame.QUIT:                    pygame.quit()                    sys.exit(0)                elif event.type == pygame.MOUSEBUTTONDOWN:                    if event.button == 1:                        mouse_pos = pygame.mouse.get_pos()                        if self.continue_btn.rect.collidepoint(mouse_pos):                            return True

    9、引入音频、图片、地图、难度json

    启动游戏主程序

    tower.py

    import cfgimport pygamefrom modules import *  '''主函数'''def main():    pygame.init()    pygame.mixer.init()    pygame.mixer.music.load(cfg.AUDIOPATHS['bgm'])    pygame.mixer.music.play(-1, 0.0)    pygame.mixer.music.set_volume(0.25)    screen = pygame.display.set_mode(cfg.SCREENSIZE)    pygame.display.set_caption("塔防游戏 -- hacklex")    # 调用游戏开始界面    start_interface = StartInterface(cfg)    is_play = start_interface.update(screen)    if not is_play:        return    # 调用游戏界面    while True:        choice_interface = ChoiceInterface(cfg)        map_choice, difficulty_choice = choice_interface.update(screen)        game_interface = GamingInterface(cfg)        game_interface.start(screen, map_path=cfg.MAPPATHS[str(map_choice)], difficulty_path=cfg.DIFFICULTYPATHS[str(difficulty_choice)])        end_interface = EndInterface(cfg)        end_interface.update(screen)  '''run'''if __name__ == '__main__':    main()

    四、游戏启动方法

    1、开发工具启动

    如果你配置了开发工具的环境VScode、sublimeText、notepad+、pycharm什么的,可以直接在工具中,运行游戏。

    如果没配置,可以使用命令启动。

    2、命令行启动 gif

    进入代码根目录,按住shift+鼠标右键,选择 此处运行powershell,然后执行代码:python tower.py

    即可 运行。

    感谢各位的阅读,以上就是"Python Pygame怎么实现塔防游戏"的内容了,经过本文的学习后,相信大家对Python Pygame怎么实现塔防游戏这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

    0