使用向量

时间:2017-05-01 23:40:09

标签: python pygame game-physics

我有一个重力矢量(形式为[r,theta]),我将其添加到我的球的速度矢量中。由于某种原因,球在弹跳后不会返回到相同的高度,而是偶尔慢慢地失去高度。我猜测有一些舍入错误或我正在使用的计算中的某些内容,但我不能隔离这个问题。

这是我的代码。你需要文件和pygame来运行它。对不起,如果有点混乱。如果你愿意,我可以发表更多评论。

每当球达到最大高度时我都会添加一个标记,所以你们就是我的意思。我希望每次弹跳时球都能恢复到完全相同的高度。

我拿了一些不必要的代码。完整的程序在pastebin链接下。

https://pastebin.com/FyejMCmg - PhysicsSim

import pygame, sys, math, tools, random, time
from pygame.locals import *

clock = pygame.time.Clock()
lines = []

class Particle:
    def __init__(self,screen,colour, mass, loc, vel):
        self.screen = screen
        self.colour = colour

        self.mass = mass

        self.x = loc[0]
        self.y = loc[1]
        self.location = self.x,self.y
        self.speed = vel[0]
        self.angle = vel[1]


    def update(self):
        global lines

        # add gravity
        self.speed,self.angle = tools.add_vectors2([self.speed,self.angle], tools.GRAVITY)

        # update position
        dt = clock.tick(60)
        self.x += self.speed * tools.SCALE * math.cos(self.angle) * dt
        self.y -= self.speed * tools.SCALE * math.sin(self.angle) * dt
        self.location = int(self.x),int(self.y)

        # border checking
        do = False
        n=[]
        if ((self.y+self.mass) > tools.SCREEN_HEIGHT):
            self.y = tools.SCREEN_HEIGHT-self.mass
            n = [0,1]
            do = True

        # adds position to array so max height so max height can be recorded
        if (self.speed==0):
            lines.append([self.screen, self.location, self.mass])

        # bounce
        if do:
            #init, convert everything to cartesian
            v = tools.polarToCartesian([self.speed, self.angle])

            #final -> initial minus twice the projection onto n, where n is the normal to the surface
            a = tools.scalarP(2*abs(tools.dotP(v,n)),n) #vector to be added to v
            v = tools.add_vectors(v,a)

            self.angle = tools.cartesianToPolar(v)[1] # does not set magnitude


        # drawing
        pygame.draw.circle(self.screen, self.colour, self.location, self.mass, 0)

# draws max height line
def draw_line(l):
    screen = l[0]
    location = l[1]
    radius = l[2]
    pygame.draw.line(screen, tools.BLACK, [location[0] + 15, location[1]-radius],[location[0] - 15, location[1]-radius])

def main():
    pygame.init()

    DISPLAY = pygame.display.set_mode(tools.SCREEN_SIZE,0,32)
    DISPLAY.fill(tools.WHITE)

    particles = []
    particles.append(Particle(DISPLAY, tools.GREEN, 10, [100,100], [0,0]))

    done = False
    while not done:
        global lines
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

        DISPLAY.fill(tools.WHITE)
        for i in particles:
            i.update()

        for l in lines:
            draw_line(l)

        pygame.display.update()

main()

https://pastebin.com/Epgqka31 - 工具

import math

#colours
WHITE =     (255, 255, 255)
BLUE =      (  0,   0, 255)
GREEN =     (  0, 255,   0)
RED =       ( 255,  0,   0)
BLACK =     (   0,  0,   0)

COLOURS = [WHITE,BLUE,GREEN,RED,BLACK]

#screen
SCREEN_SIZE = SCREEN_WIDTH,SCREEN_HEIGHT = 1000,700

#vectors
GRAVITY = [5.0, 3*math.pi/2] # not 9.8 because it seems too high
SCALE = 0.01

# converts polar coordinates to cartesian coordinates in R2
def polarToCartesian(v):
    return [v[0]*math.cos(v[1]), v[0]*math.sin(v[1])]

# converts cartesian coordinates to polar coordinates in R2
def cartesianToPolar(v):
    return [math.sqrt(v[0]**2 + v[1]**2), math.atan2(v[1],v[0])]

# dots two cartesian vectors in R2
def dotP(v1, v2):
    return v1[0]*v2[0] + v1[1]*v2[1]

# multiplies cartesian vector v by scalar s in Rn
def scalarP(s,v):
    v_=[]
    for i in v:
        v_.append(s*i)
    return v_

# returns the sum of two cartesian vectors in R2
def add_vectors(v1, v2):
    return [v1[0]+v2[0], v1[1]+v2[1]]

# returns the sum of two polar vectors in R2, equations from https://math.stackexchange.com/questions/1365622/adding-two-polar-vectors
def add_vectors2(v1,v2):
    r1,r2,t1,t2 = v1[0],v2[0],v1[1],v2[1]
    return [math.sqrt(r1**2 + r2**2 + 2*r1*r2*math.cos(t2-t1)), t1 + math.atan2(r2*math.sin(t2 - t1), r1 + r2*math.cos(t2 - t1))]

1 个答案:

答案 0 :(得分:6)

您的时间间隔dt = clock.tick(60)不是常数。如果将其更改为dt = 60,程序将按预期运行。

查看Verlet Algorithm并在您的代码中实现它。你走在正确的轨道上了!