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

我是 python 菜鸟,我正在尝试重新创建 Pong 游戏,并且我正在尝试尽可能地自己完成。

这些是我的代码当前遇到的问题:

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

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

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

这是我的类代码和程序的主要功能:

import pygame

import random

from rect_button import Button


pygame.init()


WIDTH = 800

HEIGHT = 500

window = pygame.display.set_mode((WIDTH, HEIGHT))


TITLE = "Pong"

pygame.display.set_caption(TITLE)


# COLORS

black = (0, 0, 0)

white = (255, 255, 255)

red = (255, 0, 0)

green = (0, 255, 0)


# FONTS

small_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


千万里不及你
浏览 107回答 4
4回答

繁星点点滴滴

回答每次球弹过边缘时,分数就会瞬间增加,每次球重生时分数都会回到 0。分数在主循环中不断初始化。您必须在循环之前初始化分数:def main():&nbsp; &nbsp; # [...]&nbsp; &nbsp; score_A = 0 # <--- INSERT&nbsp; &nbsp; score_B = 0&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; while run:&nbsp; &nbsp; &nbsp; &nbsp; # score_A = 0 <--- DELETE&nbsp; &nbsp; &nbsp; &nbsp; # score_B = 0

撒科打诨

回答问题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):&nbsp; &nbsp; self.x = x&nbsp; &nbsp; self.y = y&nbsp; &nbsp; self.color = color&nbsp; &nbsp; self.size = size&nbsp; &nbsp; self.direction = [random.randint(0, 1), random.randint(0, 1)]&nbsp; &nbsp; self.speed = [0.5, random.uniform(0.1, 1)]&nbsp; &nbsp;&nbsp;def draw(self, display):&nbsp; &nbsp; pygame.draw.rect(display, self.color, (self.x, self.y, self.size, self.size))def move(self):&nbsp; &nbsp; if self.direction[0]:&nbsp; &nbsp; &nbsp; &nbsp; self.x += self.speed[0]&nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; self.x -= self.speed[0]&nbsp; &nbsp; if self.direction[1]:&nbsp; &nbsp; &nbsp; &nbsp; self.y += self.speed[0]&nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; self.y -= self.speed[0]因为我们定义的方向方向是布尔值,所以改变状态也变得非常容易。如果球击中球拍,您可以简单地切换direction[0] = not direction[0]x 中的布尔值并为 y 选择一个新的随机数,而不是手动分配布尔值。def switchDirection(self):&nbsp; &nbsp; self.direction = not self.direction&nbsp; &nbsp; self.speed[1] = random.uniform(0.1, 1)move通过为 Paddle 类提供一个函数而不是在主循环中移动,Paddle 也可以稍微改进。这只是意味着您必须编写更少的代码。def move(self, vel, up=pygame.K_UP, down=pygame.K_DOWN):&nbsp; &nbsp; keys = pygame.key.get_perssed()&nbsp; &nbsp; if keys[up]:&nbsp; &nbsp; &nbsp; &nbsp; self.y -= vel&nbsp; &nbsp; if keys[down]:&nbsp; &nbsp; &nbsp; &nbsp; self.y += vel对于碰撞,我建议使用pygame.Rect()andcolliderect因为它更强大并且可能也更有效。例子:import randomimport pygameWIN = pygame.displayD = WIN.set_mode((800, 500))class Paddle:&nbsp; &nbsp; def __init__(self, x, y, width, height, vel, color):&nbsp; &nbsp; &nbsp; &nbsp; self.x = x&nbsp; &nbsp; &nbsp; &nbsp; self.y = y&nbsp; &nbsp; &nbsp; &nbsp; self.width = width&nbsp; &nbsp; &nbsp; &nbsp; self.height = height&nbsp; &nbsp; &nbsp; &nbsp; self.vel = vel&nbsp; &nbsp; &nbsp; &nbsp; self.color = color&nbsp; &nbsp; def move(self, vel, up=pygame.K_UP, down=pygame.K_DOWN):&nbsp; &nbsp; &nbsp; &nbsp; keys = pygame.key.get_pressed()&nbsp; &nbsp; &nbsp; &nbsp; if keys[up]:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.y -= vel&nbsp; &nbsp; &nbsp; &nbsp; if keys[down]:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.y += vel&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; def draw(self, window):&nbsp; &nbsp; &nbsp; &nbsp; pygame.draw.rect(window, self.color, (self.x, self.y, self.width, self.height), 0)&nbsp; &nbsp; def getRect(self):&nbsp; &nbsp; &nbsp; &nbsp; 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:&nbsp; &nbsp; def __init__(self, x, y, color, size):&nbsp; &nbsp; &nbsp; &nbsp; self.x = x&nbsp; &nbsp; &nbsp; &nbsp; self.y = y&nbsp; &nbsp; &nbsp; &nbsp; self.color = color&nbsp; &nbsp; &nbsp; &nbsp; self.size = size&nbsp; &nbsp; &nbsp; &nbsp; self.direction = [random.randint(0, 1), random.randint(0, 1)]&nbsp; &nbsp; &nbsp; &nbsp; self.speed = [0.3, random.uniform(0.2, 0.2)]&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; def draw(self, window):&nbsp; &nbsp; &nbsp; &nbsp; pygame.draw.rect(window, self.color, (self.x, self.y, self.size, self.size))&nbsp; &nbsp; def switchDirection(self):&nbsp; &nbsp; &nbsp; &nbsp; self.direction[0] = not self.direction[0]&nbsp; &nbsp; &nbsp; &nbsp; self.direction[1] = not self.direction[1]&nbsp; &nbsp; &nbsp; &nbsp; self.speed = [0.2, random.uniform(0.1, 0.5)]&nbsp; &nbsp; def bounce(self):&nbsp; &nbsp; &nbsp; &nbsp; self.direction[1] = not self.direction[1]&nbsp; &nbsp; &nbsp; &nbsp; self.speed = [0.2, random.uniform(0.01, 0.2)]&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; def move(self):&nbsp; &nbsp; &nbsp; &nbsp; if self.direction[0]:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.x += self.speed[0]&nbsp; &nbsp; &nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.x -= self.speed[0]&nbsp; &nbsp; &nbsp; &nbsp; if self.direction[1]:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.y += self.speed[1]&nbsp; &nbsp; &nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.y -= self.speed[1]&nbsp; &nbsp; def getRect(self):&nbsp; &nbsp; &nbsp; &nbsp; return pygame.Rect(self.x, self.y, self.size, self.size)&nbsp; &nbsp; def boundaries(self):&nbsp; &nbsp; &nbsp; &nbsp; if ball.x <= 10:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.switchDirection()&nbsp; &nbsp; &nbsp; &nbsp; if ball.x + self.size >= 800:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.switchDirection()&nbsp; &nbsp; &nbsp; &nbsp; if ball.y + self.size >= 490:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.bounce()&nbsp; &nbsp; &nbsp; &nbsp; if ball.y <= 0:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.bounce()ball = Ball(400, 250, (255, 0, 0), 20)while True:&nbsp; &nbsp; pygame.event.get()&nbsp; &nbsp; D.fill((255, 255, 255))&nbsp; &nbsp; ball.draw(D)&nbsp; &nbsp; ball.boundaries()&nbsp; &nbsp; ball.move()&nbsp; &nbsp; #print(ball.x, ball.y)&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; left_paddle.draw(D)&nbsp; &nbsp; right_paddle.draw(D)&nbsp; &nbsp; right_paddle.move(0.4)&nbsp; &nbsp; left_paddle.move(0.4, down=pygame.K_s, up=pygame.K_w)&nbsp; &nbsp; if left_paddle.getRect().colliderect(ball.getRect()):&nbsp; &nbsp; &nbsp; &nbsp; ball.switchDirection()&nbsp; &nbsp; if right_paddle.getRect().colliderect(ball.getRect()):&nbsp; &nbsp; &nbsp; &nbsp; ball.switchDirection()&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; WIN.flip()

