一、前言
- 本文是基于 Kivy 開源跨平臺的 Python 框架上創作的,Kivy 開源跨平臺的 Python 框架能用于開發多點觸控的用戶界面程式,允許快速簡單的互動設計,非常方便,
- 那么,如何使用 Kivy 撰寫一款乒乓球游戲呢?我們將從一個基本的應用程式開始,描述創建這個游戲的每個步驟,
- Kivy 是用 Python 和 Cython 撰寫的,基于 OpenGL ES 2,支持各種輸入設備并擁有豐富的部件庫,使用相同的代碼,可直接實作多平臺應用,包括 Windows、macOS、Linux、Android 和 iOS,
- 所有 Kivy 部件都支持多點觸控,
- 實作效果,一睹為快:

二、準備
① Python 安裝
- 在 windows 上安裝 Python:
-
- 下載 Python 的最新版本:訪問鏈接 Python 官網,在 Windows 作業系統上安裝 Python 3.10.0,大家也可以自行選擇最新版的下載,

-
- 進入下一個頁面后,拉到最下面,選擇 Windows embeddable package (64-bit) 下載:

-
- 雙擊下載完成的應用程式,記得一定要勾選 ADD Python 3.7 to PATH,否則 cmd 無法運行 Python,然后選擇 Install Now 進行安裝,默認會安裝 pip,而且將安裝到 C 盤(推薦),如果希望換一個盤安裝,可以點擊 Customize installation 在里面選擇其他的盤,
- 在 macOS 上安裝 Python:
-
- 其實 macOS 上是默認安裝了 Python 的,只不過版本是 Python2.7,其相對于現在的 Python 3 缺少了很多特性,而且速度也比 Python 3 慢,因此還是建議大家裝 Python 3,
-
- 同樣地,下載 Python 的最新版本,訪問鏈接:Python 官網,在 macOS 作業系統上安裝 Python 3.7.4,大家也可以自行選擇最新版的下載,

-
- 進入下一個頁面后,拉到最下面,選擇 macOS 64-bit universal2 installer 下載:

-
- 下載完成后得到一個 pkg 檔案,雙擊打開,按照指示步驟進行安裝即可,
② 安裝依賴
- 請選擇以下任一種方式輸入命令安裝依賴:
-
- Windows 環境打開 Cmd (開始-運行-CMD);
-
- MacOS 環境打開 Terminal (command + 空格輸入 Terminal);
-
- 如果用的是 VSCode 編輯器或 Pycharm,可以直接使用界面下方的 Terminal:
pip install kivy[base] kivy_examples
三、簡單使用 Kivy
- 首先,簡單介紹 Kivy 的基本使用,為游戲創建一個目錄和一個名為 main.py 的檔案:
# main.py
from kivy.app import App
from kivy.uix.widget import Widget
class PongGame(Widget):
pass
class PongApp(App):
def build(self):
return PongGame()
if __name__ == '__main__':
PongApp().run()
- 在命令列中輸入 python main.py 運行該應用程式,它應該只顯示一個黑色的視窗,因此我們所做的只是創建一個非常簡單的 Kivy 應用程式,它創建了一個 PongGame Widget 類的實體,并將其作為應用程式用戶界面的根元素回傳,
- 在這一點上應該把它想象成一個 Widget 的分層樹,Kivy 將這個 Widget 放在默認的視窗中,在下一步,我們將通過定義 PongGame 小部件的外觀來繪制 Pong 的背景和游戲分數,
四、Kivy - 添加簡單圖形
- 我們將使用一個 .kv 檔案來定義 PongGame 類的外觀,由于應用程式類被稱為 PongApp,可以簡單地在同一目錄下創建一個名為 pong.kv 的檔案,當應用程式運行時將會自動加載,
- 因此,為了定義游戲的外觀,創建一個名為 pong.kv 的新檔案并添加以下內容:
#:kivy 1.0.9
<PongGame>:
canvas:
Rectangle:
pos: self.center_x - 5, 0
size: 10, self.height
Label:
font_size: 70
center_x: root.width / 4
top: root.top - 50
text: "0"
Label:
font_size: 70
center_x: root.width * 3 / 4
top: root.top - 50
text: "0"
- 注意一個常見錯誤:kv檔案的名稱,例如 pong.kv,必須與應用程式的名稱一致,例如 PongApp(Ap p結尾之前的部分),
- 如果現在運行這個應用程式,應該看到中間有一個豎條,還有兩個零,那里將顯示玩家的分數,如下所示:

