为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用 pygame 编写 pong 中的弹跳运动代码

如何使用 pygame 编写 pong 中的弹跳运动代码

千万里不及你 2023-09-12 17:25:44
我是 python 菜鸟,我正在尝试重新创建 Pong 游戏,并且我正在尝试尽可能地自己完成。这些是我的代码当前遇到的问题:我基本上对球在边缘弹跳时的每一种可能的运动进行了编码。我花了几个小时的时间来研究它,并且让它工作起来,我只是想知道是否有一种更有效的方法可以用我的代码产生类似的输出(因为我知道这应该是一个初学者项目)?每次球弹过边缘时,分数就会瞬间增加,每次球重生时分数都会回到 0。如何使球在随机方向上产生?在每轮开始(和重新开始)时?这是我的类代码和程序的主要功能:import pygameimport randomfrom rect_button import Buttonpygame.init()WIDTH = 800HEIGHT = 500window = pygame.display.set_mode((WIDTH, HEIGHT))TITLE = "Pong"pygame.display.set_caption(TITLE)# COLORSblack = (0, 0, 0)white = (255, 255, 255)red = (255, 0, 0)green = (0, 255, 0)# FONTSsmall_font = pygame.font.SysFont("courier", 20)large_font = pygame.font.SysFont("courier", 60, True)class Paddle:    def __init__(self, x, y, width, height, vel, color):        self.x = x        self.y = y        self.width = width        self.height = height        self.vel = vel        self.color = color    def draw(self, window):        pygame.draw.rect(window, self.color, (self.x, self.y, self.width, self.height), 0)class Ball:    def __init__(self, x, y, side, vel, color):        self.x = x        self.y = y        self.side = side        self.vel = vel        self.color = color        self.lower_right = False        self.lower_left = True        self.upper_right = False        self.upper_left = False        self.ball_bag = []        self.last_movement = 'ball.lower_right'    def draw(self, window):        pygame.draw.rect(window, self.color, (self.x, self.y, self.side, self.side), 0)    def move_lower_right(self):        self.x += self.vel        self.y += self.vel    def move_upper_right(self):        self.x += self.vel        self.y -= self.vel    def move_upper_left(self):        self.x -= self.vel        self.y -= self.vel
查看完整描述

4 回答

?
繁星点点滴滴

TA贡献1803条经验 获得超3个赞

回答


每次球弹过边缘时,分数就会瞬间增加,每次球重生时分数都会回到 0。

分数在主循环中不断初始化。您必须在循环之前初始化分数:


def main():

    # [...]


    score_A = 0 # <--- INSERT

    score_B = 0

    

    while run:

        # score_A = 0 <--- DELETE

        # score_B = 0


查看完整回答
反对 回复 2023-09-12
?
撒科打诨

TA贡献1934条经验 获得超2个赞

回答问题1:是的。肯定有很多更有效的方法来做事。没有必要为方向制造那么多变数。简单地说direction = [True, False],其中direction[0]代表not direction[0]x 轴的左,代表右。同样,direction[1]代表 y 轴。这也解决了您在开始时随机化方向的问题。您只需 direction = [random.randint(0, 1), random.randint(0, 1)]在 init 方法中执行即可随机化方向。同样的方式,也列出速度清单。self.speed = [0.5, random.uniform(0.1, 1)]。这样,左右方向的速度将始终相同,但 y 将根据所选的随机数而变化,因此存在适当的随机性,并且您也不必硬编码随机方向。这样,移动变得非常简单。


class Ball:

def __init__(self, x, y, color, size):

    self.x = x

    self.y = y

    self.color = color

    self.size = size

    self.direction = [random.randint(0, 1), random.randint(0, 1)]

    self.speed = [0.5, random.uniform(0.1, 1)]

    

def draw(self, display):

    pygame.draw.rect(display, self.color, (self.x, self.y, self.size, self.size))


def move(self):

    if self.direction[0]:

        self.x += self.speed[0]

    else:

        self.x -= self.speed[0]

    if self.direction[1]:

        self.y += self.speed[0]

    else:

        self.y -= self.speed[0]

