python从入门到实践(第2版) 练习13-6

这一练习题要求在之前的练习中增加记录飞船碰撞次数和记录射杀外星人个数的功能,再设置游戏结束条件。

记录飞船撞多少次的功能书上的例子已经实现,不用做太多改变。

记录射杀多少个外星人的功能,我的思路是,通过对检查子弹与飞船碰撞所返回的字典进行for循环,每次循环计数增加1来实现。之所以要通过对字典进行for循环来计数,是因为如果直接计数字典事件本身,发现数值是不准确的,可能是因为字典可以存储几个键对值。

欢迎大家指正。

import sys
import pygame
from pygame.sprite import Sprite
from time import sleep

class AlienInvasion:
    """管理游戏资源和行为的类"""
    
    def __init__(self):
        """初始化游戏并创建游戏资源"""
        pygame.init()
        
        self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
        self.screen_width = self.screen.get_rect().width
        self.screen_height = self.screen.get_rect().height
        self.bg_color = (230, 230, 230)
        
        self.game_active = True
        
        self.ship = Ship(self)
        self.bullets = pygame.sprite.Group()
        self.aliens = pygame.sprite.Group()
        
        self.aliens_destroyed = 0
        
    def run_game(self):
        """开始游戏住循环"""
        while True:
            self. _check_events()
            
            if self.game_active:
                self.ship.update()
                self._update_bullets()
                self.creat_fleet()
                self._update_aliens()
                
            self._update_screen()
            
    def _check_events(self):
        """响应按键和鼠标事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                self._check_keydown_events(event)
            elif event.type == pygame.KEYUP:
                self._check_keyup_events(event)
                    
    def _check_keydown_events(self, event):
        if event.key == pygame.K_q:
            sys.exit()
        elif event.key == pygame.K_UP:
            self.ship.moving_up = True
        elif event.key == pygame.K_DOWN:
            self.ship.moving_down = True
        elif event.key == pygame.K_SPACE:
            self._fire_bullet()
            
    def _check_keyup_events(self, event):
        if event.key == pygame.K_UP:
            self.ship.moving_up = False
        elif event.key == pygame.K_DOWN:
            self.ship.moving_down = False
            
    def _fire_bullet(self):
        """创建一颗子弹,并将其加入bullets编组"""
        new_bullet = Bullet(self)
        self.bullets.add(new_bullet)
        
    def _update_bullets(self):
        """更新子弹的位置并删除消失的子弹"""
        self.bullets.update()
        
        #删除消失的子弹
        for bullet in self.bullets.copy():
            if bullet.rect.left >= self.screen_width:
                self.bullets.remove(bullet)
                
        #检查是否有子弹击中而外星人,并删掉相应的子弹和外星人
        collisions = pygame.sprite.groupcollide(
                self.bullets, self.aliens, True, True)
        if collisions:
            for aliens in collisions.keys():
                self.aliens_destroyed += 1

    def creat_fleet(self):
        """检查屏幕外星人数量,没有外星人是生成外星人"""
        if not self.aliens:
            self._create_alien()
                
    def _create_alien(self):
        """创建外星人群"""
        #计算创建外星人需要的坐标参数
        alien = Alien(self)
        alien_height = alien.rect.height
        alien_width = alien.rect.width
        ship_height = self.ship.rect.height
        
        avaliable_space_x = self.screen_width - (3 * alien_width) - ship_height
        number_aliens_x = avaliable_space_x // (2 * alien_width)
        avaliable_space_y = self.screen_height - (2 * alien_height)
        number_aliens_y = avaliable_space_y // (2 *alien_height)
        
        #创建外星人群
        for number_y in range(number_aliens_y):
            for number_x in range(number_aliens_x):
                alien = Alien(self)
                alien.x = alien.screen_width - (
                    alien_width +  2 * alien_width * number_x)
                alien.y = alien_height + 2 * alien_height * number_y
                alien.rect.x = alien.x
                alien.rect.y = alien.y
                self.aliens.add(alien)
                
    def _check_fleet_edges(self):
        """检查外星人群是否接触外边缘,如果是就改变方向"""
        for alien in self.aliens.sprites():
            if alien.check_edges():
                self._change_fleet_direction()
                break
        
    def _change_fleet_direction(self):
        """改变外星人群的移动方向,并向左移动一部分"""
        for alien in self.aliens.sprites():
            alien.rect.x -= alien.fleet_left_speed
            alien.fleet_direction *= -1
                
    def _update_aliens(self):
        """更新外星人群"""
        self._check_fleet_edges()
        self.aliens.update()
        
        if pygame.sprite.spritecollideany(self.ship, self.aliens):
            self._ship_hit()
            
        self._check_aliens_left()
        
    def _ship_hit(self):
        """响应飞船被外星人撞到。"""
        
        if self.ship.ship_limit > 0:
            self.ship.ship_limit -= 1
        
            #清空余下的子弹和外星人
            self.aliens.empty()
            self.bullets.empty()
        
            #创建新的外星人
            self._create_alien()
        
            #飞船位置初始化
            self.ship.center_ship()
        
            #暂停
            sleep(0.5)
            
        else: 
            self.game_active = False
        
    def _check_aliens_left(self):
        #响应外星人撞到屏幕左边
        screen_rect = self.screen.get_rect()
        for alien in self.aliens.sprites():
            if alien.rect.left <= screen_rect.left:
                self._ship_hit()
            break
        
    def _update_screen(self):
        self.screen.fill(self.bg_color)
        self.ship.blitme()
        for bullet in self.bullets.sprites():
            bullet.draw_bullet()
        self.aliens.draw(self.screen)
        pygame.display.flip()
            
            
class Ship:
    """管理飞船的类"""
    def __init__(self, ai_game):
        """初始化飞船并设置其初始位置"""
        self.screen = ai_game.screen
        self.screen_rect = ai_game.screen.get_rect()
        
        #加载飞创图像并获取其外接矩形
        self.image = pygame.image.load('other_files/ship.bmp')
        self.rect = self.image.get_rect()
        
        #对于每艘飞船,都将其放在屏幕左侧*
        self.rect.midleft = self.screen_rect.midleft
        
        #飞船设置
        self.ship_speed = 0.5
        self.ship_limit = 3
        
        #在飞船的属性x中存储小数值
        self.y = float(self.rect.y)
        
        #移动标志
        self.moving_up = False
        self.moving_down = False
        
    def update(self):
        """根据移动标志调整飞船位置"""
        #更新飞船的y值
        if self.moving_up and self.rect.top > 0:
            self.y -= self.ship_speed
        if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
            self.y += self.ship_speed
            
        #更新rect对象的y值
        self.rect.y = self.y
        
    def blitme(self):
        """指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect)
        
    def center_ship(self):
        """初始化飞船位置"""
        self.rect.midleft = self.screen_rect.midleft
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)
            
