Pygame小游戏练习二

@Python编程从入门到实践 Python项目练习

四、创建Ship类

建立ship.py,创建Ship类,管理飞船行为。

# ship.py
import pygame

class Ship():

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

        # 加载飞船图像
        self.image = pygame.image.load('images/ship.bmp')
        self.image = pygame.transform.scale(self.image, (37*2, 34*2))

        # 获取其外接矩形(rect为surface矩形属性)
        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_x = float(self.rect.centerx)
        self.center_y = float(self.rect.centery)

        # 移动标志
        self.moving_right = False
        self.moving_left = False
        self.moving_up = False
        self.moving_down = False

    def update(self):
        """根据移动标志调整飞船到位置"""
        # 更新飞船的center值, 而不是rect
        if self.moving_right and self.rect.right < self.screen_rect.right:
            self.center_x += self.ai_settings.ship_speed_factor
        if self.moving_left and self.rect.left > 0:
            self.center_x -= self.ai_settings.ship_speed_factor

        if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
            self.center_y += self.ai_settings.ship_speed_factor
        if self.moving_up and self.rect.top > self.screen_rect.top:
            self.center_y -= self.ai_settings.ship_speed_factor

        # 根据self.center更新rect对象
        self.rect.centerx = self.center_x
        self.rect.centery = self.center_y

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

    def center_ship(self):
        """让飞船在屏幕上居中"""
        self.center_x = self.screen_rect.centerx
        ship_half_width = self.rect.bottom - self.center_y
        self.center_y = self.screen_rect.bottom - ship_half_width

五、创建Bullet类

建立bullet.py,创建Bullet类,继承pygame.sprite中的Sprite类,作为游戏中的子弹元素。

# settings.py
import pygame

from pygame.sprite import Sprite


class Bullet(Sprite):
    """一个对子弹发射进行管理的类"""

    def __init__(self, ai_settings, screen, ship):
        super(Bullet, self).__init__()
        self.screen = screen

        # 在(0, 0)处创建一个表示子弹的矩形,将初始位置放在(0,0)
        self.rect = pygame.Rect(0, 0, ai_settings.bullet_width,
                                ai_settings.bullet_height)
        # 重设子弹位置
        self.rect.centerx = ship.rect.centerx
        # self.rect.centery = ship.rect.centery
        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)

六、创建game_functions模块

创建game_functions.py 模块,存储函数,让alien_invasion中主代码更易懂。

#game_functions.py
import sys

import pygame

from bullet import Bullet
from passenger import Passenger
from time import sleep


def check_keydown_events(event, ai_settings, screen, ship, bullet_group):
    """响应按键"""
    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_UP:
        ship.moving_up = True
    elif event.key == pygame.K_DOWN:
        ship.moving_down = True
    elif event.key == pygame.K_SPACE:
        fire_bullet(ai_settings, screen, ship, bullet_group)
    elif event.key == pygame.K_ESCAPE:
        sys.exit()


def fire_bullet(ai_settings, screen, ship, bullet_group):
    """如果没有到达限制,就发射一颗子弹"""
    # 创建一颗子弹,并将其加入到编组bullets中
    if len(bullet_group) < ai_settings.bullet_group_allowed:
        new_bullet = Bullet(ai_settings, screen, ship)
        bullet_group.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
    elif event.key == pygame.K_UP:
        ship.moving_up = False
    elif event.key == pygame.K_DOWN:
        ship.moving_down = False


def check_events(ai_settings, screen, ship, bullet_group):
    """响应按键和鼠标事件"""
    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, bullet_group)
        # 松开
        elif event.type == pygame.KEYUP:
            check_keyup_events(event, ship)


def update_screen(ai_settings, screen, ship, passenger_group, bullet_group):
    """更新屏幕上的图像,并切换到新屏幕"""

    # 每次循环时(即打开游戏运行)重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 绘制子弹
    for bullet in bullet_group:
        bullet.draw_bullet()
    ship.blitme()
    for i in passenger_group:
        i.blitme()
    #passenger_group.draw(screen)

    # 更新屏幕(隐藏旧屏,更新新屏)
    pygame.display.flip()


def update_bullet_group(ai_settings, screen, ship, passenger_group, bullet_group ):
    """更新子弹的位置,并删除已消失的子弹"""
    # 更新子弹的位置
    bullet_group.update()

    # 删除已消失的子弹
    for bullet in bullet_group.copy():
        if bullet.rect.top <= 0:
            bullet_group.remove(bullet)

    check_bullet_passenger_collisions(ai_settings, screen, ship, passenger_group,
                                      bullet_group)


