Pygame实战练习之炸弹人学院游戏

时间:2021-09-08 10:00:24

导语

在现在这个浮躁的年代:小编每次登陆王者荣耀,还有每次登陆刺激战场z!

看着里面的聊天界面,各种代打、各种的找cp。小小编觉得,我们已经失去了玩游戏的初心。

接下来,小台将带领你们走回童年时光,一起领略我们当初玩4399的单纯与天真!

Pygame实战练习之炸弹人学院游戏

还记得小时候小台每到放学时刻,就会拉着只比我小半岁的小表妹,一块去亲戚家里玩电脑

每一次打开电脑做的第一件事情就是,打开浏览器,输入4399这四个数字,那个时候觉得hao123真是一个神奇的主页!

可以让我打开4399玩各种游戏qwq,尤其是q版泡泡堂深得我心!

Pygame实战练习之炸弹人学院游戏

那今天就带大家回忆一下童年也做一款经典的炸弹人的小游戏!

Pygame实战练习之炸弹人学院游戏

正文

游戏规则还清楚哈, 我就不多做介绍了不清楚玩法的可以百度下下!

首先准备好相应的素材:【部分如下】

Pygame实战练习之炸弹人学院游戏

​炸弹人主程序:

?
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
import sys
import cfg
import random
import pygame
from modules import *
 
 
'''游戏主程序'''
def main(cfg):
    # 初始化
    pygame.init()
    pygame.mixer.init()
    pygame.mixer.music.load(cfg.bgmpath)
    pygame.mixer.music.play(-1, 0.0)
    screen = pygame.display.set_mode(cfg.screensize)
    pygame.display.set_caption('炸弹人——源码基地:#959755565#')
    # 开始界面
    interface(screen, cfg, mode='game_start')
    # 游戏主循环
    font = pygame.font.sysfont('consolas', 15)
    for gamemap_path in cfg.gamemappaths:
        # -地图
        map_parser = mapparser(gamemap_path, bg_paths=cfg.backgroundpaths, wall_paths=cfg.wallpaths, blocksize=cfg.blocksize)
        # -水果
        fruit_sprite_group = pygame.sprite.group()
        used_spaces = []
        for i in range(5):
            coordinate = map_parser.randomgetspace(used_spaces)
            used_spaces.append(coordinate)
            fruit_sprite_group.add(fruit(random.choice(cfg.fruitpaths), coordinate=coordinate, blocksize=cfg.blocksize))
        # -我方hero
        coordinate = map_parser.randomgetspace(used_spaces)
        used_spaces.append(coordinate)
        ourhero = hero(imagepaths=cfg.herozeldapaths, coordinate=coordinate, blocksize=cfg.blocksize, map_parser=map_parser, hero_name='zelda')
        # -电脑hero
        aihero_sprite_group = pygame.sprite.group()
        coordinate = map_parser.randomgetspace(used_spaces)
        aihero_sprite_group.add(hero(imagepaths=cfg.herobatmanpaths, coordinate=coordinate, blocksize=cfg.blocksize, map_parser=map_parser, hero_name='batman'))
        used_spaces.append(coordinate)
        coordinate = map_parser.randomgetspace(used_spaces)
        aihero_sprite_group.add(hero(imagepaths=cfg.herodkpaths, coordinate=coordinate, blocksize=cfg.blocksize, map_parser=map_parser, hero_name='dk'))
        used_spaces.append(coordinate)
        # -炸弹bomb
        bomb_sprite_group = pygame.sprite.group()
        # -用于判断游戏胜利或者失败的flag
        is_win_flag = false
        # -主循环
        screen = pygame.display.set_mode(map_parser.screen_size)
        clock = pygame.time.clock()
        while true:
            dt = clock.tick(cfg.fps)
            for event in pygame.event.get():
                if event.type == pygame.quit:
                    pygame.quit()
                    sys.exit(-1)
                # --↑↓←→键控制上下左右, 空格键丢炸弹
                elif event.type == pygame.keydown:
                    if event.key == pygame.k_up:
                        ourhero.move('up')
                    elif event.key == pygame.k_down:
                        ourhero.move('down')
                    elif event.key == pygame.k_left:
                        ourhero.move('left')
                    elif event.key == pygame.k_right:
                        ourhero.move('right')
                    elif event.key == pygame.k_space:
                        if ourhero.bomb_cooling_count <= 0:
                            bomb_sprite_group.add(ourhero.generatebomb(imagepath=cfg.bombpath, digitalcolor=cfg.yellow, explode_imagepath=cfg.firepath))
            screen.fill(cfg.white)
            # --电脑hero随机行动
            for hero in aihero_sprite_group:
                action, flag = hero.randomaction(dt)
                if flag and action == 'dropbomb':
                    bomb_sprite_group.add(hero.generatebomb(imagepath=cfg.bombpath, digitalcolor=cfg.yellow, explode_imagepath=cfg.firepath))
            # --吃到水果加生命值(只要是hero, 都能加)
            ourhero.eatfruit(fruit_sprite_group)
            for hero in aihero_sprite_group:
                hero.eatfruit(fruit_sprite_group)
            # --游戏元素都绑定到屏幕上
            map_parser.draw(screen)
            for bomb in bomb_sprite_group:
                if not bomb.is_being:
                    bomb_sprite_group.remove(bomb)
                explode_area = bomb.draw(screen, dt, map_parser)
                if explode_area:
                    # --爆炸火焰范围内的hero生命值将持续下降
                    if ourhero.coordinate in explode_area:
                        ourhero.health_value -= bomb.harm_value
                    for hero in aihero_sprite_group:
                        if hero.coordinate in explode_area:
                            hero.health_value -= bomb.harm_value
            fruit_sprite_group.draw(screen)
            for hero in aihero_sprite_group:
                hero.draw(screen, dt)
            ourhero.draw(screen, dt)
            # --左上角显示生命值
            pos_x = showtext(screen, font, text=ourhero.hero_name+'(our):'+str(ourhero.health_value), color=cfg.yellow, position=[5, 5])
            for hero in aihero_sprite_group:
                pos_x, pos_y = pos_x+15, 5
                pos_x = showtext(screen, font, text=hero.hero_name+'(ai):'+str(hero.health_value), color=cfg.yellow, position=[pos_x, pos_y])
            # --我方玩家生命值小于等于0/电脑方玩家生命值均小于等于0则判断游戏结束
            if ourhero.health_value <= 0:
                is_win_flag = false
                break
            for hero in aihero_sprite_group:
                if hero.health_value <= 0:
                    aihero_sprite_group.remove(hero)
            if len(aihero_sprite_group) == 0:
                is_win_flag = true
                break
            pygame.display.update()
            clock.tick(cfg.fps)
        if is_win_flag:
            interface(screen, cfg, mode='game_switch')
        else:
            break
    interface(screen, cfg, mode='game_end')
 
 
