华域联盟 Python Pygame实战练习之炸弹人学院游戏

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

文章目录[隐藏]

导语

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

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

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

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

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

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

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

正文

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

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

​炸弹人主程序:

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)

开始的界面如下:

​定义地图类:

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

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

'''墙类'''
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实战练习之炸弹人学院游戏

转载请保留出处和原文链接:https://www.cnhackhy.com/36419.htm

本文来自网络,不代表华域联盟立场,转载请注明出处。

作者: sterben

发表回复

联系我们

联系我们

2551209778

在线咨询: QQ交谈

邮箱: [email protected]

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部