Python 官方文档:入门教程 => 点击学习
这篇文章主要讲解了“python Pygame怎么实现塔防游戏”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python Pygame怎么实现塔防游戏”吧!一、环境要求w
这篇文章主要讲解了“python Pygame怎么实现塔防游戏”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python Pygame怎么实现塔防游戏”吧!
安装模块
pip install pyQt5pip install pygame
按照关卡,设计不同的塔防地图(博主只设计了三关,有兴趣的同学,学会之后,可以自己画地图),设置三种炮台,每种炮台发射不同的炮弹,每种炮弹对敌人杀伤力不一样,每种
炮台的价格也不一样。玩家通过钱币购买炮台,并设有剪出炮台的操作(有点类似植物大战僵尸里的铲子)。敌人成功抵达塔楼,游戏结束。
首先,先整理一下项目的主结构,其实看一下主结构,基本就清晰了
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'),}
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
在这里我们把游戏主界面初始化,并把三个难度的地图列出来,让玩家选择。
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
包括开始按钮,退出游戏等操作
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
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)
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
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
启动游戏主程序
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()
开发工具启动
如果你配置了开发工具的环境vscode、sublimeText、notepad+、PyCharm什么的,可以直接在工具中,运行游戏。
如果没配置,可以使用命令启动。
命令行启动 gif
进入代码根目录,按住shift+鼠标右键,选择 此处运行powershell,然后执行代码:python tower.py
即可 运行。
感谢各位的阅读,以上就是“Python Pygame怎么实现塔防游戏”的内容了,经过本文的学习后,相信大家对Python Pygame怎么实现塔防游戏这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!
--结束END--
本文标题: Python Pygame怎么实现塔防游戏
本文链接: https://lsjlt.com/news/324990.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0