因为我们定义的方向方向是布尔值,所以改变状态也变得非常容易。如果球击中球拍,您可以简单地切换direction[0] = not direction[0]x 中的布尔值并为 y 选择一个新的随机数,而不是手动分配布尔值。


def switchDirection(self):

    self.direction = not self.direction

    self.speed[1] = random.uniform(0.1, 1)

move通过为 Paddle 类提供一个函数而不是在主循环中移动,Paddle 也可以稍微改进。这只是意味着您必须编写更少的代码。


def move(self, vel, up=pygame.K_UP, down=pygame.K_DOWN):

    keys = pygame.key.get_perssed()

    if keys[up]:

        self.y -= vel

    if keys[down]:

        self.y += vel

对于碰撞,我建议使用pygame.Rect()andcolliderect因为它更强大并且可能也更有效。


例子:


import random

import pygame


WIN = pygame.display

D = WIN.set_mode((800, 500))


class Paddle:

    def __init__(self, x, y, width, height, vel, color):

        self.x = x

        self.y = y

        self.width = width

        self.height = height

        self.vel = vel

        self.color = color


    def move(self, vel, up=pygame.K_UP, down=pygame.K_DOWN):

        keys = pygame.key.get_pressed()

        if keys[up]:

            self.y -= vel

        if keys[down]:

            self.y += vel

        

    def draw(self, window):

        pygame.draw.rect(window, self.color, (self.x, self.y, self.width, self.height), 0)


    def getRect(self):

        return pygame.Rect(self.x, self.y, self.width, self.height)


left_paddle = Paddle(20, 100, 10, 50, 5, (0, 0, 0))

right_paddle = Paddle(770, 350, 10, 50, 5, (0, 0, 0))


class Ball:

    def __init__(self, x, y, color, size):

        self.x = x

        self.y = y

        self.color = color

        self.size = size

        self.direction = [random.randint(0, 1), random.randint(0, 1)]

        self.speed = [0.3, random.uniform(0.2, 0.2)]

        

    def draw(self, window):

        pygame.draw.rect(window, self.color, (self.x, self.y, self.size, self.size))


    def switchDirection(self):

        self.direction[0] = not self.direction[0]

        self.direction[1] = not self.direction[1]

        self.speed = [0.2, random.uniform(0.1, 0.5)]


    def bounce(self):

        self.direction[1] = not self.direction[1]

        self.speed = [0.2, random.uniform(0.01, 0.2)]

        

    def move(self):

        if self.direction[0]:

            self.x += self.speed[0]

        else:

            self.x -= self.speed[0]

        if self.direction[1]:

            self.y += self.speed[1]

        else:

            self.y -= self.speed[1]


    def getRect(self):

        return pygame.Rect(self.x, self.y, self.size, self.size)


    def boundaries(self):

        if ball.x <= 10:

            self.switchDirection()

        if ball.x + self.size >= 800:

            self.switchDirection()

        if ball.y + self.size >= 490:

            self.bounce()

        if ball.y <= 0:

            self.bounce()



ball = Ball(400, 250, (255, 0, 0), 20)

while True:

    pygame.event.get()

    D.fill((255, 255, 255))


    ball.draw(D)

    ball.boundaries()

    ball.move()

    #print(ball.x, ball.y)

    

    left_paddle.draw(D)

    right_paddle.draw(D)


    right_paddle.move(0.4)

    left_paddle.move(0.4, down=pygame.K_s, up=pygame.K_w)


    if left_paddle.getRect().colliderect(ball.getRect()):

        ball.switchDirection()

    if right_paddle.getRect().colliderect(ball.getRect()):

        ball.switchDirection()

    

    WIN.flip()


查看完整回答
反对 回复 2023-09-12
?
胡说叔叔

TA贡献1804条经验 获得超8个赞

