python实战===如何优雅的打飞机,python实战打飞机,这是一个打飞机的游戏


这是一个打飞机的游戏,结构如下:

技术分享图片

其中images中包含的素材为

技术分享图片  命名为alien.png

技术分享图片    命名为ship.png

游戏效果运行是这样的:

技术分享图片

敌军,也就是体型稍微大点的,在上方左右移动,并且有规律向下移动。我军目标,消灭所有飞机。但是屏幕上最多只展现3颗子弹。

一旦,我军飞机与敌军飞机碰撞,或者敌军飞机抵达底部。我军损失一条生命,一共三条。

敌军飞机全部消灭完,则到下一关,移动速度会更快。

我军每消灭一架敌军飞机获得积分,积分最高者会在界面显示。

游戏源码如下:

#alien_invasion.py  
#主程序文件"""创建Pygame窗口响应以及用户输入"""import pygamefrom settings import Settingsfrom ship import Shipimport game_functions as gffrom pygame.sprite import Groupfrom alien import Alienfrom game_stats import GameStatsfrom button import Buttonfrom Scoreboard import Scoreboarddef 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") #创建play按钮 play_button = Button(ai_settings, screen, "PLAY~") #创建一个用户存储游戏统计信息的实例 stats = GameStats(ai_settings) sb = Scoreboard(ai_settings, screen, stats) #创建一艘飞船 ship = Ship(ai_settings,screen) #创建一个用户存储子弹的编组 bullets = Group() #创建一个外星人 aliens = Group() #创建外星人群 gf.create_fleet(ai_settings, screen,ship, aliens) #开始游戏主循环 while True: #监视键盘和鼠标事件 gf.check_events(ai_settings, screen, stats,sb, play_button, ship, aliens,bullets) if stats.game_active: ship.update() #删除已消失的子弹 gf.update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets) gf.update_aliens(ai_settings, screen, stats, sb, ship, aliens, bullets) gf.update_screen(ai_settings, screen,stats, sb, ship, aliens, bullets, play_button) #让最近绘制的屏幕可见 pygame.display.flip()run_game()

#alien.pyimport pygamefrom pygame.sprite import Spriteclass Alien(Sprite):    def __init__(self,ai_settings, screen ):        """初始化外星人并且设置起始位置"""        super().__init__()        self.screen = screen        self.ai_settings = ai_settings        #加载外星人图像,并且设置其rect属性        self.image = pygame.image.load("images/alien.png")        self.rect = self.image.get_rect()        #每个外星人最初都在屏幕左上角附近        self.rect.x = self.rect.width        self.rect.y = self.rect.height        #存储外星人的准确位置        self.x = float(self.rect.x)    def blitme(self):        """在指定位置绘制外星人"""        self.screen.blit(self.image, self.rect)    def check_edges(self):        """如果外星人出于屏幕边缘,就返回True"""        screen_rect = self.screen.get_rect()        if self.rect.right >=  screen_rect.right:            return True        elif self.rect.left <= 0:            return True    def update(self):        """向左或者右移动的外星人"""        self.x += (self.ai_settings.alien_speed_factor *             self.ai_settings.fleet_direction)        self.rect.x = self.x

#bullet.pyimport pygamefrom   pygame.sprite   import Sprite  class Bullet(Sprite):    """一个对飞船发射的子弹进行管理的类"""    """Bullet类继承了我们从模块pygame.sprite中导入的Sprite类"""    def __init__(self, ai_settings, screen, ship):        """在飞船所处的位置创建一个子弹对象"""        """为创建子弹实例,需要向__init__()传递        ai_settings、screen和ship实例,还调用了super()来继承Sprite。        """        super().__init__()        self.screen = screen        """        在(0.0)处创建一个表示子弹的矩形,再设置正确的位置        我们创建了子弹的属性rect。子弹并非基于图像的,因此我们必须使用pygame.Rect()        类从空白开始创建一个矩形        """        self.rect = pygame.Rect(            0,0,ai_settings.bullet_width,ai_settings.bullet_height)        self.rect.centerx = ship.rect.centerx  #将子弹的centerx设置为飞船的rect.centerx        self.rect.top = ship.rect.top         #子弹的rect的top属性设置为飞船的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)

