一、编写函数的测试用例
为函数编写测试用例,需要使用到unittest模块和需要测试的函数,再创建一个继承自unittest.TestCase的类。例如我们现在有一个方法fun(p1,p2)返回p1和p2组成的字符串,现在编写一个测试用例,来检查函数fun(p1,p2)能否正确地工作:
import unittest
import fun
class NameTestCase(unittest.TestCase):
'''*******'''
def test_funname(self):
'''****'''
result=fun('m','n')
self.assertequal(result,'mn')
unittest.main()
其中assertequal()方法是断言方法,它就是来核实得到的结果是否与期望的结果一致。unittest.main()是让Python运行这个文件中的测试。当我们运行上面的.py文件时,所有以test_打头的方法(单元测试的方法名必须以test_打头)都将自动运行。一个测试用例中可以包含多个单元测试。NameTestCase类就是一个测试用例,其中的方法就是单元测试。
二、编写类的测试用例
对于类的测试用例的编写,其实就是和函数的测试用例一样,只不过类的测试用例需要对类中的所有方法都要在测试用例中编写相应的单元测试。由于可能在每一个单元测试中都可能用到相同的数据,这样就会造成数据的重复定义,所以为了解决这个问题,TestCase类中有一个setUp()方法,我们可以在测试用例中定义这个方法,并在该方法中定义好所需的数据,这样在运行测试用例时,Python就会先默认地运行setUp()方法,再运行其它单元测试。
至此,Python的基础语法已经结束,接下来将编写三个小的项目。 Python有一个强大的模块可以用来开发游戏,这个模块叫做pygame,它可以用来管理图形、动画乃至声音,可以用来轻松地开发复杂的游戏。只需要将开发游戏的重点放在游戏的高级逻辑上,而不用考虑繁琐而艰难的编码工作。
三、外星人入侵的2D游戏
1.规划项目
在《外星人入侵》游戏中,玩家控制着最初出现在屏幕底部中央的飞船,玩家可以使用箭头键左右移动飞船,使用空格键进行射击。游戏开始时,一群外星人出现在天空中,他们在屏幕中向下移动,玩家的任务就是射杀这些外星人。玩家将所有外星人消灭干净后,将出现一群新的外星人,他们移动的速度更快了,只要有外星人撞到了玩家的飞船或者到达了屏幕底部,玩家就损失一艘飞船。玩家损失三艘飞船后,游戏结束。
在第一个开发阶段,先创建一艘可左右移动的飞船,这艘飞船在用户按空格键时可以开火。设置好这些之后,再去研究外星人。
2.安装的步骤根据百度上的自行安装
3.这里将飞船的属性都定义在模块settings中,里面包含一个Settings类,如下:
class Settings(): """A class to store all settings for Alien Invasion.""" def __init__(self): """Initialize the game's settings.""" # 屏幕的宽度、高度和背景颜色 self.screen_width = 1200 self.screen_height = 700 self.bg_color = (230,230,230) #飞船的速度 self.ship_speed_factor = 1.5 #子弹的速度、宽度、高度、背景颜色和子弹最多连发的子弹数 self.bullet_speed_factor=1 self.bullet_width=3 self.bullet_height=15 self.bullet_color=(60,60,60) self.bullets_allowed = 3
4.对于飞船的一系列操作,把它们都放在飞船对应的模块ship中,里面有一个类Ship,如下:
import pygame class Ship(): def __init__(self,ai_settings,screen): '''初始化飞船并设置初始位置''' self.ai_settings=ai_settings self.screen=screen #加载飞船图像并获取其外接矩阵 self.image=pygame.image.load('images/ship.bmp') self.rect=self.image.get_rect() self.screen_rect=screen.get_rect() #将每艘飞船放到屏幕底部中央 self.rect.centerx=self.screen_rect.centerx self.rect.bottom=self.screen_rect.bottom #在飞船的属性center中存储小数值 self.center=float(self.rect.centerx) #移动标志 self.moving_right=False self.moving_left=False def update(self): '''根据移动标志调整飞船的位置''' if self.moving_right and self.rect.right<self.screen_rect.right: self.center+=self.ai_settings.ship_speed_factor if self.moving_left and self.rect.left>0: self.center-=self.ai_settings.ship_speed_factor #根据self.center更新rect对象 self.rect.centerx=self.center def blitme(self): '''在指定位置绘制飞船''' self.screen.blit(self.image,self.rect)
当一艘飞船需要出现在屏幕上时,首先需要确定飞船的状态,所以在Ship类的默认方法里,就是要初始化飞船的各种属性,将飞船给造出来。pygame.image.load()方法将飞船的样子先给加载出来,它是一个bmp格式的图片,接着来获取这个图片的外接矩阵,pygame有一个强大的地方,就在于它能够将所有屏幕以及屏幕中的元素通过获取它们的外接矩阵来操纵它们的位置,即使元素本身不是矩形。接着再获取屏幕的外接矩阵。接着,就可以设置飞船的位置了,我们以飞船的中心位置为操纵飞船位置的关键点,将飞船的中心位置与屏幕的中心位置相同,这样就实现了将飞船放到屏幕的中心,这样就固定了飞船的横坐标。接着,让飞船的底部与屏幕的底部相同,这样就固定了飞船的竖坐标,至此,飞船的最终位置也就确定了。
update方法,是用来移动飞船位置的,如果飞船是向右移并且没有移出屏幕范围,则飞船的中心位置就加一个步长。反之,就减一个步长。
blitme方法就是来将最终全状态的飞船在屏幕上显示出来,需要用到blit方法,提供飞船的图片和表示飞船图片位置的外接矩阵。
5.对于子弹进行的一系列操作,我们把它放在子弹对应的模块bullet中,里面包含一个Bullet类,如下:
import pygame from pygame.sprite import Sprite class Bullet(Sprite): '''一个对飞船发射的子弹进行管理的类''' def __init__(self,ai_settings,screen,ship): super().__init__() self.screen=screen #在(0,0)处创建一个表示子弹的矩形,再设置正确的位置 self.rect=pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height) self.rect.centerx=ship.rect.centerx self.rect.top=ship.rect.top #存储用小数表示的子弹位置 self.y=float(self.rect.y) self.color=ai_settings.bullet_color self.speed_factor=ai_settings.bullet_speed_factor def update(self): '''向上移动子弹''' #更新表示子弹位置的小数值 self.y-=self.speed_factor #更新表示子弹的rect的位置 self.rect.y = self.y def draw_bullet(self): """在屏幕上绘制子弹""" pygame.draw.rect(self.screen, self.color, self.rect)
同样,我们首先需要确定子弹的状态。在这里,需要介绍一个类pygame.sprite.Group,这个类的作用就是可以将游戏中相关的元素进行编组,进而实现同时来操纵编组中的所有元素。先来看是怎么确定子弹的状态的,pygame.Rect类可以绘制一个自定义外接矩阵,只需要提供在屏幕的什么位置绘制多大的矩阵即可。获得了子弹的外接矩阵后,就要来确定外接矩阵的位置了(其实对于元素的操作,就是在操作它的外接矩阵)。
update方法,就是来更新子弹的竖坐标的。
draw_bullet()方法是用来在屏幕上绘制出子弹的形状的,pygame.draw.rect()方法是用来在屏幕上绘制外接矩阵的,因为这是完全凭空来绘制外接矩阵,故方法和将由图片得到的现成的外接矩阵在屏幕上绘制出来不一样。pygame.draw.rect()方法需要知道在哪个屏幕上的哪个位置绘制出什么什么颜色的子弹。
6.监听键盘事件,并作出相应反应
import sys import pygame from bullet import Bullet def update_bullets(bullets): """更新子弹的位置,并删除已消失的子弹""" # 更新子弹的位置 bullets.update() # 删除已消失的子弹 for bullet in bullets.copy(): if bullet.rect.bottom <= 0: bullets.remove(bullet) def fire_bullet(ai_settings, screen, ship, bullets): """如果还没有到达限制,就发射一颗子弹""" #创建新子弹,并将其加入到编组bullets中 if len(bullets) < ai_settings.bullets_allowed: new_bullet = Bullet(ai_settings, screen, ship) bullets.add(new_bullet) def check_keydown_events(event,ai_settings,screen,ship,bullets): '''响应按键''' if event.key==pygame.K_RIGHT: ship.moving_right=True elif event.key==pygame.K_LEFT: ship.moving_left=True elif event.key==pygame.K_SPACE: # 创建一颗子弹,并将其加入到编组bullets中 fire_bullet(ai_settings, screen, ship, bullets) def check_keyup_events(event,ship): '''响应松开''' if event.key==pygame.K_RIGHT: ship.moving_right=False elif event.key==pygame.K_LEFT: ship.moving_left=False def check_events(ai_settings, screen, ship, bullets): '''响应按键和鼠标按键''' for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() elif event.type==pygame.KEYDOWN: check_keydown_events(event,ai_settings,screen,ship,bullets) elif event.type==pygame.KEYUP: check_keyup_events(event,ship) def update_screen(ai_settings, screen, ship, bullets): '''更新屏幕上的图像,并切换到新屏幕''' #每次循环都重绘屏幕 screen.fill(ai_settings.bg_color) #在飞船和外星人后面重绘所有子弹 for bullet in bullets.sprites(): bullet.draw_bullet() ship.blitme() #让最近绘制的屏幕可见 pygame.display.flip()
在之前的几个类中,我们已经得到了飞船和子弹,在这个类中,我们要通过check_events方法来监听键盘按键,当监听到键盘按下时,还需要来判断按下的是什么键,并进行相应方法的调用。
7.主程序文件
import pygame from pygame.sprite import Group from settings import Settings from ship import Ship import game_functions as gf def run_game(): #初始化游戏并创建一个屏幕对象 pygame.init() ai_settings=Settings() screen=pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height)) pygame.display.set_caption('Alice Invasion') #创建一艘飞船 ship=Ship(ai_settings,screen) #创建一个用于存储子弹的编组 bullets=Group() #开始游戏的主循环 while True: #监视键盘和鼠标事件 gf.check_events(ai_settings,screen,ship,bullets) ship.update() bullets.update() gf.update_bullets(bullets) gf.update_screen(ai_settings,screen,ship,bullets) run_game()在这里,首先初始化一个surface,让我们能够进行接下来一系列操作,接着获得屏幕对象。使用循环不停地监听键盘事件,当按下了左右或者空格键后,就会更新飞船的位置,删除消失的子弹,然后在设置好飞船与子弹的状态后再将飞船与子弹重新在屏幕上显示出来。