用python开发植物大战僵尸

早期的植物大战僵尸是由vc开发的,作者的想法是非常地有特色,所以今天我们来探讨下植物大战僵尸游戏的进入场景怎么开发。

我们首需要用到如下几个文件在这里插入图片描述

程序文件功能
game.py在游戏中就运行的文件
initgame.py游戏主菜单选择关卡等
loading.py游戏载入等待缓存
surface.py游戏入口点击这里

首先介绍surface.py:

# -*- coding:utf-8 -*-
import pygame
from sys import exit
from pygame.locals import *
from random import randint as r_i
pygame.init()
import initgame
import game
import loading

def help_main(screen):
	help_bg = pygame.image.load('images/Help.png').convert_alpha()
	help_width,help_height = help_bg.get_width(),help_bg.get_height()
	help_pos = 450-help_width//2,300-help_height//2
	help_run = True

	pygame.display.flip()
	while help_run:
		for event in pygame.event.get():
			if event.type == QUIT:
				exit()
			if event.type == MOUSEBUTTONDOWN:
				mosx,mosy = event.pos
				if help_pos[0]<mosx<help_pos[0]+help_width and help_pos[1]<mosy<help_pos[1]+help_height:
					help_run = False

		screen.blit(help_bg,(help_pos))
		pygame.display.update()


def calbackmain(screen):
	pygame.mixer.music.pause()
	initgame.inits(screen)
	pygame.mixer.music.play(-1,0,)
	pygame.mixer.music.set_volume(0.5)

def StartAdventur_(screen):
	beginrun = True
	beginbg = pygame.image.load('images/OptionsMenuback32.png').convert_alpha()
	optionbtn = pygame.image.load('images/OptionsBackB32.png').convert_alpha()
	optionbtn2 = pygame.image.load('images/OptionsBackB321.png').convert_alpha()
	fo = pygame.font.Font('font/msyh.ttf',35)
	myfont = fo.render("返      回", True, (255, 255, 100))
	fo2 = pygame.font.Font('font/msyh.ttf',22)
	myfont2 = fo2.render("第一大关   >>", True, (255, 255, 150))
	fo3 = pygame.font.Font('font/msyh.ttf',18)
	game_list=[	'第一关','第二关','第三关','第四关','第五关',
			    '第六关','第七关','第八关','第九关','第十关']
	pygame.display.flip()
	returnbtn = False
	Timer_return = 0 #返回的定时器
	while beginrun:
		for event in pygame.event.get():
			if event.type == QUIT:
				exit()
			if event.type == MOUSEBUTTONDOWN:
				mdx,mdy = event.pos
				# 270 440 ,360 100
				returnbtn = False
				if 270<mdx<630 and 440<mdy<540:
					returnbtn = True
				#--------------------------------------------
				#关卡系列  循环检测点击了关卡---------------
				# 360+125*list_i , 230+35*list_j---- 54 , 25
				#--------------------------------------------
				list_index = 0
				for list_j in range(5):
					for list_i in range(2):
						if 360+125*list_i<mdx<414+125*list_i and 230+35*list_j<mdy<255+35*list_j:
							print('只能点击第一关')
							if list_index == 0:
								game.game_one(screen); #进入第一关
								beginrun = False #回到游戏退出启动器
						list_index+=1


		screen.blit(beginbg,(450-beginbg.get_width()/2,300-beginbg.get_height()/2))#背景
		screen.blit(myfont2,(390,180))#第一大关
		#关卡系列
		list_index = 0
		for list_j in range(5):
			for list_i in range(2):
				myfont3 = fo3.render("%s"%(game_list[list_index]), True, (255, 255, 230))#(54,25)
				screen.blit(myfont3,(360+125*list_i,230+35*list_j))
				list_index+=1
		
		#返回按钮壁纸
		screen.blit(optionbtn,(270,440))
		screen.blit(myfont,(380,460))#返回字体
		if returnbtn:
			screen.blit(optionbtn2,(270,441))
			screen.blit(myfont,(380,461))
			Timer_return+=1
			if Timer_return>= 50:
				beginrun = False

		pygame.display.update()



