您好,登錄后才能下訂單哦!
這篇文章主要講解了“Python Pygame怎么實現塔防游戲”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Python Pygame怎么實現塔防游戲”吧!
windows系統,python3.6+
安裝模塊
pip install pyqt5 pip 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 pygame from .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 sys import 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 sys import 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 sys import json import math import random import pygame from ..sprites import Enemy from ..sprites import Turret from .pause import PauseInterface from 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 sys import 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 sys import 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 cfg import pygame from 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怎么實現塔防游戲這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。