乐趣区

关于python:详细教程教你用Python-Kivy写一个乒乓球游戏

良久没有写游戏系列教程了,明天恰好浏览到了 Kivy 这个开源跨平台的 Python 框架,它能用于开发多点触控的用户界面程序,容许疾速简略的交互设计,十分不便,于是有了制作本教程的想法。

本教程将教你如何应用 Kivy 编写一款乒乓球游戏。咱们将从一个根本的应用程序开始,形容创立这个游戏的每个步骤。

Kivy 是用 Python 和 Cython 编写的,基于 OpenGL ES 2,反对各种输出设施并领有丰盛的部件库。应用雷同的代码,你可间接实现多平台利用,包含 Windows、macOS、Linux、Android 和 iOS。所有 Kivy 部件都反对多点触控。

1. 筹备

开始之前,你要确保 Python 和 pip 曾经胜利装置在电脑上。

(可选 1) 如果你用 Python 的目标是数据分析,能够间接装置 Anaconda,它内置了 Python 和 pip.

(可选 2) 此外,举荐大家用 VSCode 编辑器,它有许多的长处。

请抉择以下任一种形式输出命令装置依赖

  1. Windows 环境 关上 Cmd (开始 - 运行 -CMD)。
  2. MacOS 环境 关上 Terminal (command+ 空格输出 Terminal)。
  3. 如果你用的是 VSCode 编辑器 或 Pycharm,能够间接应用界面下方的 Terminal。
pip install kivy[base] kivy_examples

2. 简略应用 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 的背景和游戏分数。

3.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(App 结尾之前的局部)。

如果你当初运行这个应用程序,你应该看到两头有一个竖条,还有两个零,那里将显示玩家的分数,如下所示:

能够看到,在第一行,咱们有:

#: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 像素,高度为小部件的高度。像这样定义图形的益处是,当值表达式中应用的任何小部件的属性发生变化时,渲染的矩形将自动更新。

4. 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

5. 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

6. Kivy – 球拍挪动事件

当初,咱们的球正在弹来弹去。惟一短少的是可挪动的球拍和对分数的跟踪。咱们不会再去探讨创立类和 kv 规定的所有细节,因为这些概念曾经在后面的步骤中涵盖了。

相同,让咱们把重点放在如何响应用户的输出而挪动球拍上。你能够在 Python 实用宝典公众号后盾回复: 乒乓球 ** 取得全副代码和 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)

到这一步咱们根本就实现了整个游戏的制作,如何,你心动了吗?如果你想体验一下这个游戏,能够在 Python 实用宝典公众号后盾回复: 乒乓球 取得全副代码和 kv 规定。

咱们的文章到此就完结啦,如果你感觉文章还不错,欢送关注公众号:Python 编程学习圈 ,或是返回编程学习网,理解更多编程技术常识,还有大量干货学习材料能够支付!

退出移动版