'''run'''
if __name__ == '__main__':
    while true:
        main(cfg)

开始的界面如下:

Pygame实战练习之炸弹人学院游戏

​定义地图类:

?
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
class mapparser():
    def __init__(self, mapfilepath, bg_paths, wall_paths, blocksize, **kwargs):
        self.instances_list = self.__parse(mapfilepath)
        self.bg_paths = bg_paths
        self.wall_paths = wall_paths
        self.blocksize = blocksize
        self.height = len(self.instances_list)
        self.width = len(self.instances_list[0])
        self.screen_size = (blocksize * self.width, blocksize * self.height)
    '''地图画到屏幕上'''
    def draw(self, screen):
        for j in range(self.height):
            for i in range(self.width):
                instance = self.instances_list[j][i]
                if instance == 'w':
                    elem = wall(self.wall_paths[0], [i, j], self.blocksize)
                elif instance == 'x':
                    elem = wall(self.wall_paths[1], [i, j], self.blocksize)
                elif instance == 'z':
                    elem = wall(self.wall_paths[2], [i, j], self.blocksize)
                elif instance == '0':
                    elem = background(self.bg_paths[0], [i, j], self.blocksize)
                elif instance == '1':
                    elem = background(self.bg_paths[1], [i, j], self.blocksize)
                elif instance == '2':
                    elem = background(self.bg_paths[2], [i, j], self.blocksize)
                else:
                    raise valueerror('instance parse error in mapparser.draw...')
                elem.draw(screen)
    '''随机获取一个空地'''
    def randomgetspace(self, used_spaces=none):
        while true:
            i = random.randint(0, self.width-1)
            j = random.randint(0, self.height-1)
            coordinate = [i, j]
            if used_spaces and coordinate in used_spaces:
                continue
            instance = self.instances_list[j][i]
            if instance in ['0', '1', '2']:
                break
        return coordinate
    '''根据坐标获取元素类型'''
    def getelembycoordinate(self, coordinate):
        return self.instances_list[coordinate[1]][coordinate[0]]
    '''解析.map文件'''
    def __parse(self, mapfilepath):
        instances_list = []
        with open(mapfilepath) as f:
            for line in f.readlines():
                instances_line_list = []
                for c in line:
                    if c in ['w', 'x', 'z', '0', '1', '2']:
                        instances_line_list.append(c)
                instances_list.append(instances_line_list)
        return instances_list

