zoukankan      html  css  js  c++  java
  • 『Python Kivy』官方乒乓球游戏示例解析

    本篇文章用于对Kivy框架官方所给出的一个「乒乓球」小游戏的源码进行简单地解析。我会尽可能的将方方面面的内容都说清楚。在文章的最下方为官方所给出的这个小游戏的教程以及游戏源码。

    由于篇幅所限,本文只简单介绍Kivy框架,对于Python语言的简介,请大家通过别的文章进行学习。

    Kivy简介

    Kivy 是基于Python编程语言的一种用于开发跨平台GUI客户端程序的框架。可以打包成iOS、Android、Windows、OSX等多种平台。目前已经实现一次编码,到处运行的目的。

    Kivy框架主要包含两种文件,一种为Python源码文件,一种为KV文件。Python源码文件用于控制程序的运行逻辑,KV文件用于定义用户界面。

    由于Kivy本质上是使用OpenGL进行界面的绘制的,而且通过对Kivy的经典应用「2048 by kivy」进行了简单的运行,Kivy所开发出的应用,在性能上还是可圈可点的,从某种程度上来说,要比使用HTML5/JS的应用在性能以及稳定性上,要好很多。

    关于Kivy框架的基本使用以及开发环境,可以参考我的另外两篇文章:

    创建应用

    from kivy.app import App
    from kivy.uix.widget import Widget
    
    from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty
    from kivy.vector import Vector
    from kivy.clock import Clock
    
    from random import randint
    
    class PongGame(Widget):
        pass
    
    class PongApp(App):
        def build(self):
            return PongGame()
    
    if __name__ == '__main__':
        PongApp().run()
    
    • App类是创建Kivy应用的基础。我们可以认为它是整个应用的入口,如果在我们的应用中没有引入这个类的话,我们的应用是没有办法运行起来的。
    • Widget类是创建一个「Widget」的基础。Widget是我们绘制界面最重要的类,我们的界面元素都应该继承它,不论是内置好的「文本框」还是用于绘制我们自定义界面元素的「画布」,都需要引入这个类,才能够正常工作。
    • PongGame是一个「界面元素」类,在整个Pong示例中,小球、球拍等,都是界面元素,所不同的仅仅是界面元素的层级关系。
    • PongApp是我们的「主程序」类,主要用于各种操作以及界面元素的交互等的调度。不建议在这里写入太复杂的逻辑,因为如果把复杂逻辑写在这里的话,随着我们应用的不断扩展、维护,这个类将逐步陷入「不可维护」的尴尬境地。
    • 最后一块用于「启动应用」。每一个Kivy应用都应该有这段代码。

    在Kivy中,我们使用XXXApp来控制应用的运行,使用XXX来控制应用的行为,比如PongApp以及PongGame

    绘制界面

    kv文件是kivy框架所使用的界面描绘文件,类似于c#的xaml。我们可以在kv文件中,添加各种由kivy框架本身所提供的控件,比如buttonlabel等。还可以在kv文件中使用canvas标签,并在其中绘制各种图形,比如矩形、圆形等

    在kv文件中,对于界面的描绘,是__树形__的,也就是说,在最顶层需要一个__根节点__用来作为整个应用的根。

    #:kivy 1.8.0
    
    <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文件中,

    • 第一行#:kivy 1.8.0声明当前kv文件中所用到的kivy的版本。(当前最新的版本是1.9.0 beta)
    • canvas向应用中添加了一个画板,用于在界面中绘制乒乓球游戏的各种挡板之类的界面元素。
    • 之后在canvas中对画板进行设置,包括画板的位置、尺寸等。
    • 每一个根标签,都将对应于在项目文件中的一个类。
    • 在最后加入两个标签,并在标签中设置相应的属性,这里包括字号、位置、默认文字。

    添加小球

    小球类

    # ...
    
    class PongBall(Widget):
        # 小球在x、y轴上的速度
        velocity_x = NumericProperty(0)
        velocity_y = NumericProperty(0)
    
        # 创建索引属性列表,以精简对坐标属性的使用。
        velocity = ReferenceListProperty(velocity_x, velocity_y)
    
        # ``move`` 方法将移动小球一步。
        # 这个方法将会在需要小球移动的时候被调用。
        def move(self):
            self.pos = Vector(*self.velocity) + self.pos
    
    # ...
    
    
    • 为了让我们的小球会动,我们需要给小球一个位置,然后控制这个位置以一定的速度进行改变,从而实现让小球移动的目的。
    • ReferenceListProperty 允许创建一个由其他属性构成的__元组__。在这里,我们提供了两个数值型属性,用于标示坐标。
    • 在PongBall类中,我们提供用于控制速度与位置的类属性,以及一个用于控制移动的方法。
    • kivy.vector.Vector(*largs) 用于表示一个矢量。利用矢量属性与当前的位置,可以控制移动的方向以及速度。

    绘制小球

    <PongBall>:
        size: 50, 50
        canvas:
            Ellipse:
                pos: self.pos
                size: self.size
    

    加入球拍

    绘制球拍

    <PongPaddle>:
        size: 25, 200
        canvas:
            Rectangle:
                pos:self.pos
                size:self.size
    
    ...
    
    <PongGame>:
        ...
    
        player1: player_left
        player2: player_right
    
        ...
    
        PongPaddle:
            id: player_left
            x: root.x
            center_y: root.center_y
            
        PongPaddle:
            id: player_right
            x: root.width-self.width
            center_y: root.center_y
    

    事件处理

    class PongPaddle(Widget):
        score = NumericProperty(0)
    
        def bounce_ball(self, ball):
            if self.collide_widget(ball):
                vx, vy = ball.velocity
                offset = (ball.center_y - self.center_y) / (self.height / 2)
                bounced = Vector(-1 * vx, vy)
                vel = bounced * 1.1
                ball.velocity = vel.x, vel.y + offset
    
    # ...
    
    class PongGame(Widget):
        ball = ObjectProperty(None)
        player1 = ObjectProperty(None)
        player2 = ObjectProperty(None)
    
        def serve_ball(self, vel=(4, 0)):
            self.ball.center = self.center
            self.ball.velocity = vel
    
        def update(self, dt):
            self.ball.move()
    
            # 敲击小球
            self.player1.bounce_ball(self.ball)
            self.player2.bounce_ball(self.ball)
    
            # 限定小球在屏幕中的上下边界
            if (self.ball.y < self.y) or (self.ball.top > self.top):
                self.ball.velocity_y *= -1
    
            #went of to a side to score point?
            if self.ball.x < self.x:
                self.player2.score += 1
                self.serve_ball(vel=(4, 0))
            if self.ball.x > self.
                self.player1.score += 1
                self.serve_ball(vel=(-4, 0))
    
        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
    

    参考资料

  • 相关阅读:
    游标、锁
    树形背包浅谈
    金字塔
    Codeforces Round #652 (Div. 2) 题解
    NOI1999 棋盘分割
    NEERC2002 Folding
    HDU4283 You Are the One
    Codeforces Round #646 (Div. 2) 题解
    洛谷 P1679 神奇的四次方数
    UVA12563 劲歌金曲
  • 原文地址:https://www.cnblogs.com/sitemanager/p/4111520.html
Copyright © 2011-2022 走看看