|
|
@@ -1,13 +1,15 @@ |
|
|
|
from __future__ import annotations |
|
|
|
|
|
|
|
import math |
|
|
|
import sys |
|
|
|
from datetime import datetime |
|
|
|
from datetime import datetime, timedelta |
|
|
|
from enum import Enum, auto |
|
|
|
from typing import Callable, TypedDict |
|
|
|
|
|
|
|
import cv2 |
|
|
|
import pygame |
|
|
|
from cv2 import VideoCapture |
|
|
|
from ephem import Moon, Observer, Sun # type: ignore |
|
|
|
from pygame import Rect, Surface |
|
|
|
from pygame.font import Font |
|
|
|
from pygame.mixer import Sound |
|
|
@@ -23,14 +25,15 @@ 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) |
|
|
|
KitaSun (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: |
|
|
@@ -42,21 +45,49 @@ def main ( |
|
|
|
|
|
|
|
|
|
|
|
class DeerjikaPattern (Enum): |
|
|
|
""" |
|
|
|
ニジカの状態 |
|
|
|
|
|
|
|
Members: |
|
|
|
NORMAL: 通常 |
|
|
|
RELAXED: 足パタパタ |
|
|
|
SLEEPING: 寝ニジカ |
|
|
|
""" |
|
|
|
|
|
|
|
NORMAL = auto () |
|
|
|
RELAXED = auto () |
|
|
|
SLEEPING = auto () |
|
|
|
|
|
|
|
|
|
|
|
class Direction (Enum): |
|
|
|
""" |
|
|
|
クリーチャの向き |
|
|
|
|
|
|
|
Members: |
|
|
|
LEFT: 左向き |
|
|
|
RIGHT: 右向き |
|
|
|
""" |
|
|
|
|
|
|
|
LEFT = auto () |
|
|
|
RIGHT = auto () |
|
|
|
|
|
|
|
|
|
|
|
class Game: |
|
|
|
""" |
|
|
|
ゲーム・クラス |
|
|
|
|
|
|
|
Attributes: |
|
|
|
clock (Clock): Clock オブゼクト |
|
|
|
frame (int): フレーム・カウンタ |
|
|
|
redrawers (list[Redrawer]): 再描画するクラスのリスト |
|
|
|
screen (Surface): 基底スクリーン |
|
|
|
""" |
|
|
|
|
|
|
|
clock: Clock |
|
|
|
frame: int |
|
|
|
redrawers: list[Redrawer] |
|
|
|
screen: Surface |
|
|
|
sky: Sky |
|
|
|
|
|
|
|
def __init__ ( |
|
|
|
self, |
|
|
@@ -65,6 +96,7 @@ class Game: |
|
|
|
self.clock = Clock () |
|
|
|
self.frame = 0 |
|
|
|
self.redrawers = [] |
|
|
|
self._create_sky () |
|
|
|
|
|
|
|
def redraw ( |
|
|
|
self, |
|
|
@@ -76,19 +108,46 @@ class Game: |
|
|
|
self.clock.tick (FPS) |
|
|
|
|
|
|
|
|
|
|
|
def _create_sky ( |
|
|
|
self, |
|
|
|
) -> None: |
|
|
|
self.sky = Sky () |
|
|
|
self.sky.observer = Observer () |
|
|
|
self.sky.observer.lat = '35' |
|
|
|
self.sky.observer.lon = '139' |
|
|
|
|
|
|
|
|
|
|
|
class GameObject: |
|
|
|
""" |
|
|
|
各ゲーム・オブゼクトの基底クラス |
|
|
|
|
|
|
|
Attributes: |
|
|
|
arg (float): 回転角度 (rad) |
|
|
|
ax (float): X 軸に対する加速度 (px/frame^2) |
|
|
|
ay (float): y 軸に対する加速度 (px/frame^2) |
|
|
|
enabled (bool): オブゼクトの表示可否 |
|
|
|
frame (int): フレーム・カウンタ |
|
|
|
game (Game): ゲーム基盤 |
|
|
|
height (int): 高さ (px) |
|
|
|
vx (float): x 軸に対する速度 (px/frame) |
|
|
|
vy (float): y 軸に対する速度 (px/frame) |
|
|
|
width (int): 幅 (px) |
|
|
|
x (float): X 座標 (px) |
|
|
|
y (float): Y 座標 (px) |
|
|
|
""" |
|
|
|
|
|
|
|
arg: float = 0 |
|
|
|
ax: float = 0 |
|
|
|
ay: float = 0 |
|
|
|
enabled: bool = True |
|
|
|
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 |
|
|
|
width: int |
|
|
|
x: float |
|
|
|
y: float |
|
|
|
|
|
|
|
def __init__ ( |
|
|
|
self, |
|
|
@@ -121,6 +180,13 @@ class GameObject: |
|
|
|
|
|
|
|
|
|
|
|
class Bg (GameObject): |
|
|
|
""" |
|
|
|
背景 |
|
|
|
|
|
|
|
Attributes: |
|
|
|
surface (Surface): 背景 Surface |
|
|
|
""" |
|
|
|
|
|
|
|
surface: Surface |
|
|
|
|
|
|
|
def __init__ ( |
|
|
@@ -139,11 +205,20 @@ class Bg (GameObject): |
|
|
|
|
|
|
|
|
|
|
|
class Deerjika (GameObject): |
|
|
|
surfaces: list[Surface] |
|
|
|
size: int |
|
|
|
width: int |
|
|
|
""" |
|
|
|
伊地知ニジカ |
|
|
|
|
|
|
|
Attributes: |
|
|
|
height (int): 高さ (px) |
|
|
|
scale (float): 拡大率 |
|
|
|
surfaces (list[Surface]): ニジカの各フレームを Surface にしたリスト |
|
|
|
width (int): 幅 (px) |
|
|
|
""" |
|
|
|
|
|
|
|
height: int |
|
|
|
scale: float = .8 |
|
|
|
surfaces: list[Surface] |
|
|
|
width: int |
|
|
|
|
|
|
|
def __init__ ( |
|
|
|
self, |
|
|
@@ -172,18 +247,24 @@ class Deerjika (GameObject): |
|
|
|
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], |
|
|
|
surface = pygame.transform.scale (self.surfaces[self.frame % len (self.surfaces)], |
|
|
|
(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): |
|
|
|
""" |
|
|
|
現在日時表示 |
|
|
|
|
|
|
|
Attributes: |
|
|
|
font (Font): フォント |
|
|
|
""" |
|
|
|
|
|
|
|
font: Font |
|
|
|
|
|
|
|
def __init__ ( |
|
|
@@ -205,13 +286,26 @@ class CurrentTime (GameObject): |
|
|
|
|
|
|
|
|
|
|
|
class Balloon (GameObject): |
|
|
|
surface: Surface |
|
|
|
query: str = '' |
|
|
|
""" |
|
|
|
吹出し |
|
|
|
|
|
|
|
Attributes: |
|
|
|
answer (str): 回答テキスト |
|
|
|
image_url (str, None): 画像 URL |
|
|
|
length (int): 表示する時間 (frame) |
|
|
|
query (str): 質問テキスト |
|
|
|
surface (Surface): 吹出し Surface |
|
|
|
x_flip (bool): 左右反転フラグ |
|
|
|
y_flip (bool): 上下反転フラグ |
|
|
|
""" |
|
|
|
|
|
|
|
answer: str = '' |
|
|
|
image_url: str | None = None |
|
|
|
length: int = 300 |
|
|
|
query: str = '' |
|
|
|
surface: Surface |
|
|
|
x_flip: bool = False |
|
|
|
y_flip: bool = False |
|
|
|
length: int = 300 |
|
|
|
|
|
|
|
def __init__ ( |
|
|
|
self, |
|
|
@@ -259,20 +353,130 @@ class Balloon (GameObject): |
|
|
|
query: str, |
|
|
|
answer: str, |
|
|
|
image_url: str | None = None, |
|
|
|
length: int = 300, |
|
|
|
) -> None: |
|
|
|
self.query = query |
|
|
|
self.answer = answer |
|
|
|
self.image_url = image_url |
|
|
|
self.length = length |
|
|
|
self.frame = 0 |
|
|
|
self.enabled = True |
|
|
|
|
|
|
|
|
|
|
|
class KitaSun (GameObject): |
|
|
|
""" |
|
|
|
き太く陽 |
|
|
|
|
|
|
|
Attributes: |
|
|
|
sun (Sun): ephem の太陽オブゼクト |
|
|
|
surface (Surface): き太く陽 Surface |
|
|
|
""" |
|
|
|
|
|
|
|
alt: float |
|
|
|
az: float |
|
|
|
sun: Sun |
|
|
|
surface: Surface |
|
|
|
|
|
|
|
def __init__ ( |
|
|
|
self, |
|
|
|
game: Game, |
|
|
|
): |
|
|
|
super ().__init__ (game) |
|
|
|
self.surface = pygame.transform.scale (pygame.image.load ('assets/sun.png'), (200, 200)) |
|
|
|
self.sun = Sun () |
|
|
|
|
|
|
|
def redraw ( |
|
|
|
self, |
|
|
|
) -> None: |
|
|
|
self.game.sky.observer.date = datetime.now () - timedelta (hours = 9) |
|
|
|
self.sun.compute (self.game.sky.observer) |
|
|
|
self.alt = self.sun.alt |
|
|
|
self.az = self.sun.az |
|
|
|
print (self.x, self.y) |
|
|
|
self.game.screen.blit ( |
|
|
|
pygame.transform.rotate (self.surface, -(90 + math.degrees (self.arg))), |
|
|
|
(self.x, self.y)) |
|
|
|
super ().redraw () |
|
|
|
self.x = self.new_x |
|
|
|
self.y = self.new_y |
|
|
|
if abs (self.new_arg - self.arg) > math.radians (3): |
|
|
|
self.arg = self.new_arg |
|
|
|
|
|
|
|
@property |
|
|
|
def new_x ( |
|
|
|
self, |
|
|
|
) -> float: |
|
|
|
return CWindow.WIDTH * (math.degrees (self.az) - 80) / 120 |
|
|
|
|
|
|
|
@property |
|
|
|
def new_y ( |
|
|
|
self, |
|
|
|
) -> float: |
|
|
|
return ((CWindow.HEIGHT / 2) |
|
|
|
- ((CWindow.HEIGHT / 2 + 100) * math.sin (self.alt) |
|
|
|
/ math.sin (math.radians (60)))) |
|
|
|
|
|
|
|
@property |
|
|
|
def new_arg ( |
|
|
|
self, |
|
|
|
) -> float: |
|
|
|
return math.atan2 (self.new_y - self.y, self.new_x - self.x) |
|
|
|
|
|
|
|
|
|
|
|
class Jojoko (GameObject): |
|
|
|
""" |
|
|
|
大月ヨヨコ |
|
|
|
|
|
|
|
Attributes: |
|
|
|
phase (float): 月齢 |
|
|
|
""" |
|
|
|
|
|
|
|
phase: float |
|
|
|
|
|
|
|
def __init__ ( |
|
|
|
self, |
|
|
|
): |
|
|
|
... |
|
|
|
|
|
|
|
def redraw ( |
|
|
|
self, |
|
|
|
) -> None: |
|
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
class Sky: |
|
|
|
""" |
|
|
|
天体に関する情報を保持するクラス |
|
|
|
|
|
|
|
Attributes: |
|
|
|
observer (Observer): 観測値 |
|
|
|
""" |
|
|
|
|
|
|
|
observer: Observer |
|
|
|
|
|
|
|
|
|
|
|
class CWindow: |
|
|
|
""" |
|
|
|
ウィンドゥに関する定数クラス |
|
|
|
|
|
|
|
Attributes: |
|
|
|
WIDTH (int): ウィンドゥ幅 |
|
|
|
HEIGHT (int): ウィンドゥ高さ |
|
|
|
""" |
|
|
|
|
|
|
|
WIDTH = 1024 |
|
|
|
HEIGHT = 768 |
|
|
|
|
|
|
|
|
|
|
|
class Redrawer (TypedDict): |
|
|
|
""" |
|
|
|
再描画処理を行ふゲーム・オブゼクトとその優先順位のペア |
|
|
|
|
|
|
|
Attributes: |
|
|
|
layer (int): レイア |
|
|
|
obj (GameObject): ゲーム・オブゼクト |
|
|
|
""" |
|
|
|
|
|
|
|
layer: int |
|
|
|
obj: GameObject |
|
|
|
|
|
|
|