🍖檔案開啟模式 "b"
阿新 • • 發佈:2020-11-28
此文轉載自:https://blog.csdn.net/weixin_46211269/article/details/110104002
打轉游戲詳解版
網上只要搜一下“打磚遊戲”,基本會看到很多一樣的程式碼,主要是註釋也很少,對於python不熟悉的人來說,根本看不懂,只會拿來執行著玩玩。
於是我歷經三個小時,把程式碼幾乎每一行都註釋了一遍!真是嘔心瀝血!!
點贊加個關注好嗎?以後會有更多的分享,我是川川,大二計算機,
QQ:2835809579,有問題可以留言或者加我好友詢問,我也是第一次閱讀這個程式碼根據我對程式碼的理解以及效果的分析寫的註釋,有不對的地方還請指正。
還是看看效果圖:
ok,上程式碼!!!複製貼上就能執行,還請好好看下注釋,你是來學習的不是來白嫖程式碼玩這種小遊戲的。
如果有註釋不好的地方還請指正!謝謝!!
# 匯入模組
import pygame#匯入pygame專門遊戲的模組
from pygame.locals import *#匯入pygame.locals的全部函式
import sys, random, time, math#匯入sys訪問模組,random隨機模組,time時間模組,math數學模組
class GameWindow(object):
'''建立遊戲視窗類'''
def __init__(self, *args, **kw):
self.window_length = 600#視窗高度
self.window_wide = 500#視窗寬度
# 繪製遊戲視窗,設定視窗尺寸
self.game_window = pygame.display.set_mode((self.window_length, self.window_wide))
# 設定遊戲視窗標題
pygame.display.set_caption("CatchBallGame")#標題CatchBallGame
# 定義遊戲視窗背景顏色引數
self.window_color = (135, 206, 250)#RGB配色,做背景顏色
def backgroud (self):
# 繪製遊戲視窗背景顏色
self.game_window.fill(self.window_color)#呼叫上面的RGB自定義顏色
class Ball(object):
'''建立球類'''
def __init__(self, *args, **kw):
# 設定球的半徑、顏色、移動速度引數
self.ball_color = (255, 215, 0)#球顏色,RGB
self.move_x = 1#橫向速度
self.move_y = 1#縱向速度
self.radius = 10#球半徑10
def ballready(self):
# 設定球的初始位置、
self.ball_x = self.mouse_x#球位置為滑鼠的橫座標位置
self.ball_y = self.window_wide - self.rect_wide - self.radius#縱座標以球心位置為準
# 繪製球,設定反彈觸發條件
pygame.draw.circle(self.game_window, self.ball_color, (self.ball_x, self.ball_y), self.radius)#繪製圓形的球,呼叫上面定義的視窗,球顏色,球的位置和半徑
def ballmove(self):
# 繪製球,設定反彈觸發條件
pygame.draw.circle(self.game_window, self.ball_color, (self.ball_x, self.ball_y), self.radius)#同上 程式碼一樣
self.ball_x += self.move_x#反彈,橫座標增加
self.ball_y -= self.move_y#縱座標不斷減小
# 呼叫碰撞檢測函式
self.ball_window()#碰撞的是牆還是磚塊
self.ball_rect()#球的反應是怎樣的(可以這麼理解)
# 每接5次球球速增加一倍
if self.distance < self.radius:
self.frequency += 1#接的次數加一
if self.frequency == 5:#當滿足頻率5次的時候
self.frequency = 0#歸零
self.move_x += self.move_x#速度加一倍 原來是1,現在就1+1=2,同理2+1=3
self.move_y += self.move_y#同上
self.point += self.point#分數加一
# 設定遊戲失敗條件
if self.ball_y > 520: #窗頂到球心距離大於520,那就說明已經不在擋板上了。窗頂到球心距離等於520才是一直在擋板上。
self.gameover = self.over_font.render("Game Over", False, (0, 0, 0))#定義一個遊戲結束,False就表示失敗,
self.game_window.blit(self.gameover, (100, 130))
self.over_sign = 1 #遊戲結束標識
class Rect(object):
'''建立球拍類'''
def __init__(self, *args, **kw): #初始化 def __init__()這種都代表是初始化
# 設定球拍顏色引數
self.rect_color = (255, 0, 0)#RGB控制擋板(球拍)顏色
self.rect_length = 100#球拍的長度為100
self.rect_wide = 10#球拍高度(寬度)
def rectmove(self):
# 獲取滑鼠位置引數
self.mouse_x, self.mouse_y = pygame.mouse.get_pos()#獲取滑鼠橫縱座標
# 繪製球拍,限定橫向邊界
if self.mouse_x >= self.window_length - self.rect_length // 2:#如果滑鼠橫座標大於了球拍最兩側中心位置
self.mouse_x = self.window_length - self.rect_length // 2#那麼就回歸到球心最右側位置 視窗寬度減去球拍一半的距離
if self.mouse_x <= self.rect_length // 2:#如果滑鼠橫座標小於了球拍最兩側中心位置
self.mouse_x = self.rect_length // 2#那麼滑鼠橫座標位置就是球拍位置的一半
pygame.draw.rect(self.game_window, self.rect_color, (
(self.mouse_x - self.rect_length // 2), (self.window_wide - self.rect_wide), self.rect_length, self.rect_wide))#呼叫上面的引數
class Brick(object): #定義磚塊這個類
def __init__(self, *args, **kw): #初始化
# 設定磚塊顏色引數
self.brick_color = (139, 126, 102)#RGB控制磚塊顏色
self.brick_list = [[1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1]] #定義磚塊列表,磚塊分為六列,五行,一個1代表一個磚塊
self.brick_length = 80#磚塊長度80
self.brick_wide = 20#磚塊寬度20
def brickarrange(self):
for i in range(5):
for j in range(6): #遍歷五行六列的磚塊
self.brick_x = j * (self.brick_length + 24) #控制磚塊的橫向放置
self.brick_y = i * (self.brick_wide + 20) + 40 #控制磚塊的高度
if self.brick_list[i][j] == 1: #如果是1,那就是磚塊,則執行下面的語句,把它畫出來
# 呼叫前面定義好的引數,把磚塊畫出來到視窗固定位置
pygame.draw.rect(self.game_window, self.brick_color,
(self.brick_x, self.brick_y, self.brick_length, self.brick_wide))
# 呼叫碰撞檢測函式
self.ball_brick()
if self.distanceb < self.radius: #撞擊到磚塊
self.brick_list[i][j] = 0 #磚塊就有1變為0
self.score += self.point#分數就加一
# 設定遊戲勝利條件:全部磚塊被打掉,即所有的1變為0
if self.brick_list == [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]]:
self.win = self.win_font.render("You Win", False, (0, 0, 0)) #顯示出“you win”,一切就歸零
self.game_window.blit(self.win, (100, 130)) #控制“you win”位置
self.win_sign = 1 #win的標識,贏了
class Score(object):
'''建立分數類'''
def __init__(self, *args, **kw):
# 設定初始分數,開始的時候分數為0分
self.score = 0
# 設定分數字體為楷體,大小20
self.score_font = pygame.font.SysFont('arial', 20)
# 設定初始加分點數,撞擊一次為1分
self.point = 1
# 設定初始接球次數,開始的時候撞擊磚塊0次
self.frequency = 0
def countscore(self): #定義計算分數的函式
my_score = self.score_font.render(str(self.score), False, (255, 255, 255))
self.game_window.blit(my_score, (555, 15))# 繪製玩家分數,分數的位置放在橫座標為555,距離窗頂位置15
class GameOver(object):
'''建立遊戲結束類'''
def __init__(self, *args, **kw):
# 設定Game Over字型 楷體,字型大小80
self.over_font = pygame.font.SysFont('arial', 80)
# 定義GameOver標識
self.over_sign = 0
class Win(object):
'''建立遊戲勝利類'''
def __init__(self, *args, **kw):
# 設定You Win字型 楷體,字型大小80
self.win_font = pygame.font.SysFont('arial', 80)
# 定義Win標識
self.win_sign = 0
class Collision(object):
'''碰撞檢測類'''
# 球與視窗邊框的碰撞檢測
def ball_window(self):
if self.ball_x <= self.radius or self.ball_x >= (self.window_length - self.radius):#如果球橫座標位置小於球半徑或者大於視窗寬度減去球半徑,意思就是超出邊界了
self.move_x = -self.move_x#橫座標減小一個單位,意思就是反彈了
if self.ball_y <= self.radius:#球縱座標小於半徑,意思就是隻要沒落地
self.move_y = -self.move_y#繼續向下移動
# 球與球拍的碰撞檢測
def ball_rect(self):
# 定義碰撞標識為0
self.collision_sign_x = 0
self.collision_sign_y = 0
#分三種情況,一種是直接碰到磚塊反彈到球拍;一種是碰撞到磚塊,又碰撞到牆;還有一種是碰到兩個磚塊,又碰到牆。這裡用if-elif-else討論。
if self.ball_x < (self.mouse_x - self.rect_length // 2): #如果球中心位置小於滑鼠座標減去球拍一半的長度,表示沒有超出邊界。即沒有撞牆,撞一個磚塊。
self.closestpoint_x = self.mouse_x - self.rect_length // 2#橫座標最近點位置為滑鼠位置減去球拍一半長度
self.collision_sign_x = 1#這種情況,碰撞標識用1標識
elif self.ball_x > (self.mouse_x + self.rect_length // 2):#超出邊界範圍,撞牆。碰到牆和磚塊各一次。
self.closestpoint_x = self.mouse_x + self.rect_length // 2#反彈了,橫座標最近位置為滑鼠座標加上球拍一半的長度。
self.collision_sign_x = 2#這種情況,碰撞標識用2標識
else: #上面兩種情況都不滿足的話執行下面的語句
self.closestpoint_x = self.ball_x#橫座標最近點位置就是球位置。
self.collision_sign_x = 3#這種情況,碰撞標識用3標識
if self.ball_y < (self.window_wide - self.rect_wide): #如果球的縱座標小於視窗高度減去球心的高度。意思如果就是沒有落地的話。
self.closestpoint_y = (self.window_wide - self.rect_wide)#縱座標最近距離為視窗高度減去球拍的高度
self.collision_sign_y = 1#這種情況,碰撞標識用1標識
elif self.ball_y > self.window_wide: #如果球的縱向長度大於了視窗高度,意思就是落地了
self.closestpoint_y = self.window_wide#縱座標最近位置就是視窗的高度(就剛好落地的時候)
self.collision_sign_y = 2#這種情況,碰撞標識用2標識
else:
self.closestpoint_y = self.ball_y#球的最近縱座標為球所在的位置
self.collision_sign_y = 3#這種情況,碰撞標識用3標識
# 定義球拍到圓心最近點與圓心的距離 (最近點距離減去球心橫座標的距離的平方,加上縱座標最近陸離減去球心縱座標的平方),對這整體再開根號。意思就是求的兩個位置之間的距離大小。
self.distance = math.sqrt(
math.pow(self.closestpoint_x - self.ball_x, 2) + math.pow(self.closestpoint_y - self.ball_y, 2))
# 球在球拍上左、上中、上右3種情況的碰撞檢測
if self.distance < self.radius and self.collision_sign_y == 1 and (
self.collision_sign_x == 1 or self.collision_sign_x == 2): #如果滿足:球拍到圓心最近點與圓心距離小於半徑且縱座標標識為1和橫座標標識為1或者2
if self.collision_sign_x == 1 and self.move_x > 0:#如果橫座標標識為1並且橫向速度大於0 。 向右速度大於0,向左速度小於0.!!!
self.move_x = - self.move_x#水平速度反向
self.move_y = - self.move_y#縱向速度也反向 就是反彈的意思
if self.collision_sign_x == 1 and self.move_x < 0: #如果橫向標識為1並且速度小於0 速度的大於小於零隻是根據方向來說的,並不是速度的絕對值會小於0!!!
self.move_y = - self.move_y#直豎直速度反向,就是彈回
if self.collision_sign_x == 2 and self.move_x < 0:#如果橫座標標識為2並且一定速度小於0
self.move_x = - self.move_x#水平速度反向
self.move_y = - self.move_y#縱向速度也反向 就是反彈的意思
if self.collision_sign_x == 2 and self.move_x > 0:#如果橫座標標識為2並且一定速度大於0
self.move_y = - self.move_y#豎直速度反向 ,就是彈回
if self.distance < self.radius and self.collision_sign_y == 1 and self.collision_sign_x == 3:#如果球拍到最近距離與球心距離小於球半徑並且縱座標標識為1和3
self.move_y = - self.move_y#豎直速度反向概
# 球在球拍左、右兩側中間的碰撞檢測
if self.distance < self.radius and self.collision_sign_y == 3:#如果球拍到最近距離與球心距離小於球半徑並且縱座標標識為3
self.move_x = - self.move_x#水平速度反向
# 球與磚塊的碰撞檢測
def ball_brick(self):
# 定義碰撞標識 開始標識都為0,標識沒有碰撞
self.collision_sign_bx = 0
self.collision_sign_by = 0
if self.ball_x < self.brick_x: #如果球橫座標小於磚塊橫向放置的位置大小
self.closestpoint_bx = self.brick_x #磚塊橫座標就是最近點位置
self.collision_sign_bx = 1#標識為1
elif self.ball_x > self.brick_x + self.brick_length: #如果球橫座標大於磚塊橫向放的位置大小與磚塊長度之和
self.closestpoint_bx = self.brick_x + self.brick_length#最近點位置就是磚塊橫座標放的位置大小加上磚塊的長度
self.collision_sign_bx = 2#標識為2
else:#不是上面兩種情況的話,執行下面語句
self.closestpoint_bx = self.ball_x#球的橫向最近陸離為球的中心橫座標
self.collision_sign_bx = 3#這種情況標識為3
#y方向和x方向是同理的,就不解析描述了。
if self.ball_y < self.brick_y:
self.closestpoint_by = self.brick_y
self.collision_sign_by = 1#標識為1
elif self.ball_y > self.brick_y + self.brick_wide:
self.closestpoint_by = self.brick_y + self.brick_wide
self.collision_sign_by = 2#標識為2
else:
self.closestpoint_by = self.ball_y
self.collision_sign_by = 3#標識為3
# 定義磚塊到圓心最近點與圓心的距離(兩點距離公式,根號下橫縱座標差的平方和)
self.distanceb = math.sqrt(
math.pow(self.closestpoint_bx - self.ball_x, 2) + math.pow(self.closestpoint_by - self.ball_y, 2))
# 球在磚塊上左、上中、上右3種情況的碰撞檢測 這個跟球在球拍的上左,上中,上右是一樣的類似解析,這就不概述了
if self.distanceb < self.radius and self.collision_sign_by == 1 and (
self.collision_sign_bx == 1 or self.collision_sign_bx == 2):
if self.collision_sign_bx == 1 and self.move_x > 0:
self.move_x = - self.move_x
self.move_y = - self.move_y
if self.collision_sign_bx == 1 and self.move_x < 0:
self.move_y = - self.move_y
if self.collision_sign_bx == 2 and self.move_x < 0:
self.move_x = - self.move_x
self.move_y = - self.move_y
if self.collision_sign_bx == 2 and self.move_x > 0:
self.move_y = - self.move_y
if self.distanceb < self.radius and self.collision_sign_by == 1 and self.collision_sign_bx == 3:
self.move_y = - self.move_y
# 球在磚塊下左、下中、下右3種情況的碰撞檢測 跟球在球拍的三個方向類似解析,不清楚可以看球在球拍的這三個方向解析
if self.distanceb < self.radius and self.collision_sign_by == 2 and (
self.collision_sign_bx == 1 or self.collision_sign_bx == 2):
if self.collision_sign_bx == 1 and self.move_x > 0:
self.move_x = - self.move_x
self.move_y = - self.move_y
if self.collision_sign_bx == 1 and self.move_x < 0:
self.move_y = - self.move_y
if self.collision_sign_bx == 2 and self.move_x < 0:
self.move_x = - self.move_x
self.move_y = - self.move_y
if self.collision_sign_bx == 2 and self.move_x > 0:
self.move_y = - self.move_y
if self.distanceb < self.radius and self.collision_sign_by == 2 and self.collision_sign_bx == 3:
self.move_y = - self.move_y
# 球在磚塊左、右兩側中間的碰撞檢測
if self.distanceb < self.radius and self.collision_sign_by == 3:
self.move_x = - self.move_x
class Main(GameWindow, Rect, Ball, Brick, Collision, Score, Win, GameOver):
'''建立主程式類'''
def __init__(self, *args, **kw): #初始化
super(Main, self).__init__(*args, **kw) #呼叫(繼承)父類的初始化,具體初始化看前面關於Main的類
super(GameWindow, self).__init__(*args, **kw)#呼叫(繼承)父類的初始化,呼叫前面GameWindow這個類
super(Rect, self).__init__(*args, **kw)#這是對繼承自父類的屬性進行初始化。下面同理。
super(Ball, self).__init__(*args, **kw)
super(Brick, self).__init__(*args, **kw)
super(Collision, self).__init__(*args, **kw)
super(Score, self).__init__(*args, **kw)
super(Win, self).__init__(*args, **kw)
# 定義遊戲開始標識
start_sign = 0
while True: #為真就執行
self.backgroud() #視窗背景
self.rectmove() #移動
self.countscore()#計算分數
if self.over_sign == 1 or self.win_sign == 1: #如果著兩個標識為1就結束迴圈了
break
# 獲取遊戲視窗狀態
for event in pygame.event.get():
if event.type == pygame.QUIT: #觸發事件為遊戲結束/離開
sys.exit() #退出程式
if event.type == MOUSEBUTTONDOWN:#觸發事件為滑鼠移動
pressed_array = pygame.mouse.get_pressed() # 獲取滑鼠按鍵的情況(是否被按下
if pressed_array[0]:#如果為這種情況
start_sign = 1 #開始標識為1
if start_sign == 0: #開始標識為0
self.ballready()#呼叫球位置這個類
else:#不然的話
self.ballmove()#呼叫前面球移動這個類allmove
self.brickarrange()#呼叫磚塊這個類
# 更新遊戲視窗,重新開始
pygame.display.update()
# 控制遊戲視窗重新整理頻率,頻率越小效果越好,但是要求電腦效能越高,所以不能太低
time.sleep(0.010)
if __name__ == '__main__': #執行函式
pygame.init()
pygame.font.init()
catchball = Main()