Python-kivy实现一个简单的弹球游戏(包含对常见规则的改进,以及界面的简单美化)

目录

 前言:

一、规则的简单说明

(1)关于碰撞

(2)关于计分

二、关于规则的改进

(1)关于小球运行

(2)关于智障AI的添加

(3) 关于界面的美化

 (4)添加背景音效和音乐

三、其他细节的强调

(1)widget组件

(2)kv中的画布和标签

四、完整代码

五、不足总结


 前言:

        这还是我学校学习课程上的一个项目,因为我也要考研,就没有花费太多时间去做很好的项目。所以基于网上的一个乒乓球游戏做了一些简单的改进。如下是我参考的文档和源码下载地址,大家有需要可以自取:

GitHub - attreyabhatt/Kivy-Pong-Game: Pong game created using Kivyhttps://github.com/attreyabhatt/Kivy-Pong-Game

        如果想要了解我做的这个项目,最后可以先看下面这个文档,介绍了它最基本的运行逻辑: 

乒乓球游戏教程 — Kivy 2.1.0 文档https://kivy.org/doc/stable/tutorials/pong.html


一、规则的简单说明

(1)关于碰撞

        众所周知,弹球游戏的碰撞逻辑:当小球碰到板子或边界会进行反弹,碰到上下边界要反转竖直速度,碰到左右边界要反转水平速度。

(2)关于计分

        对于计分规则更是多种多样,首先你可以定义碰到板子就加分,或者碰到己方边界,给对面加分等等。分值也是可以进行设定的。

二、关于规则的改进

(1)关于小球运行

        小球的运行过程中是符合逻辑的,这样会使得玩家在游玩的时候会预判到小球的走向,大大降低了难度,所以我在这里设置了一个无规则运行的逻辑,同时球的速度和大小会随时间进行随机改变。下面用代码说明一下:

        我先定义了几个参数,方便后续对速度和大小的改变:

speed_x = NumericProperty(0)  # 球的水平速度属性
speed_y = NumericProperty(0)  # 球的垂直速度属性
speed = ReferenceListProperty(speed_x, speed_y)  # 球的速度向量属性
r =  NumericProperty(0)   #球的大小属性
max_speed = 5  # 球的最大速度

        接着,move函数是对小球的位置进行实时更新的。而randomize函数则是小球的速度是不断变化的,其中vel_y和vel_x正数就是代表向上和向右的速度,负数反之。daxiao函数让球在20*20到80*80之前随机变化。

 def move(self):
        self.pos = Vector(*self.speed) + self.pos  # 根据速度更新球的位置

 def randomize(self):
        # 随机化速度
        vel_x = uniform(-5, 5)  # 在[-5, 10]范围内生成一个随机数作为水平速度
        vel_y = uniform(-5, 5)  # 垂直速度
        self.speed = Vector(vel_x, vel_y).normalize() * self.max_speed  # 设置球的速度向量,并将其归一化后乘以最大速度


 def daxiao(self):
        # 随机化大小
        r = uniform(20, 80)
        self.size = r , r # 在[20, 80]范围内生成一个随机数作为球的大小
        print(self.size)

        接着在后续的类中进行调用

def serve_ball(self):
     self.ball.center = self.center  # 将球的中心位置设置为窗口的中心位置
     self.ball.randomize()  # 随机化球的速度
     self.ball.daxiao()     # 随机化球的大小
     self.timer = 0  # 计时器初始化为0

(2)关于智障AI的添加

        为什么叫它智障AI呢?顾名思义,就是它的实现逻辑太简单了,我们只需要让其中一个板子的中心跟着球的中心移动就行了,并且设置好运行速度,是不是很简单阿巴巴(• •)~

def move_player2(self):
        # 根据球的位置移动玩家2的挡板
        if self.ball.center_y < self.player2.center_y:
            self.player2.center_y -= 5  # 将玩家2的挡板向下移动5个单位
        elif self.ball.center_y > self.player2.center_y:
            self.player2.center_y += 5

        然后记得在前面调用哦,这样板子就会随着我们的小球去动了,这样就不用自己一个人控制两个玩家了。当然你也可以把player1的板子也设置成自动的,这样就可以看两个板子自己玩了。

