注:
想慢慢学习的同学可以看我的 《python 入门到游戏实战专栏》(更新中)
想学 C 的同学可以看《大话系列之C语言》(基本更新完)
想学 C++ 的同学可以看《大话C++》(更新中)
想做习题的可以看《大学生C语言作业、习题100例白话详解》
作者名:1_bit
简介:CSDN博客专家,2020年博客之星TOP5,蓝桥签约作者。15-16年曾在网上直播,带领一批程序小白走上程序员之路。欢迎各位小白加我咨询我相关信息,迷茫的你会找到答案。系列教程将会在流量降低时转为付费位置,流量多时将不会,各位抓紧时间学习哟~
小媛:小 C,我想学做游戏了,有什么速成的办法吗?
小C:没有,谢谢。
小媛:我看他们都可以,直接做一个飞机大战,说是一下子就学会了。
小C:你是想先大概过一遍内容吗?还是具体的全面的学?
小媛:我想先有一点体验感,自己学的舒服玩一下也行。
小C:那就可以,1小时搞定。
小媛:这么快?那刚刚你又说不行。
小C:你不是全面学,只学基础核心就没啥问题。一个小时搞定还是可以做点东西的。
小媛:那就赶紧开始吧。
小C:那我们就学 python 吧,你觉得怎么样?
小媛:可以呀,做出来游戏就可以了。
小C:你电脑我记得有环境和编辑器,我们就用原本的就好了。
小媛:原本的是啥?
小C:那个 vscode,我们用的库是 pygame。
小媛:唔,懂了。
小C:那我们就从头开始学吧,首先打开我们的 vscode 创建一个文件叫做 game.py 进行代码的测试吧。
小媛:了解,我已经新建好了。
小C:那我们首先写一个 hello world 吧。
小媛:hello world 是什么?
小C:是一个经典的计算机程序,就是程序运行的时候会显示 hello world。
小媛:懂了,那怎么做呢?
小C:首先你要知道,编程其实就是使用不同的“魔法指令”在计算机中创造不同的东西,python 用来显示内容的指令就是 print()
,你用 print()
要显示什么字符串就在里面加上去就可以了。
小媛:这样吗?
print(helloworld)
小C:在这里需要跟你提一点,在 python 中字符串是需要使用双引号引起来的。
小媛:懂了,你的意思是这样。
print("helloworld")
小C:对的,这个时候我们点击运行按键就可以看到结果了。
小媛:出现结果了,在这里。
小C:那我们继续往下讲。我们接下来学一个容器,用来存储值。
小媛:存值的内容有什么意义吗?
小C:有呀,你想想在游戏之中其实你的血量都是存在一个容器之中,还有你的昵称,不然你觉得没有东西存那这东西怎么显示?
小媛:哈哈哈,之前不懂,现在懂了。
小C:变量也是超级简单,我们直接给变量起个名字,用个等于号就可以存值了。你现在创建一个变量你想起什么名字呢?
小媛:那就起一个名字叫做 a 就好了。
小C:那你想在这个变量 a 里面存什么值呢?
小媛:那就存一个 10 吧。
小C:那么代码就可以这样写。
a=10
小媛:就这样?
小C:是的,我们创建一个变量直接一个名字,在这个变量名右边用一个等于号连接一个值,那么这个值就会存储到这个变量中。
小媛:真简单。
小C:那你知道怎么存储一个字符串吗?
小媛:知道呀,就这样。
a="1_bit"
小C:为什么要这样写呢?
小媛:因为 a 是一个变量名,用一个等于号就可以把等于号右边的值存到左边的变量中,然后最开始你说在 python 中字符串是需要双引号标记,那就是这样写咯。
小C:不错,理解透彻,那我们开始显示变量里面所存储的内容吧。
小媛:这个就不会了,怎么显示呢?
小C:很简单,也是使用 print(),直接在 print() 的括号内填写变量名就可以了。
小媛:这样吗?
a="1_bit"
print(a)
小C:是的。
小媛:结果出来了。
小C:使用 print() 可以显示很多的内容,例如你想用字符串连接在一起显示可以使用逗号进行分隔,首先我们创建多个变量。
a="1_bit"
b="2_bit"
c="3_bit"
小媛:这样就可以创建几个变量了吗?
小C:是的,python 的代码是一行行的从上往下书写,这个切记。每一句结束后就需要换到下一行去进行编写。
小媛:懂了。
小C:那我们同时显示这几个变量的内容直接使用 print() 就可以了。在 print() 元你括号内填入几个变量使用逗号进行隔开就行。
a="1_bit"
b="2_bit"
c="3_bit"
print(a,b,c)
小媛:我运行后显示出来了。
小C:你还可以在 print() 中填入其他的字符串当作值进行输出显示。
小媛:那意思就是说使用引号把字符串引起来就可以了吧?然后使用逗号隔开?
小C:是的,这样字符串也是值,只要填入就可以输出显示。
小媛:代码是这样,我运行出来了。
a="1_bit"
b="2_bit"
c="3_bit"
print("分别输出 a b c 的值:",a,b,c)
小C:其实我们的变量是可以进行相加减的,例如以下代码和结果。
a=11
b=2
c=31
print(a+b)
print(a-b)
print(a*c)
小媛:明白了,跟日常生活中的一样。
小C:其实只是基础运算大致相同,我们可以看看下面这个示例。
a="11"
b="2"
c="31"
print(a+b)
print(a+b)
print(a+c)
小C:因为两个字符串之间做加法,这个加法指的是将两个字符串进行连接,因为字符串和数字是两个类型。带双引号的 11 是字符串的 11,而不是数字的 11,你得明白这一点。
小媛:哈哈哈,懂了。就是说数字也是字符,看不同形态下的表现。
小C:是的。
小C:接下来我们可以看下逻辑判断了,这个是非常重要的知识点。
小媛:是不是在游戏中用的很多?
小C:逻辑判断你要做啥其实都用的很多。
小媛:那我就认真学习。
小C:其实逻辑判断就像你登录游戏时,需要判断你的帐号密码一样,判断帐号密码是否正确,正确就登录游戏,错误就退出游戏,就是这个意思。
小媛:懂了。
小C:逻辑判断在 python 中使用的是 if。我们可以把这个 if 当作是一句魔法,我们在需要逻辑判断的时候就把这个打上就可以了。
小媛:明白,就跟念咒语一样。
小C:是的。我们打上 if 后,在 if 后面加上一个条件,然后使用冒号结束,就像下面一样。
a=11
if a==11:
print("a是等于11")
小媛:嗯,首先你是创建一个变量 a 存储 11 这个值,然后使用 if 语句给了一个条件,这个条件是 a==11,然后冒号结束。不过我想问一下,你在这里打了两个等于号是不是你打错了?
小C:这个没有。在 python 中是使用两个等于号进行判断左右两边是否相等,也就是判断两个等于号的坐标 a 是否等于右边的 11。
小媛:明白了,那为什么下一句 print() 前面要空几个格呢?
小C:你想想,如果条件正确了,是不是就执行一句话,条件错误了就应该执行另外一条代码?
小媛:是的。
小C:其实在这里是如果这个条件正确,就执行冒号后的下一行 print("a是等于11")
。前面使用几个空格的意思是将表示这条代码属于 if 这个判断结构内,和其他代码不是一个结构的东西,这样只要条件错误就不会执行 if 结构内的了,如果你放在外面就会被执行了。
小媛:懂了,你意思这样就可以标识是这个 if 结构内的东西了,是 if 这个结构内部的。
小C:是的,运行后将会显示结果。
小媛:我修改了 a 的值他就不会显示出来了,啥也没显示。
a=111
if a==11:
print("a是等于11")
小C:其实我们 if 语句内可以打很多代码的,因为编程是灵活的,例如这个示例:
a=11
if a==11:
print("a是等于11")
print("a是等于11")
print("a是等于11")
print("a是等于11")
print("a是等于11")
小媛:是不是都要空相同的空格呀?
小C:是的,这样才表示是同一个层级。如果你乱空空格会出错的。
小媛:明白。
小C:如果这个时候我们想知道判断错误,我们可以添加一个 else 语句,这样错误的话就是显示 else 语句内部的代码了。
a=111
if a==11:
print("a是等于11")
print("a是等于11")
print("a是等于11")
print("a是等于11")
print("a是等于11")
else:
print("判断错误")
print("判断错误")
print("判断错误")
小媛:明白了,这个 else 语句一定要紧跟着在 if 语句结束后吗?而且他是顶头的没有进行空格。
小C:是的,因为 if 和 else 是同级,如果你也空格了那不就是在 if 语句判断对后才能执行吗?这样永远就不会执行 else 语句了,并且这样写也是错误的;else 还可以紧跟在 elif 后面,当我们多条件的时候就可以使用 elif 语句。
小媛:那就举个例子吧。
小C:那你看下面。
a=2
if a==11:
print("a是等于11")
print("a是等于11")
print("a是等于11")
print("a是等于11")
print("a是等于11")
elif a==2:
print("a是等于2")
print("a是等于2")
print("a是等于2")
elif a==3:
print("a是等于3")
print("a是等于3")
print("a是等于3")
else:
print("判断错误")
print("判断错误")
print("判断错误")
小媛:elif 后面跟着的就是条件吗?例如 a2 和 a3?
小C:是的,当 if 条件判断错误后会依次进行判断,哪一个条件判断正确就执行那个条件内的代码,如果所有条件错误那么就执行 else 部分。
小媛:明白了,还有多少才能学完基础?
小C:已经学完一半了,超级快的,哈哈哈。
小媛:好,请继续。
小C:其实 if 还可以进行嵌套,例如下面这个代码。
a=2
b=3
if a==2:
if b==3:
print("完全符合要求")
else:
print("第一项要求都没符合耶")
小媛:嵌套的意思就是在 if 里面再有一个 if 吗?
小C:是的,但是里面的 if 也有层级,要表示是里面 if 内的代码还是需要使用几个空格间隔,依次往里缩。
小媛:明白了。
小C:接下来我们学习循环。当你想重复运行某一条或者某一段代码时我们可以使用循环节省我们的代码编写时间,例如下面这段代码。
i=0
while i<10:
print("你好")
i=i+1
小媛:你首先创建了一个变量 i,然后我就不懂了。
小C:while 是一个循环,就跟你使用 if 一样,使用 while 表示要开始循环了;while 之后的是一个条件,也就是满足这个条件才会循环 while 循环内的代码,这个条件使用冒号结束,是不是感觉 while 的形式跟 if 语句很像呢?
小媛:是的,感觉很相同,然后最后的两个在前面空了几个格,并且使用了相同的空格,是表示是 while 循环结构内的代码吧?
小C:是的,这个是就会执行循环,每次循环都会执行 print("你好")
和 i=i+1
。由于条件是 i<10
,i 每次循环都会加 1,第一次循环 i 是 0,第二次循环 i 是 1,然后依次类推肯定会超过 10的,这个时候就不循环了。下面就是结果。
小媛:明白了。循环也可以进行嵌套吧?
小C:是的,不过我们暂时不用讲,由于是速成,所以我们在之后的游戏制作之中再做讲解。
小媛:好的。
小C:接下来我们讲一个列表。我们在进行存储值的时候使用变量是存储一个值,那么我们使用列表就可以存储多个值了。
a=[99,6,7,85,2,3]
print(a)
print(a[0])
print(a[4])
a[0]="你好"
print("修改后的值是:",a)
小C:在这里这个 a 就是列表,然后使用一个等于号,将我们想要存储的值放到一个中括号内,并且值与值之间使用逗号进行分隔,这个时候就可以创建一个列表了。
小媛:明白了,感觉挺简单的。然后 print(a)
就是显示这个列表的值了吧?
小C:是的,然后 print(a[0])
意思就是输出这个 a 列表内的第一个元素。在列表中 0 就表示第一个元素 99,然后 1 就表示第二个元素 6,然后以此类推,我们在输出的时候使用一个变量名,然后后面使用方括号,在方括号内写上你想显示第几个元素就可以取到这个元素然后将值进行显示输出了。
小媛:懂了,然后 a[0]="你好"
的意思就是给这个位置重新赋值?
小C:是的,这个时候我们可以看到最后输出所有值的时候第一个元素的内容发生了改变。
小C:其实我们还可以使用一个循环使我们的列表一个个值进行显示,这个循环叫做 for 循环。
小媛:循环还有内容没学完吗?
小C:是的,还有一个 for 循环没进行学习,你看下面的代码示例。
a=[99,6,7,85,2,3]
for v in a:
print(v)
小C:是的,代码 for v in a:
中的 for 表示开始使用 for 循环,接下来的 v in a 你可以理解成直接在这里创建一个变量 v,然后这个变量 v 进到 a 这个列表中一个个去取值,首先会取到最开始的值,然后每次循环就会跳到下一个值,这个时候我们就可以把这个值取出,使用 print() 就可以进行显示了。
小媛:原来是这么回事,理解了。
小C:接下来我们开始编写自定义的工具了,其实 print() 我们可以称为函数,函数我们可以理解成一个工具或者说一个功能。我们需要用到这些功能的时候字节拿过来用就可以了,现在我们要编写一个菜单功能,每次用到菜单就不用自己去写那么多代码,直接使用就可以。
小媛:那这样我不是可以节省很多时间了?
小C:是的,这个就叫做自定义函数,自己编写一个函数。你可以看下面的代码示例。
def menu():
print("这是一个菜单你可以进行查看")
print("1.进入系统")
print("2.退出系统")
print("3.删除系统")
print("4.退出帐号")
print("5.关闭软件")
menu()
小媛:这个时候不会是上面的 print 直接显示的内容吗?
小C:不会,我先解释一下这个的意思吧。我们可以看到 def,def 表示你开始创建一个自定义函数,def 后就是一个函数名之后使用一个括号,这是定义函数的一种形式,之后的话我们使用冒号进行结束就可以了。
小媛:例如我想创建一个函数叫做 abc,那么是不是可以这样写。
def abc():
小C:是的,然后在冒号下一行开始编写这个函数的代码就可以了,一样的需要使用空格表示这个代码是属于这个函数内的内容。
小媛:明白了。
小C:调用函数就是使用函数的意思,直接使用函数名加一对圆括号就可以使用,此时就等于运行了函数内的代码,这个时候就显示出了内容。
小媛:意思说如果不使用就不会起作用?
小C:是的,是这个意思。
小媛:明白了。
小C:其实函数还可以接受参数,就像你使用 print() 一样需要往里面传入数据才能显示。你自己创建一个函数也可以接受一下参数,参数其实就像你生活中用电饭锅做饭,需要有米才可以煮饭,这个米就是这个电饭锅功能的参数。
小媛:懂了,那怎么做呢?
小C:很简单,在自定义函数的圆括号内创建变量,如果是多个就使用逗号进行间隔就可以了。
小媛:你的意思是说这样?
def abc(a,b):
小C:是的,例如下面这个代码。
def abc(a,b):
print(a+b)
abc(1,2)
小媛:这个时候 1 就等于存到 a 里面,然后 2 就等于存到了 b 里面是吧?
小C:是的,如果你只想函数作为计算,不输出,我们可以使用一个叫做 return 的进行值的返回。例如以下代码。
def abc(a,b):
return a+b
c=abc(1,2)
print(c)
小媛:你的意思是 return 会把 a+b 的结果给返回出去?
小C:是的,这个时候 c 就可以进行接收,abc(1,2) 计算后就等于了 3,最后输出 c 的内容就可以看到等于 3 了。
小媛:明白了。
小C:我们接下来需要学习的是面向对象。
小媛:面向对象是什么呀?我没有对象。
小C:其实面向对象不是说你要有对象,其实就是我们可以创建一个类型,这个类型实例化后就是对象。
小媛:不懂,好难。
小C:其实不难的,你看下面的示例。
class human:
name=""
age=0
def say(self):
print("hello")
def myInfo(self):
print("myName:",self.name,"myAge:",self.age)
小媛:完全看不懂啊,好难。
小C:我一个个解释给你听吧。在上面代码中的 class 就是表示现在要创建一个类别,human 就是这个类别的名称。
小媛:你的意思就是 class 是关键字,后面就是这个类型的名称时候吧?
小C:是的,在这个 human 类型中,有两个属性;一个属性叫做 name,另外一个属性叫做 age。
小媛:就跟正常变量一样,一个 name 存储的是空字符串,一个 age 存储的是年龄。
小C:是的,在这里 name 就用来存储名称,age 用来存储年龄,接下来就由两个方法,一个叫做 say 一个叫做 myInfo。
小媛:这两个是自定义函数吧?那参数为什么是个 self 呢?
小C:这个 self 我们可以理解成当前这个类型之中的意思,家长自定义函数的参数之中我们可以当做表示这个自定义函数是属于这个类。
小媛:你的意思就是加了 self 才表示是当前这个类型的方法?
小C:对的,规定是这样做的。你可以看这句代码 print("myName:",self.name,"myAge:",self.age)
,self就是表示当前这个类型,self.name 就表示是当前这个类型中的 name 这个变量,我们可以理解那个小数点为 “的” 的意思,self.name
就是当前类型中的 name 变量。
小媛:明白了。
小C:我们接着看一下下面的使用方法。
class human:
name=""
age=0
def say(self):
print("hello")
def myInfo(self):
print("myName:",self.name,"myAge:",self.age)
xiaoM=human()
xiaoM.say()
xiaoM.myInfo()
xiaoM.name="XiaoMing"
xiaoM.age=18
xiaoM.myInfo()
小C:xiaoM=human()
就是创建一个 human 对象。例如我们人是一个类型,那么具体到一个人就是一个对象,现在 human 这个类型创建到了一个具体对象存储在 xiaoM 这个变量之中。
小媛:唔,明白了,有了类型才能创建到一个具体的对象。
小C:嗯,然后我们可以通过这个对象使用这个类型的方法,因为这个对象就属于这个类型。例如 xiaoM.say()
就表示使用这个类型中的 say() 方法,然后 xiaoM.myInfo() 也是;当然我们也可以使用 xiaoM.name="XiaoMing"
去赋予这个对象中这个 name 属性值,然后在使用 myinfo 进行输出,这个时候值就改变了。
小媛:唔,全明白了,哈哈哈。
小C:接下来我们开始编写一个小游戏吧。
小媛:这么快?
小C:是的,已经可以去写了的。首先我们需要做的是准备工作,我们在命令窗口中使用 pip 命令安装 pygame 这个游戏库,你的电脑已经有 pygame 了,那我们就不需要这一步了。
pip install pygame
小媛:嗯。
小C:接下来我们的第一步是将 pygame 引入。
import pygame
小C:import 就像你的一只手,然后 pygame 就是一个工具名,连起来就是将这个工具拿过来用。
小媛:明白了。
小C:接下来我们就需要进行初始化。初始化就像你玩游戏需要创建一个角色一样,这就是初始化。
import pygame
pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("这是一个飞机游戏")
小C:上面代码中的第二条 init 就是初始化的意思。
小媛:那个小数点是不是就表示 pygame 中的 init 方法?直接使用就可以初始化?
小C:是的,pygame.display.set_mode((600,800))
这句代码我们可以理解成 pygame 这个工具中有一个工具叫做 display,display 有一个g功能就是创建窗口,名叫 set_mode,我们在 set_mode 中传入这个屏幕的宽高,并且使用括号括起来宽高就可以创建出一个屏幕了,其中 600 是宽 800 是高;之后创建了屏幕后将这个屏幕给予一个变量,之后就可以通过这个变量对这个屏幕进行操作。
小媛:简单,理解起来容易。
小C:接下来那一句代码 pygame.display.set_caption("这是一个飞机游戏")
,set_caption 是 display 的另外一个功能,可以设置标题,直接将字符串当作参数传入 set_caption 就可以了。
小媛:懂了。
小C:接下来我们需要开始游戏主循环的内容,所有游戏都是通过一个循环去监听你在游戏中做了什么事,这个时候我们可以使用 while 循环给予一个 True 做条件,True 就表示永远条件正确。
小媛:你的意思就是需要创建一个循环还一直看玩家按了什么键做了什么事?
小C:对的,你看下面代码。
import pygame
pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("这是一个飞机游戏")
while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
exit()
小C:在 while 循环内有一个 for 循环用来取游戏中发生的所有事件。pygame.event.get()
将会获取到玩家做了所有的事情,通过 for 循环一个个去取,event 这个变量就分别每次取得这些内容,使用 if 判断 event 的类型 type 如果是 pygame 游戏中的退出 QUIT 那么就执行 exit() 退出整个程序。
小媛:唔,那也可以检测上下左右按键吧?这样就可以实现移动了?
小C:是的,不过现在我们需要往这个游戏里面添加背景和角色,这些都是图片,我们可以通过加载图片资源创建背景和主角对象,我们都可以称这些元素为精灵。
小媛:精灵,好听的名字。
小C:你看下面的代码。
import pygame
bg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')
heroX=250
heroY=680
pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("这是一个飞机游戏")
while True:
screen.blit(bg,(0,0))
screen.blit(hero,(heroX,heroY))
for event in pygame.event.get():
if event.type==pygame.QUIT:
exit()
小C:上面的代码 pygame.image.load 就表示使用 pygame 中的 image 工具的 load 功能,load 就是加载图片的意思;在 load 方法中传入图片的路径就可以了,我在这里分别加载了 5 个图片,一个是背景图、一个是主角图、一个是敌人图、一个是敌人被击中后的爆炸图、一个是子弹图片。
小媛:我电脑上你是放在同样的路径下吧?
小C:是的,如果没有图片可以私聊 bit 哥(博主 https://blog.csdn.net/A757291228),他会统一发的。
小媛:明白。
小C:我们接着看 screen.blit(bg,(0,0))
代码和 screen.blit(hero,(heroX,heroY))
代码,这两句代码都是用 blit 方法,blit 方法 是 screen 的功能之一,也就是可以在屏幕中画出我们加载的图片;blit 的第一个参数是图片参数,第二个参数是整个屏幕的 x 和 y 坐标,也就是从哪里开始画;x 越大越靠右,y 越大越靠下。
小媛:那为什么我运行了代码后是一片黑屏?
小C:那是因为我们需要刷新,每次循环完我们都需要刷新整个界面,否则是不会呈现画完的效果的。你在 while 循环最后加一个代码,pygame.display.update()
,就如下所示。
import pygame
bg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')
heroX=250
heroY=680
pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("这是一个飞机游戏")
while True:
screen.blit(bg,(0,0))
screen.blit(hero,(heroX,heroY))
for event in pygame.event.get():
if event.type==pygame.QUIT:
exit()
pygame.display.update()
小媛:出来了耶。
小C:那么接下来我们来控制这个飞机左右移动吧。
小媛:期待。
小C:我们创建一个函数,用来检测用户是否按下了上下左右。
import pygame
bg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')
heroX=250
heroY=680
stepX=0 #此部分新增
stepY=0 #此部分新增
pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("这是一个飞机游戏")
def keydown_envent(event,stepX,stepY):#此部分新增
if event.key == pygame.K_RIGHT:
stepX=5
elif event.key == pygame.K_LEFT:
stepX=-5
elif event.key == pygame.K_UP:
stepY=-5
elif event.key == pygame.K_DOWN:
stepY=5
return stepX,stepY
while True:
heroX=heroX+stepX
heroY=heroY+stepY
screen.blit(bg,(0,0))
screen.blit(hero,(heroX,heroY))
for event in pygame.event.get():
if event.type==pygame.QUIT:
exit()
if event.type==pygame.KEYDOWN:#此部分新增
stepX,stepY=keydown_envent(event,stepX,stepY)
pygame.display.update()
小C:以上代码我在新增部分添加了注释,主要添加了一个 keydown_envent 方法用来检测按下事件后的处理。我们可以看到在 for 循环事件遍历中,使用 if event.type==pygame.KEYDOWN:
检测用户是否按下键,随后我们通过这个事件传入到 keydown_envent 方法中做处理,判断用户按下的是否是右键 K_RIGHT、左键 K_LEFT、上键 K_UP、下键 K_DOWN。如果是右键那么就增加下次绘制图片的 x 坐标值,下键就增加 y 坐标值这样依次类推,所以在 while 循环中就有了下面这个代码。
heroX=heroX+stepX
heroY=heroY+stepY
小媛:感觉有点像那个在书上画画,r案后翻动页码每次看到图都不一样,画上去的人物就可以动了。
小C:是的,就是这个原理,我们接着添加敌人。
import pygame,random
bg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')
heroX=250
heroY=680
stepX=0
stepY=0
enemy_speed=2#此部分新增
enemy_objs=[]#此部分新增
pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("这是一个飞机游戏")
def keydown_envent(event,stepX,stepY):
if event.key == pygame.K_RIGHT:
stepX=5
elif event.key == pygame.K_LEFT:
stepX=-5
elif event.key == pygame.K_UP:
stepY=-5
elif event.key == pygame.K_DOWN:
stepY=5
return stepX,stepY
def enemy_show(enemy_objs,startY=-40):#此部分新增
if len(enemy_objs)<5:
while len(enemy_objs)<5:
enemy_X=random.randint(0,500)
enemy_pos=[enemy_X,startY]
screen.blit(enemy,enemy_pos)
enemy_objs.append(enemy_pos)
else:
i=0
for pos in enemy_objs:
screen.blit(enemy,pos)
enemy_objs[i]=[pos[0],pos[1]+enemy_speed]
i=i+1
return enemy_objs
while True:
heroX=heroX+stepX
heroY=heroY+stepY
screen.blit(bg,(0,0))
screen.blit(hero,(heroX,heroY))
enemy_objs=enemy_show(enemy_objs) #此部分新增
for event in pygame.event.get():
if event.type==pygame.QUIT:
exit()
if event.type==pygame.KEYDOWN:#此部分新增
stepX,stepY=keydown_envent(event,stepX,stepY)
pygame.display.update()
小C:以上代码中添加了一个 enemy_show 方法,enemy_show 方法传入了一个 enemy_objs 列表用来记录创建的敌人对象,enemy_show 方法接收两个参数,还有一个是默认的 Y 坐标。在 enemy_show 中,如果敌机数量小于 5 个,那么就直接使用 while 循环进行创建,并且把创建对象的 X 和 Y 值存储到 enemy_objs 列表中,之后我们只需要控制每个敌机的位置坐标就可以控制 敌机移动了。
if len(enemy_objs)<5:
while len(enemy_objs)<5:
enemy_X=random.randint(0,500)
enemy_pos=[enemy_X,startY]
screen.blit(enemy,enemy_pos)
enemy_objs.append(enemy_pos)
小媛:你的意思是控制敌机移动只需要控制记录出现的坐标点进行绘制,那么就等于敌机在移动?
小C:是的。如果已经创建了 5 个 敌机,n阿么只需要根据他们的位置坐标进行 y 轴坐标的增加就可以了,也就是 enemy_show 方法中 else 部分的内容。
def enemy_show(enemy_objs,startY=-40):#此部分新增
if len(enemy_objs)<5:
while len(enemy_objs)<5:
enemy_X=random.randint(0,500)
enemy_pos=[enemy_X,startY]
screen.blit(enemy,enemy_pos)
enemy_objs.append(enemy_pos)
else:
i=0
for pos in enemy_objs:
screen.blit(enemy,pos)
enemy_objs[i]=[pos[0],pos[1]+enemy_speed]
i=i+1
return enemy_objs
小媛:唔,原来如此,那么 enemy_speed 加多少就表示速度了吧?我看你在前面定义这个值是 5。
小C:是的。你可以运行代码试一试。
小C:我们现在开始添加子弹吧,其实子弹添加也很简单,只需要知道我们这个主角的位置,然后使子弹在这个位置头部绘制,绘制后每次刷新后的距离都 -10 这样子弹就可以飞上去了呢。
小媛:是的,我感觉会写了。
小C:我们接着看代码吧,我们设置空格键就是子弹发射按键,这个时候我们在事件方法中添加空格事件的响应,然后绘制出一个子弹就可以了。
import pygame,random
bg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')
heroX=250
heroY=680
stepX=0
stepY=0
bullets_pos=[]#此部分新增
enemy_speed=2
enemy_objs=[]
pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("这是一个飞机游戏")
def keydown_envent(event,stepX,stepY,hero_pos):
bullet_pos=[]#此部分新增
if event.key == pygame.K_RIGHT:
stepX=5
elif event.key == pygame.K_LEFT:
stepX=-5
elif event.key == pygame.K_UP:
stepY=-5
elif event.key == pygame.K_DOWN:
stepY=5
elif event.key == pygame.K_SPACE:#此部分新增
bullet_pos=[hero_pos[0],hero_pos[1]+10]
return stepX,stepY,bullet_pos
def enemy_show(enemy_objs,startY=-40):
if len(enemy_objs)<5:
while len(enemy_objs)<5:
enemy_X=random.randint(0,500)
enemy_pos=[enemy_X,startY]
screen.blit(enemy,enemy_pos)
enemy_objs.append(enemy_pos)
else:
i=0
for pos in enemy_objs:
screen.blit(enemy,pos)
enemy_objs[i]=[pos[0],pos[1]+enemy_speed]
i=i+1
return enemy_objs
while True:
bullet_pos_=[]#此部分新增
heroX=heroX+stepX
heroY=heroY+stepY
screen.blit(bg,(0,0))
screen.blit(hero,(heroX,heroY))
enemy_objs=enemy_show(enemy_objs)
i=0
for v in bullets_pos:#此部分新增
bullets_pos[i]=[v[0],v[1]-10]
screen.blit(bullet,(bullets_pos[i][0]+45,bullets_pos[i][1]))
distance_b=[bullets_pos[i][0]+45,bullets_pos[i][1]]
i=i+1
for event in pygame.event.get():
if event.type==pygame.QUIT:
exit()
if event.type==pygame.KEYDOWN:#此部分新增
stepX,stepY,bullet_pos_=keydown_envent(event,stepX,stepY,[heroX,heroY])
if len(bullet_pos_)>0:
bullets_pos.append(bullet_pos_)
pygame.display.update()
小C:我们在响应按键的方法中添加了响应空格的处理,我们将记录当前主角所在的目标位置 bullet_pos=[hero_pos[0],hero_pos[1]+10]
,然后做为返回值返回,返回之后判断 bullet_pos_ 接收值后长度是否大于 1,大于则表示已经按下空格,则记录在 bullets_pos 列表中;之后使用循环遍历每个子弹的位置,然后在 Y 轴上减去 一个值即可发射子弹。
i=0
for v in bullets_pos:#此部分新增
bullets_pos[i]=[v[0],v[1]-10]
screen.blit(bullet,(bullets_pos[i][0]+45,bullets_pos[i][1]))
distance_b=[bullets_pos[i][0]+45,bullets_pos[i][1]]
i=i+1
小媛:那 +45 是啥意思呢?
小C:因为我们的飞机会占据一定宽度,+45 是为了保持子弹在飞机头位置中间进行发射。
小媛:明白了,我的子弹出来了。
小C:我们接下来开始添加击中摧毁吧。击中摧毁其实就是判断子弹与敌机的距离,我们使用欧氏距离就可以了,编写一个方法。
def distance(bx,by,ex,ey):
a=bx-ex
b=by-ey
return math.sqrt(a*a+b*b)
小媛:不懂怎么办。
小C:哈哈哈,这个问题不是本篇的内容,不懂公式的大家搜索一下就可以了,或者直接使用这个方法。
小媛:问题不大。
小C:接着我们在子弹移动时添加距离计算,如果子弹移动后与敌机小于一定距离,那么就在敌机位置显示出爆炸图片就可以了。
i=0
for v in bullets_pos:
bullets_pos[i]=[v[0],v[1]-10]
screen.blit(bullet,(bullets_pos[i][0]+45,bullets_pos[i][1]))
distance_b=[bullets_pos[i][0]+45,bullets_pos[i][1]]
ei=0
for ep in enemy_objs:#此部分新增
if distance(distance_b[0],distance_b[1],ep[0],ep[1])<60:
screen.blit(enemy_boom,(ep[0],ep[1]))
enemy_objs[ei]=[random.randint(0,500),-50]
ei=ei+1
i=i+1
小C:其实就是移动后,我们去循环每一辆敌机的位置,如果距离达到了我们就在那个位置显示爆炸图片,并且更改这个位置到初始位置重新掉落。
小媛:哈哈哈,可以了。
小C:那我们这个就做完了,其他内容就不说了。
小媛:行嘞,多谢小C。
小C:完整代码如下(改动了一下的)。
import pygame,random,math
bg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')
pygame.init() #初始化
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("这是一个飞机游戏")
heroX=250
heroY=680
stepX=0
stepY=0
enemy_speed=2
enemy_objs=[]
enemy_objs1=[]
enemy_objs2=[]
enemy_objs3=[]
bullets_pos=[]
bullet_speed=[]
def enemy_show(enemy_objs,startY=-40):
if len(enemy_objs)<5:
while len(enemy_objs)<5:
enemy_X=random.randint(0,500)
enemy_pos=[enemy_X,startY]
screen.blit(enemy,enemy_pos)
enemy_objs.append(enemy_pos)
else:
i=0
for pos in enemy_objs:
screen.blit(enemy,pos)
enemy_objs[i]=[pos[0],pos[1]+enemy_speed]
i=i+1
return enemy_objs
def screen_border(X,Y):
#左右屏幕
if X<0:
X=0
elif X>500:
X=500
#上下屏幕
if Y<0:
Y=0
elif Y>700:
Y=700
return X,Y
def distance(bx,by,ex,ey):
a=bx-ex
b=by-ey
return math.sqrt(a*a+b*b)
def keydown_envent(event,stepX,stepY,hero_pos):
bullet_pos=[]
if event.key == pygame.K_RIGHT:
stepX=5
elif event.key == pygame.K_LEFT:
stepX=-5
elif event.key == pygame.K_UP:
stepY=-5
elif event.key == pygame.K_DOWN:
stepY=5
elif event.key == pygame.K_SPACE:
bullet_pos=[hero_pos[0],hero_pos[1]+10]
print('space:',bullet_pos)
return stepX,stepY,bullet_pos
while True:
bullet_pos_=[]
heroX=heroX+stepX
heroY=heroY+stepY
heroX,heroY=screen_border(heroX,heroY)
screen.blit(bg,(0,0))
screen.blit(hero,(heroX,heroY))
enemy_objs=enemy_show(enemy_objs)
#enemy_objs1=enemy_show(enemy_objs1,-300)
#enemy_objs2=enemy_show(enemy_objs2,-600)
#enemy_objs3=enemy_show(enemy_objs3,-900)
print(bullets_pos)
i=0
for v in bullets_pos:
bullets_pos[i]=[v[0],v[1]-10]
screen.blit(bullet,(bullets_pos[i][0]+45,bullets_pos[i][1]))
distance_b=[bullets_pos[i][0]+45,bullets_pos[i][1]]
ei=0
for ep in enemy_objs:
if distance(distance_b[0],distance_b[1],ep[0],ep[1])<60:
print('\n\n\n\n\n\n\n\n\n\n\n\n boom')
screen.blit(enemy_boom,(ep[0],ep[1]))
enemy_objs[ei]=[random.randint(0,500),-50]
ei=ei+1
i=i+1
for event in pygame.event.get():
if event.type==pygame.QUIT:
exit()
if event.type==pygame.KEYDOWN:
stepX,stepY,bullet_pos_=keydown_envent(event,stepX,stepY,[heroX,heroY])
if len(bullet_pos_)>0:
bullets_pos.append(bullet_pos_)
pygame.display.update()