用python寫小遊戲——外星人入侵(基於pygame)
在學python之餘,根據書上的程式碼寫一個小遊戲,一方面是透過這個小遊戲來讓自己對面向物件的理解更深入一些,另一方面也為之後寫其他小遊戲打好基礎
編譯環境:pycharm+python3。7。6
標準庫:pygame,sys(pygame得安裝,sys是python自帶的,不用安裝)
pygame透過命令列安裝:
pip
install
pygame
-
i
https
:
//
pypi
。
mirrors
。
ustc
。
edu
。
cn
/
simple
/
不能訪問外網的話建議使用映象
豆瓣
http://
pypi。douban。com/simple/
清華大學
https://
pypi。tuna。tsinghua。edu。cn
/simple/
中國科學技術大學
http://
pypi。mirrors。ustc。edu。cn
/simple/
阿里雲
http://
mirrors。aliyun。com/pypi
/simple/
中國科技大學
https://
pypi。mirrors。ustc。edu。cn
/simple/
import pygame # 設計遊戲
import sys #退出遊戲
以上就是我使用的檔案,包含9個py檔案、一個image檔案、一個data檔案
其中image檔案是用來儲存外星人以及飛船影象的,在使用的時候儲存為ship。bmp檔案和alien。bmp檔案,這兩個檔案是點陣圖檔案,讀取時相對於jpg影象而言會比較快
而data檔案中有一個data。txt,裡面只有一個數據就是用來儲存最高分的
下面就給出具體程式碼
alien_invasion。py檔案,主要作用就是使用其他檔案所編寫的函式運行遊戲,起到main。py的作用
import
sys
import
pygame
from
settings
import
Settings
from
game_states
import
GameStats
from
ship
import
Ship
import
game_functions
as
gf
from
pygame。sprite
import
Group
from
button
import
Button
from
scoreboard
import
Scoreboard
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’
)
play_button
=
Button
(
ai_settings
,
screen
,
‘Play’
)
#建立play按鈕
stats
=
GameStats
(
ai_settings
)
# 建立一個用於儲存遊戲統計資訊的例項
sb
=
Scoreboard
(
ai_settings
,
screen
,
stats
)
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
。
updata
()
gf
。
updata_bullets
(
ai_settings
,
screen
,
stats
,
sb
,
ship
,
aliens
,
bullets
)
gf
。
updata_aliens
(
ai_settings
,
screen
,
stats
,
sb
,
ship
,
aliens
,
bullets
)
gf
。
updata_screen
(
ai_settings
,
screen
,
stats
,
sb
,
ship
,
aliens
,
bullets
,
play_button
)
run_game
()
ship。py檔案,其作用就是編寫ship類
import pygame
from pygame。sprite import Sprite
class Ship(Sprite):
def __init__(self,ai_settings,screen):
‘’‘初始化飛船位置’‘’
super()。__init__()
self。screen=screen
self。ai_setting=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。moving_right=False # 向右移動標誌
self。moving_left=False #向左移動標誌
def updata(self): # 根據移動位置調整飛船位置
# 更新飛船的center值而不是rect
if self。moving_right and self。rect。right 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 # 根據self。center更新rect物件 def blitme(self): ‘’‘在指定位置繪製飛船’‘’ self。screen。blit(self。image,self。rect) def center_ship(self): self。center=self。screen_rect。centerx # 讓飛船在螢幕上居中 alien。py檔案,用來編寫alien類 import pygame from pygame。sprite import Sprite class Alien(Sprite): # 表示單個外星人的類 def __init__(self,ai_settings,screen): # 初始化外星人 super()。__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) 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 updata(self): # 向左或右移動外星人 self。x+=(self。ai_settings。alien_speed_factor*self。ai_settings。fleet_direction) self。rect。x=self。x def blitem(self): # 在指定位置繪製外星人 self。screen。blit(self。image,self。rect) 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 # 在(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 updata(self): # 向上移動子彈 self。y -=self。speed_factor # 更新表示子彈位置的小數值 self。rect。y=self。y # 更新表示子彈的rect的位置 def draw_bullet(self): # 在螢幕上繪製子彈 pygame。draw。rect(self。screen,self。color,self。rect) settings。py檔案,儲存外星人入侵的所有設定的類 class Settings(): #儲存外星人入侵的所有設定的類 def __init__(self): ‘’‘初始化遊戲的靜態設定’‘’ # 螢幕設定 self。screen_width=1200 self。screen_height=650 self。bg_color=(230,230,230) # 飛船的設定 #self。ship_speed_factor=1。5 # 設定飛船的速度 self。ship_limit=3 # 子彈設定 #self。bullet_speed_factor=2 self。bullet_width=3 self。bullet_height=15 self。bullet_color=60,60,60 self。bullets_allowed=3 # 限制子彈數目 # 外星人設定 self。fleet_drop_speed = 10 # 以什麼樣的速度加快遊戲節奏 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 self。fleet_direction=1 # 1表示向右移動,-1表示向左移動 self。alien_points=10 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) button。py檔案,設定play按鈕 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=(0,255,0) self。text_color=(255,255,255) self。font=pygame。font。SysFont(None,48) # 建立按鈕的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) 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) game_states。py檔案,跟蹤遊戲的統計資訊,比如遊戲狀態,等級,分數等 class GameStats(): # 跟蹤遊戲的統計資訊 def __init__(self,ai_settings): self。ai_settings=ai_settings self。reset_stats() self。game_active=True self。game_active=False # 讓遊戲一開始處於非活動狀態 #self。high_score=0 #最高分 # 檔案操作讀取最高分 with open(‘data\data。txt’) as f: self。high_score=int(f。read()) def reset_stats(self): # 初始化 self。ships_left=self。ai_settings。ship_limit self。score=0 self。level=1 scoreboard。py檔案,顯示遊戲的最高分、等級、得分、飛船數量等資訊 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=(150,100,50) self。font=pygame。font。SysFont(None,48) # 準備初始化得分影象 self。prep_score() #當前得分影象 self。prep_high_score() # 最高得分影象 self。prep_level() # 顯示等級 self。prep_ships() # 顯示飛船數量 def prep_score(self): #將得分轉化為一幅渲染的影象 round_score=int(round(self。stats。score,-1)) score_str=‘{}{:,}’。format(‘Score:’,round_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=int(round(self。stats。high_score,-1)) high_score_str=“{}{:,}”。format(‘High_score:’,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 show_score(self): #顯示得分 self。screen。blit(self。high_score_image, self。high_score_rect) # 顯示得分 self。screen。blit(self。score_image,self。score_rect) # 顯示最高分 self。screen。blit(self。level_image,self。level_rect) # 顯示等級 self。ships。draw(self。screen) def prep_level(self): # 將等級轉換為渲染的影象 level_str=“{}{:,}”。format(‘Level:’,self。stats。level) self。level_image=self。font。render(level_str,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) game_functions。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 elif event。key==pygame。K_LEFT: ship。moving_left=True elif event。key==pygame。K_SPACE: fire_bullet(ai_settings,screen,ship,bullets) elif event。key==pygame。K_q: # 按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 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 updata_screen(ai_settings,screen,stats,sb,ship,aliens,bullets,play_button): ‘’‘更新螢幕上的影象,並切換到新螢幕’‘’ # 每次迴圈時都會重新繪製螢幕 screen。fill(ai_settings。bg_color) # 在飛船和外星人後面重繪所有子彈 for bullet in bullets。sprites(): bullet。draw_bullet() ship。blitme() aliens。draw(screen) #顯示外星人 sb。show_score() #顯示得分 if not stats。game_active: #如果遊戲處於非活動狀態,就顯示play按鈕 play_button。draw_button() pygame。display。flip() # 讓最近繪製的螢幕可見 def updata_bullets(ai_settings,screen,stats,sb,ship,aliens,bullets): #更新子彈位置並刪除消失的子彈 for bullet in bullets。sprites(): bullet。updata() for bullet in bullets。copy(): # 刪除已經消失的子彈 if bullet。rect。bottom <= 0: bullets。remove(bullet) #print(len(bullets)) check_bullet_alien_collisions(ai_settings, screen, stats,sb,ship,aliens, bullets) def 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) 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_aettings,ship_height,alien_height): # 計算螢幕可容納多少行外星人 available_space_y=(ai_aettings。screen_height-(3*alien_height)-ship_height) number_rows=int(available_space_y/(2*alien_height)) return number_rows 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+2 *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 creat_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): creat_alien(ai_settings,screen,aliens,alien_number,row_number) 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, screen,stats,sb, ship, aliens, bullets): # 響應被外星人撞到的飛船 if stats。ships_left>0: stats。ships_left -= 1 sb。prep_ships() # 更新記分牌 # 清空外星人列表和子彈列表 aliens。empty() bullets。empty() # 建立一群新的外星人,並將飛船放到螢幕底端中央 creat_fleet(ai_settings, screen, ship, aliens) ship。center_ship() sleep(0。5) # 暫停0。5秒 else: stats。game_active=False pygame。mouse。set_visible(True) # 顯示游標 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,screen,stats,sb,ship,aliens,bullets) break def updata_aliens(ai_settings,screen,stats,sb,ship,aliens,bullets): # 檢查外星人是否在邊緣,更新所有外星人位置 check_fleet_edges(ai_settings,aliens) for alien in aliens。sprites(): alien。updata() # 檢測外星人和飛船之間的碰撞 if pygame。sprite。spritecollideany(ship,aliens): # print(‘Ship hit!!!’) ship_hit(ai_settings,screen,stats,sb,ship,aliens,bullets) check_aliens_bottom(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 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) 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_ships() # 清空外星人列表以及子彈 aliens。empty() bullets。empty() # 建立一群新的外星人,並讓飛船居中 creat_fleet(ai_settings,screen,ship,aliens) ship。center_ship() def check_high_score(stats,sb): #檢查是否誕生最高分 if stats。score>stats。high_score: stats。high_score = stats。score sb。prep_high_score() with open(‘data\data。txt’,‘w’) as f: data=str(stats。high_score) f。write(data) 在所有程式碼編寫完畢之後就可以進行遊戲了 移動功能:鍵盤上的左右箭頭起到移動功能 射擊功能:鍵盤上的空格鍵起到射擊功能,為增加難度,遊戲框最多隻允許存在3顆子彈(子彈的多少可以自己調節)