1. 程式人生 > 實用技巧 >Python程式設計:從入門到實踐 專案《外星人入侵》完整程式碼

Python程式設計:從入門到實踐 專案《外星人入侵》完整程式碼

學習《Python程式設計:從入門到實踐》有段時間了,跟著書本把所有程式碼都敲了一遍,感悟很深,現在完成了《外星人入侵》專案,對於庫、類、函式、方法都有一定的理解,現在將該專案完整程式碼分享出來,以供學習。

1.首先當然是主執行檔案alien_invasion.py

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 importpygame frompygame.sprite
importGroup fromsettingsimportSettings fromgame_statsimportGameStats fromscoreboardimportScoreboard frombuttonimportButton fromshipimportShip importgame_functions as gf defrun_game(): # 初始化pygame、設定和螢幕物件 pygame.init() ai_settings=Settings() screen=pygame.display.set_mode( (ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion") # 建立Play按鈕 play_button=Button(ai_settings, screen,"Play") # 建立儲存遊戲統計資訊的例項,並建立記分牌 stats=GameStats(ai_settings) sb=Scoreboard(ai_settings, screen, stats) #建立一艘飛船、一個子彈編組和一個外星人編組 ship=Ship(ai_settings,screen) bullets=Group() aliens=Group() # 建立外星人群 gf.create_fleet(ai_settings,screen,ship,aliens)
# 開始遊戲的主迴圈 whileTrue: gf.check_events(ai_settings,screen,stats,sb,play_button,ship, aliens,bullets) ifstats.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) gf.update_screen(ai_settings,screen,stats,sb,ship,aliens, bullets,play_button) run_game()

  

2.遊戲相關引數設定settings.py

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 classSettings(): """儲存《外星人入侵》的所有設定的類""" def__init__(self): """初始化遊戲的靜態設定""" # 螢幕設定 self.screen_width=800 self.screen_height=600 self.bg_color=(230,230,230) # 飛船的設定 self.ship_speed_factor=0.3 #子彈設定 self.bullet_speed_factor=1 self.ship_limit=3 self.bullet_width=3 self.bullet_height=15 self.bullet_color=60,60,60 self.bullets_allowed=3 # 外星人設定 self.alien_speed_factor=0.1 self.fleet_drop_speed=10 # 以什麼樣的速度加快遊戲節奏 self.speedup_scale=1.01 # 外星人點數的提高速度 self.score_scale=1.1 self.initialize_dynamic_settings() # fleet_direction為1表示向右移,為-1表示向左移 self.fleet_direction=1 definitialize_dynamic_settings(self): """初始化隨遊戲進行而變化的設定""" self.ship_speed_factor=0.3 self.bullet_speed_factor=1 self.alien_speed_factor=0.1 # fleet_direction為1表示向右;為-1表示向左 self.fleet_direction=1 # 記分 self.alien_points=50 defincrease_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)

  

