居家小游戲,用 Python 實(shí)現(xiàn)植物大戰(zhàn)僵尸
在下方公眾號后臺回復(fù):JGNB,可獲取杰哥原創(chuàng)的 PDF 手冊。
作者?|?夢執(zhí).py
來源?|?CSDN博客
游戲截圖



動態(tài)演示

源碼分享
state/tool.py
import?os
import?json
from?abc?import?abstractmethod
import?pygame?as?pg
from?.?import?constants?as?c
class?State():
????def?__init__(self):
????????self.start_time?=?0.0
????????self.current_time?=?0.0
????????self.done?=?False
????????self.next?=?None
????????self.persist?=?{}
????@abstractmethod
????def?startup(self,?current_time,?persist):
????????'''abstract?method'''
????def?cleanup(self):
????????self.done?=?False
????????return?self.persist
????@abstractmethod
????def?update(self,?surface,?keys,?current_time):
????????'''abstract?method'''
class?Control():
????def?__init__(self):
????????self.screen?=?pg.display.get_surface()
????????self.done?=?False
????????self.clock?=?pg.time.Clock()
????????self.fps?=?60
????????self.keys?=?pg.key.get_pressed()
????????self.mouse_pos?=?None
????????self.mouse_click?=?[False,?False]??#?value:[left?mouse?click,?right?mouse?click]
????????self.current_time?=?0.0
????????self.state_dict?=?{}
????????self.state_name?=?None
????????self.state?=?None
????????self.game_info?=?{c.CURRENT_TIME:0.0,
??????????????????????????c.LEVEL_NUM:c.START_LEVEL_NUM}
????def?setup_states(self,?state_dict,?start_state):
????????self.state_dict?=?state_dict
????????self.state_name?=?start_state
????????self.state?=?self.state_dict[self.state_name]
????????self.state.startup(self.current_time,?self.game_info)
????def?update(self):
????????self.current_time?=?pg.time.get_ticks()
????????if?self.state.done:
????????????self.flip_state()
????????self.state.update(self.screen,?self.current_time,?self.mouse_pos,?self.mouse_click)
????????self.mouse_pos?=?None
????????self.mouse_click[0]?=?False
????????self.mouse_click[1]?=?False
????def?flip_state(self):
????????previous,?self.state_name?=?self.state_name,?self.state.next
????????persist?=?self.state.cleanup()
????????self.state?=?self.state_dict[self.state_name]
????????self.state.startup(self.current_time,?persist)
????def?event_loop(self):
????????for?event?in?pg.event.get():
????????????if?event.type?==?pg.QUIT:
????????????????self.done?=?True
????????????elif?event.type?==?pg.KEYDOWN:
????????????????self.keys?=?pg.key.get_pressed()
????????????elif?event.type?==?pg.KEYUP:
????????????????self.keys?=?pg.key.get_pressed()
????????????elif?event.type?==?pg.MOUSEBUTTONDOWN:
????????????????self.mouse_pos?=?pg.mouse.get_pos()
????????????????self.mouse_click[0],?_,?self.mouse_click[1]?=?pg.mouse.get_pressed()
????????????????print('pos:',?self.mouse_pos,?'?mouse:',?self.mouse_click)
????def?main(self):
????????while?not?self.done:
????????????self.event_loop()
????????????self.update()
????????????pg.display.update()
????????????self.clock.tick(self.fps)
????????print('game?over')
def?get_image(sheet,?x,?y,?width,?height,?colorkey=c.BLACK,?scale=1):
????????image?=?pg.Surface([width,?height])
????????rect?=?image.get_rect()
????????image.blit(sheet,?(0,?0),?(x,?y,?width,?height))
????????image.set_colorkey(colorkey)
????????image?=?pg.transform.scale(image,
???????????????????????????????????(int(rect.width*scale),
????????????????????????????????????int(rect.height*scale)))
????????return?image
def?load_image_frames(directory,?image_name,?colorkey,?accept):
????frame_list?=?[]
????tmp?=?{}
????#?image_name?is?"Peashooter",?pic?name?is?'Peashooter_1',?get?the?index?1
????index_start?=?len(image_name)?+?1?
????frame_num?=?0;
????for?pic?in?os.listdir(directory):
????????name,?ext?=?os.path.splitext(pic)
????????if?ext.lower()?in?accept:
????????????index?=?int(name[index_start:])
????????????img?=?pg.image.load(os.path.join(directory,?pic))
????????????if?img.get_alpha():
????????????????img?=?img.convert_alpha()
????????????else:
????????????????img?=?img.convert()
????????????????img.set_colorkey(colorkey)
????????????tmp[index]=?img
????????????frame_num?+=?1
????for?i?in?range(frame_num):
????????frame_list.append(tmp[i])
????return?frame_list
def?load_all_gfx(directory,?colorkey=c.WHITE,?accept=('.png',?'.jpg',?'.bmp',?'.gif')):
????graphics?=?{}
????for?name1?in?os.listdir(directory):
????????#?subfolders?under?the?folder?resources\graphics
????????dir1?=?os.path.join(directory,?name1)
????????if?os.path.isdir(dir1):
????????????for?name2?in?os.listdir(dir1):
????????????????dir2?=?os.path.join(dir1,?name2)
????????????????if?os.path.isdir(dir2):
????????????????#?e.g.?subfolders?under?the?folder?resources\graphics\Zombies
????????????????????for?name3?in?os.listdir(dir2):
????????????????????????dir3?=?os.path.join(dir2,?name3)
????????????????????????#?e.g.?subfolders?or?pics?under?the?folder?resources\graphics\Zombies\ConeheadZombie
????????????????????????if?os.path.isdir(dir3):
????????????????????????????#?e.g.?it's?the?folder?resources\graphics\Zombies\ConeheadZombie\ConeheadZombieAttack
????????????????????????????image_name,?_?=?os.path.splitext(name3)
????????????????????????????graphics[image_name]?=?load_image_frames(dir3,?image_name,?colorkey,?accept)
????????????????????????else:
????????????????????????????#?e.g.?pics?under?the?folder?resources\graphics\Plants\Peashooter
????????????????????????????image_name,?_?=?os.path.splitext(name2)
????????????????????????????graphics[image_name]?=?load_image_frames(dir2,?image_name,?colorkey,?accept)
????????????????????????????break
????????????????else:
????????????????#?e.g.?pics?under?the?folder?resources\graphics\Screen
????????????????????name,?ext?=?os.path.splitext(name2)
????????????????????if?ext.lower()?in?accept:
????????????????????????img?=?pg.image.load(dir2)
????????????????????????if?img.get_alpha():
????????????????????????????img?=?img.convert_alpha()
????????????????????????else:
????????????????????????????img?=?img.convert()
????????????????????????????img.set_colorkey(colorkey)
????????????????????????graphics[name]?=?img
????return?graphics
def?loadZombieImageRect():
????file_path?=?os.path.join('source',?'data',?'entity',?'zombie.json')
????f?=?open(file_path)
????data?=?json.load(f)
????f.close()
????return?data[c.ZOMBIE_IMAGE_RECT]
def?loadPlantImageRect():
????file_path?=?os.path.join('source',?'data',?'entity',?'plant.json')
????f?=?open(file_path)
????data?=?json.load(f)
????f.close()
????return?data[c.PLANT_IMAGE_RECT]
pg.init()
pg.display.set_caption(c.ORIGINAL_CAPTION)
SCREEN?=?pg.display.set_mode(c.SCREEN_SIZE)
GFX?=?load_all_gfx(os.path.join("resources","graphics"))
ZOMBIE_RECT?=?loadZombieImageRect()
PLANT_RECT?=?loadPlantImageRect()
state/constants.py
START_LEVEL_NUM?=?1
ORIGINAL_CAPTION?=?'Plant?VS?Zombies?Game'
SCREEN_WIDTH?=?800
SCREEN_HEIGHT?=?600
SCREEN_SIZE?=?(SCREEN_WIDTH,?SCREEN_HEIGHT)
GRID_X_LEN?=?9
GRID_Y_LEN?=?5
GRID_X_SIZE?=?80
GRID_Y_SIZE?=?100
WHITE????????=?(255,?255,?255)
NAVYBLUE?????=?(?60,??60,?100)
SKY_BLUE?????=?(?39,?145,?251)
BLACK????????=?(??0,???0,???0)
LIGHTYELLOW??=?(234,?233,?171)
RED??????????=?(255,???0,???0)
PURPLE???????=?(255,???0,?255)
GOLD?????????=?(255,?215,???0)
GREEN????????=?(??0,?255,???0)
SIZE_MULTIPLIER?=?1.3
#GAME?INFO?DICTIONARY?KEYS
CURRENT_TIME?=?'current?time'
LEVEL_NUM?=?'level?num'
#STATES?FOR?ENTIRE?GAME
MAIN_MENU?=?'main?menu'
LOAD_SCREEN?=?'load?screen'
GAME_LOSE?=?'game?los'
GAME_VICTORY?=?'game?victory'
LEVEL?=?'level'
MAIN_MENU_IMAGE?=?'MainMenu'
OPTION_ADVENTURE?=?'Adventure'
GAME_LOOSE_IMAGE?=?'GameLoose'
GAME_VICTORY_IMAGE?=?'GameVictory'
#MAP?COMPONENTS
BACKGROUND_NAME?=?'Background'
BACKGROUND_TYPE?=?'background_type'
INIT_SUN_NAME?=?'init_sun_value'
ZOMBIE_LIST?=?'zombie_list'
MAP_EMPTY?=?0
MAP_EXIST?=?1
BACKGROUND_OFFSET_X?=?220
MAP_OFFSET_X?=?35
MAP_OFFSET_Y?=?100
#MENUBAR
CHOOSEBAR_TYPE?=?'choosebar_type'
CHOOSEBAR_STATIC?=?0
CHOOSEBAR_MOVE?=?1
CHOSSEBAR_BOWLING?=?2
MENUBAR_BACKGROUND?=?'ChooserBackground'
MOVEBAR_BACKGROUND?=?'MoveBackground'
PANEL_BACKGROUND?=?'PanelBackground'
START_BUTTON?=?'StartButton'
CARD_POOL?=?'card_pool'
MOVEBAR_CARD_FRESH_TIME?=?6000
CARD_MOVE_TIME?=?60
#PLANT?INFO
PLANT_IMAGE_RECT?=?'plant_image_rect'
CAR?=?'car'
SUN?=?'Sun'
SUNFLOWER?=?'SunFlower'
PEASHOOTER?=?'Peashooter'
SNOWPEASHOOTER?=?'SnowPea'
WALLNUT?=?'WallNut'
CHERRYBOMB?=?'CherryBomb'
THREEPEASHOOTER?=?'Threepeater'
REPEATERPEA?=?'RepeaterPea'
CHOMPER?=?'Chomper'
CHERRY_BOOM_IMAGE?=?'Boom'
PUFFSHROOM?=?'PuffShroom'
POTATOMINE?=?'PotatoMine'
SQUASH?=?'Squash'
SPIKEWEED?=?'Spikeweed'
JALAPENO?=?'Jalapeno'
SCAREDYSHROOM?=?'ScaredyShroom'
SUNSHROOM?=?'SunShroom'
ICESHROOM?=?'IceShroom'
HYPNOSHROOM?=?'HypnoShroom'
WALLNUTBOWLING?=?'WallNutBowling'
REDWALLNUTBOWLING?=?'RedWallNutBowling'
PLANT_HEALTH?=?5
WALLNUT_HEALTH?=?30
WALLNUT_CRACKED1_HEALTH?=?20
WALLNUT_CRACKED2_HEALTH?=?10
WALLNUT_BOWLING_DAMAGE?=?10
PRODUCE_SUN_INTERVAL?=?7000
FLOWER_SUN_INTERVAL?=?22000
SUN_LIVE_TIME?=?7000
SUN_VALUE?=?25
ICE_SLOW_TIME?=?2000
FREEZE_TIME?=?7500
ICETRAP?=?'IceTrap'
#PLANT?CARD?INFO
CARD_SUNFLOWER?=?'card_sunflower'
CARD_PEASHOOTER?=?'card_peashooter'
CARD_SNOWPEASHOOTER?=?'card_snowpea'
CARD_WALLNUT?=?'card_wallnut'
CARD_CHERRYBOMB?=?'card_cherrybomb'
CARD_THREEPEASHOOTER?=?'card_threepeashooter'
CARD_REPEATERPEA?=?'card_repeaterpea'
CARD_CHOMPER?=?'card_chomper'
CARD_PUFFSHROOM?=?'card_puffshroom'
CARD_POTATOMINE?=?'card_potatomine'
CARD_SQUASH?=?'card_squash'
CARD_SPIKEWEED?=?'card_spikeweed'
CARD_JALAPENO?=?'card_jalapeno'
CARD_SCAREDYSHROOM?=?'card_scaredyshroom'
CARD_SUNSHROOM?=?'card_sunshroom'
CARD_ICESHROOM?=?'card_iceshroom'
CARD_HYPNOSHROOM?=?'card_hypnoshroom'
CARD_REDWALLNUT?=?'card_redwallnut'
#BULLET?INFO
BULLET_PEA?=?'PeaNormal'
BULLET_PEA_ICE?=?'PeaIce'
BULLET_MUSHROOM?=?'BulletMushRoom'
BULLET_DAMAGE_NORMAL?=?1
#ZOMBIE?INFO
ZOMBIE_IMAGE_RECT?=?'zombie_image_rect'
ZOMBIE_HEAD?=?'ZombieHead'
NORMAL_ZOMBIE?=?'Zombie'
CONEHEAD_ZOMBIE?=?'ConeheadZombie'
BUCKETHEAD_ZOMBIE?=?'BucketheadZombie'
FLAG_ZOMBIE?=?'FlagZombie'
NEWSPAPER_ZOMBIE?=?'NewspaperZombie'
BOOMDIE?=?'BoomDie'
LOSTHEAD_HEALTH?=?5
NORMAL_HEALTH?=?10
FLAG_HEALTH?=?15
CONEHEAD_HEALTH?=?20
BUCKETHEAD_HEALTH?=?30
NEWSPAPER_HEALTH?=?15
ATTACK_INTERVAL?=?1000
ZOMBIE_WALK_INTERVAL?=?70
ZOMBIE_START_X?=?SCREEN_WIDTH?+?50
#STATE
IDLE?=?'idle'
FLY?=?'fly'
EXPLODE?=?'explode'
ATTACK?=?'attack'
ATTACKED?=?'attacked'
DIGEST?=?'digest'
WALK?=?'walk'
DIE?=?'die'
CRY?=?'cry'
FREEZE?=?'freeze'
SLEEP?=?'sleep'
#LEVEL?STATE
CHOOSE?=?'choose'
PLAY?=?'play'
#BACKGROUND
BACKGROUND_DAY?=?0
BACKGROUND_NIGHT?=?1
state/main.py
from?.?import?tool
from?.?import?constants?as?c
from?.state?import?mainmenu,?screen,?level
def?main():
????game?=?tool.Control()
????state_dict?=?{c.MAIN_MENU:?mainmenu.Menu(),
??????????????????c.GAME_VICTORY:?screen.GameVictoryScreen(),
??????????????????c.GAME_LOSE:?screen.GameLoseScreen(),
??????????????????c.LEVEL:?level.Level()}
????game.setup_states(state_dict,?c.MAIN_MENU)
????game.main()
主執(zhí)行文件main.py
import?pygame?as?pg
from?source.main?import?main
if?__name__=='__main__':
????main()
????pg.quit()
推薦閱讀
Python 腳本打包 exe,auto-py-to-exe來幫你!
7 個實(shí)用的 Python 自動化代碼,別再重復(fù)造輪子了!
太酷了!手把手教你用 Python 繪制?;鶊D! | 用戶行為路徑分析
精選了20個Python實(shí)戰(zhàn)項(xiàng)目(附源碼),拿走就用!

評論
圖片
表情
