我制作了一个python程序,用pygame模拟物体(粒子)在太空中相互吸引。
然而,他们都向左移动,而不是去中心......
应该修改什么才能使粒子以正确的方式吸引?
该代码的工作原理是通过循环每个粒子来计算每个粒子及其引力的速度,然后通过再次循环每个粒子并计算这两个粒子之间的速度来计算其速度。
代码:
import pygame
import math
import time
particleMass = 1
res = 10
fps = 60
G = 6.674 * 10 ** -11
multi = 10 ** 7.5
size = (700, 700)
screen = pygame.display.set_mode(size)
particles = []
velocities = []
red = (255, 0, 0)
black = (0, 0, 0)
x = 0
y = 0
for _ in range(res ** 2):
particles.append([-size[0] / 2 + x * (size[0] / res),-size[1] / 2 + y * (size[1] / res)])
velocities.append(0)
x += 1
if x == res:
x = 0
y += 1
def norm(pos):
return [pos[0] + size[0] / 2, pos[1] + size[1] / 2]
def moveParticles(pos1, pos2, vel1, vel2):
dist = ((pos1[0] - pos2[0]) ** 2 + (pos1[1] - pos2[1]) ** 2) ** 0.5
force = (G * particleMass ** 2) / dist ** 2
vel21 = ((2 * G * particleMass ** 2) / dist) ** 0.5
vel22 = ((2 * G * particleMass ** 2) / dist) ** 0.5
angle1 = math.atan2(pos1[0] - pos2[0], pos1[1] - pos2[1])
angle2 = math.atan2(pos2[0] - pos1[0], pos2[1] - pos1[1])
resPos1 = [pos1[0] + (vel21 * multi - vel1) * math.cos(angle1), pos1[0] + (vel21 * multi - vel1) * math.sin(angle2)]
resPos2 = [pos2[0] + (vel22 * multi - vel2) * math.cos(angle2), pos2[1] + (vel22 * multi - vel2) * math.sin(angle2)]
return resPos1, resPos2, vel21, vel22
def calculatePoses(poses, velo):
clear(black)
resPoses = poses[:len(poses)]
resVelo = velo[:len(velo)]
for i in range(len(poses)):
for j in range(i):
resPoses[i], resPoses[j], resVelo[i], resVelo[j] = moveParticles(poses[i], poses[j], velo[i], velo[j])
return resPoses, resVelo
def clear(color):
pygame.draw.rect(screen, color, pygame.Rect(0, 0, size[0], size[1]))
def draw(lst):
for pos in lst:
pygame.draw.rect(screen, red, pygame.Rect(norm(pos)[0], norm(pos)[1], size[0] / res / 5, size[1] / res / 5))
while True:
start = time.time()
clear(black)
particles, velocities = calculatePoses(particles, velocities)
print(particles[0], particles[1])
draw(particles)
pygame.display.update()
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
pygame.quit()
if 1 / fps > time.time() - start:
time.sleep(1 / fps - time.time() - start)
物体被吸引到左侧,而不是像应有的那样被吸引到中心。
这与你计算引力相互作用的方式有关,你可以这样循环:
for i in range(len(poses)):
for j in range(i):
这意味着每个粒子只会受到位置列表中位于其之前的粒子的影响。因为您的粒子是从左到右排序的(因为您构建初始位置网格的方式),所以每个粒子将更容易受到其左侧粒子的影响,因此会被拉向该方向。
然后您需要确保每个粒子都受到所有其他粒子的影响。天真的解决方案是将循环修复为:
for i in range(len(poses)):
for j in range(len(poses)):
if i==j:
continue
# compute positions
但是当你有〜10k点时,请研究 scipy 成对距离计算以加快速度:https://docs.scipy.org/doc/scipy/reference/ generated/scipy.spatial.distance.cdist.html
发生这种情况是因为 (0,0) 是窗口的左上角,您已将其编码为转到 (0,0),因此它会转到窗口的左上角。
更改计算并根据窗口的大小进行调整