定义必要的一些精灵类:角色,水果等等。

?
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
'''墙类'''
class wall(pygame.sprite.sprite):
    def __init__(self, imagepath, coordinate, blocksize, **kwargs):
        pygame.sprite.sprite.__init__(self)
        self.image = pygame.image.load(imagepath)
        self.image = pygame.transform.scale(self.image, (blocksize, blocksize))
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = coordinate[0] * blocksize, coordinate[1] * blocksize
        self.coordinate = coordinate
        self.blocksize = blocksize
    '''画到屏幕上'''
    def draw(self, screen):
        screen.blit(self.image, self.rect)
        return true
 
 
'''背景类'''
class background(pygame.sprite.sprite):
    def __init__(self, imagepath, coordinate, blocksize, **kwargs):
        pygame.sprite.sprite.__init__(self)
        self.image = pygame.image.load(imagepath)
        self.image = pygame.transform.scale(self.image, (blocksize, blocksize))
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = coordinate[0] * blocksize, coordinate[1] * blocksize
        self.coordinate = coordinate
        self.blocksize = blocksize
    '''画到屏幕上'''
    def draw(self, screen):
        screen.blit(self.image, self.rect)
        return true
 
 
'''水果类'''
class fruit(pygame.sprite.sprite):
    def __init__(self, imagepath, coordinate, blocksize, **kwargs):
        pygame.sprite.sprite.__init__(self)
        self.kind = imagepath.split('/')[-1].split('.')[0]
        if self.kind == 'banana':
            self.value = 5
        elif self.kind == 'cherry':
            self.value = 10
        else:
            raise valueerror('unknow fruit %s...' % self.kind)
        self.image = pygame.image.load(imagepath)
        self.image = pygame.transform.scale(self.image, (blocksize, blocksize))
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = coordinate[0] * blocksize, coordinate[1] * blocksize
        self.coordinate = coordinate
        self.blocksize = blocksize
    '''画到屏幕上'''
    def draw(self, screen):
        screen.blit(self.image, self.rect)
        return true
 
 
