sketch_220119a

sketch.py

# -*- coding: utf-8 -*-
import pyxel
import math
from dataclasses import dataclass

N_POINTS = 100


@dataclass
class Vector:
    x: float
    y: float

    def square_mag(self):
        return self.x**2 + self.y**2

    def mag(self):
        return math.sqrt(self.mag())

    def __add__(self, v):
        return Vector(self.x + v.x, self.y + v.y)

    def __sub__(self, v):
        return Vector(self.x - v.x, self.y - v.y)

    def __neg__(self):
        return Vector(-self.x, -self.y)


neighbors_list = [
    Vector(1, 0),
    Vector(0, 1),
    Vector(-1, 0),
    Vector(0, -1),
]


def fill(v, c):

    que = []
    que.append(v)

    def is_valid_pos(p):
        return 0 <= p.x < pyxel.width and 0 <= p.y < pyxel.height

    while len(que) > 0:
        p = que.pop(0)

        for q in neighbors_list:
            r = p + q
            if is_valid_pos(r) and pyxel.pget(r.x, r.y) == pyxel.COLOR_WHITE:
                que.append(r)
                pyxel.pset(r.x, r.y, c)


class App:
    def __init__(self):
        pyxel.init(128, 128, title='app')

        self.scale = Vector(2.0, 2.0)
        self.clicked_frame = 0

        self.points = []
        for k in range(N_POINTS):
            t = 2.0 * math.pi * k / N_POINTS
            x = 16.0 * math.sin(t) ** 3
            y = -(13.0 * math.cos(t) - 5.0 * math.cos(2.0 * t)
                  - 2.0*math.cos(3.0 * t) - math.cos(4.0 * t))
            self.points.append(Vector(x, y))

    def run(self):
        pyxel.run(self.update, self.draw)

    def update(self):

        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
            self.clicked_frame = pyxel.frame_count

        t = (pyxel.frame_count - self.clicked_frame) / 30.0
        self.scale.x = 2.0 + 0.5 * math.exp(-t) * math.cos(t * 10.0)
        self.scale.y = 2.0 + 0.5 * math.exp(-t) * math.sin(t * 10.0)

    def draw(self):
        pyxel.cls(pyxel.COLOR_WHITE)

        for k in range(N_POINTS - 1):
            pyxel.line(
                pyxel.width / 2 + self.points[k].x * self.scale.x,
                pyxel.height / 2 + self.points[k].y * self.scale.y,
                pyxel.width / 2 + self.points[k+1].x * self.scale.x,
                pyxel.height / 2 + self.points[k+1].y * self.scale.y,
                pyxel.COLOR_RED
            )

        # pyxel.fill is officially implemented in v1.6.8
        # fill(Vector(pyxel.width / 2.0, pyxel.height / 2.0), pyxel.COLOR_RED)
        pyxel.fill(pyxel.width / 2.0, pyxel.height / 2.0, pyxel.COLOR_RED)


if __name__ == '__main__':
    app = App()
    app.run()