导语
>>> 这年头塔除了拆还能干什么?这款好玩上瘾的塔防游戏,了解一下!!
自从塔诞生的时候起,我们就开始让毁灭的雨点从敌人的头顶上方倾泻而下。
现在很多游戏都将塔作为一个标志性的象征,大众最熟悉的肯定是某鹅家招牌游戏里的防御塔了!
而今天我们谈的内容也跟塔有关,不卖关子了。
今天的推荐游戏是塔防游戏,它综合了策略,以及当你试着使用建立炮台防御抵,阻止敌人到达目
标的那种不小的紧张感。完整的项目源码免费的请见主页左侧!
来啊!来造房子啊!这款超耐玩的塔防游戏你都玩过吗?没玩过就对了,快跟我一起行动吧!
正文
一、准备中
1)保卫基地规则
这款保卫防御塔的小游戏它界定了塔防游戏共用的三个核心机制:
- 玩家需要不计一切代价保卫“基地(或基地的入口)”,基地被摧毁则游戏马上结束。
- 敌人将遵循一定路径,分批次对基地发起进攻。
- 玩家可以通过放置或操作不同功能的防御机制(比如炮塔这里是三款不同的),策略性地进行反击。
2)游戏思路
- 这款游戏3*3模式,主要分为三个大地图背景(不一样的界面敌人进攻路径),每个地图分为简单、中等、难度三个关卡,从简单到难。
- 敌人有一定的血量,需要一定的攻击力度才能消灭;基地也有一定的血量,进敌人会相应的减少血量达到一定的敌人基地就会毁灭。
- 初始化进入地图,会设置一定的金额给玩家,玩家需要按照自己策略摆放不同的炮台做防御,设置了三种不同的炮台价格、功能都是不一样的。
- 获取额外的金额需要消灭相应的敌人即可。
(参数都是可以大家自己设置的哈,比如:金额多给点儿、开挂无敌状态都靠自己编撒!)
3)环境安装
小编使用的环境:Python3、Pycharm社区版、Pygame模块部分自带。
模块安装:pip install -i https://pypi.douban.com/simple/ pygame
4)素材(仅部分)
其中图片素材、音乐背景素材等等还有很多就不展示了哈,完整的素材包+源码自己看主页左侧的信息自取。
二、开始敲代码
代码比较多的哈,如果文章懒得看,可以直接找我拿完整的项目自己慢慢研究也可。(仅部分)
1)配置文件
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'),
}
2)游戏开始界面
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
3)暂停游戏界面
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
4)游戏结束界面
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
5)游戏运行主程序
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("塔防游戏 ")
# 调用游戏开始界面
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)视频效果展示——![](https://i-blog.csdnimg.cn/blog_migrate/0006e7da07d036992e900a6c92912968.png)
来啊!来造房子啊!这款超耐玩的塔防游戏你都玩过吗?
2)截图效果展示——
游戏界面——
关卡——
游戏界面——
总结
于🐟茫茫人海相遇——感谢你的阅读!相遇即是缘分,如有帮助到你,记得三连哦~
我是木木子,一个不止能编程的女码农,还能教你玩游戏、制作节日惊喜、甚至撩小姐姐、小哥哥
哦......写在最后——往期也有很多精彩内容,欢迎阅读!关注我,每日更新💖💖
🎯完整的免费源码领取处:找我吖!文末可得自行领取,滴滴我也可!
🎉往期推荐阅读——
项目 1.0 《消灭病毒保卫城市》疫情防控小游戏
【Pygame实战】疫情期间给不能出门的你推荐一款爽游 《消灭病毒保卫城市》【强推】愿早日结束
项目 1.1 AI版《俄罗斯方块儿》小游戏
【普通玩家VS高手玩家】一带传奇游戏《俄罗斯方块儿》新作—实现AI自动玩游戏~
项目7.0 赛车游戏
【Pygame实战】如果你是赛车爱好者:这款新赛车游戏分分钟让你上瘾(超跑又是谁的梦想?)
项目7.1 虐单身狗游戏
🎄文章汇总——
项目1.0 Python—2021 |已有文章汇总 | 持续更新,直接看这篇就够了
(更多内容+源码都在文章汇总哦!!欢迎阅读~)