'''炸弹类'''
class bomb(pygame.sprite.sprite):
    def __init__(self, imagepath, coordinate, blocksize, digitalcolor, explode_imagepath, **kwargs):
        pygame.sprite.sprite.__init__(self)
        self.image = pygame.image.load(imagepath)
        self.image = pygame.transform.scale(self.image, (blocksize, blocksize))
        self.explode_imagepath = explode_imagepath
        self.rect = self.image.get_rect()
        # 像素位置
        self.rect.left, self.rect.top = coordinate[0] * blocksize, coordinate[1] * blocksize
        # 坐标(元素块为单位长度)
        self.coordinate = coordinate
        self.blocksize = blocksize
        # 爆炸倒计时
        self.explode_millisecond = 6000 * 1 - 1
        self.explode_second = int(self.explode_millisecond / 1000)
        self.start_explode = false
        # 爆炸持续时间
        self.exploding_count = 1000 * 1
        # 炸弹伤害能力
        self.harm_value = 1
        # 该炸弹是否还存在
        self.is_being = true
        self.font = pygame.font.sysfont('consolas', 20)
        self.digitalcolor = digitalcolor
    '''画到屏幕上'''
    def draw(self, screen, dt, map_parser):
        if not self.start_explode:
            # 爆炸倒计时
            self.explode_millisecond -= dt
            self.explode_second = int(self.explode_millisecond / 1000)
            if self.explode_millisecond < 0:
                self.start_explode = true
            screen.blit(self.image, self.rect)
            text = self.font.render(str(self.explode_second), true, self.digitalcolor)
            rect = text.get_rect(center=(self.rect.centerx-5, self.rect.centery+5))
            screen.blit(text, rect)
            return false
        else:
            # 爆炸持续倒计时
            self.exploding_count -= dt
            if self.exploding_count > 0:
                return self.__explode(screen, map_parser)
            else:
                self.is_being = false
                return false
    '''爆炸效果'''
    def __explode(self, screen, map_parser):
        explode_area = self.__calcexplodearea(map_parser.instances_list)
        for each in explode_area:
            image = pygame.image.load(self.explode_imagepath)
            image = pygame.transform.scale(image, (self.blocksize, self.blocksize))
            rect = image.get_rect()
            rect.left, rect.top = each[0] * self.blocksize, each[1] * self.blocksize
            screen.blit(image, rect)
        return explode_area
    '''计算爆炸区域'''
    def __calcexplodearea(self, instances_list):
        explode_area = []
        # 区域计算规则为墙可以阻止爆炸扩散, 且爆炸范围仅在游戏地图范围内
        for ymin in range(self.coordinate[1], self.coordinate[1]-5, -1):
            if ymin < 0 or instances_list[ymin][self.coordinate[0]] in ['w', 'x', 'z']:
                break
            explode_area.append([self.coordinate[0], ymin])
        for ymax in range(self.coordinate[1]+1, self.coordinate[1]+5):
            if ymax >= len(instances_list) or instances_list[ymax][self.coordinate[0]] in ['w', 'x', 'z']:
                break
            explode_area.append([self.coordinate[0], ymax])
        for xmin in range(self.coordinate[0], self.coordinate[0]-5, -1):
            if xmin < 0 or instances_list[self.coordinate[1]][xmin] in ['w', 'x', 'z']:
                break
            explode_area.append([xmin, self.coordinate[1]])
        for xmax in range(self.coordinate[0]+1, self.coordinate[0]+5):
            if xmax >= len(instances_list[0]) or instances_list[self.coordinate[1]][xmax] in ['w', 'x', 'z']:
                break
            explode_area.append([xmax, self.coordinate[1]])
        return explode_area
 
 