def eventinit(surf,screen,mosx,mosy):
	#-------------------------------------
	#--------------主菜单系列-------------
	#-------------------------------------
	#470,80  331,146开始冒险
	if 470<mosx<801 and 80<mosy<203:#h-23
		pygame.time.delay(50)
		StartAdventur_(screen)
	#470,205  313 131玩小游戏
	if 470<mosx<783 and 205<mosy<313:#h-23
		pygame.time.delay(50)
		
	#470,305 286 122解谜模式
	if 470<mosx<756 and 305<mosy<427:#h-23
		pygame.time.delay(50)


	#-------------------------------------
	#--------------小菜单系列-------------
	#-------------------------------------
	#810,510,65,35退出
	if mosx>810 and mosx<875 and mosy>510 and mosy<545:
			#pygame.draw.rect(screen, (255,255,0), (810,510,65,35), 1)#退出
			pygame.time.delay(50)
			calbackmain(screen) #调回主界面
	#725,520,65,35帮助
	if mosx>725 and mosx<790 and mosy>520 and mosy<555:
			pygame.draw.rect(screen, (255,255,0), (725,520,65,35), 1)#帮助
			pygame.time.delay(50)
			help_main(screen) #调用帮助函数

	#647,485,70,40选项
	if mosx>647 and mosx<717 and mosy>485 and mosy<525:
			#pygame.draw.rect(screen, (255,255,0), (647,485,70,40), 1)#选项
			pygame.time.delay(50)


def mouseover(screen,mox,moy):
	#470,80  331,146开始冒险
	if 470<mox<801 and 80<moy<203:#h-23
		return 1
	#470,205  313 131玩小游戏
	if 470<mox<783 and 205<moy<313:#h-23
		return 2
	#470,305 286 122解谜模式
	if 470<mox<756 and 305<moy<427:#h-23
		return 3

	return 0


def main():
	pygame.mixer.music.load('music/Faster.mp3')
	pygame.mixer.music.play(-1,0,)
	pygame.mixer.music.set_volume(0.5)
	screen = pygame.display.set_mode([900, 600], 0, 32)
	caption = pygame.display.set_caption('植物大战僵尸')
	screen.fill([255,255,255])
	#-------------------
	#进入最开始界面-----
	initgame.inits(screen)
	#-------------------
	surf = pygame.image.load('images/Surface.png').convert_alpha()
	StartAdventur = pygame.image.load('images/StartAdventur.png').convert_alpha()
	StartAdventur2 = pygame.image.load('images/StartAdventur2.png').convert_alpha()
	Survival = pygame.image.load('images/Survival.png').convert_alpha()
	Survival2 = pygame.image.load('images/Survival2.png').convert_alpha()
	Challenges = pygame.image.load('images/Challenges.png').convert_alpha()
	Challenges2 = pygame.image.load('images/Challenges2.png').convert_alpha()
	pygame.display.flip()
	#定义区
	capmouseover = 0
	#game.game_one(screen)#测试游戏界面 第一关卡
	#-------------------------------------------
	#s=pygame.mixer.Sound('music/button.wav')
	#s.set_volume(0.25)
	while True:
		for event in pygame.event.get():
			if event.type == QUIT:
				exit()
			if event.type == KEYDOWN:
				if event.key == K_ESCAPE:
						calbackmain(screen) #调回主界面
				if event.key == K_a:
					flag = 1
			if event.type == MOUSEBUTTONDOWN:
				mdx,mdy=event.pos
				eventinit(surf,screen,mdx,mdy)#主界面的菜单按钮

			if event.type == MOUSEMOTION:
				mox,moy = event.pos
				capmouseover = 0
				capmouseover = mouseover(screen,mox,moy)#鼠标是否经过cap

		screen.blit(surf,(0,0))#绘制平面
		#开始冒险
		screen.blit(StartAdventur,(470,80))
		if capmouseover==1:
			screen.blit(StartAdventur2,(470,80))
		#玩小游戏
		screen.blit(Survival,(470,205))
		if capmouseover == 2:
			screen.blit(Survival2,(470,205))
		#解谜模式
		screen.blit(Challenges,(470,305))
		if capmouseover == 3:
			screen.blit(Challenges2,(470,305))

		pygame.display.update()


if __name__ == '__main__':
	main()

主菜单稍微有点小长,不过代码中标识了注释也不难理解,在文件中我加入了很多图片素材都是原班植物大战僵尸的素材,后面还加了音乐提升游戏的趣味性!