(3) 关于界面的美化

        关于界面的美化我们主要是修改kv文件,以下我的完整的kv文件,我们可以设置大小、颜色等等,对于其中的具体参数,大家可以去网上查阅参考。

<PongBall>:
    canvas:
        Color:
            rgba: .9,.9,.1 ,9
        Ellipse:
            pos: self.pos
            size: self.size
            source: "出生.jpg"

<PongPaddle>:
    size: 25, 150
    canvas:
        Color:
            rgba: 1, 1, 1, .9
        Rectangle:
            pos: self.pos
            size: self.size
            source: "无标题.png"

<PongGame>:
    ball: pong_ball
    player1: player_left
    player2: player_right
    canvas:
        Color:
            rgba:1, 1, 1, .9
        Rectangle:
            size:self.size
            source:"233.jpg"
        Color:
            rgba: .2, 1, 1, .9
        Rectangle:
            pos: self.center_x - 5, 0
            size: 10, self.height

    Label:
        color: .9,.6,.1 ,9
        font_size: 70
        center_x: root.width / 4
        top: root.top - 50
        text: str(root.player2.score)

    Label:
        color: .8,.1,.1 ,9
        font_size: 70
        center_x: root.width * 3/4
        top: root.top - 50
        text: str(root.player1.score)

    PongBall:
        id: pong_ball
        center: self.parent.center

    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

         下面是我用到的一些图片:

         最终得到的界面效果如下:

 (4)添加背景音效和音乐

        对于添加音效和音乐,我们要使用kivy的一个库:

from kivy.core.audio import SoundLoader

        我们只需要下面几行代码:

sound = SoundLoader.load('away.mp3')
        if sound:
            sound.loop = True  # 设置循环播放
            sound.play()

三、其他细节的强调

(1)widget组件

1. Widget不是布局,Widget不会改变其包含的子组件的位置与大小。
2. Widget的默认大小是100*100。
3. Widget的size_hint默认是1*1,如果其父组件是一个布局组件,则其大小是父组件中的布局需要的大小。
4. on_touch_down(), on_touch_move(), on_touch_up() 等函数不进行组件边界范围判定(碰撞判定),需要调用collide_point()。

(2)kv中的画布和标签

Canvas:创建画布,下面是一些Canvas的属性介绍:

        1 .add(): 向画布中添加一个图形对象,可以是图形或者组。

        2. insert(): 在画布中指定位置之前插入一个图形对象。

        3. remove(): 从画布中删除指定的图形对象。

        4. clear(): 从画布中删除所有图形对象。

        5. size: 画布的大小,其值决定了画布的尺寸。

        6. pos: 画布的位置,其值决定了画布相对于父控件的位置。

        7. opacity: 画布的不透明度,其值在0-1之间。

        8. canvas.before: 在画布中的所有元素之前绘制的图形对象。

        9. canvas.after: 在画布中的所有元素之后绘制的图形对象。

        10. canvas.clear(): 清除整个画布。

        11. canvas.ask_update(): 强制更新画布的内容。

        12. canvas.export_to_png(): 将画布保存到PNG文件中。

Label标签:在Kivy中,Label小部件用于呈现文本,它仅支持ASCII和Unicode编码的字符串(不支持中文),在Label中,可以设置文本内容、字体、大小、颜色、对齐方式、换行、引用以及标记文字等内容

        1. text:标签显示的文本

        2. text_size:标签文本大小

        3. font_name:要使用字体的文件名

        4. font_size:文本的字体大小

        5. bold:字体使用粗体

        6. italic:字体使用斜体

        7. color:字体颜色,格式为rgba,默认为白色[1,1,1,1]

        8. halign:文本的水平对齐方式,可选参数为:left、center、right、justify

        9. valign:文本的垂直对齐方式,可选参数为:bottom、middle(或center)、top

        10. markup:是否分割所有标记的文本

        11. underline:在文本上添加下划线

        12. padding_x:小部件框内文本的水平填充

        13. padding_y:小部件框内文本的垂直填充

        14. texture:文本的纹理对象,属性更改时会自动呈现文本

        15. texture_size 文本的纹理大小,由字体大小和文本确定

        16. strikethrough:在文本中添加删除线

        17. strip:是否删除空格以及换行符

        18. outline_color:文本轮廓的颜色

        19. outline_width:文本周围轮廓的宽度,单位为像素

        20. max_line:要使用的最大行数,默认为0,表示无限制

        21. shorten:是否应该尽可能缩短文本内容,默认为False

        22. shorten_from:在哪一侧缩短文本,默认为center,可选参数为:left、right和center

        23. is_shortend:是否以缩短时间的方式进行渲染

        24. line_height:文本的行高,默认为1.0

