ファイル
nizika_broadcast/test.py
T

306 行
8.7 KiB
Python

from __future__ import annotations
import sys
from datetime import datetime
from enum import Enum, auto
from typing import Callable, TypedDict
import cv2
import pygame
from cv2 import VideoCapture
from pygame import Rect, Surface
from pygame.font import Font
from pygame.mixer import Sound
from pygame.time import Clock
from common_module import CommonModule
pygame.init ()
FPS = 30
SYSTEM_FONT = pygame.font.SysFont ('notosanscjkjp', 24, bold = True)
USER_FONT = pygame.font.SysFont ('notosanscjkjp', 32, italic = True)
DEERJIKA_FONT = pygame.font.SysFont ('07nikumarufont', 50)
def main (
) -> None:
game = Game ()
bg = Bg (game)
deerjika = Deerjika (game, DeerjikaPattern.RELAXED,
x = CWindow.WIDTH * 3 / 4, y = CWindow.HEIGHT - 120)
balloon = Balloon (game)
balloon.talk ('あいうえおかきくけこさしすせそたちつてとなにぬねの', 'あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやいゆえよらりるれろわゐうゑを')
CurrentTime (game, SYSTEM_FONT)
Sound ('assets/bgm.mp3').play (loops = -1)
while True:
for event in pygame.event.get ():
if event.type == pygame.QUIT:
pygame.quit ()
sys.exit ()
game.redraw ()
class DeerjikaPattern (Enum):
NORMAL = auto ()
RELAXED = auto ()
SLEEPING = auto ()
class Direction (Enum):
LEFT = auto ()
RIGHT = auto ()
class Game:
clock: Clock
frame: int
redrawers: list[Redrawer]
screen: Surface
def __init__ (
self,
):
self.screen = pygame.display.set_mode ((CWindow.WIDTH, CWindow.HEIGHT))
self.clock = Clock ()
self.frame = 0
self.redrawers = []
def redraw (
self,
) -> None:
for redrawer in sorted (self.redrawers, key = lambda x: x['layer']):
if redrawer['obj'].enabled:
redrawer['obj'].redraw ()
pygame.display.update ()
self.clock.tick (FPS)
class GameObject:
frame: int
game: Game
width: int
height: int
x: float
y: float
vx: float = 0
vy: float = 0
ax: float = 0
ay: float = 0
arg: float = 0
enabled: bool = True
def __init__ (
self,
game: Game,
layer: int | None = None,
enabled: bool = True,
x: float = 0,
y: float = 0,
):
self.game = game
self.enabled = enabled
self.frame = 0
if layer is None:
if self.game.redrawers:
layer = max (r['layer'] for r in self.game.redrawers) + 10
else:
layer = 0
self.game.redrawers.append ({ 'layer': layer, 'obj': self })
self.x = x
self.y = y
def redraw (
self,
) -> None:
self.x += self.vx
self.y += self.vy
self.vx += self.ax
self.vy += self.ay
self.frame += 1
class Bg (GameObject):
surface: Surface
def __init__ (
self,
game: Game,
):
super ().__init__ (game)
self.surface = pygame.image.load ('assets/bg.jpg')
self.surface = pygame.transform.scale (self.surface, (CWindow.WIDTH, CWindow.HEIGHT))
def redraw (
self,
) -> None:
self.game.screen.blit (self.surface, (self.x, self.y))
super ().redraw ()
class Deerjika (GameObject):
surfaces: list[Surface]
size: int
width: int
height: int
scale: float = .8
def __init__ (
self,
game: Game,
pattern: DeerjikaPattern = DeerjikaPattern.NORMAL,
direction: Direction = Direction.LEFT,
layer: int | None = None,
x: float = 0,
y: float = 0,
):
super ().__init__ (game, layer, x = x, y = y)
self.pattern = pattern
self.direction = direction
match pattern:
case DeerjikaPattern.NORMAL:
...
case DeerjikaPattern.RELAXED:
match direction:
case Direction.LEFT:
self.width = 1280
self.height = 720
surface = pygame.image.load ('assets/deerjika_relax_left.png')
self.surfaces = []
for x in range (0, surface.get_width (), self.width):
self.surfaces.append (
surface.subsurface (x, 0, self.width, self.height))
case Direction.RIGHT:
...
self.size = len (self.surfaces)
def redraw (
self,
) -> None:
surface = pygame.transform.scale (self.surfaces[self.frame % self.size],
(self.width * self.scale, self.height * self.scale))
self.game.screen.blit (surface, surface.get_rect (center = (self.x, self.y)))
super ().redraw ()
class CurrentTime (GameObject):
font: Font
def __init__ (
self,
game: Game,
font: Font,
):
super ().__init__ (game)
self.font = font
def redraw (
self,
) -> None:
for i in range (4):
self.game.screen.blit (
self.font.render (str (datetime.now ()), True, (0, 0, 0)),
(i % 2, i // 2 * 2))
super ().redraw ()
class Balloon (GameObject):
surface: Surface
query: str = ''
answer: str = ''
image_url: str | None = None
x_flip: bool = False
y_flip: bool = False
length: int = 300
def __init__ (
self,
game: Game,
x_flip: bool = False,
y_flip: bool = False,
):
super ().__init__ (game, enabled = False)
self.x_flip = x_flip
self.y_flip = y_flip
self.surface = pygame.transform.scale (pygame.image.load ('assets/balloon.png'),
(CWindow.WIDTH, CWindow.HEIGHT / 2))
self.surface = pygame.transform.flip (self.surface, self.x_flip, self.y_flip)
def redraw (
self,
) -> None:
if self.frame >= self.length:
self.enabled = False
return
query = self.query
if CommonModule.len_by_full (query) > 21:
query = CommonModule.mid_by_full (query, 0, 19.5) + '...'
answer = Surface ((800, ((CommonModule.len_by_full (self.answer) - 1) // 16 + 1) * 50),
pygame.SRCALPHA)
for i in range (int (CommonModule.len_by_full (self.answer) - 1) // 16 + 1):
answer.blit (DEERJIKA_FONT.render (
CommonModule.mid_by_full (self.answer, 16 * i, 16), True, (192, 0, 0)),
(0, 50 * i))
surface = self.surface.copy ()
surface.blit (USER_FONT.render ('>' + query, True, (0, 0, 0)), (120, 70))
y: int
if self.frame < 30:
y = 0
elif self.frame >= self.length - 90:
y = answer.get_height () - 100
else:
y = int ((answer.get_height () - 100) * (self.frame - 30) / (self.length - 120))
surface.blit (answer, (100, 150), Rect (0, y, 800, 100))
self.game.screen.blit (surface, (0, 0))
super ().redraw ()
def talk (
self,
query: str,
answer: str,
image_url: str | None = None,
) -> None:
self.query = query
self.answer = answer
self.image_url = image_url
self.frame = 0
self.enabled = True
class CWindow:
WIDTH = 1024
HEIGHT = 768
class Redrawer (TypedDict):
layer: int
obj: GameObject
def get_surfaces_from_video (
video_path: str,
) -> list[Surface]:
cap = VideoCapture (video_path)
if not cap.isOpened ():
return []
fps = cap.get (cv2.CAP_PROP_FPS)
surfaces: list[Surface] = []
while cap.isOpened ():
(ret, frame) = cap.read ()
if not ret:
break
frame = cv2.cvtColor (frame, cv2.COLOR_BGR2RGB)
frame_surface = pygame.surfarray.make_surface (frame)
frame_surface = pygame.transform.rotate (frame_surface, -90)
surfaces.append (pygame.transform.flip (frame_surface, True, False))
cap.release ()
return surfaces
if __name__ == '__main__':
main ()