Verlet 物理约束

问题描述 投票:0回答:1

我正在尝试使用 pygame 从头开始创建一个简单的物理求解器。我在这里关注一个教程: https://www.youtube.com/watch?v=lS_qeBy3aQI

我到达了他创建约束的部分(3:30 左右)但是当我测试我的代码时,对象在碰到约束部分的底部时会反复反弹。

这是我正在使用的代码(请注意,我将视频中使用的 C# 或 C++ 代码转换为 python,因此这可能会导致问题):

import os
os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = 'hide'
import pygame
from pygame.locals import *
from pygame import Vector2 as Vec2
import sys
pygame.init()

wnSize = (700, 700)
fps = 10

gravity = Vec2(0, 100/fps)
objs = [[i/2 for i in wnSize]]
objradius = 50

areaCenter = Vec2(wnSize[0]/2, wnSize[1]/2)
areaRadius = 350

class VarletObject:
    def __init__(self, pos):
        self.poscurr = Vec2(pos)
        self.posold = Vec2(pos)
        self.acc = Vec2(0, 0)
    def updatePos(self, dt):
        vel = self.poscurr - self.posold
        self.posold = self.poscurr.copy()
        self.poscurr = self.poscurr + vel + self.acc * dt * dt
        self.acc = Vec2(0, 0)
    def accelerate(self, acceleration):
        self.acc += Vec2(acceleration)

class Solver:
    def __init__(self, gravity, objPoses):
        self.gravity = Vec2(gravity)
        self.objs = [VarletObject(i) for i in objPoses]

    def update(self, dt):
        self.applyGravity()
        self.applyConstraint()
        self.updatePositions(dt)

    def updatePositions(self, dt):
        for obj in self.objs:
            obj.updatePos(dt)

    def applyGravity(self):
        for obj in self.objs:
            obj.accelerate(self.gravity)

    def applyConstraint(self):
        for obj in self.objs:
            to_obj = obj.poscurr - areaCenter
            dist = to_obj.length()
            if dist > areaRadius - objradius:
                print(1)
                n = to_obj/dist
                obj.poscurr = areaCenter + n * (dist - objradius)

    def draw(self, wn):
        pygame.draw.circle(wn, (0, 0, 0), areaCenter, areaRadius)
        for obj in self.objs:
            pygame.draw.circle(wn, (255, 255, 255), obj.poscurr, objradius)
            pygame.draw.line(wn, (255, 0, 0), areaCenter, obj.poscurr)


wn = pygame.display.set_mode(wnSize)

solver = Solver(gravity, objs)

clock = pygame.time.Clock()
while True:
    wn.fill((255, 255, 255))
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
    solver.update(1)
    solver.draw(wn)
    pygame.display.flip()
    clock.tick(fps)

我试过改变物体的重力和大小,并尝试摆弄约束检测并添加:

obj.posold = obj.poscurr.copy()

就在第 57 行之后,但这只是导致对象产生较小的反弹,并没有消除潜在的问题。

编辑: 代码的重要部分是约束检测功能,在视频中它是:

void applyConstraint() {
    const vec2 position{800.0f, 450.00;
    const float radius = 400. Of;
    core::foreach<VerletObject>([&](VerletObject& Obj) {
        const Vec2 to_obj = obj.position_current - position;
        const float dist = MathVec2::length(to_obj);
        // 50 is the default radius
        if (dist > radius - 50.0f) {
            const Vec2 n = to_obj / dist;
            obj.position_current = position + n * (dist - 50.0f);
        }
    });
}

从我的代码中:

for obj in self.objs:
    to_obj = obj.poscurr - areaCenter
    dist = to_obj.length()
    if dist > areaRadius - objradius:
       print(1)
       n = to_obj/dist
       obj.poscurr = areaCenter + n * (dist - objradius)
python c# physics-engine
1个回答
0
投票

问题是 (dist - 50.0f) 或 (dist - objradius),这只是将它的半径移动到更靠近该区域的中心。它应该是(areaRadius - objradius)。

© www.soinside.com 2019 - 2024. All rights reserved.