这个无限循环可以保证游戏在启动之后不会立即被终止,
在游戏开发中啊,通常会把这个无限循环叫做游戏循环,当代码执行到游戏循环内部之后,才意味着游戏的正式开始.
现在游戏循环上方的代码不能够产生动画效果,因此啊,通常在开发游戏的时候,会把一个游戏分成两个部分,游戏循环上方的部分,把它叫做游戏的初始化.
在游戏初始化阶段,就主要来创建一个游戏窗口,然后加载不同的图像,把不同的图像摆在对应的初始位置.
但是要想让这些图像产生动画效果,就需要利用到游戏循环了.
在游戏中想要实现动画效果,需要快速连续的播放动画.
而在游戏循环中呢,就可以快速的移动每一个图像的位置.
移动之后调用update方法来快速的移动,快速的更新, 就会产生一个连续的动画效果了.
介绍了在游戏开发中通常把游戏分成两个部分,一个是游戏的初始化,一个是游戏的循环.
那现在看一下游戏初始化要做的主要事情来,在游戏初始化,第1步要来创建一个游戏窗口,第2步把所有的图像加载出来,并且指定一下这些图像的初始位置,两步工作做完, 还需要额外的设置一下游戏时钟.
现在游戏准备工作做完,就可以进入游戏循环开始正式的游戏了,.
在游戏循环中啊,主要要做的几件事情,
第1件事情来设置刷新帧率,在游戏开发中要想实现高品质的动画效果每一秒钟应该更新60次显示.
游戏的动画效果就是快速连续的播放画面,所以在游戏循环中啊,先要设置一下刷新帧率.
继续来看游戏循环中要做的其他事情,第2步要检测用户的交互,所谓用户的交互,就是来检查一下用户有没有按下键盘,或者用户有没有挪动鼠标.
一旦发现用户按下键盘或者挪动鼠标,就意味着用户要让游戏中的某些图像发生位置的改变.
所以呢,先来检测一下有没有用户交互,如果检测到, 就根据用户的交互,让游戏中对应的图像发生位置的移动,这个是在游戏循环中要做的两件事情.
那如果用户没有跟游戏进行交互,就让游戏中的图像,按照游戏需求的设定,按照既定的轨迹发生移动就可以.
当把图像的位置移动之后,不要忘记调用display模块提供的update方法.
只有调用了update 方法之后,才能够在屏幕上看到最终的一个绘制结果.
接下来介绍一下怎样使用pygame 提供的游戏时钟, 来控制一下游戏循环内部的代码每秒钟执行的频率.
要在游戏中达到一个高品质的动画效果,只需要每秒把屏幕更新60次就可以.
这样就意味着游戏循环内部的代码,每秒钟只需要被重复执行60次,就能够达到一个高品质的动画效果了.
但是现在完成的程序,那个无限循环执行的太快了.
我们开发出来的程序这个游戏循环中的代码不需要执行这么快.
游戏循环中的代码每一秒钟只需要重复执行60次就可以,那怎么样解决这个问题呢?在pygame中啊,专门提供了一个时钟类
time模块下提供了一个时钟类Clock.
通过这个类就可以创建一个时钟对象.
第1步啊,在游戏初始化使用clock类创建出一个时钟对象,然后呢,在游戏循环内部,让时钟对象调用一下tick 方法,并且把希望指定的重复频率,当作参数传递给这个方法就可以.
把光标先放在游戏循环的上方,在上方啊,来创建一个时钟对象,创建了时装对象之后, 才好在游戏循环内部让时钟对象来调用tick 方法.
那现在就给时钟对象起个名字叫做clock,然后呢,使用pygame的time模块,敲一个点找到cloc这个类. 这样一个对象就创建完成.
那紧接就在无限循环内部,让时钟对象来调用一下tick 方法,写一个数字60,也就是希望无限循环内部的代码,每秒钟重复执行60次. 代码改造完成.
再来运行一下程序, 直接点击控制台,
这个就是tick 方法的作用,在游戏循环外部创建一个时钟对象,在游戏循环内部,让时钟对象调用一下tick 方法,tick 方法的参数就可以来指令while 循环内部的代码执行的频率了,
这就是时钟对象tick方法的作用.
接下来就利用游戏循环来实现一下英雄飞机的简单动画,
在开始动手之前,要重点强调一下,在游戏循环内部,每一次调用update方法之前,都应该把游戏中所有的图像全部重新绘制一遍.
看一下演练需求, 先在游戏初始化的位置定一个Rect 类型的变量,Rect 类型是pygame提供的一个矩形对象.
可以用一个矩形对象来记录一下英雄飞机的初始位置,当英雄飞机初始位置定义完成,就在游戏循环内部,每一次让英雄的y值做一个减1,y值减1是向上移动.
先把上一小节测试游戏循环执行速度的代码全部做一个删除.
删除之后, 现在增加几个单行注释,用注释的方式来明确一下这一小节要实现的目标.
第1步要在游戏循环外部, 定义一个Rect类型的变量来记录飞机的初始位置.
第二步, 当飞机的初始位置定义完成,就可以在循环体内部来修改飞机的位置.
第三步, 当飞机的位置修改之后, 需要让screen 这个对象来调用一下blit 方法,把图像做一个绘制.
第四步, 当所有的图像绘制完成,就调用update方法更新显示.
现在就先来定义一个变量,记录飞机的初始位置,使用pygame点找到Rect这个类,要创建一个矩形对象,应该依次传入x, y和宽, 高.
那x, y值呢,就可以使用之前绘制英雄的坐标值150和300.
那要指定宽, 高啊,可以来查看一下英雄飞机的图片,
在窗口的右上角有个102×126,102就是飞机图片的宽度,126就是飞机图片的高度.
那现在回到代码来指定一下飞机的宽度,102, 再指定一下飞机的高度,126,
现在飞机的初始位置定义完成,就可以在游戏循环内部来修改一下飞机的位置,使用hero_rect 找到y 这个属性,然后呢,做一个 -= 的操作.
为了看清楚飞机的移动,先做一个大幅度的移动.
把y值减少50,等下在运行代码的时候可以看清楚飞机的移动.
现在飞机的位置修改完成,就需要使用screen 对象来调一下blit 方法.
blit 方法接收两个参数,第1个参数是要绘制的图像,第2个参数, 可以传入一个坐标的元组,当然也可以传入一个矩形对象,
现在blit 方法调用完成,还要使用pygame来调用一下display这个模块的update方法.
现在代码编写完成,来运行一下程序,看看英雄的飞机能不能发生移动,
看程序启动了, 现在英雄的飞机已经能够动,但是英雄飞机移动之后,在屏幕上会留下飞机的残影.
先停止一下程序,利用这个绘图软件展示一下,为什么会出现飞机的残影.
刚刚在游游戏初始化的时候绘制了一个背景图象, 绘制了一个英雄的飞机.现在在游戏循环内部, 修改了飞机位置,并且重新做了一个绘制动作.
重新绘制之后,之前的飞机仍然会保留在屏幕中,
如果这样的话,下一次再在新的位置绘制飞机时,又会添加一个新的飞机图像,同时呢,之前的飞机仍然保留,依次类推,是不是就产生了飞机的残影.
那怎么解决这个问题,其实非常简单, 如果希望在游戏循环中只是移动飞机的位置,而不希望看到之前的飞机影像,那么就可以把背景图像先重新绘制一下.
先把背景图像重新绘制,一旦绘制完成, 之前的飞机不能够在屏幕上看到了.
这个时候再在新的位置,来绘制一下飞机图像,由于之前的飞机已经被遮挡住了,所以先绘制背景图像,再绘制英雄的飞机,从视觉上来看就能够感觉到一个飞机慢慢的向上移动了.
现在完成的代码在运行时会留下一个又一个飞机的残影,在运行确认下, 飞机向上移动留下了一个又一个残影,那现在停止一下程序,
通过刚刚的分析, 要解决飞机的残影, 只需要在绘制飞机之前把游戏的背景再重新绘制一下,那现在就让screen这个对象来调用一下blit 方法, 把游戏的背景重新绘制在(0, 0)这个位置,代码改造完成,再来运行一下程序,看看游戏启动了, 飞机也移动了.
这次飞机就不会留下残影了.
因为重新绘制了背景图片,把之前飞机的影像做了一个遮挡,遮挡之后只能看到最新绘制的飞机对象,这样呢就可以看到一个连贯的动画了.
接下来再对英雄的动画再做一个简单的扩展,
现在英雄飞机已经能够向屏幕上方飞行了,在这一小节啊,每一次修改完英雄位置之后,都来判断一下英雄的y值.
如果y值小于等于0,就把英雄挪动到屏幕的底部, 这样做会达到一个什么效果呢.
飞机来到屏幕顶部之后,英雄的y值就应该等于原点的0.
一旦来到了屏幕顶部,就把英雄挪动到屏幕的底部,让英雄的飞机从屏幕下方钻出来,继续向上飞行,
这样修改之后,英雄的飞机就能够周而复始的在屏幕中飞行了,这个就是这一小节要实现的目标.
首先找到修改飞机位置的代码,因在修改飞机位置之后,要判断一下飞机的y值,看一看y值是否小于等于0.
那现在老师啊先增加一个注释判断飞机的位置,一旦y值小于等于0,就要修改一下飞机的y值.
一旦小于等于0,通过y属性就可以修改飞机的位置了.
现在再运行一下程序,游戏启动了, 英雄飞机缓缓的向上方飞行.
英雄的飞机从下方钻出来了.飞到顶部又从下方钻出来了, 对代码进行了一个简单修改之后,现在飞机已经可以实现循环的飞行了.