2

pygame を使用して単純な 2D ウィンドウで重力をシミュレートしようとしています。それは非常に単純なもの (ドットが再び上昇して下降する) であり、メカニズムを理解しています。つまり、ベクトルとしての速度と、メインループを実行するたびに重力を表す値 g によって y 部分が一貫して減少し、その後の位置の更新ドット。

すべて正常に動作していますが、挿入する正しい値を選択するのに問題があります。現時点ではすべて試行錯誤です。半現実的な軌道を実現するために、どの数値を使用するかを決定する方法について、適切な経験則はありますか?

以下に最小限の例を挿入しました。質問にとって重要な値は次のとおりです。

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 の Web サイトから便利に借用したことに注意してください (このリンクをたどってください) 。

#!/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)

は1 秒ごとの速度の変化を表しますが、 1 秒ごとに 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

これにより、単位がより直感的になります。10 に戻しGRAVITYて、現実的な速度を使用します。

編集:

さらに、変位ベクトルにも時間が含まれている必要があります。そうでない場合、変位は FPS に依存します。x1 秒あたりのフレーム数がある場合、各更新はt = 1000/xミリ秒後に発生します。これは、各更新で Dot が「移動」に費やした時間です。Dot の動きをどのように近似するかを考えてみましょう。更新を取得し、新しい速度を計算し、その速度で数t秒間移動します。ただし、実装では、変位ベクトルは時間に依存しません。update メソッドを次のように変更します。

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 ~ 20 m/s の初期速度では、最大高さは 5 ~ 20 m しか生成されません。50 ~ 200 m/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 に答える