编译后如下:
在这里插入图片描述
接着开发initgame.py文件:

# -*- coding:utf-8 -*-
import pygame
from sys import exit
from pygame.locals import *
pygame.init()

def eventinit(mosx,mosy,loadbar_width,loadbar_height):
	if mosx>80 and mosx<loadbar_width+80:
		if mosy>450 and mosy<loadbar_height+450:
			return True
	return False

def inits(screen):
	bg = pygame.image.load('images/Logo.jpg').convert_alpha()
	logoword = pygame.image.load('images/LogoWord.jpg').convert_alpha()
	loadbar = pygame.image.load('images/interface/LoadBar.png').convert_alpha()
	loadbar_width,loadbar_height = loadbar.get_width(),loadbar.get_height()
	loadbar2 = pygame.image.load('images/interface/LoadBar11.png').convert_alpha()
	
	GameRun = 1
	Timer = 0
	flagblit = False
	flagclick = False
	pygame.display.flip()
	while GameRun:
		for event in pygame.event.get():
			if event.type == QUIT:
				exit()
			if event.type == KEYDOWN:
				if event.key == K_RETURN:
					GameRun = 0 #进入游戏
					pygame.time.delay(250)
				
			if event.type == MOUSEMOTION:
				mosx,mosy=event.pos
				flagblit=eventinit(mosx,mosy,loadbar_width,loadbar_height)
			if event.type == MOUSEBUTTONDOWN:
				mosx,mosy=event.pos
				flagclick=eventinit(mosx,mosy,loadbar_width,loadbar_height)
			

		screen.blit(bg,(0,0)) #logo壁纸
		screen.blit(logoword,(320,16))#中文壁纸
		
		#开始按钮系列
		if not flagblit:
			screen.blit(loadbar,(80,450)) #开始按钮图片1
		elif flagblit:
			screen.blit(loadbar2,(80,455))#开始按钮图片2

		if flagclick: #进入游戏
			GameRun = 0
			pygame.time.delay(250)
		#Timer+=1
		pygame.time.delay(10)
		pygame.display.update()

然后运行程序得到的结果为:
在这里插入图片描述
哈哈,是不是很精彩了,没错这就是程序和图片的魅力!

接着剖析loading.py:

