Add import to pyworlds to avoid errors.
[pyworlds.git] / src / pyworlds / basics / body.py
blob48623d1de6f2e06e8362694470c7b6fe5c254a9e
1 import soya
2 import soya.label3d
3 import pyworlds.worlds
4 from pyworlds.utils import *
7 SIM_TYPE= {
8 # none - No simulation at all.
9 # (The body gets paused)
10 'none': 0,
12 # Simulation done on each frame render
13 # (Good for fast-action games, live is good for games with low cpu use)
14 'live': 1,
16 # Simulation done in each round, and the render is interpolated
17 # (Good for simulation games than need to execute thins more often than once per frame)
18 # (Interpolation has a penalty: the object is rendered with a lag of one round)
19 'round': 2,
20 'interpolated': 2,
22 # Simulation done in both, on rounds and on each frame.
23 # (Increases CPU cost to create a simulation that doesn't need to interpolate)
24 'both': 3,
29 class Body(soya.Body):
30 def __init__(self, parent = None, model = None):
31 soya.Body.__init__(self,parent,model)
32 self.set_timefactor(1)
33 self.elapsed_render_time = 0
34 self.elapsed_round_time = 0
35 self.elapsed_real_time = 0
36 self.set_timesimulation(SIM_TYPE['live'])
37 self.time_factor = 1
38 self.min_elapse_time = 1 / 80.0
39 self.max_elapse_time = 1 / 20.0
40 self.state1 = soya.CoordSystState(self)
41 self.state2 = soya.CoordSystState(self)
42 self.state1_time = 0
43 self.state2_time = 0
44 self.round_duration = 0.04
45 self.list_elapsecalls=[self.elapsed_time]
47 def set_timesimulation(self,sim_type):
48 self.sim_type=sim_type
50 def set_timefactor(self,factor):
51 self.time_factor = factor
53 def elapse_to_time(self,new_time):
54 seconds = new_time - self.elapsed_real_time
55 total_elapsed=0
56 while seconds > self.min_elapse_time:
57 if seconds > self.max_elapse_time:
58 seconds = self.max_elapse_time
60 for elapsedcall in self.list_elapsecalls:
61 elapsedcall(seconds)
62 # if elapsed_seconds : seconds = elapsed_seconds
63 assert seconds > self.min_elapse_time / 2.0
65 self.elapsed_real_time += seconds
66 total_elapsed += seconds
67 seconds = new_time - self.elapsed_real_time
68 return total_elapsed
70 def addloopcall(self, funccall):
71 try:
72 print "Testing funccall..."
73 s=funccall(0)
74 print "return value: %s , expected 0" % s
75 assert s == 0
76 print "Ok!"
77 self.list_elapsecalls.append(funccall)
78 except:
79 raise
81 def elapsed_time(self,seconds):
82 return seconds
84 def get_absoluteangleXZ(self,vector=None):
85 parent = self.get_root()
86 if vector == None:
87 vector = soya.Vector(self,0,0,-1)
89 q=vector % parent
91 return xy_toangle(q.x,q.z)
93 def begin_round(self):
94 soya.Body.begin_round(self)
98 self.round_duration = self.parent.round_duration * self.time_factor
100 seconds = 1 * self.round_duration
101 self.elapsed_round_time += seconds
102 elapsed = 0
103 if (self.sim_type == SIM_TYPE['round'] or
104 self.sim_type == SIM_TYPE['both']):
105 elapsed = self.elapse_to_time(self.elapsed_round_time)
107 if elapsed > 0:
108 self.state1 = soya.CoordSystState(self.state2)
109 self.state2 = soya.CoordSystState(self)
110 self.state1_time = self.state2_time
111 self.state2_time = self.elapsed_round_time
114 def advance_time(self, proportion):
115 soya.Body.advance_time(self, proportion)
116 seconds = proportion * self.round_duration
117 self.elapsed_render_time += seconds
119 if (self.sim_type == SIM_TYPE['live'] or
120 self.sim_type == SIM_TYPE['both']):
121 self.elapse_to_time(self.elapsed_render_time)
122 else:
123 time1 = self.state2_time - self.state1_time
124 time2 = self.elapsed_render_time - self.state1_time
125 if time1>0:
126 factor = time2 / time1
127 self.interpolate(self.state1, self.state2, factor)
129 def end_round(self):
130 if (self.sim_type == SIM_TYPE['live'] or
131 self.sim_type == SIM_TYPE['both']):
132 pass
133 else:
134 self.interpolate(self.state1, self.state2, 1)
138 class PhysicsBody(Body):
139 def __init__(self, parent = 'scene', mesh = None, mesh_file = None, animatedmesh_file = None):
140 if parent == 'scene':
142 parent = pyworlds.worlds.scene
144 if mesh_file:
145 mesh = soya.Model.get(mesh_file)
147 if animatedmesh_file:
148 mesh = soya.AnimatedModel.get(animatedmesh_file)
150 self.mesh = mesh
152 Body.__init__(self,parent,mesh)
153 self.initialize_vars()
155 def initialize_vars(self):
156 self.speed = soya.Vector(self,0,0,0)
157 self.rotation = [0,0,0]
159 def elapsed_time(self,seconds):
160 self.add_mul_vector(seconds, self.speed)
161 #self.rotate_x(seconds * self.rotation[0])
162 #self.rotate_y(seconds * self.rotation[1])
163 #self.rotate_z(seconds * self.rotation[2])
165 self.turn_x(seconds * self.rotation[0])
166 self.turn_y(seconds * self.rotation[1])
167 self.turn_z(seconds * self.rotation[2])
171 class CharacterBody(PhysicsBody):
172 def initialize_vars(self):
173 PhysicsBody.initialize_vars(self)
174 self.states = {
175 "stop" : ["garde","attente"],
176 "walk" : ["marche"],
178 self.state = None
179 self.statecycle = None
180 self.character_setstate("stop")
181 self.desiredangle = 0
182 self.look_at_speed = 500
183 self.angle = 0
185 def elapsed_time(self, seconds):
186 PhysicsBody.elapsed_time(self, seconds)
188 self.angle = self.get_absoluteangleXZ()
189 if self.desiredangle >= 360: self.desiredangle-=360
190 if self.desiredangle < 0: self.desiredangle+=360
192 anglediff = self.desiredangle - self.angle
193 if anglediff > 180: anglediff-=360
194 if anglediff < -180: anglediff+=360
195 factor = self.look_at_speed * seconds
196 # -> we can't handle computing limit in this way:
197 #if factor > 1/elapsed : factor = 1/elapsed
198 if factor > 1/seconds:
199 factor = 1/seconds
201 anglemov = anglediff * factor
203 if abs(self.rotation[1])>abs(anglemov):
204 self.rotation[1]=(self.rotation[1]-anglemov)/2.0
205 else:
206 self.rotation[1]=(self.rotation[1]*5-anglemov)/6.0
207 if abs(anglediff)<1:
208 self.rotation[1]=-anglediff
210 return seconds
212 def character_setstate(self,newstate):
213 if newstate==self.state: return False
214 if not hasattr(self.mesh,"animations"): return False
215 if len(self.states[newstate])<1: raise
216 newstatecycle=None
217 try:
218 for statecycle in self.states[newstate]:
219 if statecycle in self.mesh.animations:
220 newstatecycle=statecycle
221 break;
222 except:
223 raise
224 if not newstatecycle:
225 print "Not found any animation for %s: " % newstate, self.states[newstate]
226 print "Available animations:", self.mesh.animations.keys()
227 raise
229 if self.statecycle:
230 self.animate_clear_cycle(self.statecycle)
231 self.statecycle = None
232 self.animate_blend_cycle(newstatecycle)
233 self.statecycle = newstatecycle
234 self.state=newstate
235 return True
241 class Label3DFlat(soya.label3d.Label3D):
242 def __init__(self, size = 0.01, compensation = 0.02, follows = None, offset = (0.0,1.0,1.0), *args, **kwargs):
243 if 'parent' not in kwargs:
244 kwargs['parent']=pyworlds.worlds.scene
245 soya.label3d.Label3D.__init__(self, *args, **kwargs)
246 self.flat_follows = follows
247 self.flat_offset = offset
248 self.flat_size = size
249 self.flat_compensation = compensation
250 self.size = size
251 self.lit = 0
253 def advance_time(self,proportion):
254 if self.flat_follows:
255 self.move(self.flat_follows)
256 self.size = self.flat_size + self.flat_compensation * self.flat_size * self.distance_to(pyworlds.worlds.camera)
258 matrix = list(self.matrix)
259 for x in range(3):
260 for y in range(3):
261 matrix[x+y*4] = pyworlds.worlds.camera.matrix[x+y*4]
262 self.matrix = tuple(matrix)
263 self.add_vector(soya.Vector(self,self.flat_offset[0],self.flat_offset[1],self.flat_offset[2]))