Python编程从入门到实践(第2版) 练习14-2

要求创建一个屏幕左侧可上下移动的飞船,和一个屏幕右侧不停上下移动的矩形,玩家可控制飞船向矩形发射子弹。

添加Play按钮用于开始游戏,如果发射三次子弹未击中目标,则游戏结束并重新显示Play按钮。

代码实现效果如下图:

代码如下:

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

class Play:
    """管理游戏行为和资源的类"""
    
    def __init__(self):
        """初始化游戏并创建游戏资源"""
        pygame.init()
    
        self.screen = pygame.display.set_mode((900, 600))
        self.screen_rect = self.screen.get_rect()
        self.ship = Ship(self)
        self.alien = Alien(self)
        self.bullets = pygame.sprite.Group()
    
        self.bg_color = (230, 230, 230)
        
        self.play_button = Button(self, "Play")
        
        #游戏初始活动状态
        self.game_active = False
        
        #子弹限制数量和剩余子弹数量
        self.bullet_limit = 3
        self.bullet_left = self.bullet_limit
        
    def run_game(self):
        """开始游戏的主循环"""
        while True:
            self._check_events()
            
            if self.game_active:
                self.ship.update()
                self.alien.update()
                self._update_bullets()
            
            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:
                if 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_q:
                    sys.exit()
                elif event.key == pygame.K_SPACE:
                    self._fire_bullet()
            
            elif event.type == pygame.KEYUP:
                if event.key == pygame.K_UP:
                    self.ship.moving_up = False
                elif event.key == pygame.K_DOWN:
                    self.ship.moving_down = False
                    
            elif event.type == pygame.MOUSEBUTTONDOWN:
                self._check_play_button()
                    
    def _check_play_button(self):
        """点击play按钮开始游戏"""
        mouse_pos = pygame.mouse.get_pos()
        click_start_button = self.play_button.rect.collidepoint(mouse_pos)
        if click_start_button and not self.game_active:
            self.game_active = True
            self.bullets.empty()
            self.alien.reset_place()
            self.bullet_left = self.bullet_limit
                    
    def _fire_bullet(self):
        """创建一个子弹,并加入编组"""
        new_bullet = Bullet(self)
        self.bullets.add(new_bullet)
        
    def _update_bullets(self):
        """更新子弹"""
        self.bullets.update()
        
        #如果有子弹超过屏幕边缘,就删除它,并将子弹上限减去1
        for bullet in self.bullets:
            if bullet.rect.left >= self.screen_rect.width:
                self.bullets.remove(bullet)
                self.bullet_left -= 1
                
        #检查子弹是否击中外星人,并做出相应的反应
        if pygame.sprite.spritecollideany(self.alien, self.bullets):
            self._shout_alien()
            
        #如果子弹上限等于0,就将游戏状态调整为False
        if self.bullet_left <= 0:
            self.game_active = False
            
    def _shout_alien(self):
        """
        子弹击中外星人后,清空子弹的编组、重置外星人的位置、重置剩余子弹的数量。
        """
        self.bullets.empty()
        self.alien.reset_place()
        sleep(0.5)
        self.bullet_left = self.bullet_limit
            
    def _update_screen(self):
        #每次循环都重新绘制屏幕
        self.screen.fill(self.bg_color)
        
        #绘制飞船、外星人、和子弹编组
        self.ship.blit()
        self.alien.blit()
        for bullet in self.bullets.sprites():
            bullet.draw_bullet()
            
        #绘制Play按钮
        if not self.game_active:
            self.play_button.draw_button()
        
            
        #让最近绘制的屏幕可见
        pygame.display.flip()
        
        
class Ship:
    """管理飞船的类"""
    
    def __init__(self, play_game):
        self.screen = play_game.screen
        self.screen_rect = play_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.moving_up = False
        self.moving_down = False
        
        self.y = float(self.rect.y)
        
    def update(self):
        if self.moving_up and self.rect.top > 0:
            self.y -= 0.5
        if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
            self.y += 0.5
            
        self.rect.y = self.y
        
    def blit(self):
        self.screen.blit(self.image, self.rect)
        
        
class Bullet(Sprite):
    """管理一个子弹的类"""
    
    def __init__(self, play_game):
        """创建一个子弹"""
        super().__init__()
        self.screen = play_game.screen
        self.color = (60, 60, 60)
        
        #创建一个表示子弹的矩形,再把它放在飞船前方
        self.rect = pygame.Rect(0, 0, 15, 3)
        self.rect.midright = play_game.ship.rect.midright
        
        #用小数表示子弹的位置
        self.x = float(self.rect.x)
        
    def update(self):
        """更新子弹位置"""
        self.x += 1.5
        self.rect.x = self.x
        
    def draw_bullet(self):
        """屏幕上绘制子弹"""
        pygame.draw.rect(self.screen, self.color, self.rect)
        
        
class Alien():
    """管理外星飞船的类"""
    def __init__(self, play_game):

        self.screen = play_game.screen
        self.screen_rect = self.screen.get_rect()
        
        self.image = pygame.image.load('other_files/alien.bmp')
        self.rect = self.image.get_rect()
        
        #外星人初始位置,屏幕右上角
        self.rect.x = self.screen_rect.width - self.rect.width
        self.rect.y = 0
        
        #表示外星人运动方向的数字,1为向下,-1 为向上
        self.direction = 1
        
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)
        
    def blit(self):
        """屏幕上绘制外星人"""
        self.screen.blit(self.image, self.rect)
        
    def update(self):
        """更新屏幕上外星人的位置"""
        self._check_edge()
        
        self.y += 0.1 * self.direction
        self.rect.y = self.y
        
    def _check_edge(self):
        """检查外星人是否接触到屏幕边缘,是则调整运动方向"""
        if self.rect.top < 0 or self.rect.bottom > self.screen_rect.bottom:
            self.direction *= -1
            
    def reset_place(self):
        self.x = self.screen_rect.width - self.rect.width
        self.y = 0
            
            
class Button:
    
    def __init__(self, play_game, msg):
        """初始化按钮属性"""
        self.screen = play_game.screen
        self.screen_rect = self.screen.get_rect()
        
        #设置按钮参数
        self.width, self.height = 200, 50
        self.button_color = (0, 255, 0)
        self.text_color = (255, 255, 255)
        self.font = pygame.font.SysFont(None, 48)
        
        #创建按钮的rect属性,并使其居中
        self.rect = pygame.Rect(0, 0, self.width, self.height)
        self.rect.center = self.screen_rect.center
        
        #创建按钮的标签
        self._prep_msg(msg)

            
    def _prep_msg(self, msg):
        """将msg渲染为图像,并使其在按钮上居中"""
        self.msg_image = self.font.render(msg, True, self.text_color, 
                        self.button_color)
        self.msg_image_rect = self.msg_image.get_rect()
        self.msg_image_rect.center = self.rect.center
        
    def draw_button(self):
        #绘制一个用颜色填充的按钮,再绘制文本
        self.screen.fill(self.button_color, self.rect)
        self.screen.blit(self.msg_image, self.msg_image_rect)
            
            
if __name__ == '__main__':
    play = Play()
    play.run_game()
    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值