1. 程式人生 > >python彈球遊戲 第三章、計算分數、顯示分數、更新難度、遊戲結束判斷

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或者右上角×退出遊戲。至此,彈球遊戲簡單實現結束

優化:讀者可以嘗試優化介面分割槽,比如得分割槽、設定區和遊戲區

         小球的運動速度是有規律的,讀者可以新增隨機量來使得小球運動速度不那麼好預測,使得遊戲攻略更難統一

         小球的速度改變目前與接觸木板位置和相對速度無關,讀者可以使之相關,和現實更逼近