四、完整代码

        注释我已经给大家写的很详细了,大家有问题可以随时留言提问哦或者私聊我

        py代码:

from random import randint, uniform  # 导入randint和uniform函数用于生成随机数
from kivy.app import App  # 导入App类,用于创建应用
from kivy.clock import Clock  # 导入Clock类,用于调度函数的定时器
from kivy.core.audio import SoundLoader
from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty  # 导入各种属性类,用于定义属性
from kivy.uix.widget import Widget  # 导入Widget类,用于创建控件
from kivy.vector import Vector  # 导入Vector类,用于处理向量运算
from kivy.core.window import Window

class PongPaddle(Widget):
    score = NumericProperty(0) # 分数属性,用于记录得分

    def bounce_ball(self, ball):
        if self.collide_widget(ball): # 如果球与挡板相撞
            ball.speed_x *= -1.1 # 改变球的水平速度,反弹出去


class PongBall(Widget):
    speed_x = NumericProperty(0)  # 球的水平速度属性
    speed_y = NumericProperty(0)  # 球的垂直速度属性
    speed = ReferenceListProperty(speed_x, speed_y)  # 球的速度向量属性
    r =  NumericProperty(0)   #球的大小属性
    max_speed = 5  # 球的最大速度

    def move(self):
        self.pos = Vector(*self.speed) + self.pos  # 根据速度更新球的位置

    def randomize(self):
        # 随机化速度
        vel_x = uniform(-5, 5)  # 在[-5, 10]范围内生成一个随机数作为水平速度
        vel_y = uniform(-5, 5)  # 垂直速度
        self.speed = Vector(vel_x, vel_y).normalize() * self.max_speed  # 设置球的速度向量,并将其归一化后乘以最大速度


    def daxiao(self):
        # 随机化大小
        r = uniform(20, 80)
        self.size = r , r # 在[20, 80]范围内生成一个随机数作为球的大小
        print(self.size)


class PongGame(Widget):
    ball = ObjectProperty(None)  # 球的实例对象属性
    player1 = ObjectProperty(None)  # 玩家1挡板的实例对象属性
    player2 = ObjectProperty(None)  # 玩家2挡板的实例对象属性
    music = None


    def serve_ball(self):
        self.ball.center = self.center  # 将球的中心位置设置为窗口的中心位置
        self.ball.randomize()  # 随机化球的速度
        self.ball.daxiao()     # 随机化球的大小
        self.timer = 0  # 计时器初始化为0

    def update(self, dt):
        self.ball.move()
        if self.timer >= 3:   # 如果计时器大于等于3秒
            self.ball.randomize()  # 随机化球的速度和大小
            self.ball.daxiao()
            self.timer = 0 # 重置计时器为0
        else:
            self.timer += dt  # 更新计时器的值,增加经过的时间
        # 球与上下边界的碰撞检测,如果球的底部超出窗口底部或者球的顶部超出窗口顶部
        if (self.ball.y < 0) or (self.ball.top > self.height):
            self.ball.speed_y *= -1   # 反转球的垂直速度,使其向相反的方向运动
        # 球与左边界的碰撞检测,如果球的左边超出窗口左边界
        if self.ball.x < 0:
            self.ball.speed_x *= -1  # 反转球的水平速度,使其向相反的方向运动
            sound1 = SoundLoader.load('你好.mp3')
            if sound1:
                #sound1.loop = True
                sound1.play()
            self.player2.score += 1       # 2 + 1
        # 球与右边界的碰撞检测,如果球的右边超出窗口右边界
        if self.ball.right > self.width:
            self.ball.speed_x *= -1  # 反转球的水平速度,使其向相反的方向运动
            sound2 = SoundLoader.load('村民叫.mp3')
            if sound2:
                #sound2.loop = True  # 设置循环播放
                sound2.play()
            self.player1.score += 1      # 1 + 1
        self.player1.bounce_ball(self.ball)
        self.player2.bounce_ball(self.ball)
        self.move_player2()

    def move_player2(self):
        # 根据球的位置移动玩家2的挡板
        if self.ball.center_y < self.player2.center_y:
            self.player2.center_y -= 5  # 将玩家2的挡板向上移动5个单位
        elif self.ball.center_y > self.player2.center_y:
            self.player2.center_y += 5

    def on_touch_move(self, touch):
        if touch.x < self.width / 1 / 4:
            self.player1.center_y = touch.y   # 根据触摸点的y坐标移动玩家1的挡板的中心位置



