Search code examples
pythonpygamegame-physicsphysics

How can I make my circles move naturally instead of not receiving gravity when they collide?


I am trying to make a simple physics simulation but the circles loose all gravity and get stuck together as soon as they collide with another circle, this makes balancing them very easy but it makes it seem very unnatural making you able to do structures that defy the laws of physics like this one.

code:

from pygame.locals import *
import pygame
import sys

pygame.init()

green = (0, 255, 0)
circles = []
gravity = 1

def input():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.MOUSEBUTTONDOWN:
            circles.append(list(event.pos))

def boundaries():
    for circle_pos in circles:
        if circle_pos[1] > 495:
            boundaries = circle_pos[1] - 495
            circle_pos[1] -= boundaries
        if circle_pos[0] < 5:
            boundaries2 = circle_pos[0]
            circle_pos[0] += boundaries2
        if circle_pos[0] > 995:
            boundaries3 = circle_pos[0] - 995
            circle_pos[0] -= boundaries3


def collision():
    for i, circle_pos_1 in enumerate(circles):
        for circle_pos_2 in circles[i + 1:]:
            dx = circle_pos_2[0] - circle_pos_1[0]  # circle_pos_2 = y val
            dy = circle_pos_2[1] - circle_pos_1[1]
            if dx * dx + dy * dy < 10 * 10:
                circle_pos_2[1] -= gravity
    for circle_pos in circles:
        pygame.draw.circle(screen, green, circle_pos, 5)


def wind():
    for circle_pos in circles:
        wind = 0
        for i in range(2):
            wind += 0.01
            circle_pos[0] -= wind


clock = pygame.time.Clock()
screen = pygame.display.set_mode((1000, 500))
while True:
    screen.fill((15, 15, 15))

    input()
    mouse_pos = pygame.mouse.get_pos()

    for circle_pos in circles:
        circle_pos[1] += gravity
    boundaries()

    collision()

    pygame.display.update()
    clock.tick(120)


Solution

  • I don't know Python, but it appears that in collision() you explicitly state that if Circle 1 and Circle 2 collide (or overlap), then gravity is remitted for Circle 2. Naturally this causes circles to stick like snowflakes. If you want them to roll off each other, you must change this function.

    I suggest you start with a much simpler problem: a circle and an inclined plane. You already seem to assume that a falling circle should have constant velocity, like a pebble sinking through water; a simple way to extend that to sliding on an inclined plane would be to have the circle slide with a speed that varies as the sine of the angle.

    Some shortcuts are possible, but if that last paragraph made no sense to you, then you must review trigonometry and basic physics. You have no chance of getting this program to work without understanding some basic physics.