Square Moviment 02

2026-02-04

"""2026-02-04
Square Moviment 02
Grade de quadrados que se expandem em direções aleatórias e retornam à posição original.
ericof.com|https://openprocessing.org/sketch/2363803
png
Sketch,py5,CreativeCoding
"""

from random import shuffle
from sketches.utils.draw import canvas
from sketches.utils.draw.cores.paletas import gera_paleta
from sketches.utils.helpers import sketches as helpers

import py5


sketch = helpers.info_for_sketch(__file__, __doc__)

cor_fundo = py5.color(0)
objs: list["SuperQuadrado"] = []
GRADE_MULT = 1.0
GRADE_CELULAS = 8
CELULA_MULT = 0.75
paleta = gera_paleta("south-africa")


def ease_in_out_quint(x):
    return 16 * x**5 if x < 0.5 else 1 - ((-2 * x + 2) ** 5) / 2


class SuperQuadrado:
    """Quadrado que se move a partir de sua posição original."""

    x: float
    y: float
    w: float
    origin_x: float
    origin_y: float
    current_x: float
    current_y: float
    from_x: float
    from_y: float
    xpm: float
    ypm: float
    len: int
    to_x: float
    to_y: float
    time: int
    time_1: int
    time_2: int
    time_3: int
    clr: py5.Py5Color

    def __init__(self, x: float, y: float, w: float, cor: py5.Py5Color):
        self.x = x
        self.y = y
        self.w = w

        self.origin_x = x
        self.origin_y = y

        self.current_x = x
        self.current_y = y

        self.from_x = self.current_x
        self.from_y = self.current_y

        self.xpm = py5.random_choice([-1, 1])
        self.ypm = py5.random_choice([-1, 1])
        self.len = int(py5.random(1, 4))

        self.to_x = self.origin_x + self.w * self.len * self.xpm
        self.to_y = self.origin_y + self.w * self.len * self.ypm

        self.time = -int(py5.random(500))
        self.time_1 = 60
        self.time_2 = self.time_1 + 200
        self.time_3 = self.time_2 + 60

        self.clr = cor

    def show(self):
        py5.no_stroke()
        py5.fill(self.clr)

        meio_w = self.w / 2
        origem_x = self.origin_x
        origem_y = self.origin_y
        atual_x = self.current_x
        atual_y = self.current_y

        with py5.begin_shape(py5.QUADS):
            py5.vertex(origem_x - meio_w, origem_y - meio_w)
            py5.vertex(origem_x + meio_w, origem_y - meio_w)
            py5.vertex(atual_x + meio_w, atual_y - meio_w)
            py5.vertex(atual_x - meio_w, atual_y - meio_w)

            py5.vertex(origem_x + meio_w, origem_y - meio_w)
            py5.vertex(origem_x + meio_w, origem_y + meio_w)
            py5.vertex(atual_x + meio_w, atual_y + meio_w)
            py5.vertex(atual_x + meio_w, atual_y - meio_w)

            py5.vertex(origem_x + meio_w, origem_y + meio_w)
            py5.vertex(origem_x - meio_w, origem_y + meio_w)
            py5.vertex(atual_x - meio_w, atual_y + meio_w)
            py5.vertex(atual_x + meio_w, atual_y + meio_w)

            py5.vertex(origem_x - meio_w, origem_y + meio_w)
            py5.vertex(origem_x - meio_w, origem_y - meio_w)
            py5.vertex(atual_x - meio_w, atual_y - meio_w)
            py5.vertex(atual_x - meio_w, atual_y + meio_w)

            py5.fill(0)
            py5.vertex(atual_x - meio_w, atual_y - meio_w)
            py5.vertex(atual_x + meio_w, atual_y - meio_w)
            py5.vertex(atual_x + meio_w, atual_y + meio_w)
            py5.vertex(atual_x - meio_w, atual_y + meio_w)

        with py5.begin_shape(py5.QUADS):
            if self.ypm == 1:
                py5.fill(0, 75)
                py5.vertex(origem_x - meio_w, origem_y - meio_w)
                py5.vertex(origem_x + meio_w, origem_y - meio_w)
                py5.vertex(atual_x + meio_w, atual_y - meio_w)
                py5.vertex(atual_x - meio_w, atual_y - meio_w)

            if self.xpm == -1:
                py5.fill(0, 150)
                py5.vertex(origem_x + meio_w, origem_y - meio_w)
                py5.vertex(origem_x + meio_w, origem_y + meio_w)
                py5.vertex(atual_x + meio_w, atual_y + meio_w)
                py5.vertex(atual_x + meio_w, atual_y - meio_w)

            if self.ypm == -1:
                py5.fill(255, 150)
                py5.vertex(origem_x + meio_w, origem_y + meio_w)
                py5.vertex(origem_x - meio_w, origem_y + meio_w)
                py5.vertex(atual_x - meio_w, atual_y + meio_w)
                py5.vertex(atual_x + meio_w, atual_y + meio_w)

            if self.xpm == 1:
                py5.fill(255, 75)
                py5.vertex(origem_x - meio_w, origem_y + meio_w)
                py5.vertex(origem_x - meio_w, origem_y - meio_w)
                py5.vertex(atual_x - meio_w, atual_y - meio_w)
                py5.vertex(atual_x - meio_w, atual_y + meio_w)

        py5.fill(self.clr)
        py5.square(self.current_x, self.current_y, self.w)

    def move(self):
        if 0 < self.time < self.time_1:
            n = py5.norm(self.time, 0, self.time_1 - 1)
            t = ease_in_out_quint(n)
            self.current_x = py5.lerp(self.from_x, self.to_x, t)
            self.current_y = py5.lerp(self.from_y, self.to_y, t)

        elif self.time_2 < self.time < self.time_3:
            n = py5.norm(self.time, self.time_2, self.time_3 - 1)
            t = ease_in_out_quint(n)
            self.current_x = py5.lerp(self.to_x, self.from_x, t)
            self.current_y = py5.lerp(self.to_y, self.from_y, t)

        if self.time > self.time_3:
            self.time = -int(py5.random(500))

            self.xpm = py5.random_choice([-1, 1])
            self.ypm = py5.random_choice([-1, 1])
            self.len = int(py5.random(1, 4))
            self.to_x = self.origin_x + self.w * self.len * self.xpm
            self.to_y = self.origin_y + self.w * self.len * self.ypm

        self.time += 1


def setup():
    py5.size(*helpers.DIMENSOES.external, py5.P3D)
    py5.color_mode(py5.HSB, 360, 100, 100)
    py5.rect_mode(py5.CENTER)
    largura, altura = helpers.DIMENSOES.internal
    grade_tam = largura * GRADE_MULT
    celula_tam = grade_tam / GRADE_CELULAS
    celula_metade = celula_tam / 2
    celula_interna_tam = celula_tam * CELULA_MULT

    for i in range(GRADE_CELULAS):
        for j in range(GRADE_CELULAS):
            x = i * celula_tam + celula_metade + ((largura - grade_tam) / 2)
            y = j * celula_tam + celula_metade + ((altura - grade_tam) / 2)
            cor = py5.random_choice(paleta)
            objs.append(SuperQuadrado(x, y, celula_interna_tam, cor))

    shuffle(objs)


def draw():
    py5.background(cor_fundo)
    with py5.push():
        py5.translate(*helpers.DIMENSOES.pos_interno, -10)
        for obj in objs:
            obj.show()
            obj.move()
    # Credits and go
    canvas.sketch_frame(
        sketch,
        cor_fundo,
        "large_transparent_white",
        "transparent_white",
        version=2,
    )


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


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


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