Почему шарики такие неустойчивые?

Это физическая симуляция, ограничивающая шары в круглой области.

Я сделал исходный код в Scratch и преобразовал его в Python в Pygame. Когда я запускал симуляцию, все шары тряслись по сравнению с исходным кодом.

Я ограничил максимальную скорость до 20, но это не помогло.

Я создал подшаги для каждого кадра, но это тоже не помогло.

import pygame
import math
import random

screen = pygame.display.set_mode((16*120,9*120))
pygame.display.set_caption('')
clock = pygame.time.Clock()

mx = 16*60
my = 9*60

global x
global y
x = []
y = []
xv = []
yv = []
prevx = []
prevy = []

for i in range(20):
    x.append(random.randint(-200,200))
    y.append(random.randint(-200,200))
    xv.append(0)
    yv.append(0)
    prevx.append(0)
    prevy.append(0)

r = 25
size = 300

sub = 20
maxvel = 20

global dist
global dx
global dy
global d

#points at something
def pointat(px,py):
    global d
    dx = px-x[i]
    dy = py-y[i]

    if dy == 0:
        if dx < 0:
            d = -90
        else:
            d = 90
    else:
        if dy < 0:
            d = 180+math.atan(dx/dy)
        else:
            d = math.atan(dx/dy)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
    screen.fill((10,10,10))
    pygame.draw.circle(screen,(100,100,100),(mx,my),size)
    for i in range(len(x)):
        pygame.draw.circle(screen,(255,255,255),(mx+x[i],my+y[i]*-1),r)

    for i in range(len(x)):
        prevx[i] = x[i]
        prevy[i] = y[i]
        for j in range(sub):

            x[i] += xv[i]/sub
            y[i] += yv[i]/sub

            y[i] -= 1/sub
            
            a = 0
            for k in range(len(x)-1):
                if a == i:
                    a += 1
                dist = math.sqrt(((x[i]-x[a])*(x[i]-x[a]))+((y[i]-y[a])*(y[i]-y[a])))
                if dist < r*2:
                    pointat(x[a],y[a])
                    x[i] += (math.sin(d)*(dist-(r*2)))
                    y[i] += (math.cos(d)*(dist-(r*2)))
                    x[a] -= (math.sin(d)*(dist-(r*2)))
                    y[a] -= (math.cos(d)*(dist-(r*2)))
                
                dist = math.sqrt((x[i]*x[i])+(y[i]*y[i]))
                if dist > size-r:
                    pointat(0,0)
                    x[i] += (math.sin(d)*(dist-(size-r)))
                    y[i] += (math.cos(d)*(dist-(size-r)))
                a += 1

        xv[i] = x[i]-prevx[i]
        yv[i] = y[i]-prevy[i]
        if xv[i] > maxvel:
            xv[i] = maxvel
        if xv[i] < -maxvel:
            xv[i] = -maxvel
        if yv[i] > maxvel:
            yv[i] = maxvel
        if yv[i] < -maxvel:
            yv[i] = -maxvel

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

Вы пытались просто увеличить частоту кадров, т.е. clock.tick(60) -> clock.tick(600)

Caridorc 15.02.2023 18:41
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Отказ от ответственности: Эта статья предназначена только для демонстрации и не должна использоваться в качестве инвестиционного совета.
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
Потяните за рычаг выброса энергососущих проектов
Потяните за рычаг выброса энергососущих проектов
На этой неделе моя команда отменила проект, над которым я работал. Неделя усилий пошла насмарку.
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Привет, люди RPA, это снова я и я несу подарки! В очередном моем приключении о том, как создавать ботов для облегчения рутины. Вот, думаю, стоит...
2
1
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Угол тригонометрических функций в модуле math измеряется в радианах, а не в градусах. d не должна быть глобальной переменной, вы можете просто вернуть угол из pointat:

def pointat(px,py):
    dx = px-x[i]
    dy = py-y[i]

    if dy == 0:
        if dx < 0:
            d = -math.pi/2
        else:
            d = math.pi/2
    else:
        if dy < 0:
            d = math.pi+math.atan(dx/dy)
        else:
            d = math.atan(dx/dy)
    return d
while True:
    # [...]

    for i in range(len(x)):
        # [...]
        for j in range(sub):
            # [...]

            for k in range(len(x)-1):
                if a == i:
                    a += 1
                dist = math.sqrt(((x[i]-x[a])*(x[i]-x[a]))+((y[i]-y[a])*(y[i]-y[a])))
                if dist < r*2:
                    d = pointat(x[a],y[a])
                    x[i] += (math.sin(d)*(dist-(r*2)))
                    y[i] += (math.cos(d)*(dist-(r*2)))
                    x[a] -= (math.sin(d)*(dist-(r*2)))
                    y[a] -= (math.cos(d)*(dist-(r*2)))
                
                dist = math.sqrt((x[i]*x[i])+(y[i]*y[i]))
                if dist > size-r:
                    d = pointat(0,0)
                    x[i] += (math.sin(d)*(dist-(size-r)))
                    y[i] += (math.cos(d)*(dist-(size-r)))
                a += 1

В целом, код в циклах можно значительно упростить. Я предлагаю реорганизовать ваш код следующим образом:

while True:
    # [...]

    for i in range(len(x)):
        prevx[i] = x[i]
        prevy[i] = y[i]
        
        for j in range(sub):
            x[i] += xv[i]/sub
            y[i] += yv[i]/sub
            y[i] -= 1/sub
            
            for a in range(len(x)):
                if a == i:
                   continue
                dx = x[i]-x[a]
                dy = y[i]-y[a]   
                dist = math.sqrt(dx*dx + dy*dy)
                if dist < r*2 and dist != 0:
                    x[i] -= dx/dist * (dist-r*2)
                    y[i] -= dy/dist * (dist-r*2)
                    x[a] += dx/dist * (dist-r*2)
                    y[a] += dy/dist * (dist-r*2)
                
                dist = math.sqrt(x[i]*x[i] + y[i]*y[i])
                if dist > size-r:
                    x[i] -= x[i]/dist * (dist-(size-r))
                    y[i] -= y[i]/dist * (dist-(size-r))

        xv[i] = max(-maxvel, min(maxvel, x[i]-prevx[i]))
        yv[i] = max(-maxvel, min(maxvel, y[i]-prevy[i]))

Большое спасибо! Теперь он намного стабильнее!

just_banana3 15.02.2023 19:17

Другие вопросы по теме