Commit | Line | Data |
---|---|---|
31237524 | 1 | from os.path import exists |
a0462193 | 2 | from os import makedirs |
c991401b | 3 | from logging import info |
3fe18d73 | 4 | from json import loads |
2aeb9f68 | 5 | from collections import namedtuple |
c991401b | 6 | from panda3d.core import AmbientLight, Texture, TextPropertiesManager, \ |
bf77b5d5 | 7 | TextNode, Spotlight, PerspectiveLens, BitMask32 |
36099535 FC |
8 | from panda3d.bullet import BulletPlaneShape, BulletGhostNode |
9 | from direct.gui.OnscreenImage import OnscreenImage | |
2aaa10d3 FC |
10 | from direct.gui.OnscreenText import OnscreenText |
11 | from direct.gui.DirectGui import DirectButton, DirectFrame | |
36099535 | 12 | from direct.gui.DirectGuiGlobals import FLAT, DISABLED, NORMAL |
1be87278 | 13 | from direct.showbase.DirectObject import DirectObject |
fe0a68a0 FC |
14 | from direct.interval.IntervalGlobal import Sequence, Func |
15 | from direct.interval.LerpInterval import LerpFunctionInterval | |
4586cbf6 FC |
16 | from pmachines.items.background import Background |
17 | from pmachines.gui.sidepanel import SidePanel | |
98741d67 | 18 | from pmachines.items.box import Box, HitStrategy |
25c59f4a | 19 | from pmachines.items.basketball import Basketball |
98741d67 | 20 | from pmachines.items.domino import Domino, DownStrategy |
1f76fd96 FC |
21 | from pmachines.items.shelf import Shelf |
22 | from pmachines.items.teetertooter import TeeterTooter | |
3466af49 | 23 | from pmachines.items.test_item import PixelSpaceTestItem, WorldSpaceTestItem |
d3a2e50a | 24 | from pmachines.editor.scene import SceneEditor |
9f095a28 | 25 | from ya2.utils.gui.cursor import MouseCursor, MouseCursorArgs |
bf77b5d5 | 26 | from ya2.utils.gfx import GfxTools, DirectGuiMixin |
9199c6aa | 27 | from ya2.utils.gui.gui import GuiTools |
1be87278 FC |
28 | |
29 | ||
30 | class Scene(DirectObject): | |
31 | ||
f7eade0f | 32 | json_files = {} |
92c29685 FC |
33 | scenes_done = [] |
34 | ||
d3a2e50a | 35 | def __init__(self, world, exit_cb, auto_close_instr, dbg_items, reload_cb, scenes, pos_mgr, testing, mouse_coords, persistent, json_name, editor, auto_start_editor): |
1be87278 FC |
36 | super().__init__() |
37 | self._world = world | |
5964572b | 38 | self._exit_cb = exit_cb |
ce302b41 | 39 | self._testing = testing |
7fa58640 | 40 | self._mouse_coords = mouse_coords |
31237524 | 41 | self._dbg_items = dbg_items |
9914cfc9 | 42 | self._reload_cb = reload_cb |
2d1773b1 | 43 | self._pos_mgr = pos_mgr |
88dde925 | 44 | for k in list(self._pos_mgr.keys()): del self._pos_mgr[k] |
6168d0c2 | 45 | self._scenes = scenes |
ce302b41 | 46 | self._start_evt_time = None |
d68aeda7 | 47 | self._enforce_result = '' |
92c29685 | 48 | self.__persistent = persistent |
f7eade0f | 49 | self.__json_name = json_name |
d3a2e50a | 50 | self.__editor = editor |
ee65fee0 | 51 | self.__scene_editor = None |
f7eade0f | 52 | self.json = {} |
d68aeda7 | 53 | self.accept('enforce_result', self.enforce_result) |
1be87278 | 54 | self._set_camera() |
9f095a28 | 55 | c = MouseCursorArgs( |
9199c6aa FC |
56 | 'assets/images/buttons/arrowUpLeft.dds', testing, (.04, 1, .04), (.5, .5, .5, 1), |
57 | (.01, .01)) | |
58 | self._cursor = MouseCursor(c) | |
4a71e3e4 | 59 | self.__set_font() |
36099535 | 60 | self._set_gui() |
1be87278 FC |
61 | self._set_lights() |
62 | self._set_input() | |
c8d8653f | 63 | self._set_mouse_plane() |
3133e30f | 64 | self.__items = [] |
067a36db | 65 | self._test_items = [] |
d5932612 | 66 | self.reset() |
0a0994e4 | 67 | self._state = 'init' |
9830561d | 68 | self._paused = False |
7c0a81ae | 69 | self._item_active = None |
e669403e | 70 | if auto_close_instr: |
32aa4dae | 71 | self.__store_state() |
e669403e | 72 | self.__restore_state() |
3466af49 | 73 | elif self.__json_name: |
e669403e | 74 | self._set_instructions() |
5964572b | 75 | self._bg = Background() |
3133e30f | 76 | self._side_panel = SidePanel(world, self._mouse_plane_node, (-5, 4), (-3, 1), 1, self.__items) |
4a71e3e4 | 77 | self._scene_tsk = taskMgr.add(self.on_frame, 'scene_on_frame') |
d3a2e50a FC |
78 | if auto_start_editor: |
79 | self._set_editor() | |
2aeb9f68 | 80 | self.accept('editor-inspector-delete', self.__on_inspector_delete) |
5964572b | 81 | |
aa577aeb | 82 | @classmethod |
f7eade0f FC |
83 | def filename(cls, scene_name): |
84 | return f'assets/scenes/{scene_name}.json' | |
8c9bf90e | 85 | |
3fe18d73 | 86 | @classmethod |
f7eade0f FC |
87 | def name(cls, scene_name): |
88 | if not scene_name in cls.json_files: | |
89 | with open(cls.filename(scene_name)) as f: | |
90 | cls.json_files[scene_name] = loads(f.read()) | |
91 | return _(cls.json_files[scene_name]['name']) | |
3fe18d73 | 92 | |
92c29685 | 93 | @classmethod |
f7eade0f | 94 | def version(cls, scene_name): |
3e3c4caf | 95 | if not scene_name: return '' |
f7eade0f FC |
96 | if not scene_name in cls.json_files: |
97 | with open(cls.filename(scene_name)) as f: | |
98 | cls.json_files[scene_name] = loads(f.read()) | |
99 | return cls.json_files[scene_name]['version'] | |
100 | ||
101 | @classmethod | |
102 | def is_done(cls, scene_name): | |
9209a23b FC |
103 | if not cls.scenes_done or len(cls.scenes_done) == 1 and not cls.scenes_done[0]: |
104 | return False | |
f7eade0f | 105 | return bool([(name, version) for name, version in cls.scenes_done if scene_name == name and cls.version(scene_name) == version]) |
92c29685 | 106 | |
0eff64a3 | 107 | def _instr_txt(self): |
f7eade0f | 108 | txt = _('Scene: ') + self.name(self.__json_name) + '\n\n' |
d3a2e50a | 109 | txt += _(self.__process_json_escape(self.__class__.json_files[self.__json_name]['instructions'])) |
aa577aeb FC |
110 | return txt |
111 | ||
112 | def __process_json_escape(self, string): | |
113 | return bytes(string, 'utf-8').decode('unicode-escape') | |
0eff64a3 | 114 | |
3133e30f FC |
115 | @property |
116 | def items(self): | |
117 | items = self.__items[:] | |
118 | if self.__scene_editor: | |
119 | items += self.__scene_editor.test_items | |
120 | return items | |
121 | ||
0eff64a3 | 122 | def _set_items(self): |
3e3c4caf | 123 | if not self.__json_name: return |
3133e30f | 124 | self.__items = [] |
067a36db | 125 | self._test_items = [] |
f7eade0f FC |
126 | if not self.json: |
127 | with open(f'assets/scenes/{self.__json_name}.json') as f: | |
128 | self.json = loads(f.read()) | |
129 | for item in self.json['start_items']: | |
25c59f4a FC |
130 | args = { |
131 | 'world': self._world, | |
132 | 'plane_node': self._mouse_plane_node, | |
133 | 'cb_inst': self.cb_inst, | |
134 | 'curr_bottom': self.current_bottom, | |
135 | 'repos': self.repos, | |
98741d67 FC |
136 | 'count': item['count'], |
137 | 'json': item} | |
25c59f4a FC |
138 | if 'mass' in item: |
139 | args['mass'] = item['mass'] | |
140 | if 'friction' in item: | |
141 | args['friction'] = item['friction'] | |
3133e30f | 142 | self.__items += [self.__code2class(item['class'])(**args)] |
2aeb9f68 | 143 | for item in self.json['items']: |
98741d67 FC |
144 | args = { |
145 | 'world': self._world, | |
146 | 'plane_node': self._mouse_plane_node, | |
147 | 'cb_inst': self.cb_inst, | |
148 | 'curr_bottom': self.current_bottom, | |
149 | 'repos': self.repos, | |
150 | 'json': item} | |
151 | args['pos'] = tuple(item['position']) | |
152 | if 'mass' in item: | |
153 | args['mass'] = item['mass'] | |
154 | if 'friction' in item: | |
155 | args['friction'] = item['friction'] | |
156 | if 'roll' in item: | |
157 | args['r'] = item['roll'] | |
158 | if 'model_scale' in item: | |
159 | args['model_scale'] = item['model_scale'] | |
2aeb9f68 FC |
160 | if 'restitution' in item: |
161 | args['restitution'] = item['restitution'] | |
162 | if 'friction' in item: | |
163 | args['friction'] = item['friction'] | |
3133e30f | 164 | self.__items += [self.__code2class(item['class'])(**args)] |
98741d67 FC |
165 | if 'strategy' in item: |
166 | match item['strategy']: | |
167 | case 'DownStrategy': | |
3133e30f | 168 | self.__items[-1].set_strategy(self.__code2class(item['strategy'])(self.__items[-1]._np, *item['strategy_args'])) |
98741d67 | 169 | case 'HitStrategy': |
3133e30f | 170 | self.__items[-1].set_strategy(self.__code2class(item['strategy'])(self.__item_with_id(item['strategy_args'][0]), self.items[-1].node, self.__items[-1]._world)) |
25c59f4a FC |
171 | |
172 | def __code2class(self, code): | |
173 | return { | |
174 | 'Box': Box, | |
175 | 'Basketball': Basketball, | |
1f76fd96 FC |
176 | 'Domino': Domino, |
177 | 'Shelf': Shelf, | |
98741d67 FC |
178 | 'TeeterTooter': TeeterTooter, |
179 | 'DownStrategy': DownStrategy, | |
180 | 'HitStrategy': HitStrategy | |
25c59f4a | 181 | }[code] |
0eff64a3 | 182 | |
98741d67 | 183 | def __item_with_id(self, id): |
3133e30f | 184 | for item in self.__items: |
98741d67 FC |
185 | if 'id' in item.json and item.json['id'] == id: |
186 | return item | |
187 | ||
0d5a5427 | 188 | def screenshot(self, task=None): |
ecdf8933 FC |
189 | tex = Texture('screenshot') |
190 | buffer = base.win.make_texture_buffer('screenshot', 512, 512, tex, True ) | |
191 | cam = base.make_camera(buffer) | |
192 | cam.reparent_to(render) | |
193 | cam.node().get_lens().set_fov(base.camLens.get_fov()) | |
194 | cam.set_pos(0, -20, 0) | |
195 | cam.look_at(0, 0, 0) | |
196 | import simplepbr | |
197 | simplepbr.init( | |
198 | window=buffer, | |
199 | camera_node=cam, | |
200 | use_normal_maps=True, | |
201 | use_emission_maps=False, | |
202 | use_occlusion_maps=True, | |
203 | msaa_samples=4, | |
204 | enable_shadows=True) | |
205 | base.graphicsEngine.renderFrame() | |
206 | base.graphicsEngine.renderFrame() | |
f7eade0f | 207 | fname = self.__json_name |
40cc6e36 FC |
208 | if not exists('assets/images/scenes'): |
209 | makedirs('assets/images/scenes') | |
63e7aeb2 | 210 | buffer.save_screenshot('assets/images/scenes/%s.png' % fname) |
ecdf8933 FC |
211 | # img = DirectButton( |
212 | # frameTexture=buffer.get_texture(), relief=FLAT, | |
213 | # frameSize=(-.2, .2, -.2, .2)) | |
0d5a5427 | 214 | return buffer.get_texture() |
ecdf8933 | 215 | |
d5932612 FC |
216 | def current_bottom(self): |
217 | curr_bottom = 1 | |
3133e30f | 218 | for item in self.__items: |
d5932612 FC |
219 | if item.repos_done: |
220 | curr_bottom = min(curr_bottom, item.get_bottom()) | |
221 | return curr_bottom | |
222 | ||
05fd23ec | 223 | def reset(self): |
3133e30f | 224 | [itm.destroy() for itm in self.__items] |
067a36db | 225 | [itm.remove_node() for itm in self._test_items] |
3133e30f | 226 | self.__items = [] |
067a36db | 227 | self._test_items = [] |
0eff64a3 | 228 | self._set_items() |
067a36db | 229 | self._set_test_items() |
0a0994e4 | 230 | self._state = 'init' |
32aa4dae FC |
231 | self._commands = [] |
232 | self._command_idx = 0 | |
ce302b41 | 233 | self._start_evt_time = None |
b41381b2 FC |
234 | if hasattr(self, '_success_txt'): |
235 | self._success_txt.destroy() | |
236 | del self._success_txt | |
237 | self.__right_btn['state'] = NORMAL | |
05fd23ec | 238 | |
d68aeda7 FC |
239 | def enforce_result(self, val): |
240 | self._enforce_result = val | |
241 | info('enforce result: ' + val) | |
fa3662a6 | 242 | |
5964572b | 243 | def destroy(self): |
fe0a68a0 | 244 | self.__intro_sequence.finish() |
d68aeda7 | 245 | self.ignore('enforce_result') |
5964572b FC |
246 | self._unset_gui() |
247 | self._unset_lights() | |
248 | self._unset_input() | |
249 | self._unset_mouse_plane() | |
3133e30f | 250 | [itm.destroy() for itm in self.__items] |
067a36db | 251 | [itm.remove_node() for itm in self._test_items] |
5964572b FC |
252 | self._bg.destroy() |
253 | self._side_panel.destroy() | |
407412a5 | 254 | self._cursor.destroy() |
5964572b | 255 | taskMgr.remove(self._scene_tsk) |
9fc7f6fb FC |
256 | if hasattr(self, '_success_txt'): |
257 | self._success_txt.destroy() | |
3e3c4caf | 258 | self.ignore('editor-inspector-delete') |
4a71e3e4 | 259 | if self.__scene_editor: self.__scene_editor.destroy() |
1be87278 FC |
260 | |
261 | def _set_camera(self): | |
262 | base.camera.set_pos(0, -20, 0) | |
263 | base.camera.look_at(0, 0, 0) | |
fe0a68a0 FC |
264 | def camera_ani(t): |
265 | start_v = (1, -5, 1) | |
266 | end_v = (0, -20, 0) | |
267 | curr_pos = ( | |
268 | start_v[0] + (end_v[0] - start_v[0]) * t, | |
269 | start_v[1] + (end_v[1] - start_v[1]) * t, | |
270 | start_v[2] + (end_v[2] - start_v[2]) * t) | |
271 | base.camera.set_pos(*curr_pos) | |
272 | self.repos() | |
273 | camera_interval = LerpFunctionInterval( | |
274 | camera_ani, | |
275 | 1.2, | |
276 | 0, | |
277 | 1, | |
278 | blendType='easeInOut') | |
279 | self.__intro_sequence = Sequence( | |
280 | camera_interval, | |
281 | Func(self.repos)) | |
282 | self.__intro_sequence.start() | |
1be87278 | 283 | |
a0acba9a | 284 | def __load_img_btn(self, path, col): |
7e487769 | 285 | img = OnscreenImage('assets/images/buttons/%s.dds' % path) |
a0acba9a FC |
286 | img.set_transparency(True) |
287 | img.set_color(col) | |
288 | img.detach_node() | |
289 | return img | |
290 | ||
36099535 | 291 | def _set_gui(self): |
01b221a6 FC |
292 | def load_images_btn(path, col): |
293 | colors = { | |
294 | 'gray': [ | |
295 | (.6, .6, .6, 1), # ready | |
296 | (1, 1, 1, 1), # press | |
297 | (.8, .8, .8, 1), # rollover | |
298 | (.4, .4, .4, .4)], | |
299 | 'green': [ | |
300 | (.1, .68, .1, 1), | |
301 | (.1, 1, .1, 1), | |
302 | (.1, .84, .1, 1), | |
303 | (.4, .1, .1, .4)]}[col] | |
a0acba9a | 304 | return [self.__load_img_btn(path, col) for col in colors] |
36099535 FC |
305 | abl, abr = base.a2dBottomLeft, base.a2dBottomRight |
306 | btn_info = [ | |
4a71e3e4 FC |
307 | ('home', self.on_home, NORMAL, abl, 'gray', _('Exit'), 'right'), |
308 | ('information', self._set_instructions, NORMAL, abl, 'gray', _('Instructions'), 'right'), | |
309 | ('right', self.on_play, NORMAL, abr, 'green', _('Run'), 'left'), | |
f26497a5 FC |
310 | #('next', self.on_next, DISABLED, abr, 'gray'), |
311 | #('previous', self.on_prev, DISABLED, abr, 'gray'), | |
312 | #('rewind', self.reset, NORMAL, abr, 'gray') | |
313 | ] | |
d3a2e50a | 314 | if self.__editor: |
4a71e3e4 | 315 | btn_info.insert(2, ('wrench', self._set_editor, NORMAL, abl, 'gray', _('Editor'), 'right')) |
36099535 | 316 | num_l = num_r = 0 |
a0acba9a | 317 | btns = [] |
4a71e3e4 | 318 | tooltip_args = self.__font, .05, (.93, .93, .93, 1) |
36099535 | 319 | for binfo in btn_info: |
01b221a6 | 320 | imgs = load_images_btn(binfo[0], binfo[4]) |
36099535 FC |
321 | if binfo[3] == base.a2dBottomLeft: |
322 | sign, num = 1, num_l | |
323 | num_l += 1 | |
324 | else: | |
325 | sign, num = -1, num_r | |
326 | num_r += 1 | |
327 | fcols = (.4, .4, .4, .14), (.3, .3, .3, .05) | |
328 | btn = DirectButton( | |
329 | image=imgs, scale=.05, pos=(sign * (.06 + .11 * num), 1, .06), | |
330 | parent=binfo[3], command=binfo[1], state=binfo[2], relief=FLAT, | |
54a1397e FC |
331 | frameColor=fcols[0] if binfo[2] == NORMAL else fcols[1], |
332 | rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'), | |
333 | clickSound=loader.load_sfx('assets/audio/sfx/click.ogg')) | |
bf77b5d5 | 334 | btn.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {}) |
36099535 | 335 | btn.set_transparency(True) |
4a71e3e4 FC |
336 | t = tooltip_args + (binfo[6],) |
337 | btn.set_tooltip(binfo[5], *t) | |
63d69e94 | 338 | self._pos_mgr[binfo[0]] = btn.pos_pixel() |
a0acba9a | 339 | btns += [btn] |
d3a2e50a FC |
340 | if self.__editor: |
341 | self.__home_btn, self.__info_btn, self.__editor_btn, self.__right_btn = btns | |
342 | else: | |
343 | self.__home_btn, self.__info_btn, self.__right_btn = btns | |
f26497a5 | 344 | # , self.__next_btn, self.__prev_btn, self.__rewind_btn |
31237524 FC |
345 | if self._dbg_items: |
346 | self._info_txt = OnscreenText( | |
347 | '', parent=base.a2dTopRight, scale=0.04, | |
348 | pos=(-.03, -.06), fg=(.9, .9, .9, 1), align=TextNode.A_right) | |
7fa58640 FC |
349 | if self._mouse_coords: |
350 | self._coords_txt = OnscreenText( | |
351 | '', parent=base.a2dTopRight, scale=0.04, | |
352 | pos=(-.03, -.12), fg=(.9, .9, .9, 1), align=TextNode.A_right) | |
353 | def update_coords(task): | |
354 | pos = None | |
355 | for hit in self._get_hits(): | |
356 | if hit.get_node() == self._mouse_plane_node: | |
357 | pos = hit.get_hit_pos() | |
358 | if pos: | |
359 | txt = '%s %s' % (round(pos.x, 3), | |
360 | round(pos.z, 3)) | |
361 | self._coords_txt['text'] = txt | |
362 | return task.cont | |
363 | self._coords_tsk = taskMgr.add(update_coords, 'update_coords') | |
36099535 | 364 | |
5964572b FC |
365 | def _unset_gui(self): |
366 | btns = [ | |
bf77b5d5 | 367 | self.__home_btn, self.__info_btn, self.__right_btn |
f26497a5 FC |
368 | #self.__next_btn, self.__prev_btn, self.__rewind_btn |
369 | ] | |
bf77b5d5 | 370 | if self.__editor: btns += [self.__editor_btn] |
5964572b | 371 | [btn.destroy() for btn in btns] |
31237524 FC |
372 | if self._dbg_items: |
373 | self._info_txt.destroy() | |
7fa58640 FC |
374 | if self._mouse_coords: |
375 | taskMgr.remove(self._coords_tsk) | |
376 | self._coords_txt.destroy() | |
5964572b | 377 | |
64eae9c7 FC |
378 | def _set_spotlight(self, name, pos, look_at, color, shadows=False): |
379 | light = Spotlight(name) | |
380 | if shadows: | |
381 | light.setLens(PerspectiveLens()) | |
1be87278 | 382 | light_np = render.attach_new_node(light) |
64eae9c7 FC |
383 | light_np.set_pos(pos) |
384 | light_np.look_at(look_at) | |
1be87278 FC |
385 | light.set_color(color) |
386 | render.set_light(light_np) | |
5964572b | 387 | return light_np |
1be87278 FC |
388 | |
389 | def _set_lights(self): | |
390 | alight = AmbientLight('alight') # for ao | |
64eae9c7 FC |
391 | alight.set_color((.15, .15, .15, 1)) |
392 | self._alnp = render.attach_new_node(alight) | |
393 | render.set_light(self._alnp) | |
394 | self._key_light = self._set_spotlight( | |
395 | 'key light', (-5, -80, 5), (0, 0, 0), (2.8, 2.8, 2.8, 1)) | |
396 | self._shadow_light = self._set_spotlight( | |
397 | 'key light', (-5, -80, 5), (0, 0, 0), (.58, .58, .58, 1), True) | |
398 | self._shadow_light.node().set_shadow_caster(True, 2048, 2048) | |
399 | self._shadow_light.node().get_lens().set_film_size(2048, 2048) | |
400 | self._shadow_light.node().get_lens().set_near_far(1, 256) | |
401 | self._shadow_light.node().set_camera_mask(BitMask32(0x01)) | |
5964572b FC |
402 | |
403 | def _unset_lights(self): | |
64eae9c7 | 404 | for light in [self._alnp, self._key_light, self._shadow_light]: |
5964572b FC |
405 | render.clear_light(light) |
406 | light.remove_node() | |
1be87278 FC |
407 | |
408 | def _set_input(self): | |
49c79300 | 409 | self.accept('mouse1', self.on_click_l) |
c8d8653f | 410 | self.accept('mouse1-up', self.on_release) |
49c79300 FC |
411 | self.accept('mouse3', self.on_click_r) |
412 | self.accept('mouse3-up', self.on_release) | |
c8d8653f | 413 | |
5964572b FC |
414 | def _unset_input(self): |
415 | for evt in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']: | |
416 | self.ignore(evt) | |
417 | ||
c8d8653f | 418 | def _set_mouse_plane(self): |
651713a9 | 419 | shape = BulletPlaneShape((0, -1, 0), 0) |
c8d8653f FC |
420 | #self._mouse_plane_node = BulletRigidBodyNode('mouse plane') |
421 | self._mouse_plane_node = BulletGhostNode('mouse plane') | |
422 | self._mouse_plane_node.addShape(shape) | |
423 | #np = render.attachNewNode(self._mouse_plane_node) | |
424 | #self._world.attachRigidBody(self._mouse_plane_node) | |
06af3aa9 | 425 | self._world.attach_ghost(self._mouse_plane_node) |
1be87278 | 426 | |
5964572b FC |
427 | def _unset_mouse_plane(self): |
428 | self._world.remove_ghost(self._mouse_plane_node) | |
429 | ||
37ba71d8 FC |
430 | def _get_hits(self): |
431 | if not base.mouseWatcherNode.has_mouse(): return [] | |
bf77b5d5 | 432 | p_from, p_to = GuiTools.get_mouse().from_to_points() |
37ba71d8 FC |
433 | return self._world.ray_test_all(p_from, p_to).get_hits() |
434 | ||
31237524 FC |
435 | def _update_info(self, item): |
436 | txt = '' | |
437 | if item: | |
438 | txt = '%.3f %.3f\n%.3f°' % ( | |
439 | item._np.get_x(), item._np.get_z(), item._np.get_r()) | |
440 | self._info_txt['text'] = txt | |
441 | ||
49c79300 | 442 | def _on_click(self, method): |
a0acba9a FC |
443 | if self._paused: |
444 | return | |
c8d8653f FC |
445 | for hit in self._get_hits(): |
446 | if hit.get_node() == self._mouse_plane_node: | |
447 | pos = hit.get_hit_pos() | |
37ba71d8 | 448 | for hit in self._get_hits(): |
ef3c36bf | 449 | for item in [i for i in self.items if hit.get_node() == i.node and i.interactable]: |
7c0a81ae FC |
450 | if not self._item_active: |
451 | self._item_active = item | |
3133e30f FC |
452 | if item not in self.__items: |
453 | method = 'on_click_l' | |
49c79300 | 454 | getattr(item, method)(pos) |
79f81d48 | 455 | img = 'move' if method == 'on_click_l' else 'rotate' |
a6843832 | 456 | if not (img == 'rotate' and not item._instantiated): |
7e487769 | 457 | self._cursor.set_image('assets/images/buttons/%s.dds' % img) |
49c79300 FC |
458 | |
459 | def on_click_l(self): | |
460 | self._on_click('on_click_l') | |
461 | ||
462 | def on_click_r(self): | |
463 | self._on_click('on_click_r') | |
c8d8653f FC |
464 | |
465 | def on_release(self): | |
32aa4dae FC |
466 | if self._item_active and not self._item_active._first_command: |
467 | self._commands = self._commands[:self._command_idx] | |
468 | self._commands += [self._item_active] | |
469 | self._command_idx += 1 | |
f26497a5 FC |
470 | #self.__prev_btn['state'] = NORMAL |
471 | #fcols = (.4, .4, .4, .14), (.3, .3, .3, .05) | |
472 | #self.__prev_btn['frameColor'] = fcols[0] | |
473 | #if self._item_active._command_idx == len(self._item_active._commands) - 1: | |
474 | # self.__next_btn['state'] = DISABLED | |
475 | # self.__next_btn['frameColor'] = fcols[1] | |
7c0a81ae | 476 | self._item_active = None |
3133e30f | 477 | [item.on_release() for item in self.__items] |
7e487769 | 478 | self._cursor.set_image('assets/images/buttons/arrowUpLeft.dds') |
37ba71d8 | 479 | |
e1438449 | 480 | def repos(self): |
3133e30f | 481 | for item in self.__items: |
d5932612 | 482 | item.repos_done = False |
3133e30f FC |
483 | self.__items = sorted(self.__items, key=lambda itm: itm.__class__.__name__) |
484 | [item.on_aspect_ratio_changed() for item in self.__items] | |
485 | self._side_panel.update(self.__items) | |
7790323d | 486 | max_x = -float('inf') |
3133e30f | 487 | for item in self.__items: |
e1438449 FC |
488 | if not item._instantiated: |
489 | max_x = max(item._np.get_x(), max_x) | |
3133e30f | 490 | for item in self.__items: |
e1438449 FC |
491 | if not item._instantiated: |
492 | item.repos_x(max_x) | |
493 | ||
494 | def on_aspect_ratio_changed(self): | |
495 | self.repos() | |
651713a9 | 496 | |
0a0994e4 | 497 | def _win_condition(self): |
3133e30f | 498 | return all(itm.strategy.win_condition() for itm in self.__items) and not self._paused |
0e86689f | 499 | |
0a0994e4 | 500 | def _fail_condition(self): |
3133e30f | 501 | return all(itm.fail_condition() for itm in self.__items) and not self._paused and self._state == 'playing' |
0a0994e4 | 502 | |
37ba71d8 | 503 | def on_frame(self, task): |
c8d8653f FC |
504 | hits = self._get_hits() |
505 | pos = None | |
506 | for hit in self._get_hits(): | |
507 | if hit.get_node() == self._mouse_plane_node: | |
508 | pos = hit.get_hit_pos() | |
509 | hit_nodes = [hit.get_node() for hit in hits] | |
7c0a81ae FC |
510 | if self._item_active: |
511 | items_hit = [self._item_active] | |
512 | else: | |
513 | items_hit = [itm for itm in self.items if itm.node in hit_nodes] | |
37ba71d8 FC |
514 | items_no_hit = [itm for itm in self.items if itm not in items_hit] |
515 | [itm.on_mouse_on() for itm in items_hit] | |
516 | [itm.on_mouse_off() for itm in items_no_hit] | |
7c0a81ae FC |
517 | if pos and self._item_active: |
518 | self._item_active.on_mouse_move(pos) | |
31237524 FC |
519 | if self._dbg_items: |
520 | self._update_info(items_hit[0] if items_hit else None) | |
3466af49 | 521 | if not self.__scene_editor and self.__json_name and self._win_condition(): |
ce302b41 | 522 | self._start_evt_time = None |
d68aeda7 | 523 | self._set_fail() if self._enforce_result == 'fail' else self._set_win() |
0a0994e4 | 524 | elif self._state == 'playing' and self._fail_condition(): |
ce302b41 | 525 | self._start_evt_time = None |
d68aeda7 | 526 | self._set_win() if self._enforce_result == 'win' else self._set_fail() |
ce302b41 FC |
527 | elif self._testing and self._start_evt_time and globalClock.getFrameTime() - self._start_evt_time > 5.0: |
528 | self._start_evt_time = None | |
d68aeda7 | 529 | self._set_win() if self._enforce_result == 'win' else self._set_fail() |
93cf86b2 | 530 | if any(itm._overlapping for itm in self.items): |
d68aeda7 | 531 | self._cursor.set_color((.9, .1, .1, 1)) |
93cf86b2 | 532 | else: |
d68aeda7 | 533 | self._cursor.set_color((.9, .9, .9, 1)) |
37ba71d8 | 534 | return task.cont |
c8d8653f | 535 | |
7850ccc4 | 536 | def cb_inst(self, item): |
3133e30f | 537 | self.__items += [item] |
7850ccc4 | 538 | |
c8d8653f | 539 | def on_play(self): |
0a0994e4 | 540 | self._state = 'playing' |
f26497a5 FC |
541 | #self.__prev_btn['state'] = DISABLED |
542 | #self.__next_btn['state'] = DISABLED | |
b41381b2 | 543 | self.__right_btn['state'] = DISABLED |
3133e30f | 544 | [itm.play() for itm in self.__items] |
ce302b41 | 545 | self._start_evt_time = globalClock.getFrameTime() |
36099535 FC |
546 | |
547 | def on_next(self): | |
32aa4dae FC |
548 | self._commands[self._command_idx].redo() |
549 | self._command_idx += 1 | |
c991401b | 550 | #fcols = (.4, .4, .4, .14), (.3, .3, .3, .05) |
f26497a5 FC |
551 | #self.__prev_btn['state'] = NORMAL |
552 | #self.__prev_btn['frameColor'] = fcols[0] | |
c991401b | 553 | #more_commands = self._command_idx < len(self._commands) |
f26497a5 FC |
554 | #self.__next_btn['state'] = NORMAL if more_commands else DISABLED |
555 | #self.__next_btn['frameColor'] = fcols[0] if more_commands else fcols[1] | |
36099535 FC |
556 | |
557 | def on_prev(self): | |
32aa4dae FC |
558 | self._command_idx -= 1 |
559 | self._commands[self._command_idx].undo() | |
c991401b | 560 | #fcols = (.4, .4, .4, .14), (.3, .3, .3, .05) |
f26497a5 FC |
561 | #self.__next_btn['state'] = NORMAL |
562 | #self.__next_btn['frameColor'] = fcols[0] | |
563 | #self.__prev_btn['state'] = NORMAL if self._command_idx else DISABLED | |
564 | #self.__prev_btn['frameColor'] = fcols[0] if self._command_idx else fcols[1] | |
36099535 | 565 | |
36099535 | 566 | def on_home(self): |
5964572b | 567 | self._exit_cb() |
36099535 | 568 | |
4a71e3e4 FC |
569 | def __set_font(self): |
570 | self.__font = base.loader.load_font('assets/fonts/Hanken-Book.ttf') | |
571 | self.__font.clear() | |
572 | self.__font.set_pixels_per_unit(60) | |
573 | self.__font.set_minfilter(Texture.FTLinearMipmapLinear) | |
574 | self.__font.set_outline((0, 0, 0, 1), .8, .2) | |
575 | ||
576 | ||
2aaa10d3 | 577 | def _set_instructions(self): |
9830561d FC |
578 | self._paused = True |
579 | self.__store_state() | |
2aaa10d3 FC |
580 | mgr = TextPropertiesManager.get_global_ptr() |
581 | for name in ['mouse_l', 'mouse_r']: | |
7e487769 | 582 | graphic = OnscreenImage('assets/images/buttons/%s.dds' % name) |
2aaa10d3 FC |
583 | graphic.set_scale(.5) |
584 | graphic.get_texture().set_minfilter(Texture.FTLinearMipmapLinear) | |
585 | graphic.get_texture().set_anisotropic_degree(2) | |
586 | mgr.set_graphic(name, graphic) | |
587 | graphic.set_z(-.2) | |
588 | graphic.set_transparency(True) | |
589 | graphic.detach_node() | |
590 | frm = DirectFrame(frameColor=(.4, .4, .4, .06), | |
591 | frameSize=(-.6, .6, -.3, .3)) | |
2aaa10d3 | 592 | self._txt = OnscreenText( |
4a71e3e4 | 593 | self._instr_txt(), parent=frm, font=self.__font, scale=0.06, |
0eff64a3 | 594 | fg=(.9, .9, .9, 1), align=TextNode.A_left) |
2aaa10d3 FC |
595 | u_l = self._txt.textNode.get_upper_left_3d() |
596 | l_r = self._txt.textNode.get_lower_right_3d() | |
597 | w, h = l_r[0] - u_l[0], u_l[2] - l_r[2] | |
a0acba9a FC |
598 | btn_scale = .05 |
599 | mar = .06 # margin | |
4a71e3e4 | 600 | z = h / 2 - self.__font.get_line_height() * self._txt['scale'][1] |
a0acba9a | 601 | z += (btn_scale + 2 * mar) / 2 |
2aaa10d3 FC |
602 | self._txt['pos'] = -w / 2, z |
603 | u_l = self._txt.textNode.get_upper_left_3d() | |
604 | l_r = self._txt.textNode.get_lower_right_3d() | |
a0acba9a FC |
605 | c_l_r = l_r[0], l_r[1], l_r[2] - 2 * mar - btn_scale |
606 | fsz = u_l[0] - mar, l_r[0] + mar, c_l_r[2] - mar, u_l[2] + mar | |
2aaa10d3 | 607 | frm['frameSize'] = fsz |
a0acba9a FC |
608 | colors = [ |
609 | (.6, .6, .6, 1), # ready | |
610 | (1, 1, 1, 1), # press | |
611 | (.8, .8, .8, 1), # rollover | |
612 | (.4, .4, .4, .4)] | |
613 | imgs = [self.__load_img_btn('exitRight', col) for col in colors] | |
614 | btn = DirectButton( | |
615 | image=imgs, scale=btn_scale, | |
616 | pos=(l_r[0] - btn_scale, 1, l_r[2] - mar - btn_scale), | |
617 | parent=frm, command=self.__on_close_instructions, extraArgs=[frm], | |
618 | relief=FLAT, frameColor=(.6, .6, .6, .08), | |
619 | rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'), | |
620 | clickSound=loader.load_sfx('assets/audio/sfx/click.ogg')) | |
bf77b5d5 | 621 | btn.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {}) |
a0acba9a | 622 | btn.set_transparency(True) |
63d69e94 | 623 | self._pos_mgr['close_instructions'] = btn.pos_pixel() |
a0acba9a | 624 | |
0a0994e4 | 625 | def _set_win(self): |
f7eade0f | 626 | self.__persistent.save_scene(self.__json_name, self.version(self.__json_name)) |
9914cfc9 FC |
627 | loader.load_sfx('assets/audio/sfx/success.ogg').play() |
628 | self._paused = True | |
629 | self.__store_state() | |
630 | frm = DirectFrame(frameColor=(.4, .4, .4, .06), | |
631 | frameSize=(-.6, .6, -.3, .3)) | |
632 | font = base.loader.load_font('assets/fonts/Hanken-Book.ttf') | |
633 | font.clear() | |
634 | font.set_pixels_per_unit(60) | |
635 | font.set_minfilter(Texture.FTLinearMipmapLinear) | |
636 | font.set_outline((0, 0, 0, 1), .8, .2) | |
637 | self._txt = OnscreenText( | |
638 | _('You win!'), | |
639 | parent=frm, | |
640 | font=font, scale=0.2, | |
641 | fg=(.9, .9, .9, 1)) | |
642 | u_l = self._txt.textNode.get_upper_left_3d() | |
643 | l_r = self._txt.textNode.get_lower_right_3d() | |
c991401b FC |
644 | #w, h = l_r[0] - u_l[0], u_l[2] - l_r[2] |
645 | h = u_l[2] - l_r[2] | |
9914cfc9 FC |
646 | btn_scale = .05 |
647 | mar = .06 # margin | |
648 | z = h / 2 - font.get_line_height() * self._txt['scale'][1] | |
649 | z += (btn_scale + 2 * mar) / 2 | |
650 | self._txt['pos'] = 0, z | |
651 | u_l = self._txt.textNode.get_upper_left_3d() | |
652 | l_r = self._txt.textNode.get_lower_right_3d() | |
653 | c_l_r = l_r[0], l_r[1], l_r[2] - 2 * mar - btn_scale | |
654 | fsz = u_l[0] - mar, l_r[0] + mar, c_l_r[2] - mar, u_l[2] + mar | |
655 | frm['frameSize'] = fsz | |
656 | colors = [ | |
657 | (.6, .6, .6, 1), # ready | |
658 | (1, 1, 1, 1), # press | |
659 | (.8, .8, .8, 1), # rollover | |
660 | (.4, .4, .4, .4)] | |
661 | imgs = [self.__load_img_btn('home', col) for col in colors] | |
662 | btn = DirectButton( | |
663 | image=imgs, scale=btn_scale, | |
664 | pos=(-2.8 * btn_scale, 1, l_r[2] - mar - btn_scale), | |
665 | parent=frm, command=self._on_end_home, extraArgs=[frm], | |
666 | relief=FLAT, frameColor=(.6, .6, .6, .08), | |
667 | rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'), | |
668 | clickSound=loader.load_sfx('assets/audio/sfx/click.ogg')) | |
bf77b5d5 | 669 | btn.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {}) |
9914cfc9 | 670 | btn.set_transparency(True) |
63d69e94 | 671 | self._pos_mgr['home_win'] = btn.pos_pixel() |
9914cfc9 FC |
672 | imgs = [self.__load_img_btn('rewind', col) for col in colors] |
673 | btn = DirectButton( | |
674 | image=imgs, scale=btn_scale, | |
675 | pos=(0, 1, l_r[2] - mar - btn_scale), | |
676 | parent=frm, command=self._on_restart, extraArgs=[frm], | |
677 | relief=FLAT, frameColor=(.6, .6, .6, .08), | |
678 | rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'), | |
679 | clickSound=loader.load_sfx('assets/audio/sfx/click.ogg')) | |
bf77b5d5 | 680 | btn.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {}) |
63d69e94 | 681 | self._pos_mgr['replay'] = btn.pos_pixel() |
9914cfc9 | 682 | btn.set_transparency(True) |
3e3c4caf FC |
683 | if self.__json_name: |
684 | enabled = self._scenes.index(self.__json_name) < len(self._scenes) - 1 | |
685 | if enabled: | |
686 | next_scene = self._scenes[self._scenes.index(self.__json_name) + 1] | |
687 | else: | |
688 | next_scene = None | |
9914cfc9 FC |
689 | else: |
690 | next_scene = None | |
3e3c4caf | 691 | enabled = False |
9914cfc9 FC |
692 | imgs = [self.__load_img_btn('right', col) for col in colors] |
693 | btn = DirectButton( | |
694 | image=imgs, scale=btn_scale, | |
695 | pos=(2.8 * btn_scale, 1, l_r[2] - mar - btn_scale), | |
696 | parent=frm, command=self._on_next_scene, | |
697 | extraArgs=[frm, next_scene], relief=FLAT, | |
698 | frameColor=(.6, .6, .6, .08), | |
699 | rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'), | |
700 | clickSound=loader.load_sfx('assets/audio/sfx/click.ogg')) | |
bf77b5d5 | 701 | btn.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {}) |
9914cfc9 | 702 | btn['state'] = NORMAL if enabled else DISABLED |
63d69e94 | 703 | self._pos_mgr['next'] = btn.pos_pixel() |
9914cfc9 FC |
704 | btn.set_transparency(True) |
705 | ||
0a0994e4 FC |
706 | def _set_fail(self): |
707 | loader.load_sfx('assets/audio/sfx/success.ogg').play() | |
708 | self._paused = True | |
709 | self.__store_state() | |
710 | frm = DirectFrame(frameColor=(.4, .4, .4, .06), | |
711 | frameSize=(-.6, .6, -.3, .3)) | |
712 | font = base.loader.load_font('assets/fonts/Hanken-Book.ttf') | |
713 | font.clear() | |
714 | font.set_pixels_per_unit(60) | |
715 | font.set_minfilter(Texture.FTLinearMipmapLinear) | |
716 | font.set_outline((0, 0, 0, 1), .8, .2) | |
717 | self._txt = OnscreenText( | |
718 | _('You have failed!'), | |
719 | parent=frm, | |
720 | font=font, scale=0.2, | |
721 | fg=(.9, .9, .9, 1)) | |
722 | u_l = self._txt.textNode.get_upper_left_3d() | |
723 | l_r = self._txt.textNode.get_lower_right_3d() | |
c991401b FC |
724 | #w, h = l_r[0] - u_l[0], u_l[2] - l_r[2] |
725 | h = u_l[2] - l_r[2] | |
0a0994e4 FC |
726 | btn_scale = .05 |
727 | mar = .06 # margin | |
728 | z = h / 2 - font.get_line_height() * self._txt['scale'][1] | |
729 | z += (btn_scale + 2 * mar) / 2 | |
730 | self._txt['pos'] = 0, z | |
731 | u_l = self._txt.textNode.get_upper_left_3d() | |
732 | l_r = self._txt.textNode.get_lower_right_3d() | |
733 | c_l_r = l_r[0], l_r[1], l_r[2] - 2 * mar - btn_scale | |
734 | fsz = u_l[0] - mar, l_r[0] + mar, c_l_r[2] - mar, u_l[2] + mar | |
735 | frm['frameSize'] = fsz | |
736 | colors = [ | |
737 | (.6, .6, .6, 1), # ready | |
738 | (1, 1, 1, 1), # press | |
739 | (.8, .8, .8, 1), # rollover | |
740 | (.4, .4, .4, .4)] | |
741 | imgs = [self.__load_img_btn('home', col) for col in colors] | |
742 | btn = DirectButton( | |
743 | image=imgs, scale=btn_scale, | |
744 | pos=(-2.8 * btn_scale, 1, l_r[2] - mar - btn_scale), | |
745 | parent=frm, command=self._on_end_home, extraArgs=[frm], | |
746 | relief=FLAT, frameColor=(.6, .6, .6, .08), | |
747 | rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'), | |
748 | clickSound=loader.load_sfx('assets/audio/sfx/click.ogg')) | |
bf77b5d5 | 749 | btn.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {}) |
63d69e94 | 750 | self._pos_mgr['home_win'] = btn.pos_pixel() |
0a0994e4 FC |
751 | btn.set_transparency(True) |
752 | imgs = [self.__load_img_btn('rewind', col) for col in colors] | |
753 | btn = DirectButton( | |
754 | image=imgs, scale=btn_scale, | |
755 | pos=(0, 1, l_r[2] - mar - btn_scale), | |
756 | parent=frm, command=self._on_restart, extraArgs=[frm], | |
757 | relief=FLAT, frameColor=(.6, .6, .6, .08), | |
758 | rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'), | |
759 | clickSound=loader.load_sfx('assets/audio/sfx/click.ogg')) | |
bf77b5d5 | 760 | btn.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {}) |
63d69e94 | 761 | self._pos_mgr['replay'] = btn.pos_pixel() |
0a0994e4 FC |
762 | btn.set_transparency(True) |
763 | ||
9914cfc9 FC |
764 | def _on_restart(self, frm): |
765 | self.__on_close_instructions(frm) | |
766 | self.reset() | |
767 | ||
768 | def _on_end_home(self, frm): | |
769 | self.__on_close_instructions(frm) | |
770 | self.on_home() | |
771 | ||
772 | def _on_next_scene(self, frm, scene): | |
773 | self.__on_close_instructions(frm) | |
774 | self._reload_cb(scene) | |
775 | ||
a0acba9a FC |
776 | def __store_state(self): |
777 | btns = [ | |
778 | self.__home_btn, self.__info_btn, self.__right_btn, | |
f26497a5 FC |
779 | #self.__next_btn, self.__prev_btn, self.__rewind_btn |
780 | ] | |
bf77b5d5 | 781 | if self.__editor: btns += [self.__editor_btn] |
a0acba9a FC |
782 | self.__btn_state = [btn['state'] for btn in btns] |
783 | for btn in btns: | |
784 | btn['state'] = DISABLED | |
3133e30f | 785 | [itm.store_state() for itm in self.__items] |
a0acba9a FC |
786 | |
787 | def __restore_state(self): | |
788 | btns = [ | |
789 | self.__home_btn, self.__info_btn, self.__right_btn, | |
f26497a5 FC |
790 | #self.__next_btn, self.__prev_btn, self.__rewind_btn |
791 | ] | |
bf77b5d5 | 792 | if self.__editor: btns += [self.__editor_btn] |
a0acba9a FC |
793 | for btn, state in zip(btns, self.__btn_state): |
794 | btn['state'] = state | |
3133e30f | 795 | [itm.restore_state() for itm in self.__items] |
a0acba9a FC |
796 | self._paused = False |
797 | ||
798 | def __on_close_instructions(self, frm): | |
799 | frm.remove_node() | |
800 | self.__restore_state() | |
067a36db FC |
801 | |
802 | def _set_test_items(self): | |
803 | def frame_after(task): | |
804 | self._define_test_items() | |
3466af49 FC |
805 | for itm in self.items: |
806 | if itm.id: | |
807 | self._pos_mgr[itm.id] = itm._model.pos2d_pixel() | |
067a36db | 808 | for itm in self._test_items: |
63d69e94 | 809 | self._pos_mgr[itm.name] = itm.pos2d_pixel() |
9209a23b | 810 | taskMgr.doMethodLater(1.4, frame_after, 'frame after') # after the intro sequence |
067a36db | 811 | |
da03f030 | 812 | def _define_test_items(self): |
3e3c4caf | 813 | if not self.__json_name: return |
f7eade0f FC |
814 | if not self.__json_name in self.__class__.json_files: |
815 | with open(self.__class__.filename(self.__json_name)) as f: | |
816 | self.__class__.json_files[self.__json_name] = loads(f.read()) | |
817 | for item in self.__class__.json_files[self.__json_name]['test_items']['pixel_space']: | |
63d69e94 | 818 | self._pos_mgr[item['id']] = tuple(item['position']) |
f7eade0f | 819 | for item in self.__class__.json_files[self.__json_name]['test_items']['world_space']: |
da03f030 FC |
820 | self._set_test_item(item['id'], tuple(item['position'])) |
821 | ||
067a36db | 822 | def _set_test_item(self, name, pos): |
bf77b5d5 | 823 | self._test_items += [GfxTools.build_empty_node(name)] |
067a36db | 824 | self._test_items[-1].set_pos(pos[0], 0, pos[1]) |
d3a2e50a | 825 | |
2aeb9f68 | 826 | def add_item(self, item): |
3133e30f | 827 | self.__items += [item] |
2aeb9f68 | 828 | |
d3a2e50a | 829 | def _set_editor(self): |
2aeb9f68 FC |
830 | fields = ['world', 'plane_node', 'cb_inst', 'curr_bottom', 'repos', 'json'] |
831 | SceneContext = namedtuple('SceneContext', fields) | |
832 | context = SceneContext( | |
833 | self._world, | |
834 | self._mouse_plane_node, | |
835 | self.cb_inst, | |
836 | self.current_bottom, | |
837 | self.repos, | |
838 | {}) | |
3466af49 | 839 | self.__scene_editor = SceneEditor(self.json, self.__json_name, context, self.add_item, self.__items, self._world, self._mouse_plane_node, self._pos_mgr) |
2aeb9f68 FC |
840 | |
841 | def __on_inspector_delete(self, item): | |
3466af49 FC |
842 | if item.__class__ in [WorldSpaceTestItem, PixelSpaceTestItem]: |
843 | for i in self._test_items: | |
844 | if item.id == i.name: | |
845 | r = i | |
846 | self._test_items.remove(r) | |
847 | else: | |
848 | self.__items.remove(item) | |
849 | j = self.json['items'] | |
850 | if item.__class__ == PixelSpaceTestItem: | |
851 | j = self.json['test_items']['pixel_space'] | |
852 | if item.__class__ == WorldSpaceTestItem: | |
853 | j = self.json['test_items']['world_space'] | |
854 | j.remove(item.json) | |
2aeb9f68 | 855 | item.destroy() |