'''角色类'''
class hero(pygame.sprite.sprite):
    def __init__(self, imagepaths, coordinate, blocksize, map_parser, **kwargs):
        pygame.sprite.sprite.__init__(self)
        self.imagepaths = imagepaths
        self.image = pygame.image.load(imagepaths[-1])
        self.image = pygame.transform.scale(self.image, (blocksize, blocksize))
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = coordinate[0] * blocksize, coordinate[1] * blocksize
        self.coordinate = coordinate
        self.blocksize = blocksize
        self.map_parser = map_parser
        self.hero_name = kwargs.get('hero_name')
        # 生命值
        self.health_value = 50
        # 炸弹冷却时间
        self.bomb_cooling_time = 5000
        self.bomb_cooling_count = 0
        # 随机移动冷却时间(仅ai电脑用)
        self.randommove_cooling_time = 100
        self.randommove_cooling_count = 0
    '''角色移动'''
    def move(self, direction):
        self.__updateimage(direction)
        if direction == 'left':
            if self.coordinate[0]-1 < 0 or self.map_parser.getelembycoordinate([self.coordinate[0]-1, self.coordinate[1]]) in ['w', 'x', 'z']:
                return false
            self.coordinate[0] = self.coordinate[0] - 1
        elif direction == 'right':
            if self.coordinate[0]+1 >= self.map_parser.width or self.map_parser.getelembycoordinate([self.coordinate[0]+1, self.coordinate[1]]) in ['w', 'x', 'z']:
                return false
            self.coordinate[0] = self.coordinate[0] + 1
        elif direction == 'up':
            if self.coordinate[1]-1 < 0 or self.map_parser.getelembycoordinate([self.coordinate[0], self.coordinate[1]-1]) in ['w', 'x', 'z']:
                return false
            self.coordinate[1] = self.coordinate[1] - 1
        elif direction == 'down':
            if self.coordinate[1]+1 >= self.map_parser.height or self.map_parser.getelembycoordinate([self.coordinate[0], self.coordinate[1]+1]) in ['w', 'x', 'z']:
                return false
            self.coordinate[1] = self.coordinate[1] + 1
        else:
            raise valueerror('unknow direction %s...' % direction)
        self.rect.left, self.rect.top = self.coordinate[0] * self.blocksize, self.coordinate[1] * self.blocksize
        return true
    '''随机行动(ai电脑用)'''
    def randomaction(self, dt):
        # 冷却倒计时
        if self.randommove_cooling_count > 0:
            self.randommove_cooling_count -= dt
        action = random.choice(['left', 'left', 'right', 'right', 'up', 'up', 'down', 'down', 'dropbomb'])
        flag = false
        if action in ['left', 'right', 'up', 'down']:
            if self.randommove_cooling_count <= 0:
                flag = true
                self.move(action)
                self.randommove_cooling_count = self.randommove_cooling_time
        elif action in ['dropbomb']:
            if self.bomb_cooling_count <= 0:
                flag = true
                self.bomb_cooling_count = self.bomb_cooling_time
        return action, flag
    '''生成炸弹'''
    def generatebomb(self, imagepath, digitalcolor, explode_imagepath):
        return bomb(imagepath=imagepath, coordinate=copy.deepcopy(self.coordinate), blocksize=self.blocksize, digitalcolor=digitalcolor, explode_imagepath=explode_imagepath)
    '''画到屏幕上'''
    def draw(self, screen, dt):
        # 冷却倒计时
        if self.bomb_cooling_count > 0:
            self.bomb_cooling_count -= dt
        screen.blit(self.image, self.rect)
        return true
    '''吃水果'''
    def eatfruit(self, fruit_sprite_group):
        eaten_fruit = pygame.sprite.spritecollide(self, fruit_sprite_group, true, none)
        for fruit in eaten_fruit:
            self.health_value += fruit.value
    '''更新角色朝向'''
    def __updateimage(self, direction):
        directions = ['left', 'right', 'up', 'down']
        idx = directions.index(direction)
        self.image = pygame.image.load(self.imagepaths[idx])
        self.image = pygame.transform.scale(self.image, (self.blocksize, self.blocksize))

效果如下:

Pygame实战练习之炸弹人学院游戏

Pygame实战练习之炸弹人学院游戏

这精致的画面还可以吧~哈哈哈啊 快夸我快夸我~

总结

安啦!文章就写到这里,你们的支持是我最大的动力,记得三连哦~木啊!

Pygame实战练习之炸弹人学院游戏

温馨提示:不要忘记点赞、关注、评论哦!看我手上的炸弹~

到此这篇关于pygame实战练习之炸弹人学院游戏的文章就介绍到这了,更多相关pygame 炸弹人学院内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/weixin_55822277/article/details/120415243