2

我正在尝试使用 pygame 在简单的 2D 窗口中模拟重力。这是非常简单的东西(一个点再次上升和下降)并且我理解机制,即作为向量的速度和 y 部分在每次运行通过主循环和随后的位置更新期间始终减少一个代表重力的值 g点。

一切正常,但我无法选择要插入的正确值。目前这一切都是反复试验。关于如何确定要使用哪些数字以实现半真实的轨迹,是否有一个很好的经验法则?

我在下面插入了一个最小示例,以下值对我的问题很重要:

window = (640, 480) # pixels
initial_speed = 20 # pixels per update along the y axis
gravity = 0.4 # deduction on initial_speed per update

现在,为什么这些数字恰好使幻觉起作用?我首先尝试使用多年前在物理课上学到的公式,但是无论有没有单位转换,模拟都是不正确的。大多数时候,我什至没有看到球,但上述值是通过反复试验发现的。

感谢您提前提供的所有帮助。如果您需要更多信息,请发表评论,我会尽力提供。

这是最小的示例。请注意,vector2D 库是从 pygame 网站方便地借用的(点击此链接

#!/usr/bin/env python

import pygame
from pygame.locals import *

from vector2D import Vec2d

pygame.init()

GRAVITY = 0.4

class Dot(pygame.sprite.Sprite):
    def __init__(self, screen, img_file, init_position, init_direction, speed):
        pygame.sprite.Sprite.__init__(self)
        self.screen = screen

        self.speed = Vec2d(speed)

        self.base_image = pygame.image.load(img_file).convert_alpha()
        self.image = self.base_image
        # A vector specifying the Dot's position on the screen
        self.pos = Vec2d(init_position)

        # The direction is a normalized vector
        self.direction = Vec2d(init_direction).normalized()

    def blitme(self):
        """ Blit the Dot onto the screen that was provided in
            the constructor.
        """
        self.screen.blit(self.image, self.pos)

    def update(self):
        self.speed.y -= GRAVITY

        displacement = Vec2d(
            self.direction.x * self.speed.x,
            self.direction.y * self.speed.y
        )
        self.pos += displacement

def main():
    DIMENSION = SCREEN_WIDTH, SCREEN_HEIGHT = 640, 480
    BG_COLOUR = 0,0,0

    # Creating the screen
    window = screen = pygame.display.set_mode(
        (SCREEN_WIDTH, SCREEN_HEIGHT), 0, 32)
    screen = pygame.display.get_surface()
    clock = pygame.time.Clock()

    dot = Dot(screen, "my/path/to/dot.jpg", (180, SCREEN_HEIGHT),
                      (0, -1), (0, 20))

    mainloop = True
    while mainloop:
        # Limit frame speed to 50 FPS
        time_passed = clock.tick(50)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                mainloop = False

        # Redraw the background
        screen.fill(BG_COLOUR)

        dot.update()
        dot.blitme()

        pygame.display.flip()

if __name__ == '__main__':
    main()
4

1 回答 1

3

定义更新(自我):

   self.speed.y -= GRAVITY

   displacement = Vec2d(
        self.direction.x * self.speed.x,
        self.direction.y * self.speed.y
    )
    self.pos += displacement

您每秒调用 Dot.update() 50 次。你使用的方程,

delta v_y = - g #* (1 second)

表示每秒速度的变化,但它每秒被调用 50 次。50*GRAVITY m/s这意味着你的速度将一秒失去,这就是为什么你被迫让你的重力如此微弱。

因此,我建议添加time_passed作为参数Dot.update,并将速度更改语句更改为

def update(self, time_passed):
    self.speed.y -= GRAVITY * time_passed/1000. #time converted from millisecond to seconds

这将使单位更直观。切换GRAVITY回 10 并使用真实的速度。

编辑:

此外,位移向量还需要包含时间,否则位移将取决于 FPS。如果您有x每秒帧数,则每次更新都会在t = 1000/x毫秒后发生。这是 Dot 在每次更新中“移动”的时间。想想我们如何近似 Dot 的运动;它得到更新,计算它的新速度并以该速度行进t几秒钟。但是,在您的实现中,位移矢量与时间无关。将更新方法更改为:

def update(self, time):
    time /= 1000.
    self.speed.y -= GRAVITY * time

    displacement = Vec2d(
        self.direction.x * self.speed.x * time,
        self.direction.y * self.speed.y * time
    )
    self.pos += displacement

现在,根据运动学,我们会得到类似的东西

max height = v0**2 / 2g

因此 10-20m/s 的初始速度只会产生 5-20m 的最大高度。如果您不想使用 50-200m/s 的速度,则可以在位移矢量中添加比例因子,例如

    displacement = Vec2d(
        self.direction.x * self.speed.x * time * scaling_factor,
        self.direction.y * self.speed.y * time * scaling_factor
    )
于 2013-06-25T15:59:26.483 回答