140行代碼實現(xiàn)Flippy Bird
話說這游戲中文名叫什么來著欢搜,死活想不起來了,算了話不多說崖瞭,140行實現(xiàn)小游戲系列第二章狂巢,依然是簡單小游戲,與數(shù)獨游戲相比书聚,在游戲界面顯示上更難一些唧领,但是在邏輯方面更簡單一些,需要處理的無非是速度雌续、加速度斩个、時間、位置驯杜、碰撞檢測受啥,界面方面則要實現(xiàn)整個動態(tài)的顯示;
依舊在最后會給出全部代碼鸽心,不過依然可以從我的?Github倉庫?Fork下來直接運行滚局,圖片資源也在那里,have fun.
運行以及玩法:
python main.py運行游戲顽频;
鼠標(biāo)點擊是暫停藤肢,再點擊則是繼續(xù);
空格鍵進行跳躍糯景;
后續(xù)擴展:
管道的出現(xiàn)可以更加隨機嘁圈,包括位置和長度等省骂,目前是很簡單的方式出現(xiàn);
游戲速度可以越來越快最住,目前是固定的钞澳;
小鳥的自由落體速度、跳躍速度等需要優(yōu)化涨缚,目前操作感覺沒有那么流暢轧粟;
增加計分系統(tǒng)、開始仗岖、重來等按鈕逃延;
小鳥圖览妖,需要的自取
游戲截圖
進行中
暫停時
死亡時
關(guān)鍵代碼分析
隨時間移動的管道
可以看到對于這個游戲轧拄,實際上移動的是管道而不是小鳥,因此這里主要是處理管道繪制的位置變化讽膏,以及整個一個循環(huán)的過程檩电,如果屏幕上顯示的管道是N個,那么可以想象是N+2個管道在不停地轉(zhuǎn)圈圈出現(xiàn)在我們的界面上就行了府树;
tunnel_list = [x-speedifx-speed>-200else2100forxintunnel_list ]defdraw_tunnel():forxintunnel_list:? ? ? ? pygame.draw.rect(screen,COLORS['darkgreen'],(x,0,100,350),0)? ? ? ? pygame.draw.rect(screen,COLORS['darkgreen'],(x+100,550,100,350),0)
自由落體的小鳥和點擊空格后跳起
不操作的情況下俐末,小鳥的上下移動是做自由落體,也就是越來越快的下降的過程奄侠,而當(dāng)我們點擊?空格?進行跳躍后卓箫,實際上改變的就是小鳥的當(dāng)前速度,因此小鳥會向上越來越慢的跳躍垄潮,直到速度為0后烹卒,繼續(xù)下降,符合基本的物理規(guī)則弯洗;
G =9.8*30# gJUMP_V =-300bird_x,bird_y =700,450bird_v =0ifnotjump:? ? bird_v += G*frameelse:? ? bird_v = JUMP_V? ? jump =Falsebird_y += frame*bird_vdefdraw_bird():screen.blit(birdImg,[bird_x,bird_y])
碰撞檢測
檢測小鳥是否碰到管道或者是掉到地上旅急,這么說是只無腳鳥咯,實際上就是檢測兩個矩形是否有重疊的部分牡整;
defrect_cover(rect1,rect2,up=True):# birdleft_up1 = (rect1[0],rect1[1])? ? left_down1 = (rect1[0],left_up1[1]+rect1[3])? ? right_up1 = (left_up1[0]+rect1[2],rect1[1])? ? right_down1 = (left_up1[0]+rect1[2],left_up1[1]+rect1[3])# tunnelleft_up2 = (rect2[0],rect2[1])? ? left_down2 = (rect2[0],left_up2[1]+rect2[3])? ? right_up2 = (left_up2[0]+rect2[2],rect2[1])? ? right_down2 = (left_up2[0]+rect2[2],left_up2[1]+rect2[3])# checkif(left_up2[0]<=right_up1[0]<=right_up2[0]):# x,肯定是右側(cè)線接觸藐吮,因此判斷bird的right即可ifupand(left_up2[1]<=right_up1[1]<=left_down2[1]):returnTrueelif(notup)and(left_up2[1]<=right_down1[1]<=left_down2[1]):returnTruereturnFalse
pygame繪制rect不支持透明度下實現(xiàn)的透明圖層
看到,實際上是借助了Surface逃贝,將其設(shè)置為想要的透明度后blit到我們的screen上即可谣辞,直接draw rect是不支持RGBA的A設(shè)置alpha的,不知道為啥這么坑爹的設(shè)計沐扳;
defdraw_dead():s = pygame.Surface(SIZE, pygame.SRCALPHA)? ? s.fill((255,255,255,240))? ? screen.blit(s, (0,0))? ? txt = font120.render('YOU DEAD',True,COLORS['black'])? ? x,y =450,400screen.blit(txt,(x,y))
全部代碼
importsysimportpygamefrompygame.colorimportTHECOLORSasCOLORSdefdraw_background():# white backgroundscreen.fill(COLORS['lightblue'])? ? pygame.draw.rect(screen,COLORS['black'],(-100,902,3000,200),5)defdraw_tunnel():forxintunnel_list:? ? ? ? pygame.draw.rect(screen,COLORS['darkgreen'],(x,0,100,350),0)? ? ? ? pygame.draw.rect(screen,COLORS['darkgreen'],(x+100,550,100,350),0)defdraw_bird():screen.blit(birdImg,[bird_x,bird_y])defdraw_context():txt = font50.render('Count time: '+str(int(count_time))+' S',True,COLORS['black'])? ? x,y =10,920screen.blit(txt,(x,y))defdraw_pause():s = pygame.Surface(SIZE, pygame.SRCALPHA)? ? s.fill((255,255,255,220))? ? screen.blit(s, (0,0))? ? txt = font120.render('PAUSE',True,COLORS['darkgray'])? ? x,y =550,400screen.blit(txt,(x,y))defdraw_dead():s = pygame.Surface(SIZE, pygame.SRCALPHA)? ? s.fill((255,255,255,240))? ? screen.blit(s, (0,0))? ? txt = font120.render('YOU DEAD',True,COLORS['black'])? ? x,y =450,400screen.blit(txt,(x,y))defrect_cover(rect1,rect2,up=True):# birdleft_up1 = (rect1[0],rect1[1])? ? left_down1 = (rect1[0],left_up1[1]+rect1[3])? ? right_up1 = (left_up1[0]+rect1[2],rect1[1])? ? right_down1 = (left_up1[0]+rect1[2],left_up1[1]+rect1[3])# tunnelleft_up2 = (rect2[0],rect2[1])? ? left_down2 = (rect2[0],left_up2[1]+rect2[3])? ? right_up2 = (left_up2[0]+rect2[2],rect2[1])? ? right_down2 = (left_up2[0]+rect2[2],left_up2[1]+rect2[3])# checkif(left_up2[0]<=right_up1[0]<=right_up2[0]):# x,肯定是右側(cè)線接觸泥从,因此判斷bird的right即可ifupand(left_up2[1]<=right_up1[1]<=left_down2[1]):returnTrueelif(notup)and(left_up2[1]<=right_down1[1]<=left_down2[1]):returnTruereturnFalsedefcheck_dead():bird_rect = (bird_x,bird_y,70,70)ifbird_rect[1]+bird_rect[3]>900:returnTrueforxintunnel_list:? ? ? ? up_rect = (x,0,100,350)? ? ? ? down_rect = (x+100,550,100,350)ifrect_cover(bird_rect,up_rect)orrect_cover(bird_rect,down_rect,up=False):returnTruereturnFalseif__name__ =="__main__":# init pygamepygame.init()# contantSIZE = [1500,1000]? ? font50 = pygame.font.SysFont('Times',50)? ? font120 = pygame.font.SysFont('Times',120)? ? G =9.8*30# gJUMP_V =-300# bridbirdPath ='bird.png'birdImg = pygame.image.load(birdPath)# tunneltunnel_list = [100,600,1100,1600,2100]# create screen 500*500screen = pygame.display.set_mode(SIZE)# variable parameterbird_x,bird_y =700,450bird_v =0count_time =0# levelspeed =5frame =0.02# main looprunning =Truepause =Falsejump =Falsedead =Falsewhilerunning:foreventinpygame.event.get():ifevent.type == pygame.QUIT:? ? ? ? ? ? ? ? running =Falsebreakelifevent.type == pygame.MOUSEBUTTONDOWN:? ? ? ? ? ? ? ? pause =notpauseelifevent.type == pygame.KEYUP:ifchr(event.key) ==' ':? ? ? ? ? ? ? ? ? ? jump =True# update dataifnotpauseandnotdead:? ? ? ? ? ? count_time += frame? ? ? ? ? ? tunnel_list = [x-speedifx-speed>-200else2100forxintunnel_list ]ifnotjump:? ? ? ? ? ? ? ? bird_v += G*frameelse:? ? ? ? ? ? ? ? bird_v = JUMP_V? ? ? ? ? ? ? ? jump =Falsebird_y += frame*bird_v# backgrounddraw_background()# tunneldraw_tunnel()# choose itemdraw_bird()# pointdraw_context()# pauseifnotdeadandpause:? ? ? ? ? ? draw_pause()# deadifdead:? ? ? ? ? ? draw_dead()# flippygame.display.flip()# pause 20mspygame.time.delay(int(frame*1000))# check win or notifcheck_dead():#print('You dead, dumb ass!!!')#breakdead =Truepygame.quit()
最后
數(shù)獨和FlippyBird都在?這里?,歡迎大家Fork下來直接運行迫皱,后續(xù)會不定期更新其他小游戲歉闰,目前以簡單的動作小游戲辖众、棋牌類為主,想到啥做啥和敬,或者大家有什么想做想玩的可以評論區(qū)告訴我哈凹炸,搞得定的我會盡快完成;
最后的最后
大家可以到我的Github上看看有沒有其他需要的東西昼弟,目前主要是自己做的機器學(xué)習(xí)項目啤它、Python各種腳本工具、有意思的小項目以及Follow的大佬舱痘、Fork的項目等: