我正在尝试使用 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)
问题是 (dist - 50.0f) 或 (dist - objradius),这只是将它的半径移动到更靠近该区域的中心。它应该是(areaRadius - objradius)。