ya2 · news · projects · code · about

ghosts for instances
[pmachines.git] / pmachines / items / box.py
CommitLineData
7850ccc4 1from panda3d.core import CullFaceAttrib, Point3, NodePath, Point2, Texture
06af3aa9 2from panda3d.bullet import BulletBoxShape, BulletRigidBodyNode, BulletGhostNode
7850ccc4 3from direct.gui.OnscreenText import OnscreenText
13263131 4from lib.lib.p3d.gfx import P3dGfxMgr
1be87278
FC
5
6class 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
06af3aa9
FC
13 self._shape = BulletBoxShape((.5, .5, .5))
14 self.node = BulletGhostNode('box')
15 self.node.add_shape(self._shape)
c8d8653f 16 self._np = render.attach_new_node(self.node)
06af3aa9
FC
17 world.attach_ghost(self.node)
18 self._model = loader.load_model('assets/gltf/box/box.gltf')
19 self._model.flatten_light()
20 self._model.reparent_to(self._np)
c8d8653f
FC
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):
13263131 29 p_from, p_to = P3dGfxMgr.world_from_to((-1, 1))
7850ccc4
FC
30 for hit in self._world.ray_test_all(p_from, p_to).get_hits():
31 if hit.get_node() == self._plane_node:
32 pos = hit.get_hit_pos()
13263131 33 corner = P3dGfxMgr.screen_coord(pos)
7850ccc4 34 bounds = self._np.get_tight_bounds()
651713a9 35 bounds = bounds[0] - self._np.get_pos(), bounds[1] - self._np.get_pos()
13263131
FC
36 self._np.set_pos(pos)
37 dist = -1, -1
38 def __update(set, get, delta):
39 set(get() + delta)
40 top_left = self._np.get_pos() + (bounds[0][0], bounds[0][1], bounds[1][2])
41 tl2d = P3dGfxMgr.screen_coord(top_left)
42 tmpnode = NodePath('tmp')
43 tmpnode.set_pos(tl2d[0], 0, tl2d[1])
44 cornernode = NodePath('corner')
45 cornernode.set_pos(corner[0], 0, corner[1])
46 dist = tmpnode.get_pos(cornernode)
47 tmpnode.remove_node()
48 cornernode.remove_node()
49 return dist
50 while dist[0] < .01:
51 dist = __update(self._np.set_x, self._np.get_x, .01)
52 while dist[2] > -.01:
53 dist = __update(self._np.set_z, self._np.get_z, -.01)
651713a9
FC
54 if not hasattr(self, '_txt'):
55 font = base.loader.load_font('assets/fonts/Hanken-Book.ttf')
56 font.clear()
57 font.set_pixels_per_unit(60)
58 font.set_minfilter(Texture.FTLinearMipmapLinear)
59 font.set_outline((0, 0, 0, 1), .8, .2)
60 self._txt = OnscreenText(
61 str(self._count), font=font, scale=0.06, fg=(.9, .9, .9, 1))
13263131
FC
62 pos = self._np.get_pos() + (bounds[1][0], bounds[0][1], bounds[0][2])
63 p2d = P3dGfxMgr.screen_coord(pos)
64 self._txt['pos'] = p2d
65
66 def get_corner(self):
67 bounds = self._np.get_tight_bounds()
68 return bounds[1][0], bounds[1][1], bounds[0][2]
37ba71d8 69
c8d8653f 70 def _set_outline_model(self):
37ba71d8
FC
71 self._outline_model = loader.load_model('assets/gltf/box/box.gltf')
72 clockw = CullFaceAttrib.MCullClockwise
73 self._outline_model.set_attrib(CullFaceAttrib.make(clockw))
c8d8653f 74 self._outline_model.reparent_to(self._np)
37ba71d8
FC
75 self._outline_model.set_scale(-1.08, -1.08, -1.08)
76 self._outline_model.set_light_off()
77 self._outline_model.set_color(.4, .4, .4, 1)
78 self._outline_model.set_color_scale(.4, .4, .4, 1)
79 self._outline_model.hide()
1be87278 80
49c79300
FC
81 def on_frame(self, task):
82 self._np.set_y(0)
83 return task.cont
84
c8d8653f 85 def play(self):
06af3aa9
FC
86 if not self._instantiated:
87 return
c8d8653f
FC
88 self._world.remove_rigid_body(self.node)
89 self.node.set_mass(1)
90 self._world.attach_rigid_body(self.node)
91
49c79300 92 def on_click_l(self, pos):
c8d8653f 93 self._start_drag_pos = pos, self._np.get_pos()
54a1397e 94 loader.load_sfx('assets/audio/sfx/grab.ogg').play()
7850ccc4 95 if not self._instantiated:
06af3aa9
FC
96 self._world.remove_ghost(self.node)
97 pos = self._np.get_pos()
98 self._np.remove_node()
99 self.node = BulletRigidBodyNode('box')
100 self.node.add_shape(self._shape)
101 self._np = render.attach_new_node(self.node)
102 self._world.attach_rigid_body(self.node)
103 self._model.reparent_to(self._np)
104 self._np.set_pos(pos)
105 self._set_outline_model()
7850ccc4
FC
106 self._instantiated = True
107 self._txt.destroy()
108 self._count -= 1
109 if self._count:
110 box = Box(self._world, self._plane_node, self._count, self._cb_inst)
111 self._cb_inst(box)
c8d8653f 112
49c79300 113 def on_click_r(self, pos):
9ba5488b 114 self._prev_rot_info = pos, self._np.get_pos(), self._np.get_r()
54a1397e 115 loader.load_sfx('assets/audio/sfx/grab.ogg').play()
49c79300 116
c8d8653f 117 def on_release(self):
9ba5488b 118 if self._start_drag_pos or self._prev_rot_info:
54a1397e 119 loader.load_sfx('assets/audio/sfx/release.ogg').play()
9ba5488b 120 self._start_drag_pos = self._prev_rot_info = None
37ba71d8
FC
121
122 def on_mouse_on(self):
123 self._outline_model.show()
124
125 def on_mouse_off(self):
9ba5488b 126 if self._start_drag_pos or self._prev_rot_info: return
37ba71d8 127 self._outline_model.hide()
c8d8653f
FC
128
129 def on_mouse_move(self, pos):
49c79300
FC
130 if self._start_drag_pos:
131 d_pos = pos - self._start_drag_pos[0]
132 self._np.set_pos(self._start_drag_pos[1] + d_pos)
9ba5488b
FC
133 if self._prev_rot_info:
134 start_vec = self._prev_rot_info[0] - self._prev_rot_info[1]
135 curr_vec = pos - self._prev_rot_info[1]
49c79300 136 d_angle = curr_vec.signed_angle_deg(start_vec, (0, -1, 0))
9ba5488b
FC
137 self._np.set_r(self._prev_rot_info[2] + d_angle)
138 self._prev_rot_info = pos, self._np.get_pos(), self._np.get_r()
651713a9
FC
139
140 def on_aspect_ratio_changed(self):
141 if not self._instantiated:
142 self._repos()