Как можно оптимизировать код для pygame?

Мне в универе выдали проект один простой, но почему-то очень страдает оптимизация. суть проста: Отобразить на экране N шариков разного размера, которые бы двигались с разной скоростью в разных направлениях без особой просадки ФПС. Вроде бы задачка несложная, но при отображении больше 200 шариков, фпс начинает заметно проседать. Подскажите, пожалуйста, чем и как это можно исправить? Я слышал про намбу, и нампай, но до этого не работал с ними, так что не знаю, как будет правильнее оптимизировать свой код под эти модули. Может, сможете мне помочь?

У меня есть две функции, одна отвечает за создание этих самых шариков так, чтобы они не накладывались друг на друга, и вторая, собственно, за рендер и обнаружение коллизий. для граф. движка использую пайгем, но думаю, что его уже навряд ли как смогу оптимизировать, ибо основная проблема в том, что эти две функции слишком тяжёлые.

import numpy as np
import numba as nb
import random as rd


res = (1152, 648)

colors = [
    (0, 0, 0),
    (29, 43, 83),
    (126, 37, 83),
    (0, 135, 81),
    (171, 82, 54),
    (95, 87, 79),
    (194, 195, 199),
    (255, 241, 232),
    (255, 0, 77),
    (255, 163, 0),
    (255, 236, 39),
    (0, 228, 54),
    (41, 173, 255),
    (131, 118, 156),
    (255, 119, 168),
    (255, 204, 170),
]

Create all the balls

def init(balls):

bals = list()
while balls > 0:
    size = rd.random() * 10 + 5
    ball = [
        (rd.random() * 0.9 + 0.05) * res[0],
        (rd.random() * 0.9 + 0.05) * res[1],
        rd.random() * 2 * np.pi,
        size,
        rd.choice(colors[1:]),
        20 - size
    ]

    cols = False
    for bal in bals:
        if (ball[0] - bal[0]) ** 2 + (ball[1] - bal[1]) ** 2 <= (ball[3] + bal[3]) ** 2:
            cols = True

    if not cols:
        bals.append(ball)
        balls -= 1

return bals

Main render func

def render(balls):

for num in range(len(balls)):
    ball = balls[num]

    # Detect collision with walls
    if ball[0] + ball[3] >= res[0] or ball[0] - ball[3] <= 0:
        ball[2] = - ball[2]
    if ball[1] + ball[3] >= res[1] or ball[1] - ball[3] <= 0:
        ball[2] = np.pi - ball[2]

    # Detect collision between balls
    for bal in range(num):
        bal = balls[bal]
        if (ball[0] - bal[0]) ** 2 + (ball[1] - bal[1]) ** 2 <= (ball[3] + bal[3]) ** 2:

            if (ball[0] - bal[0]) * (ball[1] - bal[1]) > 0:
                a = np.arccos(np.abs(ball[0] - bal[0]) / (ball[3] + bal[3]))
                ball[2] = 2 * a - ball[2]
                bal[2] = 2 * a - bal[2]

            elif (ball[0] - bal[0]) * (ball[1] - bal[1]) < 0:
                a = np.pi - np.arccos(np.abs(ball[0] - bal[0]) / (ball[3] + bal[3]))
                ball[2] = 2 * a - ball[2]
                bal[2] = 2 * a - bal[2]

    # Move ball
    ball[0] += np.sin(ball[2]) * ball[5]
    ball[1] += np.cos(ball[2]) * ball[5]

P.S. я знаю, что модель поведения шариков после столкновения друг с другом не доработана до конца и может глючить (если кто сможет и захочет всё это дело протестировать, в комментариях оставлю ссылку на репозиторий). Но у меня нет идей, как по-другому должны вести себя шарики при столкновении, так как максимум математического из своего мозга я уже выжал.


Ответы (0 шт):