如何利用pygame實(shí)現(xiàn)打飛機(jī)小游戲
效果預(yù)覽
最近上實(shí)訓(xùn)課,寫了這么一個(gè)簡(jiǎn)單的小玩意。運(yùn)行效果如下:(這個(gè)是有音效的,不過這個(gè)展示不了因?yàn)檫@里只能上傳GIF)
項(xiàng)目結(jié)構(gòu)
游戲?qū)ζ聊坏倪m配
由于我使用的是筆記本所以對(duì)于屏幕來(lái)說是進(jìn)行了縮放的,例如,我的筆記本縮放了125%
但是問題在于我們的pygame和其他的一些庫(kù)例如selenium其實(shí)是按照100%顯示的像素來(lái)算的。所以這個(gè)時(shí)候我們需要進(jìn)行一個(gè)換算。
這個(gè)也好算: 當(dāng)前顯示像素比 = 100%顯示像素比 X 縮放比
我們只需要換算一下就好了。這里我定義了一個(gè)類,來(lái)實(shí)現(xiàn)我們的需求,自動(dòng)檢測(cè)我們的電腦的屏幕縮放比,之后換算。
from win32 import win32api, win32gui, win32print from win32.lib import win32con from win32.win32api import GetSystemMetrics class ChangeRealSize(object): ''' 該類主要對(duì)屏幕進(jìn)行像素適配,按照縮放比對(duì)像素進(jìn)行換算為100%顯示 示例: RealSize = ChangeRealSize() x=RealSize.getreal_xy(500) 此時(shí)就可以換算為當(dāng)前屏幕的像素 ''' def get_real_resolution(self): """獲取真實(shí)的分辨率""" hDC = win32gui.GetDC(0) w = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES) h = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES) return w, h def get_screen_size(self): """獲取縮放后的分辨率""" w = GetSystemMetrics (0) h = GetSystemMetrics (1) return w, h def getreal_xy(self,x): '''返回按照100%來(lái)算的真實(shí)的像素值''' real_resolution = self.get_real_resolution() screen_size = self.get_screen_size() screen_scale_rate = round(real_resolution[0] / screen_size[0], 2) try: x = x/screen_scale_rate except: #對(duì)筆記本進(jìn)行適配,一般而言在100%比的機(jī)器上x不會(huì)出錯(cuò) x=1.25 return int(x)
游戲屏幕的繪制與飛機(jī)創(chuàng)建
屏幕繪制直接使用pygame.display.set_mode()的bitl()繪制方法,進(jìn)行繪制。當(dāng)然這里的背景是會(huì)動(dòng)的。所以使用到了一個(gè)精靈的派生類。
import pygame,random from ChangeRealSize import ChangeRealSize GetReal = ChangeRealSize() class GameSprite(pygame.sprite.Sprite): def __init__(self,image_path,speed=1): super().__init__() self.image = pygame.image.load(image_path) self.rect = self.image.get_rect() self.speed = speed def update(self): self.rect.y+=self.speed class Background(GameSprite): def __init__(self, image_path="./Plane_Img/background1.png",flag=False): super().__init__(image_path) if flag: self.rect.y = -self.rect.height def update(self): self.rect.y+=1 if self.rect.y >= self.rect.height: self.rect.y = -self.rect.height
實(shí)現(xiàn)的具體方法如下:
飛機(jī)類的實(shí)現(xiàn)
這個(gè)我是自己定義的所以的話,沒有辦法直接使用那個(gè)自帶的碰撞檢測(cè),我還定義了一個(gè)碰撞檢測(cè)方法。
飛機(jī)的移動(dòng)
這個(gè)和游戲類的事件檢測(cè)配合。
具體思路是用pygame.event.get()進(jìn)行事件檢測(cè)。之后檢測(cè)到按下某一個(gè)按鍵,例如向前移動(dòng)是,就會(huì)設(shè)置向前移動(dòng)的信號(hào),那么這個(gè)時(shí)候飛機(jī)就會(huì)一直往前走。當(dāng)松開后,那么設(shè)置信號(hào)為假,那么飛機(jī)就會(huì)停下來(lái)。由于飛機(jī)會(huì)一直在循環(huán)里面檢測(cè)有沒有按下那個(gè)向前,所以當(dāng)你長(zhǎng)按往前時(shí),飛機(jī)會(huì)一直往前,直到你松開。
子彈與敵機(jī)類
這個(gè)子彈和敵機(jī)都是精靈派生類的子類。所以的話就一起說一下。
重點(diǎn)要說的時(shí)子彈類的碰撞檢測(cè),和敵機(jī)的碰撞檢測(cè)。這里主要說一下子彈類,因?yàn)檫@個(gè)和敵機(jī)類似。只是有些細(xì)節(jié)不一樣。
class Bullet(GameSprite): def __init__(self,P_rect,is_hero=False,bullet_image = "./Plane_Img/bullet-3.gif",hero_rect=None): self.hero_rect = hero_rect self.bullet_image = bullet_image self.speed = 4 self.is_hero = is_hero self.P_rect = P_rect self.screen_height = GetReal.getreal_xy(800) self.screen_width = GetReal.getreal_xy(500) self.actarct_plan = False self.actract_hero=[] super().__init__(self.bullet_image,self.speed) self.rect.x = self.P_rect.x+((self.P_rect.width-self.rect.width)/2) self.rect.y = self.P_rect.y def enemy_bullet(self): #可以在這里計(jì)算飛機(jī)被擊中了多少次 #被擊中減少5點(diǎn) if not self.is_hero: bullet_x = self.rect.x + int(self.rect.width / 2) bullet_y = self.rect.y + int(self.rect.height / 2) hero_plane_x = self.hero_rect.x + int(self.hero_rect.width / 2) hero_plane_y = self.hero_rect.y + int(self.hero_rect.height / 2) subtract_y = abs(int(bullet_y - hero_plane_y)) subtract_x = abs(int(bullet_x - hero_plane_x)) if subtract_y <= int((self.rect.height + self.hero_rect.height) / 2) and \ subtract_x <= int((self.rect.width + self.hero_rect.height) / 2): self.actract_hero.append(1) return True def update(self): if self.enemy_bullet(): #直接在這里計(jì)算數(shù)字一次減少5 global HERO_PLANE_HP HERO_PLANE_HP-=5 # print(HERO_PLANE_HP) self.kill() if self.is_hero: self.rect.y-=self.speed else: super().update() if self.rect.bottom >=self.screen_height-3 : self.kill()
子彈的話分兩種,一個(gè)是飛機(jī)子彈,一個(gè)是敵機(jī)子彈,敵機(jī)的自帶檢測(cè)碰撞。一方面是方便分?jǐn)?shù)統(tǒng)計(jì)(敵機(jī)擊中飛機(jī)幾次)了另一方面也是因?yàn)轱w機(jī)是自定義的沒有辦法用pygame的事件檢測(cè)(自帶的)
敵機(jī)的爆炸
這個(gè)其實(shí)又和飛機(jī)的爆炸類似。
主要是檢測(cè)有沒有撞到飛機(jī),之后通過切換圖片就好了。當(dāng)然這個(gè)時(shí)候我是開了線程的。不然會(huì)很快閃過去,換了和沒換一樣你看不到效果。
切換圖片的函數(shù),切換完畢,刪除這個(gè)敵機(jī)類減少內(nèi)存消耗
游戲小彩蛋
這個(gè)其實(shí)就是一個(gè)自己的后面
具體作用就是修改自己的飛機(jī)的HP值為99萬(wàn)
當(dāng)然這個(gè)小游戲還沒有做完,無(wú)敵也有點(diǎn)無(wú)聊,玩久了的話。
def CheatEngine(): global HERO_PLANE_HP print("HP is %d" % HERO_PLANE_HP) while 1: key = input("maybe you can input something:") if key=='break': print("enjoy your game please Bye~") return elif key=="Huterox is best": HERO_PLANE_HP=999999 print("Now your HP is %d!!!"%HERO_PLANE_HP) return
完整代碼
import pygame,random from ChangeRealSize import ChangeRealSize GetReal = ChangeRealSize() class GameSprite(pygame.sprite.Sprite): def __init__(self,image_path,speed=1): super().__init__() self.image = pygame.image.load(image_path) self.rect = self.image.get_rect() self.speed = speed def update(self): self.rect.y+=self.speed class Background(GameSprite): def __init__(self, image_path="./Plane_Img/background1.png",flag=False): super().__init__(image_path) if flag: self.rect.y = -self.rect.height def update(self): self.rect.y+=1 if self.rect.y >= self.rect.height: self.rect.y = -self.rect.height
········································································································
import pygame,random,time,threading,os from ChangeRealSize import ChangeRealSize from GameSprite import GameSprite,Background GetReal = ChangeRealSize() GREATE_ENMEY_EVENT = pygame.USEREVENT#只能出現(xiàn)一次 HERO_FIRE_BULLTE = pygame.USEREVENT+1 #第二個(gè)事件 HERO_PLANE_HP = 300 def CheatEngine(): global HERO_PLANE_HP print("HP is %d" % HERO_PLANE_HP) while 1: key = input("maybe you can input something:") if key=='break': print("enjoy your game please Bye~") return elif key=="Huterox is best": HERO_PLANE_HP=999999 print("Now your HP is %d!!!"%HERO_PLANE_HP) return class Base(): '''飛機(jī)的初始化樣式,位置''' def __init__(self,x,y,width,height,path): self.x = GetReal.getreal_xy(x) self.y = GetReal.getreal_xy(y) self.width = GetReal.getreal_xy(width) self.height = GetReal.getreal_xy(height) self.image = pygame.image.load(path) self.rect = pygame.Rect(self.x,self.y,self.height,self.width) class Planer(Base): def __init__(self,x,y,width,height,path,screen): Base.__init__(self,x,y,width,height,path) self.Killed = False self.screen = screen self.GoStrange=False self.TurnLeft = False self.TurnRight =False self.GoBack = False self.Fire_flag = False self.Boom_path="./Plane_Img/hero_blowup_n{}.png" self.bullet_group=pygame.sprite.Group() pygame.time.set_timer(HERO_FIRE_BULLTE,250) self.Plane_need_Killed=[]#由于會(huì)重復(fù)執(zhí)行只能去用列表的數(shù)量來(lái)判斷 def Move(self): if self.Killed: self.rect=pygame.Rect(0,0,0,0) return if self.GoStrange: if self.rect.bottom <= 300: self.show() return else: self.rect.y -= 3 self.show() if self.TurnLeft: if self.rect.x<=3: self.show() return else: self.rect.x-=2 self.show() if self.TurnRight: if self.rect.x>=Game.screen_x-self.rect.width-3: self.show() return else: self.rect.x+=2 self.show() if self.GoBack: if self.rect.bottom>=Game.screen_y-30: self.show() return else: self.rect.y +=2 self.show() self.show() def Get_bullet(self): #子彈加載 if self.Killed: return if self.Fire_flag: MusicPlay().PlayPlanSound() bullet = Bullet(self.rect,True) self.bullet_group.add(bullet) def Fire(self): #子彈發(fā)射 if self.Killed: return self.bullet_group.update() self.bullet_group.draw(self.screen) def Goal(self): pass def show(self): if self.Killed: return Game.screen.blit(self.image,self.rect) # pygame.display.update() def __plane_Boom(self): if self.Killed: return for i in range(1, 5): self.image_path = self.Boom_path.format(i) self.image = pygame.image.load(self.image_path) time.sleep(0.3) time.sleep(1) self.Killed =True def Plane_Live(self): if self.Killed: return global HERO_PLANE_HP if HERO_PLANE_HP<=0: HERO_PLANE_HP =0 self.Plane_need_Killed.append(1) if len(self.Plane_need_Killed)==1: t = threading.Thread(target=self.__plane_Boom) t.start() #音樂播放類 class MusicPlay(): def __init__(self): self.bgmusic = pygame.mixer.music def PlayBg(self): self.bgmusic.load("./music/PlaneWarsBackgroundMusic.mp3") self.bgmusic.set_volume(0.3) self.bgmusic.play(-1) def StarBg(self): self.bgmusic.stop() def PlayPlanSound(self): self.PlayPlaneMusic = pygame.mixer.Sound("./music/hero_fire.wav") self.PlayPlaneMusic.set_volume(0.2) self.PlayPlaneMusic.play() def StopPlayPlanSound(self): pass #子彈類 class Bullet(GameSprite): def __init__(self,P_rect,is_hero=False,bullet_image = "./Plane_Img/bullet-3.gif",hero_rect=None): self.hero_rect = hero_rect self.bullet_image = bullet_image self.speed = 4 self.is_hero = is_hero self.P_rect = P_rect self.screen_height = GetReal.getreal_xy(800) self.screen_width = GetReal.getreal_xy(500) self.actarct_plan = False self.actract_hero=[] super().__init__(self.bullet_image,self.speed) self.rect.x = self.P_rect.x+((self.P_rect.width-self.rect.width)/2) self.rect.y = self.P_rect.y def enemy_bullet(self): #可以在這里計(jì)算飛機(jī)被擊中了多少次 #被擊中減少5點(diǎn) if not self.is_hero: bullet_x = self.rect.x + int(self.rect.width / 2) bullet_y = self.rect.y + int(self.rect.height / 2) hero_plane_x = self.hero_rect.x + int(self.hero_rect.width / 2) hero_plane_y = self.hero_rect.y + int(self.hero_rect.height / 2) subtract_y = abs(int(bullet_y - hero_plane_y)) subtract_x = abs(int(bullet_x - hero_plane_x)) if subtract_y <= int((self.rect.height + self.hero_rect.height) / 2) and \ subtract_x <= int((self.rect.width + self.hero_rect.height) / 2): self.actract_hero.append(1) return True def update(self): if self.enemy_bullet(): #直接在這里計(jì)算數(shù)字一次減少5 global HERO_PLANE_HP HERO_PLANE_HP-=5 # print(HERO_PLANE_HP) self.kill() if self.is_hero: self.rect.y-=self.speed else: super().update() if self.rect.bottom >=self.screen_height-3 : self.kill() #敵機(jī)類 class Enemy(GameSprite): def __init__(self,hero_plane,screen,image_path="./Plane_Img/enemy0.png"): self.speed = random.randint(1,3) self.image_path =image_path self.screen = screen self.hero_plane = hero_plane self.hero_bullet = self.hero_plane.bullet_group self.fire_interval = False #通過這個(gè)和另一個(gè)計(jì)時(shí)線程配合來(lái)實(shí)現(xiàn)子彈的間斷發(fā)射 self.collied_with_plan = [] super().__init__(self.image_path,self.speed) self.screen_height = GetReal.getreal_xy(800) self.screen_width = GetReal.getreal_xy(500) self.Turn_L_Flag = True self.Boom_path = "./Plane_Img/enemy0_down{}.png" self.rect.y = GetReal.getreal_xy(self.rect.top-self.rect.bottom) self.rect.x = random.randint(0, self.screen_width - self.rect.width) self.bullet_group = pygame.sprite.Group() def __Boom(self): #這里還可以對(duì)以后飛機(jī)擊落敵機(jī)的數(shù)量計(jì)數(shù) #敵機(jī)應(yīng)該檢測(cè)自己有沒有和飛機(jī)的子彈相撞 flag_killed_by_bullet = pygame.sprite.spritecollide(self,self.hero_bullet,True) if flag_killed_by_bullet or self.__IS_collied_with_plan(): #被用戶撞了HP值減少20 global HERO_PLANE_HP if len(self.collied_with_plan)==1: HERO_PLANE_HP -=20 t = threading.Thread(target=self.Boom_ing) t.start() pass def Boom_ing(self): for i in range(1, 5): self.image_path = self.Boom_path.format(i) self.image = pygame.image.load(self.image_path) time.sleep(0.2) self.kill() def __IS_collied_with_plan(self): #碰撞檢查是否與用戶飛機(jī)碰撞 center_enemy_x = self.rect.x +int(self.rect.width/2) center_enemy_y = self.rect.y +int(self.rect.height/2) center_plane_x = self.hero_plane.rect.x+int(self.hero_plane.rect.width/2) center_plane_y = self.hero_plane.rect.y+int(self.hero_plane.rect.height/2) subtract_y = abs(int(center_enemy_y-center_plane_y)) subtract_x = abs(int(center_enemy_x-center_plane_x)) if subtract_y <= int((self.rect.height+self.hero_plane.rect.height)/2) and\ subtract_x <= int((self.rect.width+self.hero_plane.rect.height)/2): self.collied_with_plan.append(1) return True def __Bullet_building(self): if self.rect.y% 50 ==0: buttle = Bullet(self.rect,bullet_image="./Plane_Img/bullet-1.gif",hero_rect=self.hero_plane.rect) self.bullet_group.add(buttle) def __Shut(self): self.bullet_group.update() self.bullet_group.draw(self.screen) def update(self): super().update() #定義敵機(jī)的出現(xiàn) self.__Boom()#監(jiān)聽是否碰撞和子彈被射擊 self.__Bullet_building() self.__Shut() if self.rect.top >= self.screen_height + 3: #//越界判斷 # self.rect.y = -20 self.kill() if self.Turn_L_Flag: self.rect.x += random.randint(1,2) if self.rect.right >= self.screen_width - 3: self.Turn_L_Flag = False else: self.rect.x -= random.randint(2, 3) if self.rect.left <= 3: self.Turn_L_Flag = True class PlayGame(object): def __init__(self): pygame.init() self.screen_x, self.screen_y = GetReal.getreal_xy(500), GetReal.getreal_xy(800) self.screen = pygame.display.set_mode((self.screen_x, self.screen_y)) self.Flush_Clcok = pygame.time.Clock() pygame.display.set_caption('英雄無(wú)敵!!!') self.enemy_group = pygame.sprite.Group() self.hero_palne = Planer(200, 500, 100, 125, "./Plane_Img/hero1.png", self.screen) pygame.time.set_timer(GREATE_ENMEY_EVENT,1000)#綁定常量事件 def __game_over(self): global HERO_PLANE_HP if self.hero_palne.Killed: while True: bye = pygame.image.load("./Plane_Img/gameover_.png") self.screen.blit(bye,(0,0)) pygame.display.update() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() os._exit(0) def __Listening_keyboard(self,hero_palne): '''鍵盤按鍵事件偵聽''' '''hero_palne部分是偵聽用戶飛機(jī)的 其余的是其他的事件偵聽 ''' for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() os._exit(0) elif event.type == pygame.KEYDOWN: #檢測(cè)鍵盤按下 if event.key == pygame.K_w or event.key == pygame.K_UP: hero_palne.GoStrange = True if event.key == pygame.K_a or event.key == pygame.K_LEFT: hero_palne.TurnLeft = True if event.key == pygame.K_d or event.key == pygame.K_RIGHT: hero_palne.TurnRight = True if event.key == pygame.K_s or event.key == pygame.K_DOWN: hero_palne.GoBack = True if event.key == pygame.K_SPACE: hero_palne.Fire_flag= True if event.type == HERO_FIRE_BULLTE: hero_palne.Get_bullet() elif event.type == pygame.KEYUP: # 檢測(cè)鍵盤松開 if event.key == pygame.K_w or event.key == pygame.K_UP: hero_palne.GoStrange = False elif event.key == pygame.K_a or event.key == pygame.K_LEFT: hero_palne.TurnLeft = False elif event.key == pygame.K_d or event.key == pygame.K_RIGHT: hero_palne.TurnRight = False elif event.key == pygame.K_s or event.key == pygame.K_DOWN: hero_palne.GoBack = False if event.key == pygame.K_SPACE: hero_palne.Fire_flag = False #敵機(jī)出現(xiàn)偵聽 elif event.type == GREATE_ENMEY_EVENT: self.__Enemy_init() def __doc__(self): pass def __BackGround_init(self): bg1 = Background() bg2 = Background(flag=True) self.back_ground = pygame.sprite.Group(bg1,bg2) def __ShowBackGround(self): self.back_ground.update() self.back_ground.draw(self.screen) def __Enemy_init(self): #臨時(shí)的東西 enemy = Enemy(self.hero_palne,self.screen) self.enemy_group.add(enemy) def __Show_enemy(self): if self.enemy_group: self.enemy_group.update() self.enemy_group.draw(self.screen) def __Check_planecollied_enemy(self): pass def star_game(self): PlayerMusic = MusicPlay() PlayerMusic.PlayBg() hero_palne = Planer(200, 500, 100, 125, "./Plane_Img/hero1.png", self.screen) self.__BackGround_init()#加載背景 self.__Enemy_init()#加載敵機(jī) while 1: self.__ShowBackGround() self.__Show_enemy() self.__Listening_keyboard(self.hero_palne ) self.hero_palne.Move() self.hero_palne.Fire() self.hero_palne.Plane_Live() self.__game_over() pygame.display.update() # 敲黑板這個(gè)方法最好只出現(xiàn)一次,就在你的游戲主循環(huán)里面實(shí)現(xiàn) self.Flush_Clcok.tick(60) if __name__ == '__main__': t = threading.Thread(target=CheatEngine) t.start() Game = PlayGame() Game.star_game()
項(xiàng)目獲取
(不會(huì)玩git的痛苦!?。。?/p>
總結(jié)
到此這篇關(guān)于如何利用pygame實(shí)現(xiàn)打飛機(jī)小游戲的文章就介紹到這了,更多相關(guān)pygame打飛機(jī)小游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- python pygame實(shí)現(xiàn)五子棋小游戲
- 詳解使用PyInstaller將Pygame庫(kù)編寫的小游戲程序打包為exe文件
- 使用PyInstaller將Pygame庫(kù)編寫的小游戲程序打包為exe文件及出現(xiàn)問題解決方法
- 使用Python第三方庫(kù)pygame寫個(gè)貪吃蛇小游戲
- python運(yùn)用pygame庫(kù)實(shí)現(xiàn)雙人彈球小游戲
- python+pygame實(shí)現(xiàn)坦克大戰(zhàn)小游戲的示例代碼(可以自定義子彈速度)
- 使用pygame編寫Flappy bird小游戲
- pygame庫(kù)實(shí)現(xiàn)俄羅斯方塊小游戲
- pygame庫(kù)實(shí)現(xiàn)移動(dòng)底座彈球小游戲
- 使用pygame實(shí)現(xiàn)垃圾分類小游戲功能(已獲校級(jí)二等獎(jiǎng))
相關(guān)文章
python實(shí)現(xiàn)數(shù)通設(shè)備tftp備份配置文件示例
這篇文章主要介紹了python實(shí)現(xiàn)數(shù)通設(shè)備tftp備份配置文件示例,需要的朋友可以參考下2014-04-04django 將自帶的數(shù)據(jù)庫(kù)sqlite3改成mysql實(shí)例
這篇文章主要介紹了django 將自帶的數(shù)據(jù)庫(kù)sqlite3改成mysql實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-07-07CentOS 6.5中安裝Python 3.6.2的方法步驟
centos 6.5默認(rèn)自帶的python版本為2.6,而下面這篇文章主要給大家介紹了關(guān)于在CentOS 6.5中安裝Python 3.6.2的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12Python 用matplotlib畫以時(shí)間日期為x軸的圖像
這篇文章主要介紹了Python 用matplotlib畫以時(shí)間日期為x軸的圖像,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08Python的Django框架中自定義模版標(biāo)簽的示例
這篇文章主要介紹了Python的Django框架中自定義模版標(biāo)簽的示例,標(biāo)簽的用處比過濾器更多,需要的朋友可以參考下2015-07-07Python datetime 格式化 明天,昨天實(shí)例
這篇文章主要介紹了Python datetime 格式化 明天,昨天實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-03-03