外星人游戏

外星人游戏主程序alien_invasion

import pygame
#import sys,当前只在模块game_functions中使用它
from settings import Settings #导入类
from ship import Ship #导入类
#from alien import Alien 由于我们不在本模块中直接创建alien所以不要导入Alien模块
import game_functions as gf #导入模块game_functions
from pygame.sprite import Group         
from game_stats import GameStats
from button import Button
from scoreboard import ScoreBoard
def run_game():
    #初始化pygame,settings和屏幕对象
    pygame.init() 
    ai_settings=Settings()#实例化设置类
    screen=pygame.display.set_mode((ai_settings.screen_width,
                                    ai_settings.screen_height))
    #创建一个宽1200,高800的屏幕
    pygame.display.set_caption("Alien Invasion")#设置标题
    
    #创建一艘飞船
    ship=Ship(ai_settings,screen)
    #创建一个用于存储子弹的编组
    bullets=Group()
    #创建一个外星人编组
    aliens =Group() #存储所有外星人
    #创建外星人群
    gf.create_fleet(ai_settings,screen,ship,aliens)#将空编组传给他
    #创建一个用于存储游戏统计信息的实例,并创建记分牌
    stats=GameStats(ai_settings)
    sb=ScoreBoard(ai_settings,screen,stats)
    #创建游戏开始按钮
    play_button = Button(ai_settings,screen,"Play")

    #开始主循环
    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,stats,screen,sb,ship,aliens,bullets)
            #print(len(bullets))#核实子弹确实已经被删除,以后本句话就可以删除,占内存
        gf.update_screen(ai_settings,screen,stats,sb,ship,aliens,bullets,play_button)
          
run_game()

设置模块

class Settings():
    
    '''存储alien所有设置'''
    def __init__(self):
        '''初始化游戏的静态设置'''
        
        #屏幕设置
        self.screen_width=1200
        self.screen_height=600
        self.bg_color = (230,230,230)#RGB值,0~255,(255,0,0)红色  (0,255,0)绿色 (0,0,255)蓝色
        
        #飞船的设置
         
        #rect的centerx属性只能存放整数
        self.ship_limit = 3
        #子弹的设置
         
        self.bullet_width=300
        self.bullet_height=15
        self.bullet_color = (255,0,0)#深灰色子弹速度比飞船速度低
        self.bullets_allowed=8#将未消失的子弹数量设置为3颗
        #外星人设置
         
        self.fleet_drop_speed = 10 #撞击屏幕的之后下降的速度
        
        
        #以什么样的速度加快游戏节奏
        self.speedup_scale=1.1
        #外星人点数的提高速度
        self.score_scale=1.5
        
        self.initalize_dynamic_settings()
        
    def initalize_dynamic_settings(self):
        '''初始化随游戏变化的设置'''
        self.ship_speed_factor=8.5 #飞船移动时,移动1.5个像素,小数可以更加细致的控制飞船速度
        self.bullet_speed_factor = 10
        self.alien_speed_factor = 5
        self.fleet_direction = 1 #为1表示向右移,-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)#确认点数不断增加之后这句话可以删掉
        

所有的函数模块

import pygame 
import sys
from bullet import Bullet
from alien import Alien
from time import sleep


def check_keydown_events(event,ai_settings,screen,ship,bullets):#编组传给check_keydown_events
    '''响应按键'''
    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: #按下空格键创建新子弹
        file_bullet(ai_settings,screen,ship,bullets)#调用发射函数
    elif event.key==pygame.K_q:
        sys.exit()
        
        
        
        
