--- tags: 1_basic --- # DEMO. Ефекти 2. Порядок ![](https://i.imgur.com/CSzk5lN.gif) Note: План: - цикл for - counter,i - процедури для організації коду --- ## Зав'язка Гостросюжетний текст про те, як раптом комусь знадобилися скіли програміста. --- 1. Зигзаг 2. Два симетричні зигзаги 3. Вікно 4. Зигзаги "за" вікном Слайди з контентом --- Живий кодинг, експерименти, демо Note: Копія коду для тих, хто не був присутній на лекції і не дивився відео. --- ### DEMO.Effects2.A0.0 (обов'язкове завдання) 3 або 4 симетричні зигзаги ---- ### DEMO.Effects2.A0.1 (обов'язкове завдання) Намалювати трикутник заданого розміру. ---- ### DEMO.Effects2.A0.2 (обов'язкове завдання) Один з перших ефектів "вогню" з'явився в 1980 роках, і з тих пір неодноразово був використаний у демках та іграх. Цей ефект реалізовували на всіх екранах, включаючи допотопні MS-DOS. Коли я вперше побачив його код в 9 класі, я не міг зрозуміти як це працює. Але виглядало дуже круто! <details> <summary>Насправді...</summary> Щоб зрозуміти цей код, треба знати: <ul> <li>координатну площину <li>двовимірні масиви, слайси масивів, операції над рядками масивів <li>матриці та роботу за матрицями: додавання, транспонування, скалярне множення <li>розуміти в якому порядку оновлюються дані в масивах та матрицях <li>кольорові схеми RGB та HSL, чим відрізняються та коли друга зручніша <li>механізм виводу пікселів на екран, дабл буфер <li>середнє арифметичне <li>додавання по модулю та коли його треба використовувати <li>8-бітні палітри <li>і це тільки теми, які не стосуються самого Python! </ul> </details> <br /> Спробуй і ти запусти "вогонь"! Вибери режим, 1 або 2, а потім переглянь код. Чи зможеш зрозуміти як воно працює? P.S. Цей та інші ефекти -- це прадіди "демосцени", мінімалістичних арт-перфомансів за допомогою програмування. В завданні [DEMO.Effects2.A3.0](#DEMO.Effects2.A3.0) є більше деталей. ```python= import pygame import random import colorsys def fps_text(clock, font): """ Повертає об'єкт Surface з текстом про кількість кадрів в секунду (frames per second, FPS) """ fps = "FPS: " + str(int(clock.get_fps())) return font.render(fps, 1, pygame.Color("violet")) def color_HSL(h, s, l): """ Перетворює колір з системи HSL в систему RGB. HSL дозволяє дуже просто робити палітру з "вогняними" кольорами На вході - кольори у діапазоні 0-255 На виході - (r,g,b), також у діапазоні 0-255 """ color = colorsys.hls_to_rgb(h/255, l/255, s/255) return tuple( int(x*255) for x in color ) def fire_palette(color_shift=0, color_split=1): """ Палітра кольорів на 256 елементів. Параметр color_shift дозволяє керувати домінантним кольором вогню """ return [ color_HSL((x / color_split + color_shift) % 256, 255, min(255, x*2)) for x in range(256) ] def check_exit(): for ev in pygame.event.get(): if ev.type == pygame.QUIT: raise KeyboardInterrupt() def fire_transform_numpy(arr): """ Ітерація "вогню" через матриці numpy """ height = arr.shape[0] for y in range(height-1): arr[y, 1:-1] = ( arr[y+1, 1:-1] + arr[y+1, :-2] + arr[y+1, 2: ] + arr[(y+2)%height, 1:-1] ) * 0.2499 def fire_transform_pixelarray(arr): """ Ітерація "вогню" через PixelArray об'єкт pygame """ w = arr.shape[0] h = arr.shape[1] for y in range(0, h-1): for x in range(0, w): arr[x, y] = int(( arr[(x - 1 + w) % w, (y + 1) % h] + arr[x % w , (y + 1) % h] + arr[(x + 1) % w , (y + 1) % h] + arr[x % w , (y + 2) % h] ) * 0.2499) def non_optimized_demo(W, H): screen = pygame.display.set_mode((W, H)) font = pygame.font.SysFont("Arial", 18) clock = pygame.time.Clock() # surface для вогню fire_surface = pygame.Surface((W, H), pygame.HWPALETTE, 8) fire_surface.set_palette(fire_palette(color_split=3)) fire_surface.fill(0) while True: screen.fill(0) # очистити екран pxarray = pygame.PixelArray(fire_surface) # Щоб зробити демонстрацію цікавішою, кожні 5 секунд будемо змінювати тип вогню if pygame.time.get_ticks() // 1000 % 10 < 5: # Нижній ряд - випадкові кольори з палітри for x in range(0, W): pxarray[x, H - 1] = random.randrange(0, 100) fire_transform_pixelarray(pxarray) pxarray.close() # Намалювати вогонь на екран screen.blit(fire_surface, (0,0)) # Намалювати текст FPS на екран screen.blit(fps_text(clock, font), (10, 0)) check_exit() clock.tick(200) # FPS, який ми хотіли би бачити pygame.display.flip() def optimized_demo(W, H): import numpy as np from pygame import surfarray screen = pygame.display.set_mode((W, H)) font = pygame.font.SysFont("Arial", 18) clock = pygame.time.Clock() # матриця для вогню. Координати - спочатку y, потім x (!!!) fire = np.zeros((H, W)).astype(int) # surface для вогню fire_surface = pygame.Surface((fire.shape[1], fire.shape[0]), pygame.HWPALETTE, 8) fire_surface.set_palette(fire_palette(120)) while True: screen.fill(0) # очистити екран # Щоб зробити демонстрацію цікавішою, кожні 5 секунд будемо змінювати тип вогню if pygame.time.get_ticks() // 1000 % 10 < 5: # Нижній ряд - випадкові кольори з палітри fire[-1] = np.random.randint(0, 150, (fire.shape[1],)) fire_transform_numpy(fire) # Намалювати вогонь на екран. Не забуваємо про порядок координат! surfarray.blit_array(fire_surface, np.transpose(fire)) screen.blit(fire_surface, (0,0)) # Намалювати текст FPS на екран screen.blit(fps_text(clock, font), (10, 0)) check_exit() clock.tick(200) # FPS, який ми хотіли би бачити pygame.display.flip() def main(): try: variant = None while variant not in ("1", "2"): variant = input( "Вибери варіант - (1) неоптимізоване демо, (2) оптимізоване демо: ") pygame.init() if variant == "1": non_optimized_demo(80, 100) else: optimized_demo(300, 150) except KeyboardInterrupt: pass finally: pygame.quit() main() ``` --- ### Додаткові завдання #### DEMO.Effects2.A1.0 https://edabit.com/challenges #### DEMO.Effects2.A1.1 #### DEMO.Effects2.A1.2 #### DEMO.Effects2.A1.3 #### DEMO.Effects2.A1.4 --- ### Додаткові завдання (складні!) #### DEMO.Effects2.A2.0 #### DEMO.Effects2.A2.1 #### DEMO.Effects2.A2.2 --- ### Real-world завдання, для експертів #### DEMO.Effects2.A3.0 В 2004 році вийшла одна комп'ютерна інді мінігра, котра наробила трошки шуму. Називалася `.kkrieger`. Чули про таку? {%youtube 9f5TYTRhC64%} Її фішка була в процедурній генерації всіх текстур, звуків та анімацій. Сьогодні Unreal Engine за допомогою мільйонів трикутників в одному об'єкті досягає практично фотореалістичності, а установлений GTA V займає 65 Гб місця на диску! Це нереально великий об'єм даних, і це в 500 000 раз більше ніж мав розмір `.kkrieger`. Розмір гри був 96Кб, і змагалась гра на конкурсі ігор розміром до 96Кб. Вона була настільки маленька, що люди думали -- це вірус. Ніхто не вірив, що шутер можна вмістити в такий маленький об'єм, доки самостійно її не запускали. Корені гри походять від поняття **"демосцени"** -- коли програмісти демонструють своє кунг-фу, керування пікселями без грузних движків, без популярних фреймворків. Тільки ти і пікселі (і аудіо). Це -- арт, мистецтво для гіків. {%youtube 9NBUM2-wkJE%} - сама демка -- https://files.scene.org/view/demos/groups/farbrausch/kkrieger-beta.zip - код гри [знаходиться на Github](https://github.com/farbrausch/fr_public/tree/master/werkkzeug3_kkrieger) - один з авторів розповів, з чого складається гра -- https://fgiesen.wordpress.com/2012/02/13/debris-opening-the-box Але завдання ось у чому: створити свою "демку", програму котра демонструє віртуозне володіння програмерськими штучками та математикою процедурної генерації.