3.按鍵及事件邏輯game_functions.py

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 importsys fromtimeimportsleep importpygame frombulletimportBullet fromalienimportAlien defcheck_keydown_events(event,ai_settings,screen,ship,bullets): """響應按鍵""" ifevent.key==pygame.K_RIGHT: ship.moving_right=True elifevent.key==pygame.K_LEFT: ship.moving_left=True elifevent.key==pygame.K_UP: ship.moving_up=True elifevent.key==pygame.K_DOWN: ship.moving_down=True elifevent.key==pygame.K_SPACE: fire_bullet(ai_settings,screen,ship,bullets) elifevent.key==pygame.K_q: sys.exit() deffire_bullet(ai_settings,screen,ship,bullets): """如果還沒有到達限制,就發射一顆子彈""" # 建立一顆子彈,並將其加入到編組bullets中 iflen(bullets) < ai_settings.bullets_allowed: new_bullet=Bullet(ai_settings,screen,ship) bullets.add(new_bullet) defcheck_keyup_events(event,ship): """響應鬆開""" ifevent.key==pygame.K_RIGHT: ship.moving_right=False elifevent.key==pygame.K_LEFT: ship.moving_left=False elifevent.key==pygame.K_UP: ship.moving_up=False elifevent.key==pygame.K_DOWN: ship.moving_down=False defcheck_events(ai_settings,screen,stats,sb,play_button,ship,aliens, bullets): """響應按鍵和滑鼠事件""" foreventinpygame.event.get(): ifevent.type==pygame.QUIT: sys.exit() elifevent.type==pygame.KEYDOWN: check_keydown_events(event,ai_settings,screen,ship,bullets) elifevent.type==pygame.KEYUP: check_keyup_events(event,ship) elifevent.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) defcheck_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) ifbutton_clickedandnotstats.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_ships() # 清空外星人列表和子彈列表 aliens.empty() bullets.empty() # 建立一群新的外星人,並讓飛船居中 create_fleet(ai_settings, screen, ship, aliens) ship.center_ship() defupdate_bullets(ai_settings,screen,stats,sb,ship,aliens,bullets): """更新子彈的位置,並刪除已消失的子彈""" # 更新子彈的位置 bullets.update() # 刪除已消失的子彈 forbulletinbullets.copy(): ifbullet.rect.bottom <=0: bullets.remove(bullet) check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets) defcheck_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets): """響應子彈和外星人的碰撞""" # 刪除發生碰撞的子彈和外星人 collisions=pygame.sprite.groupcollide(bullets, aliens,True,True) ifcollisions: foraliensincollisions.values(): stats.score+=ai_settings.alien_points*len(aliens) sb.prep_score() check_high_score(stats, sb) iflen(aliens)==0: # 如果整群外星人都被消滅,就提高一個等級 bullets.empty() ai_settings.increase_speed() # 提高等級 stats.level+=1 sb.prep_level() create_fleet(ai_settings, screen, ship, aliens) defupdate_screen(ai_settings,screen,stats,sb,ship,aliens,bullets, play_button): """更新螢幕上的影象,並切換到新螢幕""" #每次迴圈時都重繪螢幕 screen.fill(ai_settings.bg_color) # 在飛船和外星人後面重繪所有子彈 forbulletinbullets.sprites(): bullet.draw_bullet() ship.blitme() aliens.draw(screen) # 顯示得分 sb.show_score() # 如果遊戲處於非活動狀態,就繪製Play按鈕 ifnotstats.game_active: play_button.draw_button() # 讓最近繪製的螢幕可見 pygame.display.flip() defget_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)) returnnumber_aliens_x defget_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/(3*alien_height)) returnnumber_rows defcreate_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.y=alien.rect.height+2*alien.rect.height*row_number alien.rect.x=alien.x aliens.add(alien) defcreate_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) # 建立外星人群 forrow_numberinrange(number_rows): foralien_numberinrange(number_aliens_x): create_alien(ai_settings, screen, aliens, alien_number, row_number) defcheck_fleet_edges(ai_settings, aliens): """有外星人到達邊緣時採取相應的措施""" foralieninaliens.sprites(): ifalien.check_edges(): change_fleet_direction(ai_settings, aliens) break defchange_fleet_direction(ai_settings, aliens): """將整群外星人下移,並改變它們的方向""" foralieninaliens.sprites(): alien.rect.y+=ai_settings.fleet_drop_speed ai_settings.fleet_direction*=-1 defship_hit(ai_settings, stats, screen, sb, ship, aliens, bullets): """響應被外星人撞到的飛船""" ifstats.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(0.5) else: stats.game_active=False pygame.mouse.set_visible(True) defcheck_aliens_bottom(ai_settings, stats, screen, sb, ship, aliens, bullets): """檢查是否有外星人到達了螢幕底端""" screen_rect=screen.get_rect() foralieninaliens.sprites(): ifalien.rect.bottom >=screen_rect.bottom: # 像飛船被撞到一樣進行處理 ship_hit(ai_settings, stats, screen, sb, ship, aliens, bullets) break defcheck_high_score(stats, sb): """檢查是否誕生了新的最高得分""" ifstats.score > stats.high_score: stats.high_score=stats.score sb.prep_high_score() defupdate_aliens(ai_settings, stats, screen, sb, ship, aliens, bullets): """ 檢查是否有外星人位於螢幕邊緣,並更新整群外星人的位置 """ check_fleet_edges(ai_settings, aliens) aliens.update() # 檢測外星人和飛船之間的碰撞 ifpygame.sprite.spritecollideany(ship, aliens): ship_hit(ai_settings, stats, screen, sb, ship, aliens, bullets) # 檢查是否有外星人到達螢幕底端 check_aliens_bottom(ai_settings, stats, screen, sb, ship, aliens, bullets)

  

4.計分相關設定scoreboard.py

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 importpygame.font frompygame.spriteimportGroup fromshipimportShip classScoreboard(): """顯示得分資訊的類""" 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() defprep_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 defprep_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 defprep_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 defprep_ships(self): """顯示還餘下多少艘飛船""" self.ships=Group() forship_numberinrange(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) defshow_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)

  