class Bullet(Sprite):
    """管理子弹的类"""
    def __init__(self, ai_game):
        """在飞船当前位置创建一个子弹对象"""
        super().__init__()
        
        self.screen = ai_game.screen
        self.color = (255, 0, 0)
        
        #在(0,0)处创建一个表示子弹的矩形,再设置正确的位置
        self.rect = pygame.Rect(0, 0, 15, 3)
        self.rect.midright = ai_game.ship.rect.midright
        
        #存储用小数表示的子弹位置
        self.x = float(self.rect.x)
        
    def update(self):
        """向上移动子弹"""
        #更新表示子弹位置的小数值
        self.x += 2
        #更新子弹的rect的位置
        self.rect.x = self.x
        
    def draw_bullet(self):
        #在屏幕上绘制子弹
        pygame.draw.rect(self.screen, self.color, self.rect)
        
        
class Alien(Sprite):
    """单个外星人的类"""
    def __init__(self, ai_game):
        super().__init__()
        
        self.screen = ai_game.screen
        self.screen_width = self.screen.get_rect().width
        self.screen_height = self.screen.get_rect().height
        self.alien_speed = 0.3
        self.fleet_direction = 1
        self.fleet_left_speed = 150
        
        #加载外星人图像并设置其rect属性
        self.image = pygame.image.load('other_files/alien.bmp')
        self.rect = self.image.get_rect()
        
        #外星人的初始位置
        #   屏幕右上角附近
        self.rect.x = self.screen_width - self.rect.width
        self.rect.y = self.rect.height
        
        #外星人的精确位置
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)
        
    def check_edges(self):
        """检查外星人是否处于屏幕边缘"""
        screen_rect = self.screen.get_rect()
        if self.rect.bottom >= screen_rect.bottom or self.rect.top <= 0:
            return True
        
    def update(self):
        """更新外星人的移动位置"""
        self.y += (self.alien_speed * self.fleet_direction)
        self.rect.y = self.y
        
        
if __name__ == '__main__':
    #创建游戏实例并运行游戏
    ai = AlienInvasion()
    ai.run_game()
 

上一篇:实战:用python写个打飞机小游戏!怀念童年的感觉


下一篇:python基础篇(八)——Python数据结构之字典(上)