zoukankan      html  css  js  c++  java
  • Python开发的飞机打外星人小游戏

    跟着《Python从入门到实践》这本书学习的Python,这本书最后的实践部分第一个就是实现一个飞机打外星人的小游戏,跟着书的步骤一步步做最终实现了,并扩展了飞机可以上下移动的功能。

    游戏有9个py文件,分别是Alien_invasion.py游戏主程序,settings.py游戏设定,alien.py外星人,ship.py飞船,bullet.py子弹,game_status.py游戏启动与否状态,game_function游戏的函数,scoreborad游戏计数板,button.py游戏窗口的按钮。

    下面简单说一下各个文件的作用。

    首先是游戏的主程序Alien_invasion.py,主要是new一个游戏设定setting,new一个飞船,new存储子弹list,new存储外星人list,new计数板,设定初始游戏状态等游戏的初始化工作。

    import sys
    import pygame
    from pygame.sprite import Group
    
    from settings import Settings
    from game_stats import GameStats
    from scoreboard import Scoreboard
    from button import Button
    from ship import Ship
    from alien import Alien
    import game_function 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")
        stats=GameStats(ai_settings)
        sb=Scoreboard(ai_settings,screen,stats)
    
        #Play按钮
        play_button=Button(ai_settings,screen,"Play")
        #创建一艘飞船
        ship=Ship(ai_settings,screen)
        #创建用于存储子弹的编组
        bullets=Group()
        #创建一个外星人编组
        aliens=Group()
        gf.creat_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,stats,sb,screen,ship,aliens,bullets)
                gf.update_aliens(ai_settings,stats,screen,ship,aliens,bullets)
            gf.update_screen(ai_settings, screen,sb,stats,ship,aliens, bullets,play_button)  #更新屏幕
    
    
    run_game()
    View Code

    settings.py,游戏的设定程序,包括:游戏窗口大小,生命个数,飞船飞行速度,同屏子弹个数,子弹飞速等等。

    设定类在游戏主程序的时候调用有参构造函数new一个设定类。

    class Settings():
        #存储《外星人入侵》游戏的设置
    
        def __init__(self):
            #屏幕及飞船
            self.screen_width=1200
            self.screen_height=700
            self.bg_color=(230,230,230)
            self.ship_speed=3
            self.ship_lives=2
            #子弹
            self.bullet_width=5
            self.bullet_height=10
            self.bullet_speed=3
            self.bullet_color=60,60,60
            self.bullets_total=5
            #敌人
            self.alien_speed=0.5
            self.fleet_drop_speed=50    #敌人撞壁之后向下移动速度
            self.fleet_direction=1      #取1/-1为向右/向左
            self.alien_points=10
    View Code

    alien.py,外星人类,存储外星人的一些函数,外星人移动等。

    import pygame
    from pygame.sprite import Sprite
    
    class Alien(Sprite):
        def __init__(self,ai_settings,screen):
            super(Alien,self).__init__()
            self.screen=screen
            self.ai_settings=ai_settings
    
            self.image=pygame.image.load('images/alien.bmp')
            self.image=pygame.transform.scale(self.image,(50,50))   #缩放图像
            self.rect=self.image.get_rect()
    
            #把飞船初始位置设为左上角
            self.rect.x=self.rect.width
            self.rect.y=self.rect.height
    
            self.x,self.y=0.0,0.0
    
    
        def update(self):
            self.x+=self.ai_settings.alien_speed * self.ai_settings.fleet_direction
            self.rect.x=int(self.x)
    
        def check_edges(self):
            screen_rect=self.screen.get_rect()
            if self.rect.right>=screen_rect.right:
                return True
            elif self.rect.right<=0:
                return True
            else:
                return False
    
        def blitme(self):
            self.screen.blit(self.image,self.rect)
    View Code

    ship.py,飞船类,存储有关飞船的一些函数:把飞船绘制到窗口中,飞船移动,飞船发射子弹等。

    #飞船类:管理飞船的行为
    import pygame
    
    class Ship():
        def __init__(self,ai_settings,screen):
            #init初始化飞船并设置其初始位置
            self.screen=screen
            self.ai_seettings=ai_settings
    
            #self.rect取得飞船矩形     self.screen_rect取得屏幕矩形
            self.image=pygame.image.load("images/ship.bmp")
            self.image=pygame.transform.scale(self.image,(50,50))   #缩放图像
            self.rect=self.image.get_rect()
            self.screen_rect=screen.get_rect()
    
            '''
            可设置相应 rect 对象的属性center,centerx,centery 
            要让游戏元素与屏幕边缘对齐,可使用属性 top,bottom,left,right ;
            要调整游戏元素的水平或垂直位置,可使用属性 x,y ,它们分别是相应矩形左上角的 x 和 y 坐标。
            '''
            #将飞船放在屏幕最下方中央
            self.rect.centerx=self.screen_rect.centerx
            self.rect.bottom=self.screen_rect.bottom
    
            #移动标记
            self.moving_right=False
            self.moving_left=False
            self.moving_up=False
            self.moving_down=False
    
            #移动速度x/y
            self.center=float(self.rect.centerx)
            self.recty=float(self.rect.bottom)
    
        def update(self):
            #根据移动标记调整飞船位置(横轴)
            if self.moving_right and self.center<self.ai_seettings.screen_
                self.center+=self.ai_seettings.ship_speed
            if self.moving_left and self.center>0:
                self.center-=self.ai_seettings.ship_speed
            self.rect.centerx=int(self.center)
            #根据移动标记调整飞船位置(纵轴)
            if self.moving_up and self.recty>0:
                self.recty-=self.ai_seettings.ship_speed
            if self.moving_down and self.recty<self.ai_seettings.screen_height:
                self.recty+=self.ai_seettings.ship_speed
            self.rect.centery=int(self.recty)
    
        def blitme(self):
            #根据self.rect的指定位置将飞船绘制到屏幕上
            self.screen.blit(self.image,self.rect)
    
        def center_ship(self):
            self.center=float(self.screen_rect.centerx)
            self.recty=float(self.screen_rect.bottom)
    View Code

    bullet.py,子弹类,存储有关子弹的一些函数:子弹飞行,子弹与外星人碰撞等。

    import pygame
    
    from pygame.sprite import Sprite
    
    #子弹类:对飞船子弹进行管理,继承自Sprite
    class Bullet(Sprite):
        #__init__在飞船位置创建一颗子弹
        def __init__(self,ai_settings,screen,ship):
            super(Bullet,self).__init__()
            self.screen=screen
    
            #在 (0,0) 处创建一个表示子弹的矩形,再设置正确的位置
            self.rect=pygame.Rect(0, 0, ai_settings.bullet_width,ai_settings.bullet_height)
            #x轴设为飞船x轴
            self.rect.centerx = ship.rect.centerx   
            self.rect.top = ship.rect.top   #
      
            #记录self.y值用于以后改变,self.x不会变不用记录
            self.y=float(self.rect.y)
    
            #子弹颜色和速度
            self.color=ai_settings.bullet_color
            self.bullet_speed=ai_settings.bullet_speed
    
        #update将子弹向上移动
        def update(self):
            self.y-=self.bullet_speed
            self.rect.y=int(self.y)
    
        def draw_bullet(self):
            #用self.color的颜色填充self.screen的self.rect的矩形部分
            pygame.draw.rect(self.screen,self.color,self.rect)
    View Code

    game_status.py,游戏状态类,主要是为了游戏重新开始

    class GameStats():
    
        def __init__(self,ai_settings):
            self.ai_settings=ai_settings
            self.reset_stats()
    
            self.game_active=False
    
        def reset_stats(self):
            self.ship_lives=self.ai_settings.ship_lives
            self.score=0
    View Code

    game_function,调控各个函数作用的主函数。

    import sys
    from time import sleep
    import pygame
    from bullet import Bullet
    from alien import Alien
    
    #响应键盘按下事件
    def check_keydown_events(event,ai_settings,screen,ship,bullets):
        if event.key==pygame.K_RIGHT:
            ship.moving_right=True
        if event.key==pygame.K_LEFT:
            ship.moving_left=True
        if event.key==pygame.K_UP:
            ship.moving_up=True
        if event.key==pygame.K_DOWN:
            ship.moving_down=True
        if event.key==pygame.K_SPACE:
            fire_bullet(ai_settings,screen,ship,bullets)
        if event.key==pygame.K_q:
            sys.exit()
    
    def fire_bullet(ai_settings,screen,ship,bullets):
        #监测到按下空格键:创建一颗子弹
        if len(bullets)<ai_settings.bullets_total:
            new_bullet=Bullet(ai_settings,screen,ship)
            bullets.add(new_bullet)
    
    #响应键盘回弹事件
    def check_keyup_events(event,ship):
        if event.key==pygame.K_RIGHT:
            ship.moving_right=False
        if event.key==pygame.K_LEFT:
            ship.moving_left=False
        if event.key==pygame.K_UP:
            ship.moving_up=False
        if event.key==pygame.K_LEFT:
            ship.moving_down=False
    
    #监测并响应键盘鼠标事件
    def 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.MOUSEBUTTONDOWN:
                mouse_x,mouse_y=pygame.mouse.get_pos()
                check_play_buttons(ai_settings,screen,stats,sb,play_button,mouse_x,mouse_y,ship,aliens,bullets)
            elif event.type==pygame.KEYDOWN:
                check_keydown_events(event,ai_settings,screen,ship,bullets)
            elif event.type==pygame.KEYUP:
                check_keyup_events(event,ship)
    
    def check_play_buttons(ai_settings,screen,stats,sb,play_button,mouse_x,mouse_y,ship,aliens,bullets):
        if not stats.game_active and play_button.rect.collidepoint(mouse_x, mouse_y):
            pygame.mouse.set_visible(False)
    
            stats.reset_stats()
            stats.game_active = True
    
            aliens.empty()
            bullets.empty()
    
            creat_fleet(ai_settings,screen,ship,aliens)
            ship.center_ship()
    
            sb.prep_score()
    
    #功能:更新屏幕图像,绘制新的图像
    def update_screen(ai_settings, screen,stats,ship,aliens, bullets,play_button):
        #每次循环都重绘屏幕
        screen.fill(ai_setting.bg_color)
        #更新子弹group内子弹位置
        for bullet in bullets.sprites():
            bullet.draw_bullet()
        ship.blitme()
        aliens.draw(screen)
        # 如果游戏处于非活动状态,就绘制 Play 按钮
        if not stats.game_active:
            play_button.draw_button()
        #让最近绘制的屏幕可见
        pygame.display.flip()
    
    #更新子弹
    def update_bullets(ai_settings,stats,sb,screen,ship,aliens,bullets):
        bullets.update()
        for bullet in bullets.copy():
            if bullet.rect.bottom<=0:
                bullets.remove(bullet)
        #print(len(bullets))
        #内置函数:一行就双重遍历子弹和敌人,矩形重叠就消失
        collisions=pygame.sprite.groupcollide(bullets,aliens,True,True)
        #更新分数
        if collisions:
            for aliens in collisions.values():
                stats.score+=ai_settings.alien_points*len(aliens)
                sb.prep_score()
        #检测现有敌人是否为0了
        if len(aliens)==0:
            bullets.empty()
            creat_fleet(ai_settings,screen,ship,aliens)
    
    #创建外星人舰队:
    def creat_fleet(ai_settings,screen,ship,aliens):
        #创建一个外星人,并计算每行可容纳多少个外星人
        alien=Alien(ai_settings,screen)
        number_aliens_x=calc_aliens_number(ai_settings,alien.rect.width)
        row_numbers=calc_row_number(ai_settings, ship.rect.height, alien.rect.height)
    
        for row_number in range(row_numbers-1):
            for alien_number in range(number_aliens_x-1):
                creat_an_alien(ai_settings,screen,aliens,alien_number,row_number)
            
    
    def creat_an_alien(ai_settings,screen,aliens,alien_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
        alien.x=float(alien.rect.x)
        alien.y=float(alien.rect.y)
        aliens.add(alien)
    
    def calc_aliens_number(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_x
    
    def calc_row_number(ai_settings, ship_height, alien_height):
        available_space_y = (ai_settings.screen_height -(3 * alien_height) - ship_height)
        number_rows = int(available_space_y / (2 * alien_height))
        return number_rows
    
    #更新外星人
    def update_aliens(ai_settings,stats,screen,ship,aliens,bullets):
        check_fleet_edges(ai_settings,aliens)
        aliens.update()
        #
        if pygame.sprite.spritecollideany(ship,aliens):
            ship_hit(ai_settings,stats,screen,ship,aliens,bullets)
            #print("Xiba!!!")
    
    def check_fleet_edges(ai_settings,aliens):
        for alien in aliens.sprites():
            if alien.check_edges():
                change_direction(ai_settings,aliens)
                break
    
    def change_direction(ai_settings,aliens):
        for alien in aliens.sprites():
            alien.y+=ai_settings.fleet_drop_speed
            alien.rect.y=int(alien.y)
        ai_settings.fleet_direction*=-1
    
    def ship_hit(ai_settings,stats,screen,ship,aliens,bullets):
        if stats.ship_lives>0:
            stats.ship_lives-=1
    
            aliens.empty()
            bullets.empty()
    
            creat_fleet(ai_settings,screen,ship,aliens)
            ship.center_ship()
    
            sleep(0.5)
        else:
            stats.game_active=False
            pygame.mouse.set_visible(True)
    
    """ 更新屏幕上的图像,并切换到新屏幕 """
    def update_screen(ai_settings, screen, sb,stats, ship, aliens, bullets,play_button):
        #每次循环都重绘屏幕
        screen.fill(ai_settings.bg_color)
        #更新子弹group内子弹位置
        for bullet in bullets.sprites():
            bullet.draw_bullet()
        ship.blitme()
        aliens.draw(screen)
        sb.show_score()
    
        # 如果游戏处于非活动状态,就绘制 Play 按钮
        if not stats.game_active:
            sb.prep_score()
            play_button.draw_button()
    
        # 让最近绘制的屏幕可见
        pygame.display.flip()
    View Code

    scoreboard.py,计分板。

    import pygame.font
    
    class 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()
    
    
        def prep_score(self):
            score_str=str(self.stats.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)
    View Code

    button.py,按钮,只有游戏结束重新开始的按钮。

    import pygame.font
    
    class 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=(100,100,100)
            self.text_color=(255,255,255)
            self.font=pygame.font.SysFont(None,48)
    
            #创建按钮的矩形
            self.rect=pygame.Rect(0,0,self.width,self.height)
            self.rect.center=self.screen_rect.center
    
            #调用prep_msg函数绘制按钮
            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)
    View Code
  • 相关阅读:
    navigator对象及属性(userAgent)(扩展)
    最新Visual C++ 运行时
    Wakfu .pk 音频文件提取
    Flex布局学习记录
    小程序 swiper bindChange 抖动解决方法
    小程序 scroll-view 无法触发 onReachBottom 解决办法
    小程序修改按钮宽高
    db.collection(变量名)
    小程序图片轮播自适应
    微信小程序 MD5引用
  • 原文地址:https://www.cnblogs.com/clno1/p/12485548.html
Copyright © 2011-2022 走看看