#button.pyimport pygame.fontclass Button():    def __init__(self, ai_settings, screen, msg):        """初始化按钮的属性"""        self.screen = screen        self.screen_rect = screen.get_rect()        #设置按钮的尺寸和其他属性        self.width, self.height = 200, 50        self.button_color = (0, 250, 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):        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)

#game_functions.pyimport sysimport pygamefrom bullet import Bulletfrom alien import Alienfrom time import sleepdef 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:        # 创建一颗子弹,并将其加入到编组bullets中        fire_bullet(ai_settings, screen, ship, bullets)    elif event.key == pygame.K_q:        sys.exit()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 =  Falsedef check_events(ai_settings, screen, stats,sb, play_button, ship, aliens,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)        elif event.type == pygame.MOUSEBUTTONDOWN:            mouse_x,mouse_y = pygame.mouse.get_pos()            check_play_button(ai_settings, screen, stats, sb, play_button, ship,aliens, bullets, mouse_x, mouse_y)def check_play_button(    ai_settings, screen, stats, sb, play_button, ship, aliens,bullets, mouse_x, mouse_y):        button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)    if button_clicked and not stats.game_active:        # 重置游戏设置        ai_settings.initialize_dynamic_settings()        # 隐藏光标        pygame.mouse.set_visible(False)        #重置游戏        stats.reset_start()        stats.game_active = True        #重置记分牌图像        sb.prep_score()        sb.prep_high_score()        sb.prep_level()        sb.prep_ships()        # 清空外星人列表和子弹列表?        aliens.empty()        bullets.empty()        # 创建一群新的外星人,并让飞船居中        create_fleet(ai_settings, screen, ship, aliens)        ship.center_ship()def update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets,play_button):    """更新屏幕的图像,并且切换到新的屏幕"""    #每次循环时都会重新绘屏    screen.fill(ai_settings.bg_color)    for bullet in bullets.sprites():        bullet.draw_bullet()    ship.blitme()    aliens.draw(screen)    #显示得分    sb.show_score()        # 如果游戏处于非活动状态,就绘制Play按钮    if not stats.game_active:        play_button.draw_button()    #让最近绘制的屏幕可见    pygame.display.flip()def update_bullets(ai_settings, screen,stats, sb, ship, aliens, bullets):    """更新子弹的位置,并且删除已消失的子弹    在for循环中,不应从列表或编组中删除条目,因此必须遍历编组的副本。    我们使用了方法copy()来设置for循环    """    bullets.update()    for  bullet in bullets.copy():        if bullet.rect.bottom <= 0:            bullets.remove(bullet)    check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets)def check_bullet_alien_collisions(    ai_settings, screen, stats, sb, ship, aliens, bullets):    #检查子弹是否打中飞机    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)    if len(aliens) == 0:        #删除现有的子弹并新建一群外星人        bullets.empty()        ai_settings.increase_speed()  #新游戏加速        #print(ai_settings.alien_speed_factor)        create_fleet(ai_settings, screen, ship, aliens)        stats.level += 1        sb.prep_level()    if collisions:        for aliens in collisions.values():            stats.score += ai_settings.alien_points * len(aliens)            sb.prep_score()        check_high_score(stats, sb)def fire_bullet(ai_settings, screen, ship, bullets):    """如果还没有到达限制,就发射一颗子弹"""    #创建新子弹,并将其加入到编组bullets中    if len(bullets) < ai_settings.bullets_allowed:        new_bullet = Bullet(ai_settings, screen, ship)        bullets.add(new_bullet)def create_fleet(ai_settings, screen, ship, aliens):    """创建外星人群"""    #创建一个外星人并且计算一行可以容纳多少个外星人    #外星人间距为外星人的宽度    alien = Alien(ai_settings, screen)    number_aliens_x = get_number_aliens_x(ai_settings,alien.rect.width)    number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height)    #创建第一行外星人    for row_number in range(number_rows):        for alien_number in  range(number_aliens_x):            #创建一个外星人,并将其加入当前行列            create_alien(ai_settings, screen, aliens, alien_number, row_number)def get_number_aliens_x(ai_settings, alien_width):    """计算每行可以容纳多少飞机"""    available_space_x = ai_settings.screen_width - 2 * alien_width    number_aliens_x = int(available_space_x / (2 * alien_width))    return number_aliens_xdef create_alien(ai_settings, screen, aliens, alien_number, row_number):  #这里的row_number来自哪里?    """创建一个外星人并把它放在当前行列"""    alien = Alien(ai_settings, screen)    alien_width = alien.rect.width    alien.x = alien_width + 2 * alien_width * alien_number    alien.rect.x = alien.x    alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number    aliens.add(alien)def get_number_rows(ai_settings, ship_height, alien_hight):    """计算屏幕可以容纳几行外星人"""    available_space_y = (        ai_settings.screen_height - (3*alien_hight) - ship_height)    number_rows = int(available_space_y / (2*alien_hight))    return number_rowsdef update_aliens(ai_settings, screen, stats, sb, ship, aliens, bullets):    """更新外星人的位置"""    check_fleet_edges(ai_settings,aliens)    aliens.update()    #检测外星人和飞船之间的碰撞    if pygame.sprite.spritecollideany(ship, aliens):        ship_hit(ai_settings, screen, stats, sb, ship, aliens, bullets)    check_aliens_bottom(ai_settings, screen, stats, sb, ship, aliens, bullets)def check_fleet_edges(ai_settings, aliens):    """有外星人撞到边缘时候采取的措施"""    for alien in aliens.sprites():        if alien.check_edges():            change_fleet_direction(ai_settings, aliens)            breakdef change_fleet_direction(ai_settings,aliens):    """整体外星人向下移动,并且改变方向"""    for alien in aliens.sprites():        alien.rect.y += ai_settings.fleet_drop_speed    ai_settings.fleet_direction *= -1def ship_hit(ai_settings, screen, stats, sb, ship, aliens, bullets):    """响应被外星人撞到的飞船"""    #ship_left -1    if stats.ship_left > 0:        stats.ship_left -=1        #清空外星人列表和子弹列表        aliens.empty()        bullets.empty()        sb.prep_ships()        #创建一群新的外星人,并将飞船放到屏幕底端中央        create_fleet(ai_settings, screen, ship, aliens)        ship.center_ship()        #暂停        sleep(0.5)    else:        stats.game_active = False        pygame.mouse.set_visible(True)def check_aliens_bottom(ai_settings, screen, stats, sb, ship, aliens,    bullets):    """检查是否有外星人到达了屏幕底端"""    screen_rect = screen.get_rect()    for alien in aliens.sprites():        if alien.rect.bottom >= screen_rect.bottom:            #和飞船被撞处理一样            ship_hit(ai_settings, screen, stats, sb, ship, aliens, bullets)            breakdef check_high_score(stats, sb):    if stats.score > stats.high_score:        stats.high_score = stats.score        sb.prep_high_score()

