Commit | Line | Data |
---|---|---|
8ee66edd FC |
1 | from logging import info |
2 | from lib.gameobject import Colleague | |
3 | from lib.lib.bullet.bullet import ( | |
4 | BulletPhysWorld, BulletTriangleMesh, BulletTriangleMeshShape, | |
5 | BulletRigidBodyNode, BulletGhostNode) | |
6 | ||
7 | ||
8 | PhysWorld = BulletPhysWorld | |
9 | TriangleMesh = BulletTriangleMesh | |
10 | TriangleMeshShape = BulletTriangleMeshShape | |
11 | RigidBodyNode = BulletRigidBodyNode | |
12 | GhostNode = BulletGhostNode | |
13 | ||
14 | ||
15 | class CollInfo: | |
16 | ||
17 | def __init__(self, node, time): | |
18 | self.node = node | |
19 | self.time = time | |
20 | ||
21 | ||
22 | class PhysFacade: | |
23 | ||
24 | def attach_rigid_body(self, rbnode): | |
25 | return self.root.attach_rigid_body(rbnode) | |
26 | ||
27 | def remove_rigid_body(self, rbnode): | |
28 | return self.root.remove_rigid_body(rbnode) | |
29 | ||
30 | def attach_ghost(self, gnode): return self.root.attach_ghost(gnode) | |
31 | def remove_ghost(self, gnode): return self.root.remove_ghost(gnode) | |
32 | def attach_vehicle(self, vehicle): return self.root.attach_vehicle(vehicle) | |
33 | def remove_vehicle(self, vehicle): return self.root.remove_vehicle(vehicle) | |
34 | ||
35 | def ray_test_all(self, from_pos, to_pos, mask=None): | |
36 | return self.root.ray_test_all(from_pos, to_pos, mask) | |
37 | ||
38 | def ray_test_closest(self, from_pos, to_pos, mask=None): | |
39 | return self.root.ray_test_closest(from_pos, to_pos, mask) | |
40 | ||
41 | ||
42 | class PhysMgr(Colleague, PhysFacade): | |
43 | ||
44 | def __init__(self, mediator): | |
45 | Colleague.__init__(self, mediator) | |
46 | self.collision_objs = [] # objects to be processed | |
47 | self.__obj2coll = {} # {obj: [(node, coll_time), ...], ...} | |
48 | self.root = None | |
49 | self.__debug_np = None | |
50 | PhysFacade.__init__(self) | |
51 | ||
52 | def reset(self): | |
53 | self.collision_objs = [] | |
54 | self.__obj2coll = {} | |
55 | self.root = PhysWorld() | |
56 | self.root.set_gravity((0, 0, -8.5)) | |
57 | self.root.init_debug() | |
58 | ||
59 | def start(self): | |
60 | self.eng.attach_obs(self.on_frame, 2) | |
61 | ||
62 | def on_frame(self): | |
63 | self.root.do_phys(self.eng.lib.last_frame_dt, 10, 1/180.0) | |
64 | self.__do_collisions() | |
65 | ||
66 | def ray_test_closest(self, top, bottom): | |
67 | #TODO: differs from PhysFacade's signature | |
68 | return self.root.ray_test_closest(top, bottom) | |
69 | ||
70 | def add_collision_obj(self, node): self.collision_objs += [node] | |
71 | ||
72 | def remove_collision_obj(self, node): | |
73 | try: self.collision_objs.remove(node) | |
74 | except ValueError: | |
75 | info("can't remove collision object %s" % node) | |
76 | # it may happen with weapons during pause | |
77 | ||
78 | def stop(self): | |
79 | self.root.stop() | |
80 | self.root = None | |
81 | self.eng.detach_obs(self.on_frame) | |
82 | ||
83 | def __do_collisions(self): | |
84 | to_clear = self.collision_objs[:] | |
85 | # identical collisions are ignored for .25 seconds | |
86 | for obj in self.collision_objs: | |
87 | if obj not in self.__obj2coll: self.__obj2coll[obj] = [] | |
88 | # for contact in self.root.get_contacts(obj): | |
89 | # this doesn't work in 1.9, the following works | |
90 | # odd, this doesn't work too | |
91 | # for contact in self.root.wld.contact_test(obj).get_contacts(): | |
92 | result = self.root._wld.contact_test(obj) | |
93 | #TODO: access a protected member | |
94 | for contact in result.get_contacts(): | |
95 | self.__process_contact(obj, contact.get_node0(), to_clear) | |
96 | self.__process_contact(obj, contact.get_node1(), to_clear) | |
97 | for obj in to_clear: | |
98 | if obj in self.__obj2coll: # it may be that it isn't here e.g. | |
99 | # when you fire a rocket while you're very close to the prev | |
100 | # car and the rocket is removed suddenly | |
101 | for coll in self.__obj2coll[obj]: | |
102 | if self.eng.curr_time - coll.time > .25: | |
103 | self.__obj2coll[obj].remove(coll) | |
104 | ||
105 | def __process_contact(self, obj, node, to_clear): | |
106 | if node == obj: return | |
107 | if obj in to_clear: to_clear.remove(obj) | |
108 | if node in [coll.node for coll in self.__obj2coll[obj]]: return | |
109 | self.__obj2coll[obj] += [CollInfo(node, self.eng.curr_time)] | |
110 | self.eng.event.notify('on_collision', obj, node) | |
111 | ||
112 | def toggle_dbg(self): | |
113 | if self.root: self.root.toggle_dbg() |