胡说叔叔

我基本上对球在边缘弹跳时的每一种可能的运动进行了编码。我花了几个小时的时间来研究它,并且让它工作起来,我只是想知道是否有一种更有效的方法可以用我的代码产生类似的输出(因为我知道这应该是一个初学者项目)?和如何使球在随机方向上产生?在每轮开始(和重新开始)时?您可以使用浮动坐标,而不是实现球的“每个”方向。这些变量通常称为 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 对象,其中包含分数、生命和其他内容作为属性。

SMILET

关于如何减少所有球运动/碰撞代码并提高可重用性的一些值得思考的地方:import pygameclass Ball:&nbsp; &nbsp; def __init__(self, bounds, color):&nbsp; &nbsp; &nbsp; &nbsp; from random import randint, choice&nbsp; &nbsp; &nbsp; &nbsp; self.bounds = bounds&nbsp; &nbsp; &nbsp; &nbsp; self.position = pygame.math.Vector2(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; randint(self.bounds.left, self.bounds.left+self.bounds.width),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; randint(self.bounds.top, self.bounds.top+self.bounds.height)&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; &nbsp; &nbsp; self.velocity = pygame.math.Vector2(choice((-1, 1)), choice((-1, 1)))&nbsp; &nbsp; &nbsp; &nbsp; self.color = color&nbsp; &nbsp; &nbsp; &nbsp; self.size = 8&nbsp; &nbsp; def draw(self, window):&nbsp; &nbsp; &nbsp; &nbsp; pygame.draw.rect(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; window,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.color,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.position.x-self.size,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.position.y-self.size,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.size*2,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.size*2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; def update(self):&nbsp; &nbsp; &nbsp; &nbsp; self.position.x += self.velocity.x&nbsp; &nbsp; &nbsp; &nbsp; self.position.y += self.velocity.y&nbsp; &nbsp; &nbsp; &nbsp; if not self.bounds.left+self.size < self.position.x < self.bounds.left+self.bounds.width-self.size:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.velocity.x *= -1&nbsp; &nbsp; &nbsp; &nbsp; if not self.bounds.top+self.size < self.position.y < self.bounds.top+self.bounds.height-self.size:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.velocity.y *= -1def main():&nbsp; &nbsp; from random import randint&nbsp; &nbsp; window_width, window_height = 800, 500&nbsp; &nbsp; window = pygame.display.set_mode((window_width, window_height))&nbsp; &nbsp; pygame.display.set_caption("Pong")&nbsp; &nbsp; clock = pygame.time.Clock()&nbsp; &nbsp; black = (0, 0, 0)&nbsp; &nbsp; white = (255, 255, 255)&nbsp; &nbsp; padding = 20&nbsp; &nbsp; bounds = pygame.Rect(padding, padding, window_width-(padding*2), window_height-(padding*2))&nbsp; &nbsp; ball = Ball(bounds, white)&nbsp; &nbsp; def redraw_window():&nbsp; &nbsp; &nbsp; &nbsp; window.fill(black)&nbsp; &nbsp; &nbsp; &nbsp; pygame.draw.rect(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; window,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; white,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; padding,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; padding,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; window_width-(padding*2),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; window_height-(padding*2)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; &nbsp; &nbsp; ball.draw(window)&nbsp; &nbsp; &nbsp; &nbsp; pygame.display.update()&nbsp; &nbsp; while True:&nbsp; &nbsp; &nbsp; &nbsp; clock.tick(60)&nbsp; &nbsp; &nbsp; &nbsp; ball.update()&nbsp; &nbsp; &nbsp; &nbsp; for event in pygame.event.get():&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if event.type == pygame.QUIT:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; &nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; redraw_window()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue&nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; pygame.quit()&nbsp; &nbsp; return 0&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if __name__ == "__main__":&nbsp; &nbsp; import sys&nbsp; &nbsp; sys.exit(main())这不是一个完整的替代品,我只是重新实现了该类Ball。没有桨。本质上,在实例化一个球时,您传递一个pygame.Rect,它描述了允许球弹跳的边界。您还传递一个颜色元组。然后,球在边界内选择一个随机位置(该位置是 a pygame.math.Vector2,而不是存储x和y作为单独的实例变量)。球也有速度,它也是pygame.math.Vector2,因此您可以拥有独立的速度分量 - 一个用于x(水平速度),一个用于y(垂直速度)。球size的 简单地描述了球的尺寸。例如,如果size设置为8,则球将为 16x16 像素。该类Ball还有一个update方法,每个游戏循环迭代都会调用该方法。它将球移动到速度决定的下一个位置,并检查球是否与边界碰撞。如果是,则反转相应的速度分量。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python