Witam.
Mam problem z napisanym przeze mnie programem mającym symulować prostą fizykę 2D. Napisałem to w Pythonie, a do wyświetlania grafiki użyłem pygame. Na ten moment program jest w stanie poprawnie obliczyć zachowanie koła, na który działa grawitacja, a my jesteśmy nakładać siły na te koło poprzez m.in. przeciąganie jego po ekranie. Dodałem również opcję dodania nowych obiektów (kolejnych kół), jednak tutaj zaczynają się problemy. Kiedy obecnych jest więcej niż jeden obiekt, to zaczynają one dziwnie reagować na grawitację, która zaczyna być w jakiś całkowicie dziwny sposób liczona, bo choć obiekt, który stworzyłem najwcześniej dobrze reaguje na skrypt grawitacji, to następny praktycznie nie ma żadnego przyspieszenia spowodowanego grawitacją, a już każdy kolejny reaguje na grawitację coraz "lepiej" (jego przyspieszenie grawitacyjne jest coraz szybsze). Naprawdę nie mam pojęcia o co może chodzić. Przypuszczam jedynie, iż może mieć to związek z jakąś ułomnością biblioteki pygame, lub samego Pythona, jednak jest również prawdopodobne, że to ja popełniłem jakiś błąd.
Z góry dziękuję za pomoc.
Kod programu poniżej:
import pygame as pg
import math as m
gravity = 0.98
pg.init()
window = pg.display.set_mode((1600, 900))
clock = pg.time.Clock()
winx, winy = window.get_width(), window.get_height()
run = True
pW = False
pS = False
pA = False
pD = False
left_mouse_pressed = False
# CLASSES
class PhysicsObject:
x, y = None, None
acceleration = 0
mass = None
velocity = 0
vel_vector = [0, 0]
gravity = 0
friction = 0
max_velocity = 8
mode = None
shape = None
bounciness = 0
forces = [[0, 0.98], [0, 0], [0, 0]]
net_force = [0, 0]
size = 50
grounded = False
# drag
dragging = False
def __init__(self, x, y, mass, mode, shape):
self.x = x
self.y = y
self.mass = mass
self.mode = mode
self.shape = shape
def push(self, vx, vy):
self.forces.append([vx/10, vy/10])
def drag_start(self):
mx, my = pg.mouse.get_pos()
if self.size ** 2 >= ((mx - self.x) ** 2 + (my - self.y) ** 2):
self.dragging = True
def drag_end(self):
self.dragging = False
self.forces[2] = [0, 0]
def drag(self):
mx, my = pg.mouse.get_pos()
if left_mouse_pressed and self.dragging:
self.forces[2] = [((mx - self.x)/100), ((my - self.y)/100)]
def check_ground_collison(self):
if self.shape == 'circle':
if self.y + self.size >= winy:
self.grounded = True
else:
self.grounded = False
def collision_ground(self):
if self.shape == 'circle':
if self.grounded:
if self.net_force[1] > 0:
self.forces[1] = [0, -self.net_force[1]]
self.vel_vector[1] = 0
self.y = winy - self.size
else:
if len(self.forces) > 2:
self.forces[1] = [0, 0]
def border_collision(self):
if self.shape == 'circle':
if self.x - self.size < 0:
self.forces[2] = [0, self.forces[2][1]]
self.vel_vector[0] = 0
self.x = self.size
elif self.x + self.size > winx:
self.forces[2] = [0, self.forces[2][1]]
self.vel_vector[0] = 0
self.x = winx - self.size
def update(self):
if self.mode == 'top':
self.mass = self.mass
# placeholder
elif self.mode == 'front':
netx = 0
nety = 0
for x in range(len(self.forces)):
netx = netx + self.forces[x][0]
nety = nety + self.forces[x][1]
self.net_force[0] = netx
self.net_force[1] = nety
self.vel_vector[0] = self.vel_vector[0] + self.net_force[0]
self.vel_vector[1] = self.vel_vector[1] + self.net_force[1]
self.x = self.x + self.vel_vector[0]
self.y = self.y + self.vel_vector[1]
if len(self.forces) > 3:
for x in range(3, len(self.forces)):
self.forces.pop(-1)
def debug(self):
pg.draw.line(window, (255, 0, 0), (self.x, self.y), (self.x + (self.net_force[0] * 100), self.y + (self.net_force[1] * 100)), width=2) # net force
pg.draw.line(window, (0, 255, 0), (self.x, self.y), (self.x + (self.vel_vector[0] * 5), self.y + (self.vel_vector[1] * 5)), width=2) # vector of velocity
def draw(self):
if self.shape == 'rect':
pg.draw.rect(window, (0, 0, 255), (self.x, self.y, 100, 100))
elif self.shape == 'circle':
pg.draw.circle(window, (0, 0, 255), (self.x, self.y), self.size)
ball = []
ball.append(PhysicsObject(100, 100, 1, 'front', 'circle'))
while run:
for event in pg.event.get():
if event.type == pg.QUIT:
run = False
pg.quit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_w:
pW = True
if event.key == pg.K_s:
pS = True
if event.key == pg.K_a:
pA = True
if event.key == pg.K_d:
pD = True
if event.type == pg.KEYUP:
if event.key == pg.K_w:
pW = False
if event.key == pg.K_s:
pS = False
if event.key == pg.K_a:
pA = False
if event.key == pg.K_d:
pD = False
#1 - left click
#2 - middle click
#3 - right click
#4 - scroll up
#5 - scroll down
if event.type == pg.MOUSEBUTTONDOWN:
mx, my = pg.mouse.get_pos()
if event.button == 3:
ball.append(PhysicsObject(mx, my, 1, 'front', 'circle'))
if event.button == 1:
for x in ball:
x.drag_start()
left_mouse_pressed = True
if event.type == pg.MOUSEBUTTONUP:
if event.button == 1:
for x in ball:
x.drag_end()
left_mouse_pressed = False
if pW:
for x in ball:
x.push(0, -10)
if pS:
for x in ball:
x.push(0, 10)
if pA:
for x in ball:
x.push(-10, 0)
if pD:
for x in ball:
x.push(10, 0)
for x in ball:
x.update()
x.check_ground_collison()
x.collision_ground()
x.border_collision()
x.drag()
x.draw()
x.debug()
pg.display.flip()
window.fill((0, 0, 0))
clock.tick(60)