伊地知ニジカ放送局だぬ゛ん゛. https://www.youtube.com/@deerjika
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test.py 8.7 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. from __future__ import annotations
  2. import sys
  3. from datetime import datetime
  4. from enum import Enum, auto
  5. from typing import Callable, TypedDict
  6. import cv2
  7. import pygame
  8. from cv2 import VideoCapture
  9. from pygame import Rect, Surface
  10. from pygame.font import Font
  11. from pygame.mixer import Sound
  12. from pygame.time import Clock
  13. from common_module import CommonModule
  14. pygame.init ()
  15. FPS = 30
  16. SYSTEM_FONT = pygame.font.SysFont ('notosanscjkjp', 24, bold = True)
  17. USER_FONT = pygame.font.SysFont ('notosanscjkjp', 32, italic = True)
  18. DEERJIKA_FONT = pygame.font.SysFont ('07nikumarufont', 50)
  19. def main (
  20. ) -> None:
  21. game = Game ()
  22. bg = Bg (game)
  23. deerjika = Deerjika (game, DeerjikaPattern.RELAXED,
  24. x = CWindow.WIDTH * 3 / 4, y = CWindow.HEIGHT - 120)
  25. balloon = Balloon (game)
  26. balloon.talk ('あいうえおかきくけこさしすせそたちつてとなにぬねの', 'あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやいゆえよらりるれろわゐうゑを')
  27. CurrentTime (game, SYSTEM_FONT)
  28. Sound ('assets/bgm.mp3').play (loops = -1)
  29. while True:
  30. for event in pygame.event.get ():
  31. if event.type == pygame.QUIT:
  32. pygame.quit ()
  33. sys.exit ()
  34. game.redraw ()
  35. class DeerjikaPattern (Enum):
  36. NORMAL = auto ()
  37. RELAXED = auto ()
  38. SLEEPING = auto ()
  39. class Direction (Enum):
  40. LEFT = auto ()
  41. RIGHT = auto ()
  42. class Game:
  43. clock: Clock
  44. frame: int
  45. redrawers: list[Redrawer]
  46. screen: Surface
  47. def __init__ (
  48. self,
  49. ):
  50. self.screen = pygame.display.set_mode ((CWindow.WIDTH, CWindow.HEIGHT))
  51. self.clock = Clock ()
  52. self.frame = 0
  53. self.redrawers = []
  54. def redraw (
  55. self,
  56. ) -> None:
  57. for redrawer in sorted (self.redrawers, key = lambda x: x['layer']):
  58. if redrawer['obj'].enabled:
  59. redrawer['obj'].redraw ()
  60. pygame.display.update ()
  61. self.clock.tick (FPS)
  62. class GameObject:
  63. frame: int
  64. game: Game
  65. width: int
  66. height: int
  67. x: float
  68. y: float
  69. vx: float = 0
  70. vy: float = 0
  71. ax: float = 0
  72. ay: float = 0
  73. arg: float = 0
  74. enabled: bool = True
  75. def __init__ (
  76. self,
  77. game: Game,
  78. layer: int | None = None,
  79. enabled: bool = True,
  80. x: float = 0,
  81. y: float = 0,
  82. ):
  83. self.game = game
  84. self.enabled = enabled
  85. self.frame = 0
  86. if layer is None:
  87. if self.game.redrawers:
  88. layer = max (r['layer'] for r in self.game.redrawers) + 10
  89. else:
  90. layer = 0
  91. self.game.redrawers.append ({ 'layer': layer, 'obj': self })
  92. self.x = x
  93. self.y = y
  94. def redraw (
  95. self,
  96. ) -> None:
  97. self.x += self.vx
  98. self.y += self.vy
  99. self.vx += self.ax
  100. self.vy += self.ay
  101. self.frame += 1
  102. class Bg (GameObject):
  103. surface: Surface
  104. def __init__ (
  105. self,
  106. game: Game,
  107. ):
  108. super ().__init__ (game)
  109. self.surface = pygame.image.load ('assets/bg.jpg')
  110. self.surface = pygame.transform.scale (self.surface, (CWindow.WIDTH, CWindow.HEIGHT))
  111. def redraw (
  112. self,
  113. ) -> None:
  114. self.game.screen.blit (self.surface, (self.x, self.y))
  115. super ().redraw ()
  116. class Deerjika (GameObject):
  117. surfaces: list[Surface]
  118. size: int
  119. width: int
  120. height: int
  121. scale: float = .8
  122. def __init__ (
  123. self,
  124. game: Game,
  125. pattern: DeerjikaPattern = DeerjikaPattern.NORMAL,
  126. direction: Direction = Direction.LEFT,
  127. layer: int | None = None,
  128. x: float = 0,
  129. y: float = 0,
  130. ):
  131. super ().__init__ (game, layer, x = x, y = y)
  132. self.pattern = pattern
  133. self.direction = direction
  134. match pattern:
  135. case DeerjikaPattern.NORMAL:
  136. ...
  137. case DeerjikaPattern.RELAXED:
  138. match direction:
  139. case Direction.LEFT:
  140. self.width = 1280
  141. self.height = 720
  142. surface = pygame.image.load ('assets/deerjika_relax_left.png')
  143. self.surfaces = []
  144. for x in range (0, surface.get_width (), self.width):
  145. self.surfaces.append (
  146. surface.subsurface (x, 0, self.width, self.height))
  147. case Direction.RIGHT:
  148. ...
  149. self.size = len (self.surfaces)
  150. def redraw (
  151. self,
  152. ) -> None:
  153. surface = pygame.transform.scale (self.surfaces[self.frame % self.size],
  154. (self.width * self.scale, self.height * self.scale))
  155. self.game.screen.blit (surface, surface.get_rect (center = (self.x, self.y)))
  156. super ().redraw ()
  157. class CurrentTime (GameObject):
  158. font: Font
  159. def __init__ (
  160. self,
  161. game: Game,
  162. font: Font,
  163. ):
  164. super ().__init__ (game)
  165. self.font = font
  166. def redraw (
  167. self,
  168. ) -> None:
  169. for i in range (4):
  170. self.game.screen.blit (
  171. self.font.render (str (datetime.now ()), True, (0, 0, 0)),
  172. (i % 2, i // 2 * 2))
  173. super ().redraw ()
  174. class Balloon (GameObject):
  175. surface: Surface
  176. query: str = ''
  177. answer: str = ''
  178. image_url: str | None = None
  179. x_flip: bool = False
  180. y_flip: bool = False
  181. length: int = 300
  182. def __init__ (
  183. self,
  184. game: Game,
  185. x_flip: bool = False,
  186. y_flip: bool = False,
  187. ):
  188. super ().__init__ (game, enabled = False)
  189. self.x_flip = x_flip
  190. self.y_flip = y_flip
  191. self.surface = pygame.transform.scale (pygame.image.load ('assets/balloon.png'),
  192. (CWindow.WIDTH, CWindow.HEIGHT / 2))
  193. self.surface = pygame.transform.flip (self.surface, self.x_flip, self.y_flip)
  194. def redraw (
  195. self,
  196. ) -> None:
  197. if self.frame >= self.length:
  198. self.enabled = False
  199. return
  200. query = self.query
  201. if CommonModule.len_by_full (query) > 21:
  202. query = CommonModule.mid_by_full (query, 0, 19.5) + '...'
  203. answer = Surface ((800, ((CommonModule.len_by_full (self.answer) - 1) // 16 + 1) * 50),
  204. pygame.SRCALPHA)
  205. for i in range (int (CommonModule.len_by_full (self.answer) - 1) // 16 + 1):
  206. answer.blit (DEERJIKA_FONT.render (
  207. CommonModule.mid_by_full (self.answer, 16 * i, 16), True, (192, 0, 0)),
  208. (0, 50 * i))
  209. surface = self.surface.copy ()
  210. surface.blit (USER_FONT.render ('>' + query, True, (0, 0, 0)), (120, 70))
  211. y: int
  212. if self.frame < 30:
  213. y = 0
  214. elif self.frame >= self.length - 90:
  215. y = answer.get_height () - 100
  216. else:
  217. y = int ((answer.get_height () - 100) * (self.frame - 30) / (self.length - 120))
  218. surface.blit (answer, (100, 150), Rect (0, y, 800, 100))
  219. self.game.screen.blit (surface, (0, 0))
  220. super ().redraw ()
  221. def talk (
  222. self,
  223. query: str,
  224. answer: str,
  225. image_url: str | None = None,
  226. ) -> None:
  227. self.query = query
  228. self.answer = answer
  229. self.image_url = image_url
  230. self.frame = 0
  231. self.enabled = True
  232. class CWindow:
  233. WIDTH = 1024
  234. HEIGHT = 768
  235. class Redrawer (TypedDict):
  236. layer: int
  237. obj: GameObject
  238. def get_surfaces_from_video (
  239. video_path: str,
  240. ) -> list[Surface]:
  241. cap = VideoCapture (video_path)
  242. if not cap.isOpened ():
  243. return []
  244. fps = cap.get (cv2.CAP_PROP_FPS)
  245. surfaces: list[Surface] = []
  246. while cap.isOpened ():
  247. (ret, frame) = cap.read ()
  248. if not ret:
  249. break
  250. frame = cv2.cvtColor (frame, cv2.COLOR_BGR2RGB)
  251. frame_surface = pygame.surfarray.make_surface (frame)
  252. frame_surface = pygame.transform.rotate (frame_surface, -90)
  253. surfaces.append (pygame.transform.flip (frame_surface, True, False))
  254. cap.release ()
  255. return surfaces
  256. if __name__ == '__main__':
  257. main ()