5.跟蹤遊戲統計資訊

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 classGameStats(): """跟蹤遊戲的統計資訊""" def__init__(self, ai_settings): """初始化統計資訊""" self.ai_settings=ai_settings self.reset_stats() # 遊戲剛啟動時處於活動狀態 self.game_active=False # 在任何情況下都不應重置最高得分 self.high_score=0 defreset_stats(self): """初始化在遊戲執行期間可能變化的統計資訊""" self.ships_left=self.ai_settings.ship_limit self.score=0 self.level=1

  

6.“遊戲開始”按鍵設定button.py

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 importpygame.font classButton(): 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=(0,255,0) self.text_color=(255,255,255) self.font=pygame.font.SysFont('arial',48) # 建立按鈕的rect物件,並使其居中 self.rect=pygame.Rect(0,0,self.width,self.height) self.rect.center=self.screen_rect.center # 按鈕的標籤只需建立一次 self.prep_msg(msg) defprep_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 defdraw_button(self): # 繪製一個用顏色填充的按鈕,再繪製文字 self.screen.fill(self.button_color,self.rect) self.screen.blit(self.msg_image,self.msg_image_rect)

  

7.飛船相關設定ship.py

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 importpygame frompygame.spriteimportSprite classShip(Sprite): def__init__(self, ai_settings,screen): """初始化飛船並設定其初始位置""" super(Ship,self).__init__() self.screen=screen self.ai_settings=ai_settings # 載入飛船影象並獲取其外接矩形 self.image=pygame.image.load('images/ship.bmp') self.rect=self.image.get_rect() self.screen_rect=screen.get_rect() # 將每艘新飛船放在螢幕底部中央 self.rect.centerx=self.screen_rect.centerx self.rect.bottom=self.screen_rect.bottom # 在飛船的屬性center中儲存小數值 self.center=float(self.rect.centerx) self.centery=float(self.rect.centery) # 移動標誌 self.moving_right=False self.moving_left=False self.moving_up=False self.moving_down=False defupdate(self): """根據移動標誌調整飛船的位置""" # 更新飛船的center值,而不是rect ifself.moving_rightandself.rect.right <self.screen_rect.right: self.center+=self.ai_settings.ship_speed_factor ifself.moving_leftandself.rect.left >0: self.center-=self.ai_settings.ship_speed_factor ifself.moving_upandself.rect.top >0: self.centery-=self.ai_settings.ship_speed_factor ifself.moving_downandself.rect.bottom <self.screen_rect.bottom: self.centery+=self.ai_settings.ship_speed_factor # 根據self.center更新rect物件 self.rect.centerx=self.center self.rect.centery=self.centery defcenter_ship(self): """讓飛船在螢幕上居中""" self.center=self.screen_rect.centerx self.centery=self.screen_rect.bottom defblitme(self): """在指定位置繪製飛船""" self.screen.blit(self.image,self.rect)

  

8.外星人相關設定alien.py

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 importpygame frompygame.spriteimportSprite classAlien(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/alien.bmp') self.rect=self.image.get_rect() # 每個外星人最初都在螢幕左上角附近 self.rect.x=self.rect.width self.rect.y=self.rect.height # 儲存外星人的準確位置 self.x=float(self.rect.x) defblitme(self): """在指定位置繪製外星人""" self.screen.blit(self.image,self.rect) defcheck_edges(self): """如果外星人位於螢幕邊緣,就返回True""" screen_rect=self.screen.get_rect() ifself.rect.right >=screen_rect.right: returnTrue elifself.rect.left <=0: returnTrue defupdate(self): """向左或右移動外星人""" self.x+=(self.ai_settings.alien_speed_factor* self.ai_settings.fleet_direction) self.rect.x=self.x

  

9.子彈相關設定bullet.py

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 importpygame frompygame.spriteimportSprite classBullet(Sprite): """一個對飛船發射的子彈進行管理的類""" 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) 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 defupdate(self): """向上移動子彈""" #更新表示子彈位置的小數值 self.y-=self.speed_factor #更新表示子彈的rect的位置 self.rect.y=self.y defdraw_bullet(self): """在螢幕上繪製子彈""" pygame.draw.rect(self.screen,self.color,self.rect)

  

關於ship.py檔案中
self.image = pygame.image.load(‘images/ship.bmp’)
和alien.py檔案中
self.image = pygame.image.load(‘images/alien.bmp’)
程式碼裡的圖片,需要各位自行在根目錄下新建資料夾和影象

另外,自己在除錯專案的過程中,常常有報錯,其中主要錯誤的反而是忘了下劃線、冒號還有程式碼縮排,程式碼縮排要麼完全使用空格,要麼全都使用tab進行縮排,python在識別縮排上非常嚴格。

寫給自己,也分享給大家。