2013-06-24 19 views
1

我想用pygame在簡單的2D窗口中模擬重力。這是非常簡單的東西(點再次上升和下降),我理解力學,即速度作爲一個向量,y部分在每次穿過主循環和隨後更新位置的過程中始終由代表重力的值g減小點。

這一切都工作正常,但我無法選擇正確的值插入。這一切都是嘗試和錯誤。 在如何確定使用哪些數字以獲得半現實的外觀軌跡方面,是否有一個很好的經驗法則?帶pygame的簡單2D引力;價值準則?

我插一個小例子,下面,與我的問題以下值重要:

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的網站(follow this link

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

選擇一個你想要一個像素表示的單位,然後取實數這些東西的價值和插入他們。 –

+0

@Lattyware:我試過了,但正如我非常簡短地提到,如果我使用數字這樣g = 9.81(或10爲清酒的簡單性),實際上發生在窗口內實際上很少的計算。我試圖分配諸如50px對應於1m等東西,但轉換使它更糟糕。你有什麼建議來規避這個問題?感謝您的幫助順便說一句。非常感謝! – Nebelhom

回答

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次。這意味着你的速度將永遠失去第二名,這就是爲什麼你不得不讓你的重力變得如此脆弱。

所以,我會建議增加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的運動;它會得到一個更新,計算它的新速度並以該速度在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,這樣初始速度/秒只會產生的最大高度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 
    ) 
+0

非常感謝您的回答!這現在很有意義。其中一個(facepalm)時刻;)。然而,我注意到的一件事是,改變每秒幀數時,Dot向天花板上升的高度有所不同(50:幾乎接觸頂部; 25:略低於窗戶一半的高度; 10 :在下降之前甚至沒有下三分之一)。我該如何調整這個距離,以使每秒的幀距離獨立? – Nebelhom

+0

是的,這是一個很好的觀點。檢查編輯。 – wflynny

+0

太棒了!隨着scaling_factor你甚至回答了一個問題,我正在努力,但沒有問;)偉大的東西!遊戲物理101.非常感謝! – Nebelhom