#game_stats.pyclass GameStats():    """游戏统计信息"""    def __init__(self,ai_settings):        """初始化统计信息"""        self.ai_settings = ai_settings        self.reset_start()        #游戏一开始就是非活动状态        self.game_active = False        # 在任何情况下都不应重置最高得分        self.high_score = 0    def reset_start(self):        """初始化在游戏运行期间可能变化的统计信息"""        self.ship_left = self.ai_settings.ship_limit        self.score = 0        self.level = 1        

#Scoreboard.pyimport pygame.fontfrom pygame.sprite import Groupfrom ship import Shipclass Scoreboard():    """显示信息得分的类"""    def __init__(self, ai_settings, screen, stats):        self.screen  = screen        self.screen_rect = screen.get_rect()        self.ai_settings = ai_settings        self.stats = stats        #显示得分信息时使用的字体设置        self.text_color = (30, 30, 30)        self.font = pygame.font.SysFont(None, 48)                #准备初始得分图像 和最高得分        self.prep_score()        self.prep_high_score()        self.prep_level()        self.prep_ships()    def prep_score(self):        rounded_score = int(round(self.stats.score, -1))        score_str = "{:,}".format(rounded_score)        self.score_image = self.font.render(            score_str,True, self.text_color, self.ai_settings.bg_color)        #将得分放在屏幕右上角        self.score_rect = self.score_image.get_rect()        self.score_rect.right  = self.screen_rect.right -20        self.score_rect.top = 20    def show_score(self):        self.screen.blit(self.score_image, self.score_rect)        self.screen.blit(self.high_score_image, self.high_score_rect)         self.screen.blit(self.level_image, self.level_rect)        self.ships.draw(self.screen)    def prep_high_score(self):        """渲染最高分为图像"""        high_score = int(round(self.stats.high_score,-1))        high_score_str = "{:,}".format(high_score)        self.high_score_image = self.font.render(high_score_str, True,            self.text_color, self.ai_settings.bg_color)        #最高得分在顶部中央        self.high_score_rect = self.high_score_image.get_rect()        self.high_score_rect.centerx = self.screen_rect.centerx        self.high_score_rect.top = self.screen_rect.top    def prep_level(self):        """将等级转换为渲染的图像"""        self.level_image = self.font.render(str(self.stats.level), True,             self.text_color, self.ai_settings.bg_color)        #位置        self.level_rect = self.level_image.get_rect()        self.level_rect.right = self.score_rect.right        self.level_rect.top = self.score_rect.bottom + 10    def prep_ships(self):        self.ships = Group()        for ship_number in range(self.stats.ship_left):            ship = Ship(self.ai_settings, self.screen)            ship.rect.x = 10 + ship_number * ship.rect.width            ship.rect.y = 10            self.ships.add(ship)

