-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
kanaraimasu.py
213 lines (178 loc) · 7.02 KB
/
kanaraimasu.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import asyncio
import pygame
from pygame.locals import RESIZABLE
import sys
import time
from assets import AssetsPreparation
from utils import Collections, Settings, Theme
from screens import (
GameScreen,
KanaSelectScreen,
KanjiOptionsScreen,
MenuScreen,
SettingsScreen,
)
from widgets import Text
try:
pygame.mixer.init(buffer=512)
has_audio = True
except:
has_audio = False
pygame.init()
class Kanaraimasu:
def __init__(self, run_async=False, prepare_assets_only=False):
# set the display name
pygame.display.set_caption("Kanaraimasu - Learn to draw kana")
# initialize the game parameters
self.fps = Settings.get("fps")
self.run_async = run_async
# initialize the screen and render surfaces
width = Settings.get("width")
height = Settings.get("height")
fullscreen = pygame.FULLSCREEN if Settings.get("fullscreen") else 0
self.screen_size = (width, height)
self.pg_screen = pygame.display.set_mode(
self.screen_size, RESIZABLE | fullscreen
)
self.render_size = (1920, 1080)
self.render_surface = pygame.Surface(self.render_size)
self.prepare_assets()
if prepare_assets_only:
return
self.show_splash_screen()
# initialize the screens
self.screens = {
"gamescreen": GameScreen(self.render_surface, self.render_size),
"optionsforhiragana": KanaSelectScreen(
self.render_surface, self.render_size, "hiragana"
),
"optionsforkatakana": KanaSelectScreen(
self.render_surface, self.render_size, "katakana"
),
"optionsforkanji": KanjiOptionsScreen(
self.render_surface, self.render_size
),
"menuscreen": MenuScreen(self.render_surface, self.render_size),
"settingsscreen": SettingsScreen(
self.render_surface, self.render_size
),
}
self.set_screen_id("menuscreen")
# sets the screen size in all screens
self.set_screen_size(self.screen_size)
self.game_time = time.time()
# run the game loop forever
if not run_async:
while True:
self.game_loop()
def game_loop(self):
# process timing stuff
current_time = time.time()
time_delta = current_time - self.game_time
self.game_time = current_time
self.process_event_loop()
self.screen_size = self.pg_screen.get_size()
# update game logics
self.screens[self.screen_id].update(time_delta)
self.screens[self.screen_id].draw()
# this draws the render_surface onto the pg_screen
self.render()
if not self.run_async and self.fps != 0:
target_sleep = 1000 / self.fps
delta = (time.time() - self.game_time) * 1000
if target_sleep - delta > 0:
pygame.time.delay(int(target_sleep - delta))
def process_event_loop(self):
self.results = {}
screen = self.screens[self.screen_id]
for event in pygame.event.get():
# handle closing the window
if event.type == pygame.QUIT:
print("shutting down...")
sys.exit()
# handle video resize events
elif event.type == pygame.VIDEORESIZE:
print("videoresize")
self.set_screen_size(event.dict["size"])
# handle minimize/maximize buttons
elif event.type == pygame.VIDEOEXPOSE:
print("videoexpose")
self.set_screen_size(self.pg_screen.get_size())
# handle key presses
elif event.type == pygame.KEYDOWN:
self.add_result(screen.key_press(event))
# handle mouse presses/releases/moves
elif event.type == pygame.MOUSEBUTTONDOWN:
event = self.set_render_mouse_pos(event)
self.add_result(screen.mouse_event(event))
elif event.type == pygame.MOUSEBUTTONUP:
event = self.set_render_mouse_pos(event)
self.add_result(screen.mouse_event(event))
elif event.type == pygame.MOUSEMOTION:
event = self.set_render_mouse_pos(event)
self.add_result(screen.mouse_event(event))
self.process_results()
def set_render_mouse_pos(self, event):
event.pos = self.s2r(event.pos)
return event
def add_result(self, result):
if result:
self.results = {**self.results, **result}
def process_results(self):
if self.results.get("screen_id"):
self.set_screen_id(self.results["screen_id"])
action = self.results.get("action")
if action == "reapply_theme":
# reload the assets
self.prepare_assets()
# reapply the (new) theme to the GUI
Collections.reapply_theme()
def set_screen_id(self, screen_id):
self.screen_id = screen_id
# TODO: temporary render the splash screen when gamescreen is loaded
# till the performance issue of loading the gamescreen is fixed
if self.screen_id == "gamescreen":
self.show_splash_screen()
# call prepare function so screens can do JIT (re)initialization
# before becomming active/visible
self.screens[self.screen_id].prepare()
def set_screen_size(self, screen_size):
self.screen_size = screen_size
Settings.set("width", self.screen_size[0])
Settings.set("height", self.screen_size[1])
for screen_id, screen in self.screens.items():
screen.set_screen_size(self.screen_size)
def render(self):
self.pg_screen.blit(
pygame.transform.smoothscale(
self.render_surface, self.screen_size
),
(0, 0),
)
pygame.display.update()
def show_splash_screen(self, loading_text="Loading..."):
self.render_surface.fill(Theme.get_color("background"))
Text(
self.render_surface, (0, 200, 1920, 400), "Kanaraimasu"
).set_font_size(200).set_themed().render()
Text(
self.render_surface, (0, 700, 1920, 200), loading_text
).set_themed().render()
self.render()
asyncio.sleep(0)
def s2r(self, pos):
# convert screen coordinate/pos to render surface coordinate/pos
x = pos[0] * self.render_size[0] / self.screen_size[0]
y = pos[1] * self.render_size[1] / self.screen_size[1]
return (x, y)
def r2s(self, pos):
# convert render surface coordinate/pos to screen coordinate/pos
x = pos[0] * self.screen_size[0] / self.render_size[0]
y = pos[1] * self.screen_size[1] / self.render_size[1]
return (x, y)
def prepare_assets(self):
self.show_splash_screen("Preparing assets...")
AssetsPreparation().run()
if __name__ == "__main__":
# start the main function if this script is executed
Kanaraimasu()