(5)Python筆記:使用pygame庫製作打方塊小遊戲

閒來無事研究了下pygame庫,讓我想起了大學時用C++寫出貪吃蛇時的興奮感,不過貌似pygame很久沒跟新了?而且用python寫遊戲也不大高效,但是拿來試試思路,算法還是不錯的。
首先上張效果圖:
這裏寫圖片描述
這裏寫圖片描述
現在包含的功能很簡單,就是打開遊戲時有一個start的按鈕,點擊後進入遊戲,球擊中磚塊會有一定概率出現獎勵物品(3種:1.球加速,2.板子加速,3.增加球的數量),板子在碰到掉下來的獎勵物品時會得到上述中對應的buff,並持續一段時間。球與底部接觸時判斷遊戲結束,可以點擊出現的start重新遊戲,遊戲中按P鍵暫停,A,D板子左右運動,Q退出遊戲。

代碼下載:
https://github.com/SecondMagic/pygame-

就挑幾個重點的地方講講吧:
1.寫之前要先考慮好整個遊戲中出現的物品的劃分,把球,板子,磚塊,顯示文字,按鈕都獨立抽象出來,當要使用時新建對象即可直接使用。之後要考慮功能劃分,這裏是分成遊戲物品位置重新計算,物品顯示,用戶事件,碰撞檢測幾部分,將相應功能的代碼放到一起能夠使得代碼可讀性增加,也方便後期的重構。
下面是遊戲的主流程,

#遊戲界面,球,板子,磚塊,按鈕,文字變量初始化
setting = Setting() #獲取遊戲配置信息
    pygame.init()
    screen = pygame.display.set_mode((setting.screen_width,setting.screen_height))
    pygame.display.set_caption("Game")
    #screen.fill(setting.screen_color)
    button_start = Button('Start') #開始遊戲按鈕
    bricks = Group() #磚塊組初始化
    bat = Bat() #板子初始化
    ball = Ball() 
    balls = Group()
    balls.add(ball) #球組初始化,因爲開始時就含有一個球,所以初始化時添加一個球
    buffs = Group() #buff組初始化
    info_score = Info(100,50) #文字初始化
    info_max_score = Info(200,50) #文字初始化
    info_bat_speed = Info(400,50) #文字初始化
    info_ball_speed = Info(600,50) #文字初始化
    rewards = Group() #獎勵組初始化
while True:
        screen.blit(setting.background_image,(0,0))
        #用戶鍵盤,鼠標事件
        event_check(setting,button_start,bricks,bat,balls,rewards,buffs)
        #判斷遊戲是否通關
        if setting.total_score != 0 and setting.total_score <= setting.score :
            setting.game_stats = False
            setting.max_score = setting.score
            setting.score = 0
        #判斷遊戲是否開啓
        if setting.game_stats == False:
            button_start.draw()
        #判斷遊戲是否暫停
        elif setting.game_stop == True:
            #由於遊戲暫停,所以不進行遊戲物品的位置更新計算,只繪製暫停時物品的位置
            for brick in bricks:
                brick.draw_brick()
            for reward in rewards:
                reward.draw_reward()
            bat.draw_bat()
            for sball in balls:
                sball.draw_ball()
            button_start.draw()
            info_score.draw_info()
            info_max_score.draw_info()
            info_bat_speed.draw_info()
            info_ball_speed.draw_info()
        #遊戲開啓,並在進行中
        else :
            #板子,球,磚塊,獎勵位置重新計算
            for sball in balls :
                sball.update_position(setting)
            bat.update_position(setting)
            rewards.update()
            buffs.update()
            check_change(balls,bat,bricks,setting,rewards,buffs)
            info_score.get_info('scroe:'+str(setting.score))
            info_max_score.get_info('max:'+str(setting.max_score))
            info_bat_speed.get_info('bat speed:'+str(setting.bat_speed))
            info_ball_speed.get_info('ball speed:'+str(setting.ball_speed))

            #buff時間計算,buff時間到了就將其去除出buff隊列,並按照buff類型恢復設置
            for buff in buffs:
                if buff.check_time():
                    buff.change_other(setting,balls)
                    buffs.remove(buff)
            #板子,球,磚塊,獎勵繪製
            for reward in rewards:
                if reward.check() :
                    rewards.remove(reward)
                else :
                    reward.draw_reward()
            for brick in bricks:
                brick.draw_brick()
            bat.draw_bat()
            for sball in balls:
                sball.draw_ball()
            info_score.draw_info()
            info_max_score.draw_info()
            info_bat_speed.draw_info()
            info_ball_speed.draw_info()
        pygame.display.flip()

