Commit | Line | Data |
---|---|---|
7850ccc4 | 1 | from panda3d.core import CullFaceAttrib, Point3, NodePath, Point2, Texture |
1be87278 | 2 | from panda3d.bullet import BulletBoxShape, BulletRigidBodyNode |
7850ccc4 FC |
3 | from direct.gui.OnscreenText import OnscreenText |
4 | ||
1be87278 FC |
5 | |
6 | class Box: | |
7 | ||
7850ccc4 | 8 | def __init__(self, world, plane_node, count, cb_inst): |
c8d8653f | 9 | self._world = world |
7850ccc4 FC |
10 | self._plane_node = plane_node |
11 | self._count = count | |
12 | self._cb_inst = cb_inst | |
1be87278 FC |
13 | shape = BulletBoxShape((.5, .5, .5)) |
14 | self.node = BulletRigidBodyNode('box') | |
1be87278 | 15 | self.node.add_shape(shape) |
c8d8653f | 16 | self._np = render.attach_new_node(self.node) |
1be87278 FC |
17 | world.attach_rigid_body(self.node) |
18 | model = loader.load_model('assets/gltf/box/box.gltf') | |
19 | model.flatten_light() | |
c8d8653f FC |
20 | model.reparent_to(self._np) |
21 | self._set_outline_model() | |
22 | self._start_drag_pos = None | |
9ba5488b | 23 | self._prev_rot_info = None |
7850ccc4 | 24 | self._instantiated = False |
49c79300 | 25 | taskMgr.add(self.on_frame, 'on_frame') |
651713a9 | 26 | self._repos() |
7850ccc4 | 27 | |
651713a9 | 28 | def _repos(self): |
7850ccc4 FC |
29 | p_from, p_to = Point3(), Point3() # in camera coordinates |
30 | base.camLens.extrude((-1, 1), p_from, p_to) | |
31 | p_from = render.get_relative_point(base.cam, p_from) # global coords | |
32 | p_to = render.get_relative_point(base.cam, p_to) # global coords | |
33 | for hit in self._world.ray_test_all(p_from, p_to).get_hits(): | |
34 | if hit.get_node() == self._plane_node: | |
35 | pos = hit.get_hit_pos() | |
36 | bounds = self._np.get_tight_bounds() | |
651713a9 FC |
37 | bounds = bounds[0] - self._np.get_pos(), bounds[1] - self._np.get_pos() |
38 | margin = .3, .2 | |
39 | dpos = bounds[1][0] + margin[0], 0, -bounds[1][2] - margin[1] | |
7850ccc4 FC |
40 | self._np.set_pos(pos + dpos) |
41 | new_node = NodePath('temp') | |
42 | new_node.set_pos(pos + dpos + (bounds[1][0], bounds[1][1], -bounds[1][2])) | |
43 | coord3d = new_node.get_pos(base.cam) | |
44 | coord2d = Point2() | |
45 | base.camLens.project(coord3d, coord2d) | |
46 | coord_r2d = Point3(coord2d[0], 0, coord2d[1]) | |
47 | coord_a2d = base.aspect2d.get_relative_point(render2d, coord_r2d) | |
651713a9 FC |
48 | if not hasattr(self, '_txt'): |
49 | font = base.loader.load_font('assets/fonts/Hanken-Book.ttf') | |
50 | font.clear() | |
51 | font.set_pixels_per_unit(60) | |
52 | font.set_minfilter(Texture.FTLinearMipmapLinear) | |
53 | font.set_outline((0, 0, 0, 1), .8, .2) | |
54 | self._txt = OnscreenText( | |
55 | str(self._count), font=font, scale=0.06, fg=(.9, .9, .9, 1)) | |
56 | self._txt['pos'] = coord_a2d[0], coord_a2d[2] | |
7850ccc4 | 57 | new_node.remove_node() |
37ba71d8 | 58 | |
c8d8653f | 59 | def _set_outline_model(self): |
37ba71d8 FC |
60 | self._outline_model = loader.load_model('assets/gltf/box/box.gltf') |
61 | clockw = CullFaceAttrib.MCullClockwise | |
62 | self._outline_model.set_attrib(CullFaceAttrib.make(clockw)) | |
c8d8653f | 63 | self._outline_model.reparent_to(self._np) |
37ba71d8 FC |
64 | self._outline_model.set_scale(-1.08, -1.08, -1.08) |
65 | self._outline_model.set_light_off() | |
66 | self._outline_model.set_color(.4, .4, .4, 1) | |
67 | self._outline_model.set_color_scale(.4, .4, .4, 1) | |
68 | self._outline_model.hide() | |
1be87278 | 69 | |
49c79300 FC |
70 | def on_frame(self, task): |
71 | self._np.set_y(0) | |
72 | return task.cont | |
73 | ||
c8d8653f FC |
74 | def play(self): |
75 | self._world.remove_rigid_body(self.node) | |
76 | self.node.set_mass(1) | |
77 | self._world.attach_rigid_body(self.node) | |
78 | ||
49c79300 | 79 | def on_click_l(self, pos): |
c8d8653f | 80 | self._start_drag_pos = pos, self._np.get_pos() |
54a1397e | 81 | loader.load_sfx('assets/audio/sfx/grab.ogg').play() |
7850ccc4 FC |
82 | if not self._instantiated: |
83 | self._instantiated = True | |
84 | self._txt.destroy() | |
85 | self._count -= 1 | |
86 | if self._count: | |
87 | box = Box(self._world, self._plane_node, self._count, self._cb_inst) | |
88 | self._cb_inst(box) | |
c8d8653f | 89 | |
49c79300 | 90 | def on_click_r(self, pos): |
9ba5488b | 91 | self._prev_rot_info = pos, self._np.get_pos(), self._np.get_r() |
54a1397e | 92 | loader.load_sfx('assets/audio/sfx/grab.ogg').play() |
49c79300 | 93 | |
c8d8653f | 94 | def on_release(self): |
9ba5488b | 95 | if self._start_drag_pos or self._prev_rot_info: |
54a1397e | 96 | loader.load_sfx('assets/audio/sfx/release.ogg').play() |
9ba5488b | 97 | self._start_drag_pos = self._prev_rot_info = None |
37ba71d8 FC |
98 | |
99 | def on_mouse_on(self): | |
100 | self._outline_model.show() | |
101 | ||
102 | def on_mouse_off(self): | |
9ba5488b | 103 | if self._start_drag_pos or self._prev_rot_info: return |
37ba71d8 | 104 | self._outline_model.hide() |
c8d8653f FC |
105 | |
106 | def on_mouse_move(self, pos): | |
49c79300 FC |
107 | if self._start_drag_pos: |
108 | d_pos = pos - self._start_drag_pos[0] | |
109 | self._np.set_pos(self._start_drag_pos[1] + d_pos) | |
9ba5488b FC |
110 | if self._prev_rot_info: |
111 | start_vec = self._prev_rot_info[0] - self._prev_rot_info[1] | |
112 | curr_vec = pos - self._prev_rot_info[1] | |
49c79300 | 113 | d_angle = curr_vec.signed_angle_deg(start_vec, (0, -1, 0)) |
9ba5488b FC |
114 | self._np.set_r(self._prev_rot_info[2] + d_angle) |
115 | self._prev_rot_info = pos, self._np.get_pos(), self._np.get_r() | |
651713a9 FC |
116 | |
117 | def on_aspect_ratio_changed(self): | |
118 | if not self._instantiated: | |
119 | self._repos() |