# -*- coding:utf-8 -*-
import pygame,os
from sys import exit
from pygame.locals import *
pygame.init()
def loading(screen,xpos_add_values):
	pygame.display.flip()
	gamerun = True
	FlagMeterEmpty = pygame.image.load('images/interface/FlagMeterEmpty.png').convert_alpha()
	FlagMeterFull = pygame.image.load('images/interface/FlagMeterFull.png').convert_alpha()
	FlagMeterParts1 = pygame.image.load('images/interface/FlagMeterParts1.png').convert_alpha()
	xpos,ypos=450-FlagMeterEmpty.get_width()//2,300-FlagMeterEmpty.get_height()//2
	xpos_width = 0
	Timer = 0
	Timer_loading_font = 0
	fo = pygame.font.Font('font/msyh.ttf',25)
	fontlist = [
				'.  ','.. ','...'
				]
	fl_i = 0
	while gamerun:
		for event in pygame.event.get():
			if event.type == QUIT:
				exit()
		screen.fill([0,0,0])

		#----------
		#进度条系列
		#----------

		#绘制空进度条载入中。。。
		screen.blit(FlagMeterEmpty,(xpos,ypos))
		pygame.draw.rect(screen, (255,255,100), (xpos+7,ypos+7,xpos_width,7))
		screen.blit(FlagMeterParts1,(xpos+7+xpos_width,ypos))

		myfont = fo.render("载入中%s"%(fontlist[fl_i]), True, (0, 200, 0))
		screen.blit(myfont,(450-myfont.get_width()//2,ypos+100))#载入字体
		Timer_loading_font+=1
		if Timer_loading_font == 5:
			Timer_loading_font=0
			fl_i += 1
		if fl_i==3:
			fl_i = 0

		if xpos_width<145:
			xpos_width += 5
		else:
			#绘制满进度
			screen.fill([0,0,0])
			screen.blit(FlagMeterFull,(xpos,ypos))
			#启动定时器
			Timer += xpos_add_values
		if Timer >= 30:
			gamerun = False


		pygame.time.delay(xpos_add_values)	
		pygame.display.update()


上面的loading.py是载入游戏等待时显示的一个动画,可以看做是一个过载动画。
在这里插入图片描述

最后插入游戏中设计的场景代码

game.py

# -*- coding:utf-8 -*-
import pygame,os
from sys import exit
from random import randint as r_i
from pygame.locals import *
pygame.init()
import initgame
import loading

def game_one(screen):
	pygame.mixer.music.load('music/Look up at the.mp3')
	pygame.mixer.music.play(-1,0,)
	#--------------
	#载入等待区系列
	loading.loading(screen,r_i(20, 30)) #第二个是延迟毫秒
	#--------------
	gamerun = True
	background = pygame.image.load('images/interface/background1unsodded.jpg').convert_alpha()
	button = pygame.image.load('images/interface/Button.png').convert_alpha()
	but_width,but_height = button.get_width(),button.get_height()
	fo = pygame.font.Font('font/msyh.ttf',21)
	myfont = fo.render("暂  停", True, (0, 230, 0))
	myfont2 = fo.render("菜  单", True, (0, 230, 0))
	plantshadow = pygame.image.load('images/plantshadow32.png').convert_alpha()
	zombies_dir = 'images/Zombies/Zombie/zombies/'
	zombies_files = os.listdir(zombies_dir) #僵尸动画列表
	zom_len = len(zombies_files) #僵尸帧动画数组数量
	zom_Timer = 0 #僵尸动画定时器
	zom_index = 0#僵尸帧动画当前位置
	Ifshowzom_action = True #是否显示僵尸动画 是否显示
	zom_width_add_flag = False#僵尸回拖是否为真
	zom_width_add = 0	#僵尸回拖距离
	#壁纸拖动变量定义
	width_add = 0
	maxadd_width = -495
	bg_Timer = 1 #壁纸回拖定时器
	bg_timerflag = False
	beginer = False
	#---------------------------------------------
	#定义僵尸个数列表 -随机  区域--585,130,200,330
	# 坐标位置随机区域585-785  130-460------------
	#---------------------------------------------
	zom_n = [
					[r_i(585,835), r_i(130, 460)]	,
					[r_i(585,835), r_i(130, 460)]	,
					[r_i(585,835), r_i(130, 460)]	,
					[r_i(585,835), r_i(130, 460)]	,
					[r_i(585,835), r_i(130, 460)]	
				]
	#僵尸排列问题
	zom_n_temp = []
	for zoo in zom_n:
		zom_n_temp.append(zoo[1])
	zom_n_temp=sorted(zom_n_temp)
	zom_index_index = 0
	for zoo in zom_n:
		zom_n[zom_index_index][1] = zom_n_temp[zom_index_index]
		zom_index_index += 1
	#植物卡片1号豌豆
	PeashooterG = pygame.image.load('images/Card/Plants/PeashooterG.png').convert_alpha()
	Peashooter = pygame.image.load('images/Card/Plants/Peashooter.png').convert_alpha()
	SunBack = pygame.image.load('images/interface/SunBack.png').convert_alpha()
	#草皮----
	sod1row = pygame.image.load('images/interface/sod1row.png').convert_alpha()
	SodRoll = pygame.image.load('images/interface/SodRoll.png').convert_alpha()
	SodRoll = pygame.transform.scale(SodRoll,( int(SodRoll.get_width()*0.7) , int(SodRoll.get_height()*0.9) ))
	SodRollCap = pygame.image.load('images/interface/SodRollCap.png').convert_alpha()
	SodRollCap = pygame.transform.scale(SodRollCap, (int(SodRollCap.get_width()*0.7), int(SodRollCap.get_height()*0.7)))
	
	#草皮宽度变化变量
	sod1row_change_value = 0
	sod_vas = 25
	grass_card_flag = False

	#font 
	fo = pygame.font.Font('font/msyh.ttf',18)
	myfon = fo.render('100', True, (0,0,0))
	myfon2 = fo.render('17', True, (0,0,0))
	pygame.display.flip()
	while gamerun:
		for event in pygame.event.get():
			if event.type == QUIT:
				exit()
		#区域
		screen.fill([0,0,0])
		screen.blit(background,(width_add,0))
		if width_add>=maxadd_width and beginer == False:
			width_add-=5
		else:
			beginer = True

		if beginer:

			#壁纸拖回动画定时
			if bg_Timer:bg_Timer+=1
			if bg_Timer == 200:#到达时间
				bg_Timer = 0 #定时器还原不增加了
				bg_timerflag = True
				zom_width_add_flag = True #僵尸回拖为真
				#Ifshowzom_action = False #是否显示僵尸动画
			if bg_timerflag:#标志成立 则拖动壁纸
				width_add+=5
				if width_add > -115:
					width_add=-115
					bg_timerflag = False#到达指定位置不拖动壁纸了
					
				
			#暂停开始系列
			screen.blit(button,(900-but_width*2,0))
			screen.blit(myfont,(900-but_width*2+27,5)) #暂停  开始
			#菜单系列
			screen.blit(button,(900-but_width*1,0))
			screen.blit(myfont2,(900-but_width*1+27,5))#菜单
			#开始游戏僵尸动画系列
				
			if width_add>=-115:
				if grass_card_flag == False:
					#植物卡片绘制 一号豌豆
					screen.blit(PeashooterG,(0,0))
				else:
					screen.blit(Peashooter,(0,0))
					screen.blit(SunBack,(120,0))
				screen.blit(myfon,(60,37))

				#草皮滚动动画
				#草皮元素透明慢慢增长
				for i in range(sod1row.get_width()):
					for j in range(sod1row.get_height()):
						temp = sod1row.get_at((i,j))
						if i<sod1row_change_value:
							if temp[0] or temp[1] or temp[2]:
								temp[3] = 255
						elif i >=sod1row_change_value:
							temp[3] = 0
						sod1row.set_at((i,j),temp)

				#绘制草皮动画
				screen.blit(sod1row,(132,300-sod1row.get_height()/2)) #草皮
				if sod1row_change_value<sod1row.get_width():
					sod1row_change_value+=sod_vas

					screen.blit(SodRoll,(75+sod1row_change_value,270-SodRoll.get_height()/2))#土
					screen.blit(SodRollCap,(71+sod1row_change_value,335-SodRollCap.get_height()/2))#卷土

				else:
					grass_card_flag = True

		

			#僵尸动画系列
			if Ifshowzom_action:
				zombie_ = pygame.image.load('images/Zombies/Zombie/zombies/%s'%(zombies_files[zom_index]) ).convert_alpha()
				#----------------------------------------------------------------------------------
				#僵尸产生的区域绘制如下函数--------------------------------------------------------
				#pygame.draw.rect(screen, (255,255,255), (585,130,250,330), 1)#僵尸产生位置区域绘制
				#----------------------------------------------------------------------------------
				#遍历所有僵尸
				if zom_width_add_flag: #当壁纸回拖时的变量
					zom_width_add+=5
					if zom_width_add==500:#当回拖到0点是僵尸动画的位置不移动了
						zom_width_add_flag=False#僵尸不会拖了
						Ifshowzom_action = False #僵尸不产生动画了
				#绘制所有僵尸动画场景
				for zom_i in range(len(zom_n)):
					screen.blit(zombie_,(zom_n[zom_i][0]+zom_width_add,zom_n[zom_i][1])) #绘制僵尸
					screen.blit(plantshadow,(zom_n[zom_i][0]+5+zom_width_add,zom_n[zom_i][1]+102))#w+5,h+102 绘制影子
				#僵尸定时器
				zom_Timer+=1#定时器加1
				if zom_Timer==9: #时间为90毫秒
					zom_Timer = 0#
					#到达了定时时间,僵尸图片帧下标更改
					zom_index+=1
					if zom_index==zom_len: #帧下标到达最大值归零
						zom_index=0

		#区域
		pygame.time.delay(10)
		pygame.display.update()

敲击回车,运行游戏结果如下图:
在这里插入图片描述
我们看到僵尸的位置是随机的,这里我们用到了随机算法,让僵尸固定在一个区域随机生成。
结果是不是很有趣了,真正的完成了一个植物大战僵尸的场景。但是要完全开发一个植物大战僵尸还需要一定的时间呢,作者抽空完成!

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