class PongApp(App):
    def build(self):
        self.title = '一个弹球游戏嘿嘿嘿'
        game = PongGame()
        game.serve_ball()  # 开始游戏,将球放在中心位置并随机化速度和大小
        sound = SoundLoader.load('qsbl.mp3')
        if sound:
            sound.loop = True  # 设置循环播放
            sound.play()
        Clock.schedule_interval(game.update, 1.0 / 60.0)  # 使用Clock类的schedule_interval方法以1/60秒的间隔调用game.update函数

        return game

PongApp().run()  # 创建PongApp的实例对象并运行应用程序

        kv代码:

<PongBall>:
    canvas:
        Color:
            rgba: .9,.9,.1 ,9
        Ellipse:
            pos: self.pos
            size: self.size
            source: "出生.jpg"

<PongPaddle>:
    size: 25, 150
    canvas:
        Color:
            rgba: 1, 1, 1, .9
        Rectangle:
            pos: self.pos
            size: self.size
            source: "无标题.png"

<PongGame>:
    ball: pong_ball
    player1: player_left
    player2: player_right
    canvas:
        Color:
            rgba:1, 1, 1, .9
        Rectangle:
            size:self.size
            source:"233.jpg"
        Color:
            rgba: .2, 1, 1, .9
        Rectangle:
            pos: self.center_x - 5, 0
            size: 10, self.height

    Label:
        color: .9,.6,.1 ,9
        font_size: 70
        center_x: root.width / 4
        top: root.top - 50
        text: str(root.player2.score)

    Label:
        color: .8,.1,.1 ,9
        font_size: 70
        center_x: root.width * 3/4
        top: root.top - 50
        text: str(root.player1.score)

    PongBall:
        id: pong_ball
        center: self.parent.center

    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

五、不足总结

        仍有一些bug,比如速度过快会在边界一直卡死。对于难度的设置可以在做一个难度选择的界面,这样可以根据难度调整速度。

        希望这些可以帮助大家~如果觉得帮助到了你,请留个赞给我吧~

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,下面是一个简单弹球游戏Kivy实现: ```python 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 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): ball = ObjectProperty(None) def serve_ball(self): # 球的初始位置和速度随机生成 self.ball.center = self.center self.ball.velocity = Vector(randint(-8, 8), randint(-8, 8)) def update(self, dt): # 更新球的位置 self.ball.move() # 碰撞检测 if (self.ball.y < 0) or (self.ball.top > self.height): self.ball.velocity_y *= -1 if (self.ball.x < 0) or (self.ball.right > self.width): self.ball.velocity_x *= -1 def on_touch_move(self, touch): # 移动板子 if touch.x < self.width / 2: self.player1.center_y = touch.y if touch.x > self.width - self.width / 2: self.player2.center_y = touch.y class PongApp(App): def build(self): game = PongGame() game.serve_ball() Clock.schedule_interval(game.update, 1.0 / 60.0) return game if __name__ == '__main__': PongApp().run() ``` 这个弹球游戏包含一个球和两个板子,玩家通过触摸屏幕来移动板子,让球不落地,并通过板子将球反弹。游戏规则可以根据自己的喜好进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值