- 可以看到,在第一行有:
#:kivy 1.0.9
- 每個 kv 檔案都需要第一行,它應該以 #:kivy 及一個空格開頭,然后是它要使用的 Kivy 版本(因此 Kivy 可以確保您至少擁有所需的版本,或者稍后處理向后兼容性),
- 再往下看 kv 檔案里定義了三個元素,一個 canvas 和兩個 label:
-
- 先說說兩個 label,它們代表的是左右兩個數字,設定了 font_size(字體大小), center_x(中心位置), top(離頂部距離),text(文本),此外可以看到 root.width 和 root.top 的使用,這樣寫的好處是能跟跟隨視窗寬度和高度的變化而變化,
-
- 另一個元素 canvas,它的下面定義了 Rectangle 引數,意思是向畫布添加一個矩形,將矩形的 pos 設定為小部件水平中心左側 5 個像素,y 設定為 0,這就定義了矩形的顯示位置,
- 矩形的大小 size 設定為寬度為 10 像素,高度為小部件的高度,像這樣定義圖形的好處是,當值運算式中使用的任何小部件的屬性發生變化時,渲染的矩形將自動更新,
五、Kivy - 增加乒乓球球體
- 現在有了一個基本的乒乓球場(雖然很簡陋),但我們仍然需要球拍和一個球來打球,從球開始,添加一個新的 PongBall 類來創建一個小部件,它將成為我們的球并使它彈跳起來,
- PongBall 類:
class PongBall(Widget):
# velocity of the ball on x and y axis
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
# referencelist property so we can use ball.velocity as
# a shorthand, just like e.g. w.pos for w.x and w.y
velocity = ReferenceListProperty(velocity_x, velocity_y)
# ``move`` function will move the ball one step. This
# will be called in equal intervals to animate the ball
def move(self):
self.pos = Vector(*self.velocity) + self.pos
- 白球的 kv 配置如下:
<PongBall>:
size: 50, 50
canvas:
Ellipse:
pos: self.pos
size: self.size
- 為了使這一切順利進行,還必須為球體增加所用的 Property 屬性類,如下,是這一步更新后的 python 代碼和 kv 檔案:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ReferenceListProperty
from kivy.vector import Vector
class PongBall(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
velocity = ReferenceListProperty(velocity_x, velocity_y)
def move(self):
self.pos = Vector(*self.velocity) + self.pos
class PongGame(Widget):
pass
class PongApp(App):
def build(self):
return PongGame()
if __name__ == '__main__':
PongApp().run()
- kv 檔案如下:
#:kivy 1.0.9
<PongBall>:
size: 50, 50
canvas:
Ellipse:
pos: self.pos
size: self.size
<PongGame>:
canvas:
Rectangle:
pos: self.center_x - 5, 0
size: 10, self.height
Label:
font_size: 70
center_x: root.width / 4
top: root.top - 50
text: "0"
Label:
font_size: 70
center_x: root.width * 3 / 4
top: root.top - 50
text: "0"
PongBall:
center: self.parent.center
六、Kivy - 增加乒乓球體運動
- 現在我們的目的是讓這個球動起來,因此必須定期呼叫 move 函式讓它動起來,使用 Kivy 提供的 Clock 函式可以輕易地做到這一點:
Clock.schedule_interval(game.update, 1.0/60.0)
- 這一行將導致游戲物件的更新函式每秒被呼叫 60 次,
- 不過還有一個問題,想確保 PongBall 的移動函式被定期呼叫,但是在代碼中沒有任何對球物件的參考,因為只是通過 kv 檔案在 PongGame 類的 kv 規則中添加了它,
- 由于要做的不僅僅是移動球(比如把球從墻上彈下來,然后再彈到球員的球拍上),我們可能需要為 PongGame 類建立一個更新方法:
class PongGame(Widget):
def update(self, dt):
# call ball.move and other stuff
pass
class PongApp(App):
def build(self):
game = PongGame()
Clock.schedule_interval(game.update, 1.0/60.0)
return game
- 然而,這仍然不能改變我們沒有對 kv 規則所創建的 PongBall 進行操作的這一事實,為了解決這個問題,可以給 PongGame 類添加一個 ObjectProperty,并將其與 kv 規則中創建的 widget 掛鉤,
- 一旦這樣做了,就可以很容易地在更新方法中參考球的屬性,甚至可以讓它從邊緣彈起:
class PongGame(Widget):
ball = ObjectProperty(None)
def update(self, dt):
self.ball.move()
# bounce off top and bottom
if (self.ball.y < 0) or (self.ball.top > self.height):
self.ball.velocity_y *= -1
# bounce off left and right
if (self.ball.x < 0) or (self.ball.right > self.width):
self.ball.velocity_x *= -1
- 在 kv 檔案中將其與代碼中設定的 id: ball 映射起來:
<PongGame>:
ball: pong_ball
# ... (canvas and Labels)
PongBall:
id: pong_ball
center: self.parent.center
七、Kivy - 球拍移動事件
- 現在,球正在彈來彈去,唯一缺少的是可移動的球拍和對分數的跟蹤,這里不會再去討論創建類和 kv 規則的所有細節,因為這些概念已經在前面的步驟中涵蓋了,
- 相反,把重點放在如何回應用戶的輸入而移動球拍上,在 Kivy 中,小部件可以通過實作 on_touch_down、on_touch_move 和 on_touch_up 方法對輸入做出反應,默認情況下,Widget 類實作這些方法時,只是在其子部件上呼叫相應的方法來傳遞事件,直到其中一個子部件回傳 True,
- 乒乓運動是非常簡單的,球拍只需要向上和向下移動,事實上,它是如此簡單,甚至不需要讓球員小部件自己處理事件,只需為 PongGame 類實作 on_touch_move 函式:
def on_touch_move(self, touch):
if touch.x < self.width/3:
self.player1.center_y = touch.y
if touch.x > self.width - self.width/3:
self.player2.center_y = touch.y
- 我們將在 NumericProperty 中保留每個球員的分數,PongGame 的分數標簽通過改變 NumericProperty score 來保持更新,這反過來又會更新 PongGame 的子標簽文本屬性,
- 這是如何實作的?因為 Kivy 屬性會自動系結到其對應的kv檔案中的任何參考,當球從兩側逃出時,我們將通過 PongGame 類中的更新方法來更新分數并再次發球,
- PongPaddle 類也實作了一個 bounce_ball 方法,這樣球就會根據它擊中球拍的位置而產生不同方向的彈跳,非常有意思,下面是 PongPaddle 類的代碼:
class PongPaddle(Widget):
score = NumericProperty(0)
def bounce_ball(self, ball):
if self.collide_widget(ball):
speedup = 1.1
offset = 0.02 * Vector(0, ball.center_y-self.center_y)
ball.velocity = speedup * (offset - ball.velocity)
- 結果如下:

- 到這一步,基本就完成了整個乒乓球游戲的制作,如何,你心動了嗎?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/321469.html
標籤:其他
下一篇:勇闖迷塔小游戲(c++)
