Colisões 6

2024-07-26

"""2024-07-26
Colisões 6
Exercício utilizando pymunk e colisões com muros invisíveis
png
Sketch,py5,CreativeCoding
"""

from collections import deque

import py5
import pymunk

from utils import helpers

space = pymunk.Space()
space.gravity = (0, 0)


MARGEM = 200
MARGEM_INTERNA = int(MARGEM * 1.3)

POSICAO_MURO = [
    ((MARGEM, MARGEM), (helpers.LARGURA - MARGEM, MARGEM)),
    ((helpers.LARGURA, MARGEM), (helpers.LARGURA - MARGEM, helpers.ALTURA - MARGEM)),
    (
        (helpers.LARGURA - MARGEM, helpers.ALTURA - MARGEM),
        (MARGEM, helpers.ALTURA - MARGEM),
    ),
    ((MARGEM, helpers.ALTURA - MARGEM), (MARGEM, MARGEM)),
]


PARTICULAS = None

LIMITES = []

sketch = helpers.info_for_sketch(__file__, __doc__)


def cria_particula(space, x0, y0, raio, massa, cor) -> pymunk.Circle:
    inercia = pymunk.moment_for_circle(massa, 0, raio, (0, 0))
    body = pymunk.Body(massa, inercia)
    body.position = x0, y0
    shape = pymunk.Circle(body, raio, (0, 0))
    shape._color = cor
    shape.elasticity = py5.random(0.6, 0.8)
    shape.friction = 0.99
    space.add(body, shape)
    return shape


def cria_limites(space):
    for inicio, final in POSICAO_MURO:
        limite = pymunk.Segment(space.static_body, inicio, final, 60)
        limite.elasticity = 0.1
        limite.friction = 0.99
        space.add(limite)
        LIMITES.append(limite)


def adiciona_ponto(space, x, y):
    limite = pymunk.Segment(space.static_body, (x, y), (x, y), 2)
    limite.elasticity = 0.2
    limite.friction = 0.99
    space.add(limite)


def setup():
    global PARTICULAS
    py5.size(helpers.LARGURA, helpers.ALTURA, py5.P3D)
    py5.color_mode(py5.HSB, 360, 100, 100)
    PARTICULAS = {}
    cria_limites(space)
    s = 80
    b = 80
    i = 0
    pontos = [
        (
            py5.random_int(MARGEM_INTERNA, py5.width - MARGEM_INTERNA),
            py5.random_int(MARGEM_INTERNA, py5.height - MARGEM_INTERNA),
        )
        for _ in range(24)
    ]
    for x0, y0 in pontos:
        key = f"particula_{i:02d}"
        raio = py5.random_int(2, 6)
        massa = raio * py5.random_int(3, 5)
        h = y0 % 180 + 10
        cor = py5.color(h, s, b)
        particula = cria_particula(space, x0, y0, raio=raio, massa=massa, cor=cor)
        particula.body.apply_impulse_at_world_point(
            (particula.body.position.x, particula.body.position.y),
            (
                py5.random_int(-4000, 4000),
                py5.random_int(-4000, 3000),
            ),
        )
        PARTICULAS[key] = {"particula": particula, "posicoes": deque(maxlen=5000)}
        i += 1


def draw():
    py5.background(0)
    for particula in PARTICULAS.values():
        p = particula["particula"]
        particula["posicoes"].append((p.body.position.x, p.body.position.y))
        py5.stroke(p._color)
        py5.stroke_cap(py5.ROUND)
        posicoes = len(particula["posicoes"])
        for idx, (x, y) in enumerate(particula["posicoes"]):
            adiciona_ponto(space, x, y)
            py5.stroke_weight(p.radius * (idx / posicoes))
            if not idx:
                py5.point(x, y)
            else:
                x0, y0 = particula["posicoes"][idx - 1]
                py5.line(x0, y0, x, y)

    # Avança a simulação
    space.step(1 / py5.get_frame_rate())
    helpers.write_legend(sketch=sketch)


def key_pressed():
    key = py5.key
    if key == " ":
        save_and_close()


def save_and_close():
    py5.no_loop()
    helpers.save_sketch_image(sketch)
    py5.exit_sketch()


if __name__ == "__main__":
    py5.run_sketch()