Pygame實(shí)戰(zhàn)練習(xí)之炸彈人學(xué)院游戲
導(dǎo)語(yǔ)
在現(xiàn)在這個(gè)浮躁的年代:小編每次登陸王者榮耀,還有每次登陸刺激戰(zhàn)場(chǎng)Z!
看著里面的聊天界面,各種代打、各種的找cp。小小編覺(jué)得,我們已經(jīng)失去了玩游戲的初心。
接下來(lái),小臺(tái)將帶領(lǐng)你們走回童年時(shí)光,一起領(lǐng)略我們當(dāng)初玩4399的單純與天真!
還記得小時(shí)候小臺(tái)每到放學(xué)時(shí)刻,就會(huì)拉著只比我小半歲的小表妹,一塊去親戚家里玩電腦
每一次打開(kāi)電腦做的第一件事情就是,打開(kāi)瀏覽器,輸入4399這四個(gè)數(shù)字,那個(gè)時(shí)候覺(jué)得hao123真是一個(gè)神奇的主頁(yè)!
可以讓我打開(kāi)4399玩各種游戲qwq,尤其是Q版泡泡堂深得我心!
那今天就帶大家回憶一下童年也做一款經(jīng)典的炸彈人的小游戲!
正文
游戲規(guī)則還清楚哈, 我就不多做介紹了不清楚玩法的可以百度下下!
首先準(zhǔn)備好相應(yīng)的素材:【部分如下】
炸彈人主程序:
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#') # 開(kāi)始界面 Interface(screen, cfg, mode='game_start') # 游戲主循環(huán) 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 # -主循環(huán) 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隨機(jī)行動(dòng) 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: # --爆炸火焰范圍內(nèi)的Hero生命值將持續(xù)下降 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則判斷游戲結(jié)束 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)
開(kāi)始的界面如下:
定義地圖類:
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) '''隨機(jī)獲取一個(gè)空地''' 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 '''根據(jù)坐標(biāo)獲取元素類型''' 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 # 坐標(biāo)(元素塊為單位長(zhǎng)度) self.coordinate = coordinate self.blocksize = blocksize # 爆炸倒計(jì)時(shí) self.explode_millisecond = 6000 * 1 - 1 self.explode_second = int(self.explode_millisecond / 1000) self.start_explode = False # 爆炸持續(xù)時(shí)間 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: # 爆炸倒計(jì)時(shí) 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: # 爆炸持續(xù)倒計(jì)時(shí) 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 '''計(jì)算爆炸區(qū)域''' def __calcExplodeArea(self, instances_list): explode_area = [] # 區(qū)域計(jì)算規(guī)則為墻可以阻止爆炸擴(kuò)散, 且爆炸范圍僅在游戲地圖范圍內(nèi) 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 # 炸彈冷卻時(shí)間 self.bomb_cooling_time = 5000 self.bomb_cooling_count = 0 # 隨機(jī)移動(dòng)冷卻時(shí)間(僅AI電腦用) self.randommove_cooling_time = 100 self.randommove_cooling_count = 0 '''角色移動(dòng)''' 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 '''隨機(jī)行動(dòng)(AI電腦用)''' def randomAction(self, dt): # 冷卻倒計(jì)時(shí) 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): # 冷卻倒計(jì)時(shí) 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))
效果如下:
這精致的畫面還可以吧~哈哈哈啊 快夸我快夸我~
總結(jié)
安啦!文章就寫到這里,你們的支持是我最大的動(dòng)力,記得三連哦~木??!
溫馨提示:不要忘記點(diǎn)贊、關(guān)注、評(píng)論哦!看我手上的炸彈~
到此這篇關(guān)于Pygame實(shí)戰(zhàn)練習(xí)之炸彈人學(xué)院游戲的文章就介紹到這了,更多相關(guān)Pygame 炸彈人學(xué)院內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Python中生成隨機(jī)數(shù)據(jù)的示例詳解
在日常工作編程中存在著各種隨機(jī)事件,同樣在編程中生成隨機(jī)數(shù)字的時(shí)候也是一樣。每當(dāng)在?Python?中生成隨機(jī)數(shù)據(jù)、字符串或數(shù)字時(shí),最好至少大致了解這些數(shù)據(jù)是如何生成的。所以本文將詳細(xì)為大家講解一下Python是如何生成隨機(jī)數(shù)據(jù),需要的可以參考一下2022-04-04C#返回當(dāng)前系統(tǒng)所有可用驅(qū)動(dòng)器符號(hào)的方法
這篇文章主要介紹了C#返回當(dāng)前系統(tǒng)所有可用驅(qū)動(dòng)器符號(hào)的方法,涉及C#操作系統(tǒng)硬件驅(qū)動(dòng)的相關(guān)技巧,需要的朋友可以參考下2015-04-04Python實(shí)現(xiàn)批量獲取當(dāng)前文件夾下的文件名
這篇文章主要為大家詳細(xì)介紹了如何利用Python實(shí)現(xiàn)批量獲取當(dāng)前文件夾下的文件名,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02使用python搭建代理IP池實(shí)現(xiàn)接口設(shè)置與整體調(diào)度
在網(wǎng)絡(luò)爬蟲(chóng)中,代理IP池是一個(gè)非常重要的組件,由于許多網(wǎng)站對(duì)單個(gè)IP的請(qǐng)求有限制,因此,我們需要一個(gè)代理IP池,在本文中,我們將使用Python來(lái)構(gòu)建一個(gè)代理IP池,然后,我們將使用這個(gè)代理IP池來(lái)訪問(wèn)我們需要的數(shù)據(jù),文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下2023-12-12詳解Python數(shù)據(jù)可視化編程 - 詞云生成并保存(jieba+WordCloud)
這篇文章主要介紹了Python數(shù)據(jù)可視化編程 - 詞云生成并保存(jieba+WordCloud),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03基于Python實(shí)現(xiàn)俄羅斯方塊躲閃小游戲
這篇文章主要為大家詳細(xì)介紹了如何基于Python實(shí)現(xiàn)有趣的俄羅斯方塊躲閃小游戲,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-04-04