这里有九个.py文件,在工作的间隙,和老板斗智斗勇,终于完成了,实现了游戏的功能,恰逢博客园开通,虽然是对着书上的代码敲了一遍,但是对pygam这个库的了解增加了一些,作为一个python初学者,也作为一个堂堂西电通信科班出来的人,竟然没有用过python表示狗血,仅以此记录我亡羊补牢,为时不晚的茫茫深飘路,如果我的代码有幸被你搜到
你可以copy进你的编辑器,然后运行
python.exe .\alien_invasion.py
随后就会出现这个一个简易版的飞船大战游戏,缺点是本来应该是飞船和外星人,我找不到合适的图,因为要bmp格式图像,我现在还只是在网站上在线转换。所以美工效果不行,谅解!
下面附上window目录下文件
ship3.bmp是为了逗姑娘,把飞船设置成他的照片,哈哈哈。就这样吧,欢迎大家和我进行讨论,我希望通过这个博客园记录一下,我的CT+IT之路。
alien_invasion.py
#coding=utf-8 import sys import pygame from setting import Settings from ship import Ship from pygame.sprite import Group from game_stats import GameStats from button import Button from scoreboard import Scoreboard #from alien import Alien import game_functions as gf#名称太长,想要给它取个别名,以后每次用到它的时候都用它的别名代替它 def run_game(): #初始化pygame、设置和屏幕对象 pygame.init()#初始化所有导入的 pygame 模块#返回的一个pygame.Surface对象,而元组(1200,800)代表屏幕设置的长宽 ai_settings=Settings()#调用类使用 #这里的ai_注意这个写法是上面被调用的 screen=pygame.display.set_mode(#创建一个长宽的窗口 (ai_settings.screen_width,ai_settings.screen_height))#pygame.display.set_mode(resolution=(0,0),flags=0,depth=0) pygame.display.set_caption("Alien Invasion") #创建一个用于存储游戏统计信息的实例 # 创建存储游戏统计信息的实例,并创建记分牌 stats=GameStats(ai_settings) sb=Scoreboard(ai_settings,screen,stats) #print stats # 创建一艘飞船 ship=Ship(ai_settings,screen) # 创建Play按钮 play_button = Button(ai_settings,screen,"Play") # print play_button #创建一个外星人 # alien=Alien(ai_settings,screen) # bg_color=(230,230,100)#设置背景色 #创建一个用于存储子弹的编组 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)#我们需要更新调用的check_events() 代码,将ship 作为实参传递给它 ship.update() #删除已消失的子弹 if stats.game_active: ship.update() gf.update_bullets(ai_settings,screen,stats,sb,ship,aliens,bullets) #print(len(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) # 每次循环时都重绘屏 # 让最近绘制的屏幕可见 run_game()
ship.py
#-*- coding=utf-8 -*- #ship.py import pygame from pygame.sprite import Sprite class Ship(Sprite): def __init__(self,ai_settings,screen): """初始化飞船并设置其初始位置""" super(Ship,self).__init__() self.screen=screen self.ai_setting=ai_settings self.image=pygame.image.load(r'images\ship2.bmp') self.rect=self.image.get_rect()#处理矩形(rect 对象) self.screen_rect=screen.get_rect() #将每艘飞船放在屏幕底部中央 self.rect.centerx=self.screen_rect.centerx#要将游戏元素居中,可设置相应rect 对象的属性center 、centerx 或centery self.rect.bottom=self.screen_rect.bottom #在飞船的属性center中存储小数值 self.center=float(self.rect.centerx)#因为centerx只能存储整数 #移动标志 self.moving_right=False#为Ship类添加一个名为moving_right的属性 self.moving_left=False def update(self): #和一个名为update的方法 """根据移动标志调整飞船的位置""" #更新飞船的center值,而不是rect #self.rect.right返回飞船外接矩形的右边缘的 x 坐标 if self.moving_right and self.rect.right<self.screen_rect.right: #为什么用两个if是因为防止同时按住左键和右键 self.center+=self.ai_setting.ship_speed_factor if self.moving_left and self.rect.left>0:#飞船将在触及屏幕左边缘或右边缘后停止移动 self.center-=self.ai_setting.ship_speed_factor 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
setting.py
#coding=utf-8 class Settings(): """存储《外星人入侵》的所有设置的类""" def __init__(self): """初始化游戏的静态设置""" #屏幕设置 self.screen_width=1200 self.screen_height=800 self.bg_color=(230,180,230) #飞船的设置 self.ship_limit=3 self.bullet_width=3 self.bullet_height=15 self.bullet_color=60,60,60 self.bullets_allowed=3 # 外星人设置 self.fleet_drop_speed=50 # 以什么样的速度加快游戏节奏 ❶ 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
game_function.py
#-*-coding=utf-8-*- #这个模块中导入了事件检查循环要使用的sys 和pygame 。 #当前,函数check_events() 不需要任何形参,其函数体复制了alien_invasion.py的事件循环。 import sys import pygame from bullet import Bullet from alien import Alien from time import sleep def check_keydown_events(event,ai_settings,screen,ship,bullets): """响应按键""" if event.key==pygame.K_RIGHT: ship.moving_right=True #print "K_RIGHT",pygame.K_RIGHT # print "RIGHTde ",event.key elif event.key==pygame.K_LEFT: ship.moving_left=True # print "LEFTde :",event.key elif event.key==pygame.K_SPACE: # 创建一颗子弹,并将其加入到编组bullets中 fire_bullet(ai_settings,screen,ship,bullets) # if len(bullets)<ai_settings.bullets_allowed: # new_bullet=Bullet(ai_settings,screen,ship) # bullets.add(new_bullet)#add() 方法用于给集合添加元素,如果添加的元素在集合中已存在,则不执行任何操作。 # print new_bullet elif event.key==pygame.K_q:#玩家按Q时结束游戏,设置成e也行键盘 sys.exit() 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 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() 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_cliked=play_button.rect.collidepoint(mouse_x,mouse_y) if button_cliked and not stats.game_active:#test if a point is inside a rectangle #重置游戏统计信息 #Returns true if the given point is inside the rectangle stats.reset_stats() stats.game_active= True #重置记分牌图像 sb.prep_score() sb.prep_high_score() sb.prep_level() sb.prep_ships() #清空外星人列表和子弹列表 # 重置游戏设置 ai_settings.initialize_dynamic_settings() pygame.mouse.set_visible(False) #隐藏光标 stats.reset_stats()#单击了Play按钮且 且 游戏当前处于非活动状态 stats.game_active=True #清空外星人列表和子弹列表 aliens.empty() bullets.empty() #创建一群新的外星人,并将飞船居中 create_fleet(ai_settings,screen,ship,aliens) ship.center_ship() #def check_events(ship): # for event in pygame.event.get():#从队列中获取事件get events from the queue这是一个pygame的事件 # if event.type ==pygame.QUIT:#,并将事件循环替换为对函数check_events() 调用 # sys.exit() # elif event.type==pygame.KEYDOWN:#KEYDOWN是个事件 # if event.key==pygame.K_RIGHT: # ship.moving_right=True # elif event.key==pygame.K_LEFT: # ship.moving_left=True # elif event.type==pygame.KEYUP: # if event.key==pygame.K_RIGHT:#如果因玩家按下K_LEFT 键而触发了KEYDOWN 事件,我们就将moving_left 设置为True # ship.moving_right=False # elif event.key==pygame.K_LEFT:#如果因玩家松开K_LEFT 而触发了KEYUP 事件,我们就将moving_left 设置 为False # ship.moving_left=False # #向右移动飞船 # ship.rect.centerx+=1 # # def update_screen(ai_settings,screen,stats,sb,ship,aliens,bullets,play_button): """更新屏幕上的图像,并切换到新屏幕""" #每次循环时都重绘屏幕 screen.fill(ai_settings.bg_color)#screen.fill() 用背景色填充屏 #在飞船和外星人后面重绘所有子弹 for bullet in bullets.sprites(): bullet.draw_bullet() ship.blitme()#填充背景后,我们调 用ship.blitme() 将飞船绘制到屏幕上,确保它出现在背景前面 aliens.draw(screen)#在屏幕上绘制编组中的每个外星人 #alien.blitme() # 显示得分 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): """更新子弹的位置,并删已消失的子弹""" #更新子弹的位置 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) # collisions=pygame.sprite.groupcollide(bullets,aliens,True,True) #if len(aliens)==0: #删除现有的子弹并新建一群外星人 # bullets.empty() # create_fleet(ai_settings,screen,ship,aliens) def check_bullet_alien_collisions(ai_settings,screen,stats,sb,ship,aliens,bullets): """响应子弹和外星人的碰撞""" #删除发生碰撞的子弹和外星人 collisions=pygame.sprite.groupcollide(bullets,aliens,True,True)#当为True的时候,会删除组中所有冲突的精灵,False的时候不会删除冲突的精灵 if collisions: for aliens in collisions.values(): stats.score += ai_settings.alien_points*len(aliens) sb.prep_score() check_high_score(stats,sb) if len(aliens)==0: #删除现有的子弹,并创建一个新的外星人群 # 如果整群外星人都被消灭,就提高一个等级 bullets.empty() ai_settings.increase_speed() # 提高等级 ❶ stats.level += 1 sb.prep_level() create_fleet(ai_settings, screen, ship, aliens) #def create_fleet(ai_settings, screen, aliens): # """创建外星人群""" # # 创建一个外星人,并计算一行可容纳多少个外星人 # # 外星人间距为外星人宽度 ❶ # alien = Alien(ai_settings, screen) # alien_width = alien.rect.width # available_space_x = ai_settings.screen_width - alien_width # number_aliens_x = int(available_space_x / (1.5* alien_width)) # # 创建第一行外星人 ❺ # for alien_number in range(number_aliens_x): # # 创建一个外星人并将其加入当前行 ❻ # alien = Alien(ai_settings, screen) # alien.x = alien_width + 1.5* alien_width * alien_number # alien.rect.x = alien.x # aliens.add(alien) #def create_fleet(ai_settings,screen,aliens): # """创建外星人群""" # #创建一个外星人,并计算一行可容纳多少个外星人 # #外星人间距为外星人宽度的1/2 # alien=Alien(ai_settings,screen) # alien_width=alien.rect.width # available_space_x=ai_settings.screen_width-2*alien_width # number_aliens_x=int(available_sapce_x/(1.5*alien_width) # #创建第一行外星人 # for alien_number in range(number_aliens_x): # # 创建一个外星人并将其加入当前行 ❻ # alien = Alien(ai_settings, screen) # alien.x=alien_width+1.5*alien_width*alien_number # alien.rect.x=alien.x # aliens.add(alien) def get_number_aliens_x(ai_settings,alien_width): """计算每行可容纳多少个外星人""" available_sapce_x=ai_settings.screen_width-0.5*alien_width number_aliens_x=int(available_sapce_x/(1.5*alien_width)) return number_aliens_x 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+1.5*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 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 alien_number in range(number_aliens_x): # create_alien(ai_settings,screen,aliens,alien_number,row_number) #创建外星人群 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_rows(ai_settings,ship_height,alien_height): """计算屏幕可容纳多少行外星人""" available_space_y=(ai_settings.screen_height-(2*alien_height)-ship_height) number_rows=int(available_space_y/(3*alien_height)) return number_rows def ship_hit(ai_settings,screen,stats,sb,ship,aliens,bullets): """响应被外星人撞到的飞船""" #将ships_left减1 if stats.ships_left>0: #将ships_left减1 stats.ships_left-=1 # 更新记分牌 ❺ sb.prep_ships() #清空外星人列表和子弹列表 aliens.empty() bullets.empty() # 创建一群新的外星人,并将飞船放到屏幕底端中央 create_fleet(ai_settings,screen,ship,aliens) ship.center_ship() #暂停 sleep(1) else : stats.game_active=False pygame.mouse.set_visible(True) def 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) print("Ship hit!!!") #方法spritecollideany() 接受两个实参:一个精灵和一个编组。它检查编组是否有成员与精灵发生了碰撞, #并在找到与精灵发生了碰撞的成员后就停止遍历编组 # 检查是否有外星人到达屏幕底端 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) 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 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,stats,screen,ship,aliens,bullets) break def check_high_score(stats, sb): """检查是否诞生了新的最高得分""" if stats.score > stats.high_score: stats.high_score = stats.score sb.prep_high_score()
bullet.py
#-*-coding=utf-8-*- import pygame from pygame.sprite import Sprite class Bullet(Sprite): """一个对飞船发射的子弹进行管理的类""" def __init__(self,ai_settings,screen,ship): """在飞船所处的位置创建一个子弹对象""" super(Bullet,self).__init__()#super() 函数是用于调用父类(超类)的一个方法。 self.screen=screen#python中的super( test, self).__init__() #首先找到test的父类(比如是类A),然后把类test的对象self转换为类A的对象,然后“被转换”的类A对象调用自己的__init__函数 #在(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) 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)
scoreboard.py
#-*-coding=utf-8-*- import pygame.font#在屏幕上显示文本,因此我们首先导入模块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) # 准备初始得分图像 # 准备包含最高得分和当前得分的图像 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.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)
button.py
#-*-coding=utf-8-*- 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)#设置button_color 让按钮的rect 对象为亮绿色 self.text_color=(255,255,255)#置text_color 让文本为白色 self.font=pygame.font.SysFont(None,48)#实参None 让Pygame 使用默认字体,而48 指定了文本的字号 #创建按钮的rect对象,并使其居中#为让按钮在屏幕上居中,我们创建一个表示按钮的rect self.rect=pygame.Rect(0,0,self.width,self.height) self.rect.center=self.screen_rect.center#,并将其center 属性设置为屏幕的center 属性 #按钮的标签只需创建一次 self.prep_msg(msg) def prep_msg(self,msg):#方法prep_msg() 接受实参self 以及要渲染为图像的文本(msg )。 """将msg渲染为图像,并使其在按钮上居中""" self.msg_image=self.font.render(msg,True,self.text_color, self.button_color)#方法font.render() 还接受一个布尔实参,该实参指定开启还是关闭反锯齿功能(反锯齿让文本的边缘更平滑 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)#调用screen.fill() 来绘制表示按钮的矩形 self.screen.blit(self.msg_image,self.msg_image_rect)#再调用screen.blit() ,并向它传递一幅图像以及与该图像相关联的rect 对象
game_stats.py
#-*-coding=utf-8-*- class GameStats(): """跟踪游戏的统计信息""" def __init__(self,ai_settings): """初始化统计信息""" self.ai_settings=ai_settings self.reset_stats() # 游戏刚启动时处于活动状态 self.game_active = False # 在任何情况下都不应重置最高得分 self.high_score = 0 def reset_stats(self): """初始化在游戏运行期间可能变化的统计信息""" self.ships_left=self.ai_settings.ship_limit self.score=0 self.level=1
alien.py
#-*-coding=utf-8-*- import sys 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 #加载外星人图像,并设置其rect属性 self.image=pygame.image.load('images/ship2.bmp') self.rect=self.image.get_rect() #每个外星人最初都在屏幕左上角附近 self.rect.x=self.rect.width*1/2 self.rect.y=self.rect.height*1/2#获得图像的宽度 #存储外星人的准确位置 self.x=float(self.rect.x) def blitme(self): """在指定位置绘制外星人""" self.screen.blit(self.image,self.rect) def update(self): """向左向右移动外星人""" self.x+=(self.ai_settings.alien_speed_factor*self.ai_settings.fleet_direction) self.rect.x=self.x def check_edges(self): """如果外星人位于屏幕边缘,就返回True""" screen_rect=self.screen.get_rect() #如果外星人的rect 的right 属性大于或等于屏幕的rect 的right 属性,就说明外星人位于屏幕右边缘 if self.rect.right>=screen_rect.right: #外星人的rect 的left 属性小于或等于0,就说明外星人位于屏幕左边 return True elif self.rect.left<=0: return True