#settings.pyclass Settings():    """    存储游戏所有设置的类    """    def __init__(self):        """初始化游戏的设置"""        #屏幕设置        self.screen_width = 1200        self.screen_height = 800        self.bg_color = (230, 230, 230)        # 飞船的设置        self.ship_speed_factor = 1.5        self.ship_limit = 3        #子弹设置        self.bullet_speed_factor = 3          self.bullet_width = 1    #这里更改子弹的宽度        self.bullet_height = 15        self.bullet_color = 60, 60, 60        self.bullets_allowed = 300   #这里更改子弹的个数        # 外星人设置        self.fleet_drop_speed = 10         #默认10        # 以什么样的速度加快游戏节奏        self.speedup_scale = 1.1        #分数的提高速度        self.score_scale = 1.5        self.initialize_dynamic_settings()    def initialize_dynamic_settings(self):        #初始化随游戏进行而变化的设置        self.ship_speed_factor = 1.5        self.bullet_speed_factor = 3        self.alien_speed_factor = 1        # fleet_direction为1表示向右;为-1表示向左        self.fleet_direction = 1        #积分        self.alien_points = 50    def increase_speed(self):        #提高速度设置        self.ship_speed_factor *= self.speedup_scale        self.bullet_speed_factor *= self.speedup_scale        self.alien_speed_factor *= self.speedup_scale        self.alien_points = int(self.alien_points * self.score_scale)        print(self.alien_points)

#ship.pyimport pygamefrom pygame.sprite import Spriteclass Ship(Sprite):    def __init__(self, ai_settings, screen):        """初始化飞船并设置其初始位置"""        super(Ship, self).__init__()        self.screen = screen        self.ai_settings = ai_settings        #加载飞船图像并获取其外接矩形        self.image = pygame.image.load(‘images/ship.png‘)       #加载图像        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 = float(self.rect.centerx)        #移动标志        self.moving_right = False        self.moving_left =   False    def update(self):        """根据移动标志调整飞船的位置"""        # 更新飞船的center值,而不是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    def blitme(self):        """在指定位置绘制飞船"""        self.screen.blit(self.image, self.rect)    def center_ship(self):        """让飞船在屏幕上居中"""        self.center = self.screen_rect.centerx

python实战===如何优雅的打飞机

评论关闭