2.總體功能類別劃分好壞直接影響到後續功能擴展時的容易度,完成後可以開始考慮遊戲內容,首先是讓板子在用戶按A,D鍵時左右移動,通過用戶事件監聽就可以很輕鬆的實現,主要麻煩的一點是用戶一直按住方向鍵時讓板子也一直運動,這時可以通過給板子設置2個方向標識,比如left和right,初始化時都爲0,當用戶按住A時left=1,放開時left=0,right同理,在重新計算板子位置時,板子的位置就可以如下: 板子現在x座標位置=板子原來x座標位置 - left * 板子運動速度 + right * 板子運動速度 ,這樣就可以解決一直按住按鍵時板子的移動問題了

def update_position(self,setting):
        if self.rect.left - setting.bat_speed*self.dir_left >= 0:
            self.rect.centerx -= setting.bat_speed*self.dir_left
        if self.rect.right + setting.bat_speed*self.dir_right <= setting.screen_width:
            self.rect.centerx += setting.bat_speed*self.dir_right

3.球的運行設置,球的話首先要初始化出現時的位置,由於遊戲時如果一直是從一個固定位置發出球,球的方向也固定的話遊戲就非常無趣了,所以初始位置,和運動方向最好都做成隨機的,方向的話直接使用45度角,初始時隨機向左或右,在碰到上左右邊界時相應改變運行方向即可,在碰到底部時遊戲結束,當然這個放到碰撞檢測中也可以。關於球與板子,磚塊的碰撞,獎勵與板子的碰撞檢測,則可以單獨出來。使得代碼更加清晰。

4.球與板子的碰撞檢測,因爲如下圖,會有左右2種運行軌跡,單靠pygame提供的矩形疊加檢測是不夠分辨的,所以需要加上更加細緻判斷:
這裏寫圖片描述

#sball 球 ;bat 板子
if sball.rect.left < bat.rect.left and sball.rect.right >= bat.rect.left and sball.dir_x == 1 :
                #球與板子左邊緣相撞,且球的x軸運行方向爲向右,則x軸運動方向修改爲向左
                sball.dir_x *=-1
            if sball.rect.left <= bat.rect.right and sball.rect.right > bat.rect.right and sball.dir_x == -1:
            #球與板子右邊緣相撞,且球的x軸運行方向爲向左,則x軸運動方向修改爲向右
                sball.dir_x *=-1

5.獎勵和buff,當球擊中磚塊時,有一定概率產生獎勵(當然也通過對磚塊增加type字段來實現擊中某一些特定磚塊時產生獎勵)獎勵初始位置爲被擊磚塊中心處,運行方向向下,當板子接觸到獎勵時刪除該獎勵對象並新增一個buff對象,buff對象用來描述當前遊戲中所獲得各種獎勵增益效果和控制其持續時間。在主流程中添加buff組遍歷,每經過一次主流程就重新計算buff持續時間,時間到了就恢復因buff而改變的遊戲屬性即可。

#給出相應片段,可以到上面所提供的總體代碼中查找相應位置
if param.down_speed == 3 and len(balls) <3: #球數量加1
            balls.add(Ball())
            buffs.add(Buff(param,setting))
        if param.down_speed == 2 and setting.bat_speed < setting.bat_speed_max : #板子速度增加
            setting.bat_speed += setting.bat_speed_change
            buffs.add(Buff(param,setting))
        if param.down_speed == 1 and setting.ball_speed <= setting.ball_speed_max : #球速度增加
            setting.ball_speed += setting.ball_speed_change
            buffs.add(Buff(param,setting))


#禮物時間計算
            for buff in buffs:
                if buff.check_time():
                    buff.change_other(setting,balls)
                    buffs.remove(buff)

#獎勵時間更新
buffs.update()

class Buff(Sprite):
    def __init__(self,reward,setting):
        super().__init__()
        self.type = reward.down_speed
        if self.type == 1:
            self.limit_time = setting.reward_type1_limit_time
        elif self.type == 2:
            self.limit_time = setting.reward_type2_limit_time
        elif self.type == 3:
            self.limit_time = setting.reward_type3_limit_time
    def update(self):
        self.limit_time -= 1
    def check_time(self):
        if self.limit_time <= 0:
            return True
        else :
            return False
    def change_other(self,setting,balls):
        if self.type == 1:  #球加速
            setting.ball_speed -= setting.ball_speed_change
        elif self.type == 2: #板子加速
            setting.bat_speed -= setting.bat_speed_change
        elif self.type == 3: #球數量增加
            i = len(balls)
            k = 1
            for sball in balls:
                if k == i :
                    balls.remove(sball)
                k += 1

大致麻煩的地方基本就這些了,置於後續擴展板子的長度變化,多關卡什麼的,也是可以通過少量修改原代碼實現的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章