上一节已经完成了飞船的左右移动,这节来完成调节飞船移动的速度,以及射击。
在上一张我们知道飞船每次移动1像素,而且有时候会移动到屏幕之外。我们可以设置飞船移动速度,在Setting 类修改
#存储外星人游戏开发的设置
class Setting():
def __init__(self):
self.screen_width=600 #设置屏幕高度宽度,背景颜色
self.screen_height=600
self.bg_color=(230,230,230)
self.ship_speed_factor=1.5 #设置飞船移动
设置移动速度为1.5.但在ship类中因为rect的centerx不能存储小数值,所以创建一个center
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#创建飞船类
import pygame
class Ship():
def __init__(self,ai_settings,screen):
self.screen=screen
self.ai_settings=ai_settings
#图片存在images文件夹下,名字是ship.bmp
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
self.center=float(self.rect.centerx) #因为rect的centerx只能储存整数值,在飞船的center储存小数值
self.moving_right=False #设置移动标志
self.moving_left=False
def update(self):
if self.moving_right: #根据移动标志,来调整位置
self.center+=self.ai_settings.ship_speed_factor #更新飞船的center的值,不是rect
if self.moving_left:
self.center-=self.ai_settings.ship_speed_factor
self.rect.centerx=self.center #来更新rect对象
def blitme(self):
self.screen.blit(self.image,self.rect)
因为我们把速度设置放在setting类里,所以在这里就要有ai_settings的形参,用于传送信息,在主程序里:
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
import pygame
from setting import Setting
from ship import Ship
import game_functions as gf
def run_game():
pygame.init() #初始化,创建屏幕对象
ai_settings=Setting() #创建一个800*800的屏幕
screen=pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion") #对于这个窗口的命名为Alien Invasion
ship=Ship(ai_settings,screen) #创建飞船
while True:
gf.check_events(ship)
ship.update()
gf.update_screen(ai_settings,screen,ship)
run_game()
输出时,速度比之前是快了。
再限制一下飞船的活动范围,防止在游戏屏幕外面,我们可以通过检查self.center的值是否等于屏幕的边缘值,就可以解决该问题。我们在修改ship类:
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#创建飞船类
import pygame
class Ship():
def __init__(self,ai_settings,screen):
self.screen=screen
self.ai_settings=ai_settings
#图片存在images文件夹下,名字是ship.bmp
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
self.center=float(self.rect.centerx) #因为rect的centerx只能储存整数值,在飞船的center储存小数值
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 #更新飞船的center的值,不是rect
if self.moving_left and self.rect.left>0:
self.center-=self.ai_settings.ship_speed_factor
self.rect.centerx=self.center #来更新rect对象
def blitme(self):
self.screen.blit(self.image,self.rect)
再运行主程序,就会发现飞船就在在屏幕里移动,不会在屏幕之外。
接下来再针对于射击:
我们先编写子弹的矩形,以及按键空格键发送子弹,子弹向上发送,直至上边缘消失,创建一个bullet类。我们先在设置类添子弹设置:
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#存储外星人游戏开发的设置
class Setting():
def __init__(self):
self.screen_width=600 #设置屏幕高度宽度,背景颜色
self.screen_height=600
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=(0,0,255)
设置子弹的速度,矩形的长宽以及颜色,
接下来就是创建子弹类:
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#设置子弹类
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite): #一个对子弹管理的类,继承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
self.rect.y=self.y
def draw_bullet(self): #绘制子弹
pygame.draw.rect(self.screen,self.color,self.rect)
导入pygame,因为子弹不是基于图像的,所以就使用pygame.Rect类来从空白开始创建一个矩形,创建这个这个类的实例的时候,必提供矩形左上角的x.y坐标以及矩形的长宽,我们在(0.0)创建这个矩形,接下来的两行代码将它移到正确的位置,子弹的初始位置是取决于飞船的位置。
主程序如下:
在主程序里创造一个编组,用于存储所有的有效的子弹,用于管理发射出去的子弹。这个编组是pygame.sprite.Group 的一个实例,类似于列表,它绘制子弹以及更新每个子弹的位置。
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
import pygame
from setting import Setting
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
def run_game():
pygame.init() #初始化,创建屏幕对象
ai_settings=Setting() #创建一个800*800的屏幕
screen=pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion") #对于这个窗口的命名为Alien Invasion
ship=Ship(ai_settings,screen) #创建飞船
bullets=Group()
while True:
gf.check_events(ai_settings,screen,ship,bullets)
ship.update()
bullets.update()
gf.update_screen(ai_settings,screen,ship,bullets)
run_game()
功能模块:
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#游戏的功能模块,包括响应键盘鼠标事件,移动飞船等
import sys
import pygame
from bullet import 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: #响应按空格键
new_bullet=Bullet(ai_settings,screen,ship)
bullets.add(new_bullet)
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()
编组bullets传递给check_keydown_events(),按下空格键的时候,创建一颗新子弹,并使用方法add将其加入到编组bullets中,之后,bullets.sprites()返回一个列表,包含于编组里的所有子弹,我们在遍历列表,对所有的子弹调用draw_bullet()。
删除已经消失的子弹:
子弹到达顶部消失,并不是因为说它不存在了,而是因为pygame无法在屏幕外绘制他们,他们的坐标为负值,会一直消耗内存和处理能力。我们要将这些子弹删除,怎么删除,我们可以 检查子弹的坐标位置,当bottom=0的时候就代表到达顶部。
主程序如下:
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
import pygame
from setting import Setting
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
def run_game():
pygame.init() #初始化,创建屏幕对象
ai_settings=Setting() #创建一个800*800的屏幕
screen=pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion") #对于这个窗口的命名为Alien Invasion
ship=Ship(ai_settings,screen) #创建飞船
bullets=Group()
while True:
gf.check_events(ai_settings,screen,ship,bullets)
ship.update()
bullets.update()
#删除子弹
for bullet in bullets.copy():
if bullet.rect.bottom<=0:
bullets.remove(bullet)
print(len(bullets)) #打印长度。只是为了确认下有没有消失,后面可以删掉
gf.update_screen(ai_settings,screen,ship,bullets)
run_game()
我们使用copy来产生一个bullets的副本,遍历这个副本。
限制子弹数量:
在设置类修改程序:
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#存储外星人游戏开发的设置
class Setting():
def __init__(self):
self.screen_width=600 #设置屏幕高度宽度,背景颜色
self.screen_height=600
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=(0,0,255)
self.bullets_allowed=3
接下来在功能模块来检查子弹数:
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#游戏的功能模块,包括响应键盘鼠标事件,移动飞船等
import sys
import pygame
from bullet import 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: #响应按空格键
if len(bullets)<ai_settings.bullets_allowed:
new_bullet=Bullet(ai_settings,screen,ship)
bullets.add(new_bullet)
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()
再运行主程序看看实际结果:
重构整个函数:
1.功能模块:
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#游戏的功能模块,包括响应键盘鼠标事件,移动飞船等
import sys
import pygame
from bullet import 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: #响应按空格键
fire_bullet(ai_settings,screen,ship,bullets)
def fire_bullet(ai_settings,screen,ship,bullets): #发射子弹
if len(bullets)<ai_settings.bullets_allowed:
new_bullet=Bullet(ai_settings,screen,ship)
bullets.add(new_bullet)
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()
def update_bullets(bullets): #更新子弹的位置,并删除已消失的子弹
bullets.update()
for bullet in bullets.copy():
if bullet.rect.bottom<=0:
bullets.remove(bullet)
主程序如下:
#-*-coding:GBK-*-
#-*-coding:utf-8-*-
import pygame
from setting import Setting
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
def run_game():
pygame.init() #初始化,创建屏幕对象
ai_settings=Setting() #创建一个800*800的屏幕
screen=pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion") #对于这个窗口的命名为Alien Invasion
ship=Ship(ai_settings,screen) #创建飞船
bullets=Group()
while True:
gf.check_events(ai_settings,screen,ship,bullets)
ship.update()
gf.update_bullets(bullets)
gf.update_screen(ai_settings,screen,ship,bullets)
run_game()