脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - Python Pygame实战之塔防游戏的实现

Python Pygame实战之塔防游戏的实现

2022-11-04 10:41LexSaints Python

这篇文章主要介绍了如何利用Python中的Pygame模块制作简单的塔防小游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起动手试一试

一、环境要求

windows系统,python3.6+

安装模块

?
1
2
pip install pyqt5
pip install pygame

二、游戏介绍

1、游戏目标

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

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

2、先上游戏效果图

Python Pygame实战之塔防游戏的实现

三、完整开发流程

1、项目主结构

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

Python Pygame实战之塔防游戏的实现

2、详细配置

config.py

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
'''配置文件'''
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、定义敌人、塔楼、子弹的类

Python Pygame实战之塔防游戏的实现

turrent.py 以炮塔类为例

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
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

5、游戏开始界面

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

start.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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

6、游戏运行

gaming.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
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)

7、游戏暂停

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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

8、游戏结束及分数

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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

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

启动游戏主程序

tower.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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实战之塔防游戏的实现的详细内容,更多关于Python Pygame塔防游戏的资料请关注服务器之家其它相关文章!

原文链接:https://lexsaints.blog.csdn.net/article/details/115672270

延伸 · 阅读

精彩推荐
  • Pythonpython3获取当前文件的上一级目录实例

    python3获取当前文件的上一级目录实例

    下面小编就为大家分享一篇python3获取当前文件的上一级目录实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    a13633246211042021-02-06
  • Pythonpython买卖股票的最佳时机(基于贪心/蛮力算法)

    python买卖股票的最佳时机(基于贪心/蛮力算法)

    这篇文章主要介绍了python买卖股票的最佳时机(基于贪心/蛮力算法),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值...

    剑峰随心11772021-08-02
  • PythonPython常用模块介绍

    Python常用模块介绍

    这篇文章主要介绍了Python常用模块介绍,本文罗列了如python运行时服务、数学、数据结构、算法和代码简化、string 和 text 处理、python数据库访问等模块,需要...

    脚本之家7682020-05-14
  • PythonPython下opencv使用hough变换检测直线与圆

    Python下opencv使用hough变换检测直线与圆

    在数字图像中,往往存在着一些特殊形状的几何图形,像检测马路边一条直线,检测人眼的圆形等等,有时我们需要把这些特定图形检测出来,本文就详细...

    on2way4692021-12-03
  • Pythonpython线程池(threadpool)模块使用笔记详解

    python线程池(threadpool)模块使用笔记详解

    这篇文章主要介绍了python线程池(threadpool)模块使用笔记详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    Xiao2i4872020-12-18
  • Python对Python中Iterator和Iterable的区别详解

    对Python中Iterator和Iterable的区别详解

    今天小编就为大家分享一篇对Python中Iterator和Iterable的区别详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    passionkk5062021-04-09
  • Python解决python文件双击运行秒退的问题

    解决python文件双击运行秒退的问题

    今天小编就为大家分享一篇解决python文件双击运行秒退的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    牛巨侠8962021-07-19
  • Python全面介绍python中很常用的单元测试框架unitest

    全面介绍python中很常用的单元测试框架unitest

    这篇文章主要介绍了python中很常用的单元测试框架unitest的相关资料,帮助大家更好的利用python进行单元测试,感兴趣的朋友可以了解下...

    luyuze959022021-08-13