我基本上对球在边缘弹跳时的每一种可能的运动进行了编码。我花了几个小时的时间来研究它,并且让它工作起来,我只是想知道是否有一种更有效的方法可以用我的代码产生类似的输出(因为我知道这应该是一个初学者项目)?

如何使球在随机方向上产生?在每轮开始(和重新开始)时?

您可以使用浮动坐标,而不是实现球的“每个”方向。这些变量通常称为 dx 和 dy。通过这种方式获得球的随机或反向方向很简单,只需使用 dx 和 dy 的随机或反向值即可。

你的球的更新应该如下所示:

def update(self. dt):
    self.x += self.dx * self.speed * time_elapsed
    self.y += self.dy * self.speed * time_elapsed # Time elasped is often called dt.

每次球弹过边缘时,分数就会瞬间增加,每次球重生时分数都会回到 0。

理想情况下,您应该有一个 GameState 对象,其中包含分数、生命和其他内容作为属性。



查看完整回答
反对 回复 2023-09-12
?
SMILET

TA贡献1796条经验 获得超4个赞

关于如何减少所有球运动/碰撞代码并提高可重用性的一些值得思考的地方:


import pygame



class Ball:


    def __init__(self, bounds, color):

        from random import randint, choice

        self.bounds = bounds

        self.position = pygame.math.Vector2(

            randint(self.bounds.left, self.bounds.left+self.bounds.width),

            randint(self.bounds.top, self.bounds.top+self.bounds.height)

        )

        self.velocity = pygame.math.Vector2(choice((-1, 1)), choice((-1, 1)))

        self.color = color

        self.size = 8


    def draw(self, window):

        pygame.draw.rect(

            window,

            self.color,

            (

                self.position.x-self.size,

                self.position.y-self.size,

                self.size*2,

                self.size*2

            ),

            0

        )


    def update(self):

        self.position.x += self.velocity.x

        self.position.y += self.velocity.y

        if not self.bounds.left+self.size < self.position.x < self.bounds.left+self.bounds.width-self.size:

            self.velocity.x *= -1

        if not self.bounds.top+self.size < self.position.y < self.bounds.top+self.bounds.height-self.size:

            self.velocity.y *= -1



def main():


    from random import randint


    window_width, window_height = 800, 500


    window = pygame.display.set_mode((window_width, window_height))

    pygame.display.set_caption("Pong")


    clock = pygame.time.Clock()


    black = (0, 0, 0)

    white = (255, 255, 255)


    padding = 20


    bounds = pygame.Rect(padding, padding, window_width-(padding*2), window_height-(padding*2))


    ball = Ball(bounds, white)


    def redraw_window():

        window.fill(black)

        pygame.draw.rect(

            window,

            white,

            (

                padding,

                padding,

                window_width-(padding*2),

                window_height-(padding*2)

            ),

            1

        )


        ball.draw(window)


        pygame.display.update()


    while True:

        clock.tick(60)

        ball.update()

        for event in pygame.event.get():

            if event.type == pygame.QUIT:

                break

        else:

            redraw_window()

            continue

        break

    pygame.quit()

    return 0

        


if __name__ == "__main__":

    import sys

    sys.exit(main())

这不是一个完整的替代品,我只是重新实现了该类Ball。没有桨。本质上,在实例化一个球时,您传递一个pygame.Rect,它描述了允许球弹跳的边界。您还传递一个颜色元组。然后,球在边界内选择一个随机位置(该位置是 a pygame.math.Vector2,而不是存储x和y作为单独的实例变量)。球也有速度,它也是pygame.math.Vector2,因此您可以拥有独立的速度分量 - 一个用于x(水平速度),一个用于y(垂直速度)。球size的 简单地描述了球的尺寸。例如,如果size设置为8,则球将为 16x16 像素。


该类Ball还有一个update方法,每个游戏循环迭代都会调用该方法。它将球移动到速度决定的下一个位置,并检查球是否与边界碰撞。如果是,则反转相应的速度分量。


查看完整回答
反对 回复 2023-09-12
  • 4 回答
  • 0 关注
  • 80 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信