经过一周的奋斗,我现在终于将完整版的代码编辑出来了,有点可惜没有声音(我有查资源但是没有成功,希望能有大神分享经验,指出不足)
一、代码分类
不要再一个代码框里面编辑所有的代码,不然后续想要增加功能的时候会非常麻烦。
二、安装Pygame模块
请到https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyame中查询你所需要的版本。下载合适的文件后,将它复制到你的项目文件夹中。再打开命令窗口,切换到该文件所在文件夹,并使用pip来运行它
三、模块解释
pygame是一个跨平台的python模块,有很好的交互性。专为电子游戏设计,包含图像、声音。建立在SDL基础上,允许实时电子游戏研发,无需被低级语言束缚。
另完整版代码项目请见https://github.com/fromzore/alien_invasion
四、创建设置类settings.py
class Settings(object): '''存储这个游戏的所有设置类''' def __init__(self): '''初始化游戏的静态设置''' #屏幕设置 self.screen_width=512 self.screen_height=640 # self.bg_color=(230,250,250) #子弹设置 self.bullets_allowed=3 #外星人设置 self.fleet_drop_speed=10 self.ship_limit=3 #以什么样的速度加快游戏节奏 self.speedup_scale=1.1 self.initialize_dynamic_settings() def initialize_dynamic_settings(self): '''初始化随游戏进行而变化的设置''' self.bullet_speed_factor = 0.5 self.alien_speed_factor=0.4 self.fleet_direction = 1 # 1表示右移,-1表示左移 #记分 self.alien_points=1 def increase_speed(self): '''提高速度设置''' self.bullet_speed_factor*=self.speedup_scale self.alien_speed_factor*=self.speedup_scale
五、创建飞船类ship.py
import pygame class Ship(object): def __init__(self,screen): '''初始化飞船,并设定其初始位置''' self.screen=screen #加载飞船图像,并获取其外接矩形 self.image=pygame.image.load('images/img/plane_2.png') self.screen_image=pygame.image.load('images/bg_2.jpg') self.rect=self.image.get_rect()#获取飞船外接矩形 self.screen_rect=screen.get_rect()#获取表示屏幕的矩形 self.screen_image_rect=self.screen_image.get_rect() #将每艘新飞船放在屏幕底部中央 self.screen_image_rect.centerx=self.screen_rect.centerx self.screen_image_rect.bottom = self.screen_rect.bottom 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 def update(self): ''' 根据移动标示移动飞船''' if self.moving_right and self.rect.right<self.screen_rect.right: self.rect.centerx+=1 if self.moving_left and self.rect.left>0: self.rect.centerx-=1 if self.moving_up and self.rect.top>0: self.rect.centery-=1 if self.moving_down and self.rect.bottom<640: self.rect.centery+=1 def center_ship(self): '''让飞船在屏幕上居中''' self.centerx=self.screen_rect.centerx self.rect.bottom = self.screen_rect.bottom def blitme(self): '''在指定位置绘制飞船''' self.screen.blit(self.screen_image, self.screen_image_rect) self.screen.blit(self.image, self.rect) # blitme(),根据self.rect将图片绘制到屏幕上。
六、重构模块game_functions.py
import sys import pygame from bullet import Bullet from Alien import Alien from time import sleep def get_number_rows(ai_settings,ship_height,alien_height): available_space_y=ai_settings.screen_height-alien_height-alien_height/2-ship_height number_row=int(available_space_y/(alien_height))-1 return number_row def creat_fleet(ai_settings,screen,ship,aliens):#fleet舰队 '''创建外星人群''' 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): creat_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-alien_width/2 number_alien_x=int(available_space_x/(alien_width))-1 return number_alien_x #创建第一行外星人 def creat_alien(ai_settings,screen,aliens,alien_number,row_number): #创建第一个外星人并将其加入当前行 alien=Alien(ai_settings,screen) alien_width = alien.rect.width alien.x=alien_width/4+alien_width*alien_number*6/4 alien.rect.y=alien.rect.height/4+alien.rect.height*row_number*5/4 alien.rect.x=alien.x aliens.add(alien) # def g_music(): # pygame.mixer.init() # # 加载音乐 # pygame.mixer.music.load("images/music.mp3") # while True: # # 检查音乐流播放,有返回True,没有返回False # # 如果没有音乐流则选择播放 # if pygame.mixer.music.get_busy() == False: # pygame.mixer.music.play() def check_keydown_events(event,ship,ai_settings,screen,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_UP: ship.moving_up = True elif event.key == pygame.K_DOWN: ship.moving_down = True elif event.key==pygame.K_SPACE: 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 = False elif event.key == pygame.K_UP: ship.moving_up = False elif event.key == pygame.K_DOWN: ship.moving_down = False def check_events(ship,ai_settings,screen,stats,sb,play_button,bullets,aliens): for event in pygame.event.get(): if event.type == pygame.QUIT : sys.exit() elif event.type==pygame.KEYDOWN: check_keydown_events(event,ship,ai_settings,screen,bullets) elif event.type==pygame.KEYUP: check_keyup_events(event,ship) elif event.type==pygame.MOUSEBUTTONDOWN: mouse_x,mouse_y=pygame.mouse.get_pos()#返回一个元祖,其中包含玩家单击鼠标时的x和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按钮的rect内 if button_clicked and not stats.game_active: #重置游戏设置 ai_settings.initialize_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_ship_number() #清空外星人列表和子弹列表 aliens.empty() bullets.empty() #创建一群新的外星人,并让飞船居中 creat_fleet(ai_settings,screen,ship,aliens) ship.center_ship() 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 update_screen(ai_settings,screen,stats,sb,ship,aliens,bullets,play_button): # screen.fill(ai_settings.bg_color) ship.blitme() for bullet in bullets.sprites():#这里因为之前的是绘制飞船时绘制的屏幕,所以for循环只能在ship绘制之后 bullet.draw_bullet() 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): bullets.update() # 删除消失的子弹 for bullet in bullets.copy(): if bullet.rect.top<=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 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() creat_fleet(ai_settings,screen,ship,aliens) def ship_hit(ai_settings,stats,screen,sb,ship,aliens,bullets): '''响应外星人撞到的飞船''' if stats.ship_left>0: #将ship_left减一 stats.ship_left-=1 sb.prep_ship_number() #清空外星人列表和子弹列表 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_aliens(ai_settings,stats,screen,sb,ship,aliens,bullets): '''更新外星人群中所有外星人的位置''' check_fleet_edges(ai_settings,aliens) aliens.update() if pygame.sprite.spritecollideany(ship, aliens): ship_hit(ai_settings,stats,screen,sb,ship,aliens,bullets) #检查是否有外星人到达屏幕底端 check_aliens_bottom(ai_settings,stats,screen,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,stats,screen,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()
七、创建Bllet类bullet.py
import pygame from pygame.sprite import Sprite class Bullet(Sprite): '''一个对飞船发射子弹进行管理的类''' def __init__(self,ai_settings,screen,ship): super(Bullet, self).__init__() self.screen=screen self.bullet_image = pygame.image.load('images/bullet.png') self.rect = self.bullet_image.get_rect() self.rect.centerx=ship.rect.centerx self.rect.top=ship.rect.top self.y=float( self.rect.y) self.speed_factor=ai_settings.bullet_speed_factor def update(self): '''向上移动子弹''' #更新表示子弹位置的小数值 self.rect.centery-=self.speed_factor def draw_bullet(self): self.screen.blit(self.bullet_image, self.rect)
八、创建Alien类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 #加载外星人图像,并设置其rect属性 self.image=pygame.image.load('images/img/enemy_small.png') self.rect=self.image.get_rect() #每个外星人最初都在荧幕左上角附近 self.rect.x=self.rect.width/4 self.rect.y=self.rect.height/4 #存储外星人的准确位置 self.x=float(self.rect.x) 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 def blitme(self): '''在指定位置绘制外星人''' self.screen.blit(self.image,self.rect)
九、game_stats.py
class GameStats(object): """跟踪游戏的统计信息""" 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.ship_left=self.ai_settings.ship_limit self.score=0 self.level=1
十、创建Button类button.py
import pygame.font class Button(object): def __init__(self,ai_settiins,screen,msg): '''初始化按钮的属性''' self.screen=screen self.screen_rect=screen.get_rect() #设置按钮的尺寸和其他属性 self.width,self.height=90,50 self.button_color=(0,150,150) self.text_color=(255,255,255) self.font=pygame.font.SysFont(None,28)#指定字体来渲染文本,None指用默认字体,38是文本的字号 #创建按钮的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): '''将msg渲染为图像,并使其在按钮上居中''' self.msg_image=self.font.render(msg,True,self.text_color,self.button_color)#将储存在msg中的文本转换为图像,布尔实参指定是开启还是关闭反锯齿功能 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)
十一、scoreboard.py
import pygame.font class Scoreboard(object): '''显示得分信息的类''' 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,18) self.bg_color=(0,130,150) #准备初始得分图像和最高分图像 self.prep_score() self.prep_high_score() self.prep_level() self.prep_ship_number() def prep_score(self): '''将得分转换为一副渲染的图像''' score_str="Score:"+"{:,}".format(self.stats.score) self.score_image=self.font.render(score_str,True,self.text_color,self.bg_color) #将得分放在屏幕右上角 self.score_rect=self.score_image.get_rect() self.score_rect.right=self.screen_rect.right-10 self.score_rect.top=10 def prep_high_score(self): '''将最高分转换为渲染图像''' high_score_str="HighScore:"+"{:,}".format(self.stats.high_score) self.high_score_image=self.font.render(high_score_str,True,self.text_color,self.bg_color) #将最高分放在屏幕顶部中央 self.high_score_rect=self.high_score_image.get_rect() self.high_score_rect.top=self.score_rect.top self.high_score_rect.centerx=self.screen_rect.centerx def prep_level(self): '''将等级转换为一副渲染的图像''' self.level_image=self.font.render(("Level:"+str(self.stats.level)),True,self.text_color,self.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+5 def prep_ship_number(self): '''将飞船数量转换为一副渲染的图像''' self.shipnumber_image = self.font.render(("ShipNumber:" + str(self.stats.ship_left)), True, self.text_color, self.bg_color) # 将得分放在屏幕左上角 self.shipnumber_rect = self.shipnumber_image.get_rect() self.shipnumber_rect.left = self.screen_rect.left+5 self.shipnumber_rect.top = self.score_rect.top 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.screen.blit(self.shipnumber_image,self.shipnumber_rect)