def check_bullet_passenger_collisions(ai_settings,screen, ship, passenger_group,
                                      bullet_group):
    # 检查是否有子弹击中了乘客
    # 如果是这样,就删除相应的子弹和乘客
    # groupcollide()返回字典,实参为True即删除发生碰撞的子弹或外星人
    collisions = pygame.sprite.groupcollide(bullet_group, passenger_group, False, True)

    if len(passenger_group) == 0:
        # 删除现有子弹并新建一波新的乘客
        bullet_group.empty()
        create_fleet(ai_settings, screen, ship, passenger_group)


def get_number_passenger_x(ai_settings, passenger_width):
    """计算每行可以容纳多少个乘客"""
    available_space_x = ai_settings.screen_width - 2 * passenger_width
    number_passenger_x = int(available_space_x / (2 * passenger_width))
    return number_passenger_x


def get_number_rows(ai_settings, ship_height, passenger_height):
    """计算屏幕可以容纳多少行的乘客"""
    available_space_y = (ai_settings.screen_height - passenger_height - ship_height)
    number_rows = int(available_space_y / (1.5 * passenger_height))
    return number_rows


def create_passenger(ai_settings, screen, passenger_group, passenger_number, row_number):
    """创建一个乘客并将其放在当前行"""
    passenger = Passenger(ai_settings, screen)
    passenger_width = passenger.rect.width

    passenger.x = passenger_width + 2 * passenger_width * passenger_number
    passenger.rect.x = passenger.x
    passenger.rect.y = 0.5 * passenger.rect.height + 1.5 * passenger.rect.height * row_number
    passenger_group.add(passenger)


def create_fleet(ai_settings, screen, ship, passgener_group):
    """创建乘客群"""
    # 创建一个乘客,并计算一行可以容纳多少人
    passenger = Passenger(ai_settings, screen)
    number_passenger_x = get_number_passenger_x(ai_settings, passenger.rect.width)
    number_rows = get_number_rows(ai_settings, ship.rect.height, passenger.rect.height)

    # 创建乘客群
    for row_number in range(number_rows):
        for passenger_number in range(number_passenger_x):
            create_passenger(ai_settings, screen, passgener_group, passenger_number,
                             row_number)


def change_fleet_direction(ai_settings, passenger_group):
    """将整群乘客下移,并改变它们的方向"""
    for passenger in passenger_group.sprites():
        passenger.rect.y += ai_settings.fleet_drop_speed
    ai_settings.fleet_direction *= -1


def check_fleet_edges(ai_settings, passenger_group):
    """有外星人到达边缘时采取相应的措施"""
    for passenger in passenger_group.sprites():
        if passenger.check_edges():
            change_fleet_direction(ai_settings, passenger_group)
            break


def ship_hit(ai_settings, stats, screen, ship, passenger_group, bullet_group):
    """响应被乘客撞到的飞船"""
    if stats.ships_left > 0:
        # 讲ship_left减一
        stats.ships_left -= 1
        # 清空乘客列表和子弹列表
        passenger_group.empty()
        bullet_group.empty()

        # 创建一群新的外星人,并讲飞船放在屏幕底部中央
        create_fleet(ai_settings, screen, ship, passenger_group)
        ship.center_ship()
        # 暂停
        sleep(0.5)
    else:
        stats.game_active = False


def check_passenger_group_bottom(ai_settings, stats, screen, ship, passenger_group, bullet_group):
    """检查是否有外星人到达屏幕底端"""
    screen_rect = screen.get_rect()
    for passenger in passenger_group.sprites():
        if passenger.rect.bottom >= screen_rect.bottom:
            # 像飞船被撞到一样进行处理
            ship_hit(ai_settings, stats, screen, ship, passenger_group, bullet_group)
            break


def update_passenger_group(ai_settings, stats, screen, ship, passenger_group, bullet_group):
    """检查是否有乘客在边缘,并更新乘客群中所有乘客的位置"""
    check_fleet_edges(ai_settings, passenger_group)
    passenger_group.update()

    # 检测外星人和飞船之间的碰撞
    if pygame.sprite.spritecollideany(ship, passenger_group):
        ship_hit(ai_settings, stats, screen, ship, passenger_group, bullet_group)
    # 检查是否有外星让到达屏幕底端
    check_passenger_group_bottom(ai_settings, stats, screen, ship, passenger_group, bullet_group)


posted @ 2019-08-15 20:51  gg12138  阅读(304)  评论(0编辑  收藏  举报