def file_bullet(ai_settings,screen,ship,bullets):
    '''如果没有达到限制就发射一颗子弹'''
    if len(bullets)<ai_settings.bullets_allowed: #现在子弹的数量
        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
    elif event.key==pygame.K_LEFT:#判断是否按得是左箭头
        ship.moving_left=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.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()#pygame.mouse.get_pos返回一个元组,包含鼠标的想,和y坐标
            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):
   
    '''在玩家单击play按钮时开始游戏'''
    
    button_clicked=play_button.rect.collidepoint(mouse_x,mouse_y)#检查鼠标时是否在play_button.rect中,结果为True False
    if button_clicked and not stats.game_active: #当且仅当玩家按按钮,且游戏处于非活跃状态,游戏才重新开始,不然玩家在游戏过程按中原本按钮的位置游戏也会重新开始
        
        #重置游戏
        ai_settings.initalize_dynamic_settings()
        
        #隐藏光标
        pygame.mouse.set_visible(False)
        
        #重置游戏统计信息
        stats.reset_stats()
        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():#方法bullets.sprites返回一个列表,包含编组bullets中所有精灵
        bullet.draw_bullet()#对每个精灵调用draw_bullet函数画图
    ship.blitme()###填充背景之后才将飞船绘制到屏幕上,确保飞船出现在屏幕前面    
     #在飞船和子弹后面绘制外星人
    aliens.draw(screen)#对编组调用draw时,pygame自动绘制编组中的每个元素,位置有rect决定,在屏幕上绘制每一个外星人
    
    #显示得分
    sb.show_score()
    
    #如果屏幕属于非活动状态就运行游戏
    if not stats.game_active:
        play_button.draw_button()
        
    #让最近屏幕可见
    pygame.display.flip() #图像翻转,,绘制一个空屏幕并不断擦去旧屏幕,使得只有新屏幕可见
    

def update_bullets(ai_settings,screen,stats,sb,ship,aliens,bullets): #函数用来管理子弹
    '''更新子弹的位置,删除已经消失的子弹'''
    bullets.update()#子弹位置更新
    #删除已经消失的子弹
    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
    check_bullet_alien_collision(ai_settings,screen,stats,sb,ship,aliens,bullets)
    
def check_bullet_alien_collision(ai_settings,screen,stats,sb,ship,aliens,bullets):
            
    #检查是否有子弹击中了外星人,如果是这样就删除相应的子弹和外星人
    collisions = pygame.sprite.groupcollide(bullets,aliens,True,True)
       #方法sprite.groupcollide(),将子弹的rect与外星人的rect比较,并返回一个字典,其中包含发生碰撞重叠的子弹和外星人,键是子弹,值是外星人,两个True告诉pygame删除发生碰撞的子弹和外星人
    if collisions:
        for aliens in collisions.values():
            stats.score += ai_settings.alien_points*len(aliens)
            sb.prep_score()
        check_high_score(stats,sb)
     #j检查aliens是否为空,如果是,删除剩下的子弹,并再次创建一群外星人
    if len(aliens) == 0:
        
        #如果整群外星人都被消灭,就提高一个等级
        bullets.empty()
        ai_settings.increase_speed()
        
        #提高等级
        stats.level +=1
        sb.prep_level()
        
        create_fleet(ai_settings,screen,ship,aliens)
    
def check_high_score(stats,sb):
    '''检查是否诞生了最高分'''
    if stats.score>stats.high_score:
        stats.high_score=stats.score
        sb.prep_high_score()
            
def check__fleet_edges(ai_settings,aliens):
    '''有外星人到达边缘时采取相应的措施'''
    for alien in aliens.sprites():
        if alien.check_edges():
            change_fleet_direction(ai_settings,aliens)
            break
            
def change_fleet_direction(ai_settings,aliens):
    '''将整群外星人下移,并改变他们的方向'''
    for alien in aliens.sprites():
        alien.rect.y += ai_settings.fleet_drop_speed
    ai_settings.fleet_direction*= -1


def ship_hit(ai_settings,stats,screen,sb,ship,aliens,bullets):
    '''响应被外星人撞击之后的飞船'''
    if stats.ships_left > 0:
        #将ship_left -1
        stats.ships_left -=1
        
        #更新记分牌
        sb.prep_ships()
    
        #清空外星人列表和子弹列表
        aliens.empty()
        bullets.empty()
    
        #创建一群新的外星人,并将飞船放在屏幕底部中央
        create_fleet(ai_settings,screen,ship,aliens)
        ship.center_ship()
        #暂停,为了让用户看清飞船与外星人碰撞了
        sleep(0.5)
    else:
        stats.game_active =False #玩家没有飞船,就将标准设置为false 结束游戏
        pygame.mouse.set_visible(True)
    
def check_aliens_bottom(ai_settings,stats,screen,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,stats,screen,sb,ship,aliens,bullets)
            break #有一个到达底部就无需检查其他
    
    
def update_aliens(ai_settings,stats,screen,sb,ship,aliens,bullets):
    '''检查是否有外星人到达边缘,并更新外星人的位置'''
    check__fleet_edges(ai_settings,aliens)
    aliens.update()
    #检查是否有外星人到达屏幕底端
    check_aliens_bottom(ai_settings,stats,screen,sb,ship,aliens,bullets)
    
    
    #检查外星人和飞船之间的碰撞
    if pygame.sprite.spritecollideany(ship,aliens):#spritecollideany()接受两个实参,一个精灵和一个编组,检查编组里面是否有成员跟精灵碰撞,如果有则返回编组里的成员,执行接下来的操作,没有则返回None。
        ship_hit(ai_settings,stats,screen,sb,ship,aliens,bullets)
         
            
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_x

def get_number_rows(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 create_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#每个外星人的位置都是通过设置x坐标实现,占用一个宽度的空白
    alien.rect.x=alien.x
    alien.rect.y=alien.rect.height+2*alien.rect.height*row_number
    aliens.add(alien)#将创建好的加到编组aliens中
    
    
    
    
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): 
            #从0开始到要创建的外星人数,。每一行的个数
            create_alien(ai_settings,screen,aliens,alien_number,row_number)
         

子弹

#创建子弹类
import pygame
from pygame.sprite import Sprite #Sprint精灵,通过使用精灵,可以将游戏中相关元素编组,相当于列表
class Bullet(Sprite):
    '''一个对飞船发射的子弹进行管理的类'''
    def __init__(self,ai_settings,screen,ship):
        super().__init__()
        self.screen=screen
        
        #在(0,0)处创建一个表示子弹的矩形,再设置正确的位置
        self.rect =pygame.Rect(0,0,ai_settings.bullet_width,
                               ai_settings.bullet_height)
        self.rect.centerx=ship.rect.centerx
        self.rect.top=ship.rect.top#子弹应该从飞船顶部射出
        
        #存储用小数表的子弹的位置
        self.y=float(self.rect.y) #y可以微调子弹的设计速度
        self.color=ai_settings.bullet_color
        self.speed_factor=ai_settings.bullet_speed_factor
    def update(self):
        '''向上移动子弹'''
        self.y-= self.speed_factor #更新表示子弹的小数值,子弹向上运动,y坐标不断减小
        #更新表示子弹的rect位置
        self.rect.y=self.y
    def draw_bullet(self):
        '''在屏幕上绘制子弹'''
        pygame.draw.rect(self.screen,self.color,self.rect)#用color填空表示子弹的矩形rect占screen的部分
        

按钮

import pygame.font #导入字体模块,让pygame能够将文本渲染到屏幕上

class Button():
    def __init__(self,ai_settings,screen,msg): #msg是要在按钮上显示的文本
        '''初始化按钮属性'''
        self.screen =screen
        self.screen_rect = screen.get_rect()
        
        #设置按钮尺寸和其他属性
        self.width,self.height = 200,50 
        self.button_color=(0,255,0) #按钮的rect为绿色
        self.text_color=(255,255,255)#文本为白色
        self.font =pygame.font.SysFont(None,48) #指定使用默认字体,48号大小的字体渲染文本
        
        #创建按钮的rect对象,并使其居中
        self.rect = pygame.Rect(0,0,self.width,self.height) #pygame.Rect创建一个新的矩阵对象,在原点处,指定高,宽
        self.rect.center =self.screen_rect.center#将center属性设置为屏幕的center属性
        #按钮标签只需要创建一次
        
        self.prep_msg(msg) #调用方法prep_msg()
        
    def prep_msg(self,msg):
        '''将msg渲染为图像,并使其在按钮上居中'''
        self.msg_image = self.font.render(msg,True,self.text_color,
                                          self.button_color)#font.render将存储在msg中的文本转化为图像,True开启反锯齿功能,文本背景颜色为按钮颜色
        self.msg_image_rect =self.msg_image.get_rect()#创建文本图像的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)#传递图像,已经图像相关连的rect对象 在屏幕上绘制文本
       ```

外星人模块

import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
    '''表示单个外星人的类'''
    def __init__(self,ai_settings,screen):
        
        '''初始化外星人并设置初始位置'''
        super().__init__()
        self.ai_settings=ai_settings
        self.screen=screen
        
        #加载外星人图像,并设置rect属性
        self.image=pygame.image.load("images/alien.bmp") #加载图像
        self.rect=self.image.get_rect()#获取图像alien的矩阵对象
        
        #每个外星人初始位置都在屏幕左上角附近
        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()#获取屏幕的rect属性
        if self.rect.right >=screen_rect.right:#rect右属性大于屏幕rect右属性或者,左rect属性小于0,都说明在屏幕边缘
            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
        

飞船

import pygame
from pygame.sprite import Sprite#创建飞船编组
class Ship(Sprite):#创建飞船类,负责飞船的大部分行为  
    def __init__(self,ai_settings,screen): #添加ai——settings,让飞船可以获得其速度设置,后者指定要将飞船放在什么位置
        '''初始化飞船,并设置初始位置'''
        super().__init__()
        self.screen=screen
        self.ai_settings=ai_settings
        #加载飞船图,并获取外接矩阵
        self.image=pygame.image.load("images/ship.bmp") #加载图像
        self.rect=self.image.get_rect()#获取图像ship的矩阵对象
        self.screen_rect=screen.get_rect()#获取屏幕的矩阵对象
           
        #将每艘新飞船放在屏幕底部中央
        self.rect.centerx=self.screen_rect.centerx #将图像ship的中心x坐标放在屏幕中心x坐标
        self.rect.bottom=self.screen_rect.bottom #将ship的底放在屏幕的底部
        
        self.center=float(self.rect.centerx)#重新定义属性,将self.rect.centerx的值转化为小数
        #移动标志
        self.moving_right=False
        self.moving_left=False
    def update(self):
        '''根据移动标志调整飞船的位置'''
        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): #方法blit 实现位块传输
        '''在指定位置绘制飞船'''
        self.screen.blit(self.image,self.rect) #它根据self.rect 指定的位置将图像绘制到屏幕上
    def center_ship(self):
        '''让飞船在屏幕中央'''
        self.center =self.screen_rect.centerx
        

统计信息


class GameStats():
    '''跟踪游戏的统计信息'''
    def __init__(self,ai_settings):
        '''初始化统计信息'''
        self.ai_settings=ai_settings
        self.reset_stats() #调用方法reset_stats()
        #游戏启动时处于活动状态
        self.game_active =  False#将游戏一开始状态设置为非活动状态,按下play按钮才开始游戏
        #在任何情况下都不应该重置高分
        self.high_score = 0
        
    def reset_stats(self):
        '''初始化在游戏运行期间可能变化的统计信息'''
        self.ships_left=self.ai_settings.ship_limit
        self.score = 0
        self.level =1

得分信息

import pygame.font
from pygame.sprite import Group
from ship import Ship
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)
        
        #准备初始得分图像h和最高分的图像
        self.prep_score()
        self.prep_high_score()
        self.prep_level()
        self.prep_ships()
        
    def  prep_score(self):
        '''将得分转化为一幅渲染的图像'''
        rounded_score = round(self.stats.score,-1)#round函数是让小数精确到小数点后面多少位,-1表示圆整到最近的10的整数倍
        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 prep_high_score(self):
        '''将最高分转化为一幅渲染的图像'''
        high_score= 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.score_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.ships_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)
            
    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)#对编组调用draw,即可在屏幕上绘制飞船


两张位图:外星人和飞船

外星人
飞船

游戏运行结果
游戏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值