31660ece45ebdf563fcafc44ecca778d4310a68b
1 from os
.path
import exists
2 from os
import makedirs
3 from logging
import info
5 from panda3d
.core
import AmbientLight
, Texture
, TextPropertiesManager
, \
6 TextNode
, Spotlight
, PerspectiveLens
, BitMask32
, NodePath
7 from panda3d
.bullet
import BulletPlaneShape
, BulletGhostNode
8 from direct
.gui
.OnscreenImage
import OnscreenImage
9 from direct
.gui
.OnscreenText
import OnscreenText
10 from direct
.gui
.DirectGui
import DirectButton
, DirectFrame
11 from direct
.gui
.DirectGuiGlobals
import FLAT
, DISABLED
, NORMAL
12 from direct
.showbase
.DirectObject
import DirectObject
13 from direct
.interval
.IntervalGlobal
import Sequence
, Func
14 from direct
.interval
.LerpInterval
import LerpFunctionInterval
15 from pmachines
.items
.background
import Background
16 from pmachines
.gui
.sidepanel
import SidePanel
17 from ya2
.utils
.cursor
import MouseCursor
18 from ya2
.p3d
.gfx
import P3dGfxMgr
19 from ya2
.p3d
.p3d
import LibP3d
22 class Scene(DirectObject
):
27 def __init__(self
, world
, exit_cb
, auto_close_instr
, dbg_items
, reload_cb
, scenes
, pos_mgr
, testing
, mouse_coords
, persistent
):
30 self
._exit
_cb
= exit_cb
31 self
._testing
= testing
32 self
._mouse
_coords
= mouse_coords
33 self
._dbg
_items
= dbg_items
34 self
._reload
_cb
= reload_cb
35 self
._pos
_mgr
= pos_mgr
38 self
._start
_evt
_time
= None
39 self
._enforce
_res
= ''
40 self
.__persistent
= persistent
41 self
.accept('enforce_res', self
.enforce_res
)
43 self
._cursor
= MouseCursor(
44 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
49 self
._set
_mouse
_plane
()
55 self
._item
_active
= None
58 self
.__restore
_state
()
60 self
._set
_instructions
()
61 self
._bg
= Background()
62 self
._side
_panel
= SidePanel(world
, self
._mouse
_plane
_node
, (-5, 4), (-3, 1), 1, self
.items
)
63 self
._scene
_tsk
= taskMgr
.add(self
.on_frame
, 'on_frame')
72 with
open(cls
.filename
) as f
:
73 cls
.json
= loads(f
.read())
74 return cls
.json
['version']
78 return bool([(name
, version
) for name
, version
in cls
.scenes_done
if cls
.__name
__ == name
and cls
.version() == version
])
87 def screenshot(self
, task
=None):
88 tex
= Texture('screenshot')
89 buffer = base
.win
.make_texture_buffer('screenshot', 512, 512, tex
, True )
90 cam
= base
.make_camera(buffer)
91 cam
.reparent_to(render
)
92 cam
.node().get_lens().set_fov(base
.camLens
.get_fov())
93 cam
.set_pos(0, -20, 0)
100 use_emission_maps
=False,
101 use_occlusion_maps
=True,
104 base
.graphicsEngine
.renderFrame()
105 base
.graphicsEngine
.renderFrame()
106 fname
= self
.__class
__.__name
__
107 if not exists('assets/images/scenes'):
108 makedirs('assets/images/scenes')
109 buffer.save_screenshot('assets/images/scenes/%s.png' % fname
)
110 # img = DirectButton(
111 # frameTexture=buffer.get_texture(), relief=FLAT,
112 # frameSize=(-.2, .2, -.2, .2))
113 return buffer.get_texture()
115 def current_bottom(self
):
117 for item
in self
.items
:
119 curr_bottom
= min(curr_bottom
, item
.get_bottom())
123 [itm
.destroy() for itm
in self
.items
]
124 [itm
.remove_node() for itm
in self
._test
_items
]
126 self
._test
_items
= []
128 self
._set
_test
_items
()
131 self
._command
_idx
= 0
132 self
._start
_evt
_time
= None
133 if hasattr(self
, '_success_txt'):
134 self
._success
_txt
.destroy()
135 del self
._success
_txt
136 self
.__right
_btn
['state'] = NORMAL
138 def enforce_res(self
, val
):
139 self
._enforce
_res
= val
140 info('enforce res: ' + val
)
143 self
.__intro
_sequence
.finish()
144 self
.ignore('enforce_res')
148 self
._unset
_mouse
_plane
()
149 [itm
.destroy() for itm
in self
.items
]
150 [itm
.remove_node() for itm
in self
._test
_items
]
152 self
._side
_panel
.destroy()
153 self
._cursor
.destroy()
154 taskMgr
.remove(self
._scene
_tsk
)
155 if hasattr(self
, '_success_txt'):
156 self
._success
_txt
.destroy()
158 def _set_camera(self
):
159 base
.camera
.set_pos(0, -20, 0)
160 base
.camera
.look_at(0, 0, 0)
165 start_v
[0] + (end_v
[0] - start_v
[0]) * t
,
166 start_v
[1] + (end_v
[1] - start_v
[1]) * t
,
167 start_v
[2] + (end_v
[2] - start_v
[2]) * t
)
168 base
.camera
.set_pos(*curr_pos
)
170 camera_interval
= LerpFunctionInterval(
175 blendType
='easeInOut')
176 self
.__intro
_sequence
= Sequence(
179 self
.__intro
_sequence
.start()
181 def __load_img_btn(self
, path
, col
):
182 img
= OnscreenImage('assets/images/buttons/%s.dds' % path
)
183 img
.set_transparency(True)
189 def load_images_btn(path
, col
):
192 (.6, .6, .6, 1), # ready
193 (1, 1, 1, 1), # press
194 (.8, .8, .8, 1), # rollover
200 (.4, .1, .1, .4)]}[col
]
201 return [self
.__load
_img
_btn
(path
, col
) for col
in colors
]
202 abl
, abr
= base
.a2dBottomLeft
, base
.a2dBottomRight
204 ('home', self
.on_home
, NORMAL
, abl
, 'gray'),
205 ('information', self
._set
_instructions
, NORMAL
, abl
, 'gray'),
206 ('right', self
.on_play
, NORMAL
, abr
, 'green'),
207 #('next', self.on_next, DISABLED, abr, 'gray'),
208 #('previous', self.on_prev, DISABLED, abr, 'gray'),
209 #('rewind', self.reset, NORMAL, abr, 'gray')
213 for binfo
in btn_info
:
214 imgs
= load_images_btn(binfo
[0], binfo
[4])
215 if binfo
[3] == base
.a2dBottomLeft
:
219 sign
, num
= -1, num_r
221 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
223 image
=imgs
, scale
=.05, pos
=(sign
* (.06 + .11 * num
), 1, .06),
224 parent
=binfo
[3], command
=binfo
[1], state
=binfo
[2], relief
=FLAT
,
225 frameColor
=fcols
[0] if binfo
[2] == NORMAL
else fcols
[1],
226 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
227 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
228 btn
.set_transparency(True)
229 self
._pos
_mgr
.register(binfo
[0], LibP3d
.wdg_pos(btn
))
231 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
= btns
232 # , self.__next_btn, self.__prev_btn, self.__rewind_btn
234 self
._info
_txt
= OnscreenText(
235 '', parent
=base
.a2dTopRight
, scale
=0.04,
236 pos
=(-.03, -.06), fg
=(.9, .9, .9, 1), align
=TextNode
.A_right
)
237 if self
._mouse
_coords
:
238 self
._coords
_txt
= OnscreenText(
239 '', parent
=base
.a2dTopRight
, scale
=0.04,
240 pos
=(-.03, -.12), fg
=(.9, .9, .9, 1), align
=TextNode
.A_right
)
241 def update_coords(task
):
243 for hit
in self
._get
_hits
():
244 if hit
.get_node() == self
._mouse
_plane
_node
:
245 pos
= hit
.get_hit_pos()
247 txt
= '%s %s' % (round(pos
.x
, 3),
249 self
._coords
_txt
['text'] = txt
251 self
._coords
_tsk
= taskMgr
.add(update_coords
, 'update_coords')
253 def _unset_gui(self
):
255 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
256 #self.__next_btn, self.__prev_btn, self.__rewind_btn
258 [btn
.destroy() for btn
in btns
]
260 self
._info
_txt
.destroy()
261 if self
._mouse
_coords
:
262 taskMgr
.remove(self
._coords
_tsk
)
263 self
._coords
_txt
.destroy()
265 def _set_spotlight(self
, name
, pos
, look_at
, color
, shadows
=False):
266 light
= Spotlight(name
)
268 light
.setLens(PerspectiveLens())
269 light_np
= render
.attach_new_node(light
)
270 light_np
.set_pos(pos
)
271 light_np
.look_at(look_at
)
272 light
.set_color(color
)
273 render
.set_light(light_np
)
276 def _set_lights(self
):
277 alight
= AmbientLight('alight') # for ao
278 alight
.set_color((.15, .15, .15, 1))
279 self
._alnp
= render
.attach_new_node(alight
)
280 render
.set_light(self
._alnp
)
281 self
._key
_light
= self
._set
_spotlight
(
282 'key light', (-5, -80, 5), (0, 0, 0), (2.8, 2.8, 2.8, 1))
283 self
._shadow
_light
= self
._set
_spotlight
(
284 'key light', (-5, -80, 5), (0, 0, 0), (.58, .58, .58, 1), True)
285 self
._shadow
_light
.node().set_shadow_caster(True, 2048, 2048)
286 self
._shadow
_light
.node().get_lens().set_film_size(2048, 2048)
287 self
._shadow
_light
.node().get_lens().set_near_far(1, 256)
288 self
._shadow
_light
.node().set_camera_mask(BitMask32(0x01))
290 def _unset_lights(self
):
291 for light
in [self
._alnp
, self
._key
_light
, self
._shadow
_light
]:
292 render
.clear_light(light
)
295 def _set_input(self
):
296 self
.accept('mouse1', self
.on_click_l
)
297 self
.accept('mouse1-up', self
.on_release
)
298 self
.accept('mouse3', self
.on_click_r
)
299 self
.accept('mouse3-up', self
.on_release
)
301 def _unset_input(self
):
302 for evt
in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']:
305 def _set_mouse_plane(self
):
306 shape
= BulletPlaneShape((0, -1, 0), 0)
307 #self._mouse_plane_node = BulletRigidBodyNode('mouse plane')
308 self
._mouse
_plane
_node
= BulletGhostNode('mouse plane')
309 self
._mouse
_plane
_node
.addShape(shape
)
310 #np = render.attachNewNode(self._mouse_plane_node)
311 #self._world.attachRigidBody(self._mouse_plane_node)
312 self
._world
.attach_ghost(self
._mouse
_plane
_node
)
314 def _unset_mouse_plane(self
):
315 self
._world
.remove_ghost(self
._mouse
_plane
_node
)
318 if not base
.mouseWatcherNode
.has_mouse(): return []
319 p_from
, p_to
= P3dGfxMgr
.world_from_to(base
.mouseWatcherNode
.get_mouse())
320 return self
._world
.ray_test_all(p_from
, p_to
).get_hits()
322 def _update_info(self
, item
):
325 txt
= '%.3f %.3f\n%.3f°' % (
326 item
._np
.get_x(), item
._np
.get_z(), item
._np
.get_r())
327 self
._info
_txt
['text'] = txt
329 def _on_click(self
, method
):
332 for hit
in self
._get
_hits
():
333 if hit
.get_node() == self
._mouse
_plane
_node
:
334 pos
= hit
.get_hit_pos()
335 for hit
in self
._get
_hits
():
336 for item
in [i
for i
in self
.items
if hit
.get_node() == i
.node
and i
.interactable
]:
337 if not self
._item
_active
:
338 self
._item
_active
= item
339 getattr(item
, method
)(pos
)
340 img
= 'move' if method
== 'on_click_l' else 'rotate'
341 if not (img
== 'rotate' and not item
._instantiated
):
342 self
._cursor
.set_image('assets/images/buttons/%s.dds' % img
)
344 def on_click_l(self
):
345 self
._on
_click
('on_click_l')
347 def on_click_r(self
):
348 self
._on
_click
('on_click_r')
350 def on_release(self
):
351 if self
._item
_active
and not self
._item
_active
._first
_command
:
352 self
._commands
= self
._commands
[:self
._command
_idx
]
353 self
._commands
+= [self
._item
_active
]
354 self
._command
_idx
+= 1
355 #self.__prev_btn['state'] = NORMAL
356 #fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
357 #self.__prev_btn['frameColor'] = fcols[0]
358 #if self._item_active._command_idx == len(self._item_active._commands) - 1:
359 # self.__next_btn['state'] = DISABLED
360 # self.__next_btn['frameColor'] = fcols[1]
361 self
._item
_active
= None
362 [item
.on_release() for item
in self
.items
]
363 self
._cursor
.set_image('assets/images/buttons/arrowUpLeft.dds')
366 for item
in self
.items
:
367 item
.repos_done
= False
368 self
.items
= sorted(self
.items
, key
=lambda itm
: itm
.__class
__.__name
__)
369 [item
.on_aspect_ratio_changed() for item
in self
.items
]
370 self
._side
_panel
.update(self
.items
)
371 max_x
= -float('inf')
372 for item
in self
.items
:
373 if not item
._instantiated
:
374 max_x
= max(item
._np
.get_x(), max_x
)
375 for item
in self
.items
:
376 if not item
._instantiated
:
379 def on_aspect_ratio_changed(self
):
382 def _win_condition(self
):
385 def _fail_condition(self
):
386 return all(itm
.fail_condition() for itm
in self
.items
) and not self
._paused
and self
._state
== 'playing'
388 def on_frame(self
, task
):
389 hits
= self
._get
_hits
()
391 for hit
in self
._get
_hits
():
392 if hit
.get_node() == self
._mouse
_plane
_node
:
393 pos
= hit
.get_hit_pos()
394 hit_nodes
= [hit
.get_node() for hit
in hits
]
395 if self
._item
_active
:
396 items_hit
= [self
._item
_active
]
398 items_hit
= [itm
for itm
in self
.items
if itm
.node
in hit_nodes
]
399 items_no_hit
= [itm
for itm
in self
.items
if itm
not in items_hit
]
400 [itm
.on_mouse_on() for itm
in items_hit
]
401 [itm
.on_mouse_off() for itm
in items_no_hit
]
402 if pos
and self
._item
_active
:
403 self
._item
_active
.on_mouse_move(pos
)
405 self
._update
_info
(items_hit
[0] if items_hit
else None)
406 if self
._win
_condition
():
407 self
._start
_evt
_time
= None
408 self
._set
_fail
() if self
._enforce
_res
== 'fail' else self
._set
_win
()
409 elif self
._state
== 'playing' and self
._fail
_condition
():
410 self
._start
_evt
_time
= None
411 self
._set
_win
() if self
._enforce
_res
== 'win' else self
._set
_fail
()
412 elif self
._testing
and self
._start
_evt
_time
and globalClock
.getFrameTime() - self
._start
_evt
_time
> 5.0:
413 self
._start
_evt
_time
= None
414 self
._set
_win
() if self
._enforce
_res
== 'win' else self
._set
_fail
()
415 if any(itm
._overlapping
for itm
in self
.items
):
416 self
._cursor
.cursor_img
.img
.set_color(.9, .1, .1, 1)
418 self
._cursor
.cursor_img
.img
.set_color(.9, .9, .9, 1)
421 def cb_inst(self
, item
):
425 self
._state
= 'playing'
426 #self.__prev_btn['state'] = DISABLED
427 #self.__next_btn['state'] = DISABLED
428 self
.__right
_btn
['state'] = DISABLED
429 [itm
.play() for itm
in self
.items
]
430 self
._start
_evt
_time
= globalClock
.getFrameTime()
433 self
._commands
[self
._command
_idx
].redo()
434 self
._command
_idx
+= 1
435 #fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
436 #self.__prev_btn['state'] = NORMAL
437 #self.__prev_btn['frameColor'] = fcols[0]
438 #more_commands = self._command_idx < len(self._commands)
439 #self.__next_btn['state'] = NORMAL if more_commands else DISABLED
440 #self.__next_btn['frameColor'] = fcols[0] if more_commands else fcols[1]
443 self
._command
_idx
-= 1
444 self
._commands
[self
._command
_idx
].undo()
445 #fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
446 #self.__next_btn['state'] = NORMAL
447 #self.__next_btn['frameColor'] = fcols[0]
448 #self.__prev_btn['state'] = NORMAL if self._command_idx else DISABLED
449 #self.__prev_btn['frameColor'] = fcols[0] if self._command_idx else fcols[1]
454 def _set_instructions(self
):
457 mgr
= TextPropertiesManager
.get_global_ptr()
458 for name
in ['mouse_l', 'mouse_r']:
459 graphic
= OnscreenImage('assets/images/buttons/%s.dds' % name
)
460 graphic
.set_scale(.5)
461 graphic
.get_texture().set_minfilter(Texture
.FTLinearMipmapLinear
)
462 graphic
.get_texture().set_anisotropic_degree(2)
463 mgr
.set_graphic(name
, graphic
)
465 graphic
.set_transparency(True)
466 graphic
.detach_node()
467 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
468 frameSize
=(-.6, .6, -.3, .3))
469 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
471 font
.set_pixels_per_unit(60)
472 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
473 font
.set_outline((0, 0, 0, 1), .8, .2)
474 self
._txt
= OnscreenText(
475 self
._instr
_txt
(), parent
=frm
, font
=font
, scale
=0.06,
476 fg
=(.9, .9, .9, 1), align
=TextNode
.A_left
)
477 u_l
= self
._txt
.textNode
.get_upper_left_3d()
478 l_r
= self
._txt
.textNode
.get_lower_right_3d()
479 w
, h
= l_r
[0] - u_l
[0], u_l
[2] - l_r
[2]
482 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
483 z
+= (btn_scale
+ 2 * mar
) / 2
484 self
._txt
['pos'] = -w
/ 2, z
485 u_l
= self
._txt
.textNode
.get_upper_left_3d()
486 l_r
= self
._txt
.textNode
.get_lower_right_3d()
487 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
488 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
489 frm
['frameSize'] = fsz
491 (.6, .6, .6, 1), # ready
492 (1, 1, 1, 1), # press
493 (.8, .8, .8, 1), # rollover
495 imgs
= [self
.__load
_img
_btn
('exitRight', col
) for col
in colors
]
497 image
=imgs
, scale
=btn_scale
,
498 pos
=(l_r
[0] - btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
499 parent
=frm
, command
=self
.__on
_close
_instructions
, extraArgs
=[frm
],
500 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
501 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
502 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
503 btn
.set_transparency(True)
504 self
._pos
_mgr
.register('close_instructions', LibP3d
.wdg_pos(btn
))
507 self
.__persistent
.save_scene(self
.__class
__.__name
__, self
.version())
508 loader
.load_sfx('assets/audio/sfx/success.ogg').play()
511 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
512 frameSize
=(-.6, .6, -.3, .3))
513 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
515 font
.set_pixels_per_unit(60)
516 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
517 font
.set_outline((0, 0, 0, 1), .8, .2)
518 self
._txt
= OnscreenText(
521 font
=font
, scale
=0.2,
523 u_l
= self
._txt
.textNode
.get_upper_left_3d()
524 l_r
= self
._txt
.textNode
.get_lower_right_3d()
525 #w, h = l_r[0] - u_l[0], u_l[2] - l_r[2]
529 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
530 z
+= (btn_scale
+ 2 * mar
) / 2
531 self
._txt
['pos'] = 0, z
532 u_l
= self
._txt
.textNode
.get_upper_left_3d()
533 l_r
= self
._txt
.textNode
.get_lower_right_3d()
534 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
535 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
536 frm
['frameSize'] = fsz
538 (.6, .6, .6, 1), # ready
539 (1, 1, 1, 1), # press
540 (.8, .8, .8, 1), # rollover
542 imgs
= [self
.__load
_img
_btn
('home', col
) for col
in colors
]
544 image
=imgs
, scale
=btn_scale
,
545 pos
=(-2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
546 parent
=frm
, command
=self
._on
_end
_home
, extraArgs
=[frm
],
547 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
548 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
549 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
550 btn
.set_transparency(True)
551 self
._pos
_mgr
.register('home_win', LibP3d
.wdg_pos(btn
))
552 imgs
= [self
.__load
_img
_btn
('rewind', col
) for col
in colors
]
554 image
=imgs
, scale
=btn_scale
,
555 pos
=(0, 1, l_r
[2] - mar
- btn_scale
),
556 parent
=frm
, command
=self
._on
_restart
, extraArgs
=[frm
],
557 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
558 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
559 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
560 self
._pos
_mgr
.register('replay', LibP3d
.wdg_pos(btn
))
561 btn
.set_transparency(True)
562 enabled
= self
._scenes
.index(self
.__class
__) < len(self
._scenes
) - 1
564 next_scene
= self
._scenes
[self
._scenes
.index(self
.__class
__) + 1]
567 imgs
= [self
.__load
_img
_btn
('right', col
) for col
in colors
]
569 image
=imgs
, scale
=btn_scale
,
570 pos
=(2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
571 parent
=frm
, command
=self
._on
_next
_scene
,
572 extraArgs
=[frm
, next_scene
], relief
=FLAT
,
573 frameColor
=(.6, .6, .6, .08),
574 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
575 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
576 btn
['state'] = NORMAL
if enabled
else DISABLED
577 self
._pos
_mgr
.register('next', LibP3d
.wdg_pos(btn
))
578 btn
.set_transparency(True)
581 loader
.load_sfx('assets/audio/sfx/success.ogg').play()
584 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
585 frameSize
=(-.6, .6, -.3, .3))
586 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
588 font
.set_pixels_per_unit(60)
589 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
590 font
.set_outline((0, 0, 0, 1), .8, .2)
591 self
._txt
= OnscreenText(
592 _('You have failed!'),
594 font
=font
, scale
=0.2,
596 u_l
= self
._txt
.textNode
.get_upper_left_3d()
597 l_r
= self
._txt
.textNode
.get_lower_right_3d()
598 #w, h = l_r[0] - u_l[0], u_l[2] - l_r[2]
602 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
603 z
+= (btn_scale
+ 2 * mar
) / 2
604 self
._txt
['pos'] = 0, z
605 u_l
= self
._txt
.textNode
.get_upper_left_3d()
606 l_r
= self
._txt
.textNode
.get_lower_right_3d()
607 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
608 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
609 frm
['frameSize'] = fsz
611 (.6, .6, .6, 1), # ready
612 (1, 1, 1, 1), # press
613 (.8, .8, .8, 1), # rollover
615 imgs
= [self
.__load
_img
_btn
('home', col
) for col
in colors
]
617 image
=imgs
, scale
=btn_scale
,
618 pos
=(-2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
619 parent
=frm
, command
=self
._on
_end
_home
, extraArgs
=[frm
],
620 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
621 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
622 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
623 self
._pos
_mgr
.register('home_win', LibP3d
.wdg_pos(btn
))
624 btn
.set_transparency(True)
625 imgs
= [self
.__load
_img
_btn
('rewind', col
) for col
in colors
]
627 image
=imgs
, scale
=btn_scale
,
628 pos
=(0, 1, l_r
[2] - mar
- btn_scale
),
629 parent
=frm
, command
=self
._on
_restart
, extraArgs
=[frm
],
630 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
631 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
632 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
633 self
._pos
_mgr
.register('replay', LibP3d
.wdg_pos(btn
))
634 btn
.set_transparency(True)
636 def _on_restart(self
, frm
):
637 self
.__on
_close
_instructions
(frm
)
640 def _on_end_home(self
, frm
):
641 self
.__on
_close
_instructions
(frm
)
644 def _on_next_scene(self
, frm
, scene
):
645 self
.__on
_close
_instructions
(frm
)
646 self
._reload
_cb
(scene
)
648 def __store_state(self
):
650 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
651 #self.__next_btn, self.__prev_btn, self.__rewind_btn
653 self
.__btn
_state
= [btn
['state'] for btn
in btns
]
655 btn
['state'] = DISABLED
656 [itm
.store_state() for itm
in self
.items
]
658 def __restore_state(self
):
660 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
661 #self.__next_btn, self.__prev_btn, self.__rewind_btn
663 for btn
, state
in zip(btns
, self
.__btn
_state
):
665 [itm
.restore_state() for itm
in self
.items
]
668 def __on_close_instructions(self
, frm
):
670 self
.__restore
_state
()
672 def _set_test_items(self
):
673 def frame_after(task
):
674 self
._define
_test
_items
()
675 for itm
in self
._test
_items
:
676 self
._pos
_mgr
.register(itm
.name
, P3dGfxMgr
.pos2d_p2d(itm
))
677 taskMgr
.doMethodLater(.01, frame_after
, 'frame after')
679 def _set_test_item(self
, name
, pos
):
680 self
._test
_items
+= [NodePath(name
)]
681 self
._test
_items
[-1].set_pos(pos
[0], 0, pos
[1])