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
  • 相关阅读:
    Windows 科研软件推荐
    有关Python 包 (package) 的基本知识
    《Using Python to Access Web Data》Week4 Programs that Surf the Web 课堂笔记
    Coursera助学金申请模板
    《Using Databases with Python》 Week2 Basic Structured Query Language 课堂笔记
    Jupyter 解决单个变量输出问题
    解决 pandas 中打印 DataFrame 行列显示不全的问题
    《Using Python to Access Web Data》 Week3 Networks and Sockets 课堂笔记
    缓存击穿及解决方案
    jvm垃圾收集器
  • 原文地址:https://www.cnblogs.com/clno1/p/12485548.html
Copyright © 2011-2022 走看看