6029d720c98ddf9558ce6ca94b0b0e63e9bbc350
1 from os
.path
import exists
2 from os
import makedirs
3 from logging
import info
4 from panda3d
.core
import AmbientLight
, Texture
, TextPropertiesManager
, \
5 TextNode
, Spotlight
, PerspectiveLens
, BitMask32
, NodePath
6 from panda3d
.bullet
import BulletPlaneShape
, BulletGhostNode
7 from direct
.gui
.OnscreenImage
import OnscreenImage
8 from direct
.gui
.OnscreenText
import OnscreenText
9 from direct
.gui
.DirectGui
import DirectButton
, DirectFrame
10 from direct
.gui
.DirectGuiGlobals
import FLAT
, DISABLED
, NORMAL
11 from direct
.showbase
.DirectObject
import DirectObject
12 from direct
.interval
.IntervalGlobal
import Sequence
, Func
13 from direct
.interval
.LerpInterval
import LerpFunctionInterval
14 from pmachines
.items
.background
import Background
15 from pmachines
.gui
.sidepanel
import SidePanel
16 from ya2
.utils
.cursor
import MouseCursor
17 from ya2
.p3d
.gfx
import P3dGfxMgr
18 from ya2
.p3d
.p3d
import LibP3d
21 class Scene(DirectObject
):
25 def __init__(self
, world
, exit_cb
, auto_close_instr
, dbg_items
, reload_cb
, scenes
, pos_mgr
, testing
, mouse_coords
, persistent
):
28 self
._exit
_cb
= exit_cb
29 self
._testing
= testing
30 self
._mouse
_coords
= mouse_coords
31 self
._dbg
_items
= dbg_items
32 self
._reload
_cb
= reload_cb
33 self
._pos
_mgr
= pos_mgr
36 self
._start
_evt
_time
= None
37 self
._enforce
_res
= ''
38 self
.__persistent
= persistent
39 self
.accept('enforce_res', self
.enforce_res
)
41 self
._cursor
= MouseCursor(
42 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
47 self
._set
_mouse
_plane
()
53 self
._item
_active
= None
56 self
.__restore
_state
()
58 self
._set
_instructions
()
59 self
._bg
= Background()
60 self
._side
_panel
= SidePanel(world
, self
._mouse
_plane
_node
, (-5, 4), (-3, 1), 1, self
.items
)
61 self
._scene
_tsk
= taskMgr
.add(self
.on_frame
, 'on_frame')
69 return bool([(name
, version
) for name
, version
in cls
.scenes_done
if cls
.__name
__ == name
and cls
.version
== version
])
78 def screenshot(self
, task
=None):
79 tex
= Texture('screenshot')
80 buffer = base
.win
.make_texture_buffer('screenshot', 512, 512, tex
, True )
81 cam
= base
.make_camera(buffer)
82 cam
.reparent_to(render
)
83 cam
.node().get_lens().set_fov(base
.camLens
.get_fov())
84 cam
.set_pos(0, -20, 0)
91 use_emission_maps
=False,
92 use_occlusion_maps
=True,
95 base
.graphicsEngine
.renderFrame()
96 base
.graphicsEngine
.renderFrame()
97 fname
= self
.__class
__.__name
__
98 if not exists('assets/images/scenes'):
99 makedirs('assets/images/scenes')
100 buffer.save_screenshot('assets/images/scenes/%s.png' % fname
)
101 # img = DirectButton(
102 # frameTexture=buffer.get_texture(), relief=FLAT,
103 # frameSize=(-.2, .2, -.2, .2))
104 return buffer.get_texture()
106 def current_bottom(self
):
108 for item
in self
.items
:
110 curr_bottom
= min(curr_bottom
, item
.get_bottom())
114 [itm
.destroy() for itm
in self
.items
]
115 [itm
.remove_node() for itm
in self
._test
_items
]
117 self
._test
_items
= []
119 self
._set
_test
_items
()
122 self
._command
_idx
= 0
123 self
._start
_evt
_time
= None
124 if hasattr(self
, '_success_txt'):
125 self
._success
_txt
.destroy()
126 del self
._success
_txt
127 self
.__right
_btn
['state'] = NORMAL
129 def enforce_res(self
, val
):
130 self
._enforce
_res
= val
131 info('enforce res: ' + val
)
134 self
.__intro
_sequence
.finish()
135 self
.ignore('enforce_res')
139 self
._unset
_mouse
_plane
()
140 [itm
.destroy() for itm
in self
.items
]
141 [itm
.remove_node() for itm
in self
._test
_items
]
143 self
._side
_panel
.destroy()
144 self
._cursor
.destroy()
145 taskMgr
.remove(self
._scene
_tsk
)
146 if hasattr(self
, '_success_txt'):
147 self
._success
_txt
.destroy()
149 def _set_camera(self
):
150 base
.camera
.set_pos(0, -20, 0)
151 base
.camera
.look_at(0, 0, 0)
156 start_v
[0] + (end_v
[0] - start_v
[0]) * t
,
157 start_v
[1] + (end_v
[1] - start_v
[1]) * t
,
158 start_v
[2] + (end_v
[2] - start_v
[2]) * t
)
159 base
.camera
.set_pos(*curr_pos
)
161 camera_interval
= LerpFunctionInterval(
166 blendType
='easeInOut')
167 self
.__intro
_sequence
= Sequence(
170 self
.__intro
_sequence
.start()
172 def __load_img_btn(self
, path
, col
):
173 img
= OnscreenImage('assets/images/buttons/%s.dds' % path
)
174 img
.set_transparency(True)
180 def load_images_btn(path
, col
):
183 (.6, .6, .6, 1), # ready
184 (1, 1, 1, 1), # press
185 (.8, .8, .8, 1), # rollover
191 (.4, .1, .1, .4)]}[col
]
192 return [self
.__load
_img
_btn
(path
, col
) for col
in colors
]
193 abl
, abr
= base
.a2dBottomLeft
, base
.a2dBottomRight
195 ('home', self
.on_home
, NORMAL
, abl
, 'gray'),
196 ('information', self
._set
_instructions
, NORMAL
, abl
, 'gray'),
197 ('right', self
.on_play
, NORMAL
, abr
, 'green'),
198 #('next', self.on_next, DISABLED, abr, 'gray'),
199 #('previous', self.on_prev, DISABLED, abr, 'gray'),
200 #('rewind', self.reset, NORMAL, abr, 'gray')
204 for binfo
in btn_info
:
205 imgs
= load_images_btn(binfo
[0], binfo
[4])
206 if binfo
[3] == base
.a2dBottomLeft
:
210 sign
, num
= -1, num_r
212 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
214 image
=imgs
, scale
=.05, pos
=(sign
* (.06 + .11 * num
), 1, .06),
215 parent
=binfo
[3], command
=binfo
[1], state
=binfo
[2], relief
=FLAT
,
216 frameColor
=fcols
[0] if binfo
[2] == NORMAL
else fcols
[1],
217 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
218 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
219 btn
.set_transparency(True)
220 self
._pos
_mgr
.register(binfo
[0], LibP3d
.wdg_pos(btn
))
222 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
= btns
223 # , self.__next_btn, self.__prev_btn, self.__rewind_btn
225 self
._info
_txt
= OnscreenText(
226 '', parent
=base
.a2dTopRight
, scale
=0.04,
227 pos
=(-.03, -.06), fg
=(.9, .9, .9, 1), align
=TextNode
.A_right
)
228 if self
._mouse
_coords
:
229 self
._coords
_txt
= OnscreenText(
230 '', parent
=base
.a2dTopRight
, scale
=0.04,
231 pos
=(-.03, -.12), fg
=(.9, .9, .9, 1), align
=TextNode
.A_right
)
232 def update_coords(task
):
234 for hit
in self
._get
_hits
():
235 if hit
.get_node() == self
._mouse
_plane
_node
:
236 pos
= hit
.get_hit_pos()
238 txt
= '%s %s' % (round(pos
.x
, 3),
240 self
._coords
_txt
['text'] = txt
242 self
._coords
_tsk
= taskMgr
.add(update_coords
, 'update_coords')
244 def _unset_gui(self
):
246 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
247 #self.__next_btn, self.__prev_btn, self.__rewind_btn
249 [btn
.destroy() for btn
in btns
]
251 self
._info
_txt
.destroy()
252 if self
._mouse
_coords
:
253 taskMgr
.remove(self
._coords
_tsk
)
254 self
._coords
_txt
.destroy()
256 def _set_spotlight(self
, name
, pos
, look_at
, color
, shadows
=False):
257 light
= Spotlight(name
)
259 light
.setLens(PerspectiveLens())
260 light_np
= render
.attach_new_node(light
)
261 light_np
.set_pos(pos
)
262 light_np
.look_at(look_at
)
263 light
.set_color(color
)
264 render
.set_light(light_np
)
267 def _set_lights(self
):
268 alight
= AmbientLight('alight') # for ao
269 alight
.set_color((.15, .15, .15, 1))
270 self
._alnp
= render
.attach_new_node(alight
)
271 render
.set_light(self
._alnp
)
272 self
._key
_light
= self
._set
_spotlight
(
273 'key light', (-5, -80, 5), (0, 0, 0), (2.8, 2.8, 2.8, 1))
274 self
._shadow
_light
= self
._set
_spotlight
(
275 'key light', (-5, -80, 5), (0, 0, 0), (.58, .58, .58, 1), True)
276 self
._shadow
_light
.node().set_shadow_caster(True, 2048, 2048)
277 self
._shadow
_light
.node().get_lens().set_film_size(2048, 2048)
278 self
._shadow
_light
.node().get_lens().set_near_far(1, 256)
279 self
._shadow
_light
.node().set_camera_mask(BitMask32(0x01))
281 def _unset_lights(self
):
282 for light
in [self
._alnp
, self
._key
_light
, self
._shadow
_light
]:
283 render
.clear_light(light
)
286 def _set_input(self
):
287 self
.accept('mouse1', self
.on_click_l
)
288 self
.accept('mouse1-up', self
.on_release
)
289 self
.accept('mouse3', self
.on_click_r
)
290 self
.accept('mouse3-up', self
.on_release
)
292 def _unset_input(self
):
293 for evt
in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']:
296 def _set_mouse_plane(self
):
297 shape
= BulletPlaneShape((0, -1, 0), 0)
298 #self._mouse_plane_node = BulletRigidBodyNode('mouse plane')
299 self
._mouse
_plane
_node
= BulletGhostNode('mouse plane')
300 self
._mouse
_plane
_node
.addShape(shape
)
301 #np = render.attachNewNode(self._mouse_plane_node)
302 #self._world.attachRigidBody(self._mouse_plane_node)
303 self
._world
.attach_ghost(self
._mouse
_plane
_node
)
305 def _unset_mouse_plane(self
):
306 self
._world
.remove_ghost(self
._mouse
_plane
_node
)
309 if not base
.mouseWatcherNode
.has_mouse(): return []
310 p_from
, p_to
= P3dGfxMgr
.world_from_to(base
.mouseWatcherNode
.get_mouse())
311 return self
._world
.ray_test_all(p_from
, p_to
).get_hits()
313 def _update_info(self
, item
):
316 txt
= '%.3f %.3f\n%.3f°' % (
317 item
._np
.get_x(), item
._np
.get_z(), item
._np
.get_r())
318 self
._info
_txt
['text'] = txt
320 def _on_click(self
, method
):
323 for hit
in self
._get
_hits
():
324 if hit
.get_node() == self
._mouse
_plane
_node
:
325 pos
= hit
.get_hit_pos()
326 for hit
in self
._get
_hits
():
327 for item
in [i
for i
in self
.items
if hit
.get_node() == i
.node
and i
.interactable
]:
328 if not self
._item
_active
:
329 self
._item
_active
= item
330 getattr(item
, method
)(pos
)
331 img
= 'move' if method
== 'on_click_l' else 'rotate'
332 if not (img
== 'rotate' and not item
._instantiated
):
333 self
._cursor
.set_image('assets/images/buttons/%s.dds' % img
)
335 def on_click_l(self
):
336 self
._on
_click
('on_click_l')
338 def on_click_r(self
):
339 self
._on
_click
('on_click_r')
341 def on_release(self
):
342 if self
._item
_active
and not self
._item
_active
._first
_command
:
343 self
._commands
= self
._commands
[:self
._command
_idx
]
344 self
._commands
+= [self
._item
_active
]
345 self
._command
_idx
+= 1
346 #self.__prev_btn['state'] = NORMAL
347 #fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
348 #self.__prev_btn['frameColor'] = fcols[0]
349 #if self._item_active._command_idx == len(self._item_active._commands) - 1:
350 # self.__next_btn['state'] = DISABLED
351 # self.__next_btn['frameColor'] = fcols[1]
352 self
._item
_active
= None
353 [item
.on_release() for item
in self
.items
]
354 self
._cursor
.set_image('assets/images/buttons/arrowUpLeft.dds')
357 for item
in self
.items
:
358 item
.repos_done
= False
359 self
.items
= sorted(self
.items
, key
=lambda itm
: itm
.__class
__.__name
__)
360 [item
.on_aspect_ratio_changed() for item
in self
.items
]
361 self
._side
_panel
.update(self
.items
)
362 max_x
= -float('inf')
363 for item
in self
.items
:
364 if not item
._instantiated
:
365 max_x
= max(item
._np
.get_x(), max_x
)
366 for item
in self
.items
:
367 if not item
._instantiated
:
370 def on_aspect_ratio_changed(self
):
373 def _win_condition(self
):
376 def _fail_condition(self
):
377 return all(itm
.fail_condition() for itm
in self
.items
) and not self
._paused
and self
._state
== 'playing'
379 def on_frame(self
, task
):
380 hits
= self
._get
_hits
()
382 for hit
in self
._get
_hits
():
383 if hit
.get_node() == self
._mouse
_plane
_node
:
384 pos
= hit
.get_hit_pos()
385 hit_nodes
= [hit
.get_node() for hit
in hits
]
386 if self
._item
_active
:
387 items_hit
= [self
._item
_active
]
389 items_hit
= [itm
for itm
in self
.items
if itm
.node
in hit_nodes
]
390 items_no_hit
= [itm
for itm
in self
.items
if itm
not in items_hit
]
391 [itm
.on_mouse_on() for itm
in items_hit
]
392 [itm
.on_mouse_off() for itm
in items_no_hit
]
393 if pos
and self
._item
_active
:
394 self
._item
_active
.on_mouse_move(pos
)
396 self
._update
_info
(items_hit
[0] if items_hit
else None)
397 if self
._win
_condition
():
398 self
._start
_evt
_time
= None
399 self
._set
_fail
() if self
._enforce
_res
== 'fail' else self
._set
_win
()
400 elif self
._state
== 'playing' and self
._fail
_condition
():
401 self
._start
_evt
_time
= None
402 self
._set
_win
() if self
._enforce
_res
== 'win' else self
._set
_fail
()
403 elif self
._testing
and self
._start
_evt
_time
and globalClock
.getFrameTime() - self
._start
_evt
_time
> 5.0:
404 self
._start
_evt
_time
= None
405 self
._set
_win
() if self
._enforce
_res
== 'win' else self
._set
_fail
()
406 if any(itm
._overlapping
for itm
in self
.items
):
407 self
._cursor
.cursor_img
.img
.set_color(.9, .1, .1, 1)
409 self
._cursor
.cursor_img
.img
.set_color(.9, .9, .9, 1)
412 def cb_inst(self
, item
):
416 self
._state
= 'playing'
417 #self.__prev_btn['state'] = DISABLED
418 #self.__next_btn['state'] = DISABLED
419 self
.__right
_btn
['state'] = DISABLED
420 [itm
.play() for itm
in self
.items
]
421 self
._start
_evt
_time
= globalClock
.getFrameTime()
424 self
._commands
[self
._command
_idx
].redo()
425 self
._command
_idx
+= 1
426 #fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
427 #self.__prev_btn['state'] = NORMAL
428 #self.__prev_btn['frameColor'] = fcols[0]
429 #more_commands = self._command_idx < len(self._commands)
430 #self.__next_btn['state'] = NORMAL if more_commands else DISABLED
431 #self.__next_btn['frameColor'] = fcols[0] if more_commands else fcols[1]
434 self
._command
_idx
-= 1
435 self
._commands
[self
._command
_idx
].undo()
436 #fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
437 #self.__next_btn['state'] = NORMAL
438 #self.__next_btn['frameColor'] = fcols[0]
439 #self.__prev_btn['state'] = NORMAL if self._command_idx else DISABLED
440 #self.__prev_btn['frameColor'] = fcols[0] if self._command_idx else fcols[1]
445 def _set_instructions(self
):
448 mgr
= TextPropertiesManager
.get_global_ptr()
449 for name
in ['mouse_l', 'mouse_r']:
450 graphic
= OnscreenImage('assets/images/buttons/%s.dds' % name
)
451 graphic
.set_scale(.5)
452 graphic
.get_texture().set_minfilter(Texture
.FTLinearMipmapLinear
)
453 graphic
.get_texture().set_anisotropic_degree(2)
454 mgr
.set_graphic(name
, graphic
)
456 graphic
.set_transparency(True)
457 graphic
.detach_node()
458 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
459 frameSize
=(-.6, .6, -.3, .3))
460 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
462 font
.set_pixels_per_unit(60)
463 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
464 font
.set_outline((0, 0, 0, 1), .8, .2)
465 self
._txt
= OnscreenText(
466 self
._instr
_txt
(), parent
=frm
, font
=font
, scale
=0.06,
467 fg
=(.9, .9, .9, 1), align
=TextNode
.A_left
)
468 u_l
= self
._txt
.textNode
.get_upper_left_3d()
469 l_r
= self
._txt
.textNode
.get_lower_right_3d()
470 w
, h
= l_r
[0] - u_l
[0], u_l
[2] - l_r
[2]
473 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
474 z
+= (btn_scale
+ 2 * mar
) / 2
475 self
._txt
['pos'] = -w
/ 2, z
476 u_l
= self
._txt
.textNode
.get_upper_left_3d()
477 l_r
= self
._txt
.textNode
.get_lower_right_3d()
478 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
479 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
480 frm
['frameSize'] = fsz
482 (.6, .6, .6, 1), # ready
483 (1, 1, 1, 1), # press
484 (.8, .8, .8, 1), # rollover
486 imgs
= [self
.__load
_img
_btn
('exitRight', col
) for col
in colors
]
488 image
=imgs
, scale
=btn_scale
,
489 pos
=(l_r
[0] - btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
490 parent
=frm
, command
=self
.__on
_close
_instructions
, extraArgs
=[frm
],
491 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
492 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
493 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
494 btn
.set_transparency(True)
495 self
._pos
_mgr
.register('close_instructions', LibP3d
.wdg_pos(btn
))
498 self
.__persistent
.save_scene(self
.__class
__.__name
__, self
.version
)
499 loader
.load_sfx('assets/audio/sfx/success.ogg').play()
502 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
503 frameSize
=(-.6, .6, -.3, .3))
504 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
506 font
.set_pixels_per_unit(60)
507 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
508 font
.set_outline((0, 0, 0, 1), .8, .2)
509 self
._txt
= OnscreenText(
512 font
=font
, scale
=0.2,
514 u_l
= self
._txt
.textNode
.get_upper_left_3d()
515 l_r
= self
._txt
.textNode
.get_lower_right_3d()
516 #w, h = l_r[0] - u_l[0], u_l[2] - l_r[2]
520 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
521 z
+= (btn_scale
+ 2 * mar
) / 2
522 self
._txt
['pos'] = 0, z
523 u_l
= self
._txt
.textNode
.get_upper_left_3d()
524 l_r
= self
._txt
.textNode
.get_lower_right_3d()
525 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
526 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
527 frm
['frameSize'] = fsz
529 (.6, .6, .6, 1), # ready
530 (1, 1, 1, 1), # press
531 (.8, .8, .8, 1), # rollover
533 imgs
= [self
.__load
_img
_btn
('home', col
) for col
in colors
]
535 image
=imgs
, scale
=btn_scale
,
536 pos
=(-2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
537 parent
=frm
, command
=self
._on
_end
_home
, extraArgs
=[frm
],
538 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
539 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
540 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
541 btn
.set_transparency(True)
542 self
._pos
_mgr
.register('home_win', LibP3d
.wdg_pos(btn
))
543 imgs
= [self
.__load
_img
_btn
('rewind', col
) for col
in colors
]
545 image
=imgs
, scale
=btn_scale
,
546 pos
=(0, 1, l_r
[2] - mar
- btn_scale
),
547 parent
=frm
, command
=self
._on
_restart
, extraArgs
=[frm
],
548 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
549 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
550 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
551 self
._pos
_mgr
.register('replay', LibP3d
.wdg_pos(btn
))
552 btn
.set_transparency(True)
553 enabled
= self
._scenes
.index(self
.__class
__) < len(self
._scenes
) - 1
555 next_scene
= self
._scenes
[self
._scenes
.index(self
.__class
__) + 1]
558 imgs
= [self
.__load
_img
_btn
('right', col
) for col
in colors
]
560 image
=imgs
, scale
=btn_scale
,
561 pos
=(2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
562 parent
=frm
, command
=self
._on
_next
_scene
,
563 extraArgs
=[frm
, next_scene
], relief
=FLAT
,
564 frameColor
=(.6, .6, .6, .08),
565 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
566 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
567 btn
['state'] = NORMAL
if enabled
else DISABLED
568 self
._pos
_mgr
.register('next', LibP3d
.wdg_pos(btn
))
569 btn
.set_transparency(True)
572 loader
.load_sfx('assets/audio/sfx/success.ogg').play()
575 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
576 frameSize
=(-.6, .6, -.3, .3))
577 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
579 font
.set_pixels_per_unit(60)
580 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
581 font
.set_outline((0, 0, 0, 1), .8, .2)
582 self
._txt
= OnscreenText(
583 _('You have failed!'),
585 font
=font
, scale
=0.2,
587 u_l
= self
._txt
.textNode
.get_upper_left_3d()
588 l_r
= self
._txt
.textNode
.get_lower_right_3d()
589 #w, h = l_r[0] - u_l[0], u_l[2] - l_r[2]
593 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
594 z
+= (btn_scale
+ 2 * mar
) / 2
595 self
._txt
['pos'] = 0, z
596 u_l
= self
._txt
.textNode
.get_upper_left_3d()
597 l_r
= self
._txt
.textNode
.get_lower_right_3d()
598 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
599 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
600 frm
['frameSize'] = fsz
602 (.6, .6, .6, 1), # ready
603 (1, 1, 1, 1), # press
604 (.8, .8, .8, 1), # rollover
606 imgs
= [self
.__load
_img
_btn
('home', col
) for col
in colors
]
608 image
=imgs
, scale
=btn_scale
,
609 pos
=(-2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
610 parent
=frm
, command
=self
._on
_end
_home
, extraArgs
=[frm
],
611 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
612 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
613 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
614 self
._pos
_mgr
.register('home_win', LibP3d
.wdg_pos(btn
))
615 btn
.set_transparency(True)
616 imgs
= [self
.__load
_img
_btn
('rewind', col
) for col
in colors
]
618 image
=imgs
, scale
=btn_scale
,
619 pos
=(0, 1, l_r
[2] - mar
- btn_scale
),
620 parent
=frm
, command
=self
._on
_restart
, extraArgs
=[frm
],
621 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
622 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
623 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
624 self
._pos
_mgr
.register('replay', LibP3d
.wdg_pos(btn
))
625 btn
.set_transparency(True)
627 def _on_restart(self
, frm
):
628 self
.__on
_close
_instructions
(frm
)
631 def _on_end_home(self
, frm
):
632 self
.__on
_close
_instructions
(frm
)
635 def _on_next_scene(self
, frm
, scene
):
636 self
.__on
_close
_instructions
(frm
)
637 self
._reload
_cb
(scene
)
639 def __store_state(self
):
641 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
642 #self.__next_btn, self.__prev_btn, self.__rewind_btn
644 self
.__btn
_state
= [btn
['state'] for btn
in btns
]
646 btn
['state'] = DISABLED
647 [itm
.store_state() for itm
in self
.items
]
649 def __restore_state(self
):
651 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
652 #self.__next_btn, self.__prev_btn, self.__rewind_btn
654 for btn
, state
in zip(btns
, self
.__btn
_state
):
656 [itm
.restore_state() for itm
in self
.items
]
659 def __on_close_instructions(self
, frm
):
661 self
.__restore
_state
()
663 def _set_test_items(self
):
664 def frame_after(task
):
665 self
._define
_test
_items
()
666 for itm
in self
._test
_items
:
667 self
._pos
_mgr
.register(itm
.name
, P3dGfxMgr
.pos2d_p2d(itm
))
668 taskMgr
.doMethodLater(.01, frame_after
, 'frame after')
670 def _set_test_item(self
, name
, pos
):
671 self
._test
_items
+= [NodePath(name
)]
672 self
._test
_items
[-1].set_pos(pos
[0], 0, pos
[1])