python入门_day13_chap12_游戏项目_飞船移动且不超边缘

12.6驾驶飞船

1.响应案件

每当用户按键时,都将在Pygame中注册一个事件。事件都是通过方法pygame.event.get() 获取的,因此在函数check_events() 中,我们需要指定要检查哪些类型的事 件。

每次按键都被注册为一个KEYDOWN 事件。
检测到KEYDOWN 事件时,我们需要检查按下的是否是特定的键。例如,如果按下的是右箭头键,我们就增大飞船的rect.centerx 值,将飞船向右移动:

game_functions.py

import sys
import pygame


def check_events(ship):
    """ 响应键盘和鼠标事件"""
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            sys.exit()
        elif event.type==pygame.KEYDOWN:
            if event.key==pygame.K_RIGHT:
                #飞船右移动1像素
                ship.rect.centerx+=1

def update_screen(ai_settings,screen,ship):
    
    #更新屏幕上的图像,并切换到新屏幕
    screen.fill(ai_settings.bg_color)
    ship.blitme()
    #让最近绘制的屏幕可见
    pygame.display.flip()

alien_invasion.py

import pygame

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("Alien Invasion")

    #创建一艘飞船
    ship=Ship(screen)

    
    #开始游戏主循环
    while True:
        gf.check_events(ship)

        gf.update_screen(ai_settings,screen,ship)




run_game()

2.允许不断移动

对ship.py进行修改:

在方法__init__() 中,我们添加了属性self.moving_right ,并将其初始值设置为False 。
接下来,我们添加了方法update() ,它在前述标志为True 时向 右移动飞船。

import pygame

class Ship():

    def __init__(self,screen):
        """ 初始化飞船并设置其初始位置"""
        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

        #移动标志
        self.moving_right=False


    def update(self):
        """ 根据移动标志调整飞船位置"""
        if self.moving_right:
            self.rectt.centerx+=1

    def blitme(self):
        """ 在指定位置绘制飞船"""
        self.screen.blit(self.image,self.rect)

修改game_functions.py

我们修改了游戏在玩家按下右箭头键时响应的方式:不直接调整飞船的位置,而只是将moving_right 设置为True 。
添加了一个新的elif 代码块,用 于响应KEYUP 事件:玩家松开右箭头键(K_RIGHT )时,我们将moving_right 设置为False 。


def check_events(ship):
    """ 响应键盘和鼠标事件"""
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            sys.exit()

        elif event.type==pygame.KEYDOWN:
            if event.key==pygame.K_RIGHT:
                ship.moving_right=True
        
        elif event.type==pygame.KEYUP:
            if event.key==pygame.K_RIGHT:
                ship.moving_right=False

def update_screen(ai_settings,screen,ship):
    --snip--

最后,我们需要修改alien_invasion.py 中的while 循环,以便每次执行循环时都调用飞船的方法update() :

 #开始游戏主循环
while True:
    gf.check_events(ship)
    ship.update()
    gf.update_screen(ai_settings,screen,ship)

飞船的位置将在检测到键盘事件后(但在更新屏幕前)更新。这样,玩家输入时,飞船的位置将更新,从而确保使用更新后的位置将飞船绘制到屏幕上。

3.左右移动

我们将再次修改Ship 类和函数check_events() 。下面显示了对Ship 类的方法__init__() 和update() 所做 的相关修改:

class Ship():

    def __init__(self,screen):
        """ 初始化飞船并设置其初始位置"""
        --snip--
        #移动标志
        self.moving_right=False
        self.moving_left=False


    def update(self):
        """ 根据移动标志调整飞船位置"""
        if self.moving_right:
            self.rect.centerx+=1
        if self.moving_left:
            self.rect.centerx-=1

一个细节: update()方法中用了两个if,而不是elif。
两个if的用意是,当玩家同时按下左右箭头的时候能够保持位置不变。
若用elif则右箭始终处于优先的状态

gane_functions.py

def check_events(ship):
    """ 响应键盘和鼠标事件"""
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            sys.exit()

        elif event.type==pygame.KEYDOWN:
            if event.key==pygame.K_RIGHT:
                ship.moving_right=True
            elif event.key==pygame.K_LEFT:
                ship.moving_left=True

        elif event.type==pygame.KEYUP:
            if event.key==pygame.K_RIGHT:
                ship.moving_right=False
            elif event.key==pygame.K_LEFT:
                ship.moving_left=False

4.调整飞船速度

每次执行while 循环时,飞船最多移动1像素,但我们可以在Settings 类中添加属性ship_speed_factor ,用于控制飞船的速度。我们将根据这个属性决定飞船在 每次循环时最多移动多少距离。

在settings.py中添加这个新属性:

self.ship_speed_factor=1.5
需要移动飞船时,我们将移动1.5像素而不是1像素。

class Settings():
    """ 存储《外星人入侵》的所有设置的类"""

    def __init__(self):
        --snip--
        
        #飞船的设置
        self.ship_speed_factor=1.5

rect 的centerx 等属性只能存储整数值,因此我们需要对Ship 类做些修改:

import pygame

class Ship():


 ①   def __init__(self,ai_settings,screen):
        """ 初始化飞船并设置其初始位置"""
        self.screen=screen
      ② self.ai_settings=ai_settings

        #加载飞船图像并获取其他外接矩形
        --snip--

        #将每艘新飞船放在屏幕底部中央
        --snip--

   ③     #在飞船的属性center中存储小数值
        self.center=float(self.rect.centerx)
        
        #移动标志
        --snip--

    def update(self):
        """ 根据移动标志调整飞船位置"""
        #更新飞船的centerx值,而不是rectif self.moving_right:
            self.center+=self.ai_settings.ship_speed_factor
        if self.moving_left:
            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)

alien_invasion.py

 #创建一艘飞船
    ship=Ship(ai_settings,screen)

5.限制飞船的活动范围

为了让飞船到达屏幕边缘后停止移动,我们将修改Ship 类的方 法update() :

ship.py

def update(self):
        """ 根据移动标志调整飞船位置"""
        #更新飞船的centerx值,而不是rect
        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

self.rect.right 返回飞船外接矩形的右边缘的 x 坐标,如果这个值小于self.screen_rect.right 的值, 就说明飞船未触及屏幕右边缘。左边缘的情况与此类似:如果rect 的左边缘的 x 坐标大于零,就说明飞船未触及屏幕左边缘。
这确保仅当飞船在屏幕内时, 才调整self.center 的值。

6.重构check_events()

def check_keydown_events(event,ship):
    """ 响应按键"""
    if event.type==pygame.K_RIGHT:
        ship.moving_right=True
    elif event.type==pygame.K_LEFT:
        ship.moving_left=True

def check_keyup_events(event,ship):
    """ 响应松开"""
    if event.type==pygame.K_RIGHT:
        ship.moving_right=False
    elif event.type==pygame.K_LEFT:
        ship.moving_left=False

def check_events(ship):
    """响应按键和鼠标事件"""
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            sys.exit()
        elif event.type==pygame.KEYDOWN:
            check_keydown_events(event,ship)
        elif event.type==pygame.KEYUP:
            check_keyup_events(event,ship)

你可能感兴趣的:(Python从入门到实战)