python彈球遊戲 第三章、計算分數、顯示分數、更新難度、遊戲結束判斷
設計概要
前兩章我們實現了介面、球、木板的建立,並使得球可以相對邊緣彈來彈去,木板可以通過ws,上下鍵來移動,構成了遊戲的基本框架。接下來需要新增函式來實現遊戲的可玩性
1、左右板子玩家的分數。通過檢測小球與板子的碰撞來增加玩家的分數,因此需要調節的量:
1)對象板子應該具有分數屬性
2)對象板子應該具有單次分數增加量的屬性,以及難度相關的屬性
3)物件小球的碰壁檢測應該修改,分為一般碰壁和碰撞板子的兩種情況
4)物件小球應該具有遊戲難度相關的屬性
2、左右玩家分數的顯示。進度條顯示是街機類遊戲常用技巧,這裡也採用。因此需要:
1)有一個畫分數進度條的函式
2)顯示分數數字的函式
3、隨著遊戲程序難度的增加。難度增加的點應該是球碰撞木板之後,分別有三個需要改變的值:
1)小球運動速度增加
2)木板移動速度增加(靈敏度)
3)遊戲單次得分增加(越到後面一次接球得分越多)
4、遊戲結束判斷。左右有一個人的遊戲得分達到某個閾值就結束
五個模組的程式碼
game_main.py
import pygame from game_settings import Settings from board import Board from ball import Ball import game_function as gf pygame.init()#初始化 settings=Settings()#獲取設定引數 screen=pygame.display.set_mode((settings.screen_width,settings.screen_height))#建立一個介面,限制長寬 screen.fill(settings.screen_color)#介面上色 pygame.display.set_caption(settings.screen_text)#介面上文字 bd1=Board(screen,settings,'left')#定義左板,定義只需要一次 bd2=Board(screen,settings,'right')#定義右板 ball=Ball(screen,settings)#定義球 while True: gf.update_screen(settings,screen,ball,bd1,bd2)
這個模組和第二章一樣,無需任何改變
game_settings.py
class Settings(): def __init__(self): self.setting_screen() self.setting_board() self.setting_ball() self.setting_score() self.game_active=False def setting_screen(self):#設定介面 self.screen_color=[0,250,250] self.screen_width=420 self.screen_height=600 self.screen_text='彈球遊戲' def setting_board(self):#設定板子 self.board_height=100 self.board_width=5 self.board_colorl=[0,250,0] self.board_colorr=[0,0,250] self.board_location=int(self.screen_height/2-self.board_height/2) self.board_speed=0.4#只有一個維度運動 self.board_increase_speed=1.005#木板靈敏度增加係數 def setting_ball(self):#設定彈球引數 self.ball_color=[253,122,70] self.ball_rad=10 self.ball_width=3 self.ball_speedx=0.2#運動速度 self.ball_speedy=0.2 self.ball_increase_speedx=1.02#每次碰撞後加速因子 self.ball_increase_speedy=1.01 def setting_score(self):#設定得分面板 self.score_speed=4#分數初始疊加速度 self.score_height=10#得分條高度 self.score_colorl=[0,250,0]#得分條顏色 self.score_colorr=[0,0,250] self.score_increase_speed=1.01#得分條隨著進度加快比例
得分面板屬性需要加進來了
board.py
import pygame
class Board():
def __init__(self,screen,settings,option):
self.screen=screen
self.settings=settings
self.option=option
if option=='left':#如果建立左板,那麼左邊距為0
self.left=0
self.color=settings.board_colorl
if option=='right':#如果建立右板,左邊距為如下
self.left=screen.get_rect().right-self.settings.board_width
self.color=settings.board_colorr
#board具有四個引數,遊戲程序中可能會改變的量
self.y=settings.board_location
self.width=settings.board_width
self.height=settings.board_height
self.speed=settings.board_speed
self.increase_speed=settings.board_increase_speed
self.moving_up=False#初始兩個方向都不許移動,只有在按下按鍵才移動
self.moving_down=False
self.prey=float(self.y)#儲存y方向畫素距離的浮點值,因為速度可以是小數,所以該值需要小數
self.score=0.0
self.score_speed=settings.score_speed
self.increase_score=settings.score_increase_speed
def draw_board(self):
pygame.draw.rect(self.screen,self.color,[self.left,self.y,self.width,self.height])#畫板子
def update(self):#更新板子的位置
if self.moving_up and self.y>self.screen.get_rect().top+35:#上邊界在35的一條線
self.prey-=self.speed
if self.moving_down and self.y<self.screen.get_rect().bottom-self.height:
self.prey+=self.speed
self.y=int(self.prey)
木板的更新較少,木板裡面速度屬性的更新放在了ball物件裡面了,這個操作不太好,不過對於這個小遊戲影響不大
ball.py
import pygame
class Ball():
def __init__(self,screen,settings):
self.screen=screen
self.rad=settings.ball_rad#球相關的引數,遊戲程序中可能會有所改變
self.color=settings.ball_color
self.width=settings.ball_width
self.centerx=int(screen.get_rect().width/2)
self.centery=int(screen.get_rect().height/2)
self.prex=float(self.centerx)#因為後面速度可能是小數,因此需要一個變數儲存精確的位置資訊
self.prey=float(self.centery)
self.xspeed=settings.ball_speedx
self.yspeed=settings.ball_speedy
self.increasex=settings.ball_increase_speedx
self.increasey=settings.ball_increase_speedy
self.screen_left=screen.get_rect().left
self.screen_right=screen.get_rect().right
self.screen_top=screen.get_rect().top
self.screen_bottom=screen.get_rect().bottom
def draw_ball(self):
pygame.draw.circle(self.screen,self.color,[self.centerx,self.centery],self.rad,self.width)
def update(self,boardl,boardr):
self.update_speed(boardl,boardr)#更新速度
self.prex+=self.xspeed#精確值
self.prey+=self.yspeed
self.centerx=int(self.prex)#轉換為可在螢幕上顯示的整點值
self.centery=int(self.prey)
def update_speed(self,boardl,boardr):#更新速度
if self.centerx>self.screen_right-self.rad:#達到最右邊
self.xspeed=-abs(self.xspeed)
if self.centery in range(boardr.y,boardr.y+boardr.height):
boardr.score+=boardr.score_speed
self.xspeed=self.xspeed*self.increasex
self.yspeed=self.yspeed*self.increasey
boardr.score_speed=boardr.score_speed*boardr.increase_score
boardl.score_speed=boardl.score_speed*boardl.increase_score
boardl.speed=boardl.speed*boardl.increase_speed
boardr.speed=boardr.speed*boardr.increase_speed
if self.centerx<self.screen_left+self.rad:#達到最左邊
self.xspeed=abs(self.xspeed)
if self.centery in range(boardl.y,boardl.y+boardl.height):
boardl.score+=boardl.score_speed
self.xspeed=self.xspeed*self.increasex
self.yspeed=self.yspeed*self.increasey
boardr.score_speed=boardr.score_speed*boardr.increase_score
boardl.score_speed=boardl.score_speed*boardl.increase_score
boardl.speed=boardl.speed*boardl.increase_speed
boardr.speed=boardr.speed*boardr.increase_speed
if self.centery>self.screen_bottom-self.rad:#達到最下邊
self.yspeed=-abs(self.yspeed)
if self.centery<self.screen_top+self.rad+35:#達到最上邊
self.yspeed=abs(self.yspeed)
Ball物件的改動較大主要是碰撞邊界的時候如果碰到木板,就需要響應很多變化
game_function.py
import sys
import pygame
def update_screen(settings,screen,ball,boardl,boardr):#遊戲第一個函式,更新介面
screen.fill(settings.screen_color)#在screen中填充一定顏色
pygame.draw.line(screen,[0,0,0],[0,35],[screen.get_rect().width,35],3)
check_event(settings,boardl,boardr)
option=check_over(settings,screen,boardl,boardr)
show_result(screen,option)
if settings.game_active:
boardl.update()
boardr.update()
ball.update(boardl,boardr)
boardl.draw_board()#畫左板
boardr.draw_board()#畫右板
ball.draw_ball()#畫圓形
draw_score(settings,screen,boardl,boardr)
pygame.display.flip()#更新所有display物件
def check_event(settings,bd1,bd2):#所有外端輸入都在這個函式中響應
for event in pygame.event.get():
if event.type==pygame.QUIT:#點選'x'離開
sys.exit()
if event.type==pygame.KEYDOWN:#按下鍵盤
response_keydown(event,settings,bd1,bd2)
if event.type==pygame.KEYUP:#鬆開鍵盤
response_keyup(event,bd1,bd2)
def response_keydown(event,settings,bd1,bd2):#對按下鍵盤作出響應
if event.key==pygame.K_w:#w對應允許bd1上移
bd1.moving_up=True
if event.key==pygame.K_s:#s對應允許bd1下移
bd1.moving_down=True
if event.key==pygame.K_UP:#上鍵對應bd2上移
bd2.moving_up=True
if event.key==pygame.K_DOWN:#下鍵對應bd2下移
bd2.moving_down=True
if event.key==pygame.K_ESCAPE:#按下ESC退出遊戲
sys.exit()
if event.key==pygame.K_SPACE:
settings.game_active=not settings.game_active
def response_keyup(event,bd1,bd2):#鬆開按鍵的響應,和按下對應相反
if event.key==pygame.K_w:
bd1.moving_up=False
if event.key==pygame.K_s:
bd1.moving_down=False
if event.key==pygame.K_UP:
bd2.moving_up=False
if event.key==pygame.K_DOWN:
bd2.moving_down=False
def draw_score(settings,screen,bd1,bd2):#畫得分條以及得分數字
colorl=settings.score_colorl
colorr=settings.score_colorr
height=settings.score_height
width=screen.get_rect().width
score1=str(int(bd1.score))
score2=str(int(bd2.score))
font=pygame.font.SysFont(None,30)
image1=font.render(score1,True,[0,250,0],[0,250,250])
image2=font.render(score2,True,[0,0,250],[0,250,250])
rect1=image1.get_rect()
rect2=image2.get_rect()
rect1.left=0
rect2.right=screen.get_rect().right
rect1.top=height
rect2.top=height
screen.blit(image1,rect1)
screen.blit(image2,rect2)
if bd1.score!=0:
pygame.draw.rect(screen,colorl,[0,0,int(bd1.score),height])
if bd2.score!=0:
pygame.draw.rect(screen,colorr,[width-int(bd2.score),0,int(bd2.score),height])
def check_over(settings,screen,bd1,bd2):#檢查遊戲是否結束
width=screen.get_rect().width
if bd1.score>width/2.0:
settings.game_active=False
return -1#左邊獲勝
if bd2.score>width/2.0:
settings.game_active=False
return 1#右邊獲勝
else:
return 0
def show_result(screen,option):#將最終結果顯示在介面正中
if option==-1:
text='綠方勝'
color=[0,250,0]
if option==1:
text='藍方勝'
color=[0,0,250]
if option==0:
return
result_font=pygame.font.SysFont('方正隸變簡體',70)
result_image=result_font.render(text,True,color,[0,250,250])
result_rect=result_image.get_rect()
result_rect.centerx=screen.get_rect().centerx
result_rect.centery=screen.get_rect().centery
screen.blit(result_image,result_rect)
遊戲函式新增和遊戲得分有關的函式,遊戲結束標誌的判斷。執行介面如下:
上述五個模組放在一個目錄下,執行主函式game_main.py,空格實現遊戲暫停和繼續。ws操作左邊木板上下,上下鍵操作右邊木板上下,Esc或者右上角×退出遊戲。至此,彈球遊戲簡單實現結束
優化:讀者可以嘗試優化介面分割槽,比如得分割槽、設定區和遊戲區
小球的運動速度是有規律的,讀者可以新增隨機量來使得小球運動速度不那麼好預測,使得遊戲攻略更難統一
小球的速度改變目前與接觸木板位置和相對速度無關,讀者可以使之相關,和現實更逼近