Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1 | -- |
2 | -- AnimatedVehicle |
3 | -- Class for all AnimatedVehicles |
4 | -- |
5 | -- @author Stefan Geiger |
6 | -- @date 16/10/09 |
7 | -- |
8 | -- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved. |
9 | |
10 | source("dataS/scripts/vehicles/specializations/AnimatedVehicleStartEvent.lua"); |
11 | source("dataS/scripts/vehicles/specializations/AnimatedVehicleStopEvent.lua"); |
12 | AnimatedVehicle = {}; |
13 | |
14 | function AnimatedVehicle.prerequisitesPresent(specializations) |
15 | return true; |
16 | end; |
17 | |
18 | function AnimatedVehicle:preLoad(xmlFile) |
19 | self.loadSpeedRotatingPartFromXML = Utils.overwrittenFunction(self.loadSpeedRotatingPartFromXML, AnimatedVehicle.loadSpeedRotatingPartFromXML); |
20 | self.loadWorkAreaFromXML = Utils.overwrittenFunction(self.loadWorkAreaFromXML, AnimatedVehicle.loadWorkAreaFromXML); |
21 | end |
22 | |
23 | function AnimatedVehicle:load(xmlFile) |
24 | |
25 | self.playAnimation = SpecializationUtil.callSpecializationsFunction("playAnimation"); |
26 | self.stopAnimation = SpecializationUtil.callSpecializationsFunction("stopAnimation"); |
27 | self.getIsAnimationPlaying = AnimatedVehicle.getIsAnimationPlaying; |
28 | self.getRealAnimationTime = AnimatedVehicle.getRealAnimationTime; |
29 | self.setRealAnimationTime = SpecializationUtil.callSpecializationsFunction("setRealAnimationTime"); |
30 | self.getAnimationTime = AnimatedVehicle.getAnimationTime; |
31 | self.getAnimationDuration = AnimatedVehicle.getAnimationDuration; |
32 | self.setAnimationTime = SpecializationUtil.callSpecializationsFunction("setAnimationTime"); |
33 | self.setAnimationStopTime = SpecializationUtil.callSpecializationsFunction("setAnimationStopTime"); |
34 | self.setAnimationSpeed = SpecializationUtil.callSpecializationsFunction("setAnimationSpeed"); |
35 | self.resetAnimationValues = AnimatedVehicle.resetAnimationValues; |
36 | self.resetAnimationPartValues = AnimatedVehicle.resetAnimationPartValues; |
37 | self.getIsSpeedRotatingPartActive = Utils.overwrittenFunction(self.getIsSpeedRotatingPartActive, AnimatedVehicle.getIsSpeedRotatingPartActive); |
38 | self.getIsWorkAreaActive = Utils.overwrittenFunction(self.getIsWorkAreaActive, AnimatedVehicle.getIsWorkAreaActive); |
39 | |
40 | self.animations = {}; |
41 | |
42 | local i=0; |
43 | while true do |
44 | local key = string.format("vehicle.animations.animation(%d)", i); |
45 | if not hasXMLProperty(xmlFile, key) then |
46 | break; |
47 | end; |
48 | |
49 | local name = getXMLString(xmlFile, key.."#name"); |
50 | if name ~= nil then |
51 | local animation = {}; |
52 | animation.name = name; |
53 | animation.parts = {}; |
54 | animation.currentTime = 0; |
55 | animation.currentSpeed = 1; |
56 | animation.looping = Utils.getNoNil(getXMLBool(xmlFile, key .. "#looping"), false); |
57 | |
58 | local partI = 0; |
59 | while true do |
60 | local partKey = key..string.format(".part(%d)", partI); |
61 | if not hasXMLProperty(xmlFile, partKey) then |
62 | break; |
63 | end; |
64 | |
65 | local node = Utils.indexToObject(self.components, getXMLString(xmlFile, partKey.."#node")); |
66 | local startTime = getXMLFloat(xmlFile, partKey.."#startTime"); |
67 | local duration = getXMLFloat(xmlFile, partKey.."#duration"); |
68 | local endTime = getXMLFloat(xmlFile, partKey.."#endTime"); |
69 | local direction = Utils.sign(Utils.getNoNil(getXMLInt(xmlFile, partKey.."#direction"), 0)); |
70 | local startRot = Utils.getRadiansFromString(getXMLString(xmlFile, partKey.."#startRot"), 3); |
71 | local endRot = Utils.getRadiansFromString(getXMLString(xmlFile, partKey.."#endRot"), 3); |
72 | local startTrans = Utils.getVectorNFromString(getXMLString(xmlFile, partKey.."#startTrans"), 3); |
73 | local endTrans = Utils.getVectorNFromString(getXMLString(xmlFile, partKey.."#endTrans"), 3); |
74 | local startScale = Utils.getVectorNFromString(getXMLString(xmlFile, partKey.."#startScale"), 3); |
75 | local endScale = Utils.getVectorNFromString(getXMLString(xmlFile, partKey.."#endScale"), 3); |
76 | local visibility = getXMLBool(xmlFile, partKey.."#visibility"); |
77 | local componentJointIndex = getXMLInt(xmlFile, partKey.."#componentJointIndex"); |
78 | local componentJoint; |
79 | if componentJointIndex ~= nil then |
80 | componentJoint = self.componentJoints[componentJointIndex+1]; |
81 | end |
82 | local startRotLimit = Utils.getRadiansFromString(getXMLString(xmlFile, partKey.."#startRotLimit"), 3); |
83 | local endRotLimit = Utils.getRadiansFromString(getXMLString(xmlFile, partKey.."#endRotLimit"), 3); |
84 | local startTransLimit = Utils.getVectorNFromString(getXMLString(xmlFile, partKey.."#startTransLimit"), 3); |
85 | local endTransLimit = Utils.getVectorNFromString(getXMLString(xmlFile, partKey.."#endTransLimit"), 3); |
86 | |
87 | if startTime ~= nil and (duration ~= nil or endTime ~= nil) and |
88 | ( (node ~= nil and (endRot ~= nil or endTrans ~= nil or endScale ~= nil or visibility ~= nil)) or |
89 | (componentJoint ~= nil and (endRotLimit ~= nil or endTransLimit ~= nil))) |
90 | then |
91 | if endTime ~= nil then |
92 | duration = endTime - startTime; |
93 | end; |
94 | local part = {}; |
95 | part.node = node; |
96 | part.startTime = startTime*1000; |
97 | part.duration = duration*1000; |
98 | part.direction = direction; |
99 | if node ~= nil then |
100 | if endRot ~= nil then |
101 | part.startRot = startRot; |
102 | part.endRot = endRot; |
103 | end; |
104 | if endTrans ~= nil then |
105 | part.startTrans = startTrans; |
106 | part.endTrans = endTrans; |
107 | end; |
108 | if endScale ~= nil then |
109 | part.startScale = startScale; |
110 | part.endScale = endScale; |
111 | end; |
112 | |
113 | part.visibility = visibility; |
114 | end |
115 | if self.isServer then |
116 | if componentJoint ~= nil then |
117 | if endRotLimit ~= nil then |
118 | part.componentJoint = componentJoint; |
119 | part.startRotLimit = startRotLimit; |
120 | part.endRotLimit = endRotLimit; |
121 | end |
122 | if endTransLimit ~= nil then |
123 | part.componentJoint = componentJoint; |
124 | part.startTransLimit = startTransLimit; |
125 | part.endTransLimit = endTransLimit; |
126 | end |
127 | end |
128 | end |
129 | table.insert(animation.parts, part); |
130 | end; |
131 | partI = partI + 1; |
132 | end; |
133 | |
134 | -- sort parts by start/end time |
135 | animation.partsReverse = {}; |
136 | for _, part in ipairs(animation.parts) do |
137 | table.insert(animation.partsReverse, part); |
138 | end; |
139 | table.sort(animation.parts, AnimatedVehicle.animPartSorter); |
140 | table.sort(animation.partsReverse, AnimatedVehicle.animPartSorterReverse); |
141 | |
142 | AnimatedVehicle.initializeParts(self, animation); |
143 | |
144 | animation.currentPartIndex = 1; |
145 | animation.duration = 0; |
146 | for _, part in ipairs(animation.parts) do |
147 | animation.duration = math.max(animation.duration, part.startTime + part.duration); |
148 | end; |
149 | |
150 | self.animations[name] = animation; |
151 | end; |
152 | |
153 | i = i+1; |
154 | end; |
155 | |
156 | self.activeAnimations = {}; |
157 | end; |
158 | |
159 | function AnimatedVehicle.initializeParts(self, animation) |
160 | local numParts = table.getn(animation.parts); |
161 | |
162 | for i=1, numParts do |
163 | local part = animation.parts[i]; |
164 | |
165 | -- find the next rot part |
166 | if part.endRot ~= nil then |
167 | for j=i+1, numParts do |
168 | local part2 = animation.parts[j]; |
169 | if part.node == part2.node and part2.endRot ~= nil then |
170 | if part.startTime + part.duration > part2.startTime+0.001 then |
171 | print("Warning: overlapping rotation parts for node "..getName(part.node).." in " .. animation.name.. " "..self.configFileName); |
172 | end |
173 | part.nextRotPart = part2; |
174 | part2.prevRotPart = part; |
175 | if part2.startRot == nil then |
176 | part2.startRot = {part.endRot[1], part.endRot[2], part.endRot[3]}; |
177 | end |
178 | break; |
179 | end |
180 | end |
181 | end |
182 | |
183 | -- find the next trans part |
184 | if part.endTrans ~= nil then |
185 | for j=i+1, numParts do |
186 | local part2 = animation.parts[j]; |
187 | if part.node == part2.node and part2.endTrans ~= nil then |
188 | if part.startTime + part.duration > part2.startTime+0.001 then |
189 | print("Warning: overlapping translation parts for node "..getName(part.node).." in " .. animation.name.. " "..self.configFileName); |
190 | end |
191 | part.nextTransPart = part2; |
192 | part2.prevTransPart = part; |
193 | if part2.startTrans == nil then |
194 | part2.startTrans = {part.endTrans[1], part.endTrans[2], part.endTrans[3]}; |
195 | end |
196 | break; |
197 | end |
198 | end |
199 | end |
200 | |
201 | -- find the next scale part |
202 | if part.endScale ~= nil then |
203 | for j=i+1, numParts do |
204 | local part2 = animation.parts[j]; |
205 | if part.node == part2.node and part2.endScale ~= nil then |
206 | if part.startTime + part.duration > part2.startTime+0.001 then |
207 | print("Warning: overlapping scale parts for node "..getName(part.node).." in " .. animation.name.. " "..self.configFileName); |
208 | end |
209 | part.nextScalePart = part2; |
210 | part2.prevScalePart = part; |
211 | if part2.startScale == nil then |
212 | part2.startScale = {part.endScale[1], part.endScale[2], part.endScale[3]}; |
213 | end |
214 | break; |
215 | end |
216 | end |
217 | end |
218 | |
219 | if self.isServer then |
220 | -- find the next joint rot limit part |
221 | if part.endRotLimit ~= nil then |
222 | for j=i+1, numParts do |
223 | local part2 = animation.parts[j]; |
224 | if part.componentJoint == part2.componentJoint and part2.endRotLimit ~= nil then |
225 | if part.startTime + part.duration > part2.startTime+0.001 then |
226 | print("Warning: overlapping joint rot limit parts for component joint "..getName(part.componentJoint.jointNode).." in " .. animation.name.. " "..self.configFileName); |
227 | end |
228 | part.nextRotLimitPart = part2; |
229 | part2.prevRotLimitPart = part; |
230 | if part2.startRotLimit == nil then |
231 | part2.startRotLimit = {part.endRotLimit[1], part.endRotLimit[2], part.endRotLimit[3]}; |
232 | end |
233 | break; |
234 | end |
235 | end |
236 | end |
237 | |
238 | -- find the next joint trans limit part |
239 | if part.endTransLimit ~= nil then |
240 | for j=i+1, numParts do |
241 | local part2 = animation.parts[j]; |
242 | if part.componentJoint == part2.componentJoint and part2.endTransLimit ~= nil then |
243 | if part.startTime + part.duration > part2.startTime+0.001 then |
244 | print("Warning: overlapping joint trans limit parts for component joint "..getName(part.componentJoint.jointNode).." in " .. animation.name.. " "..self.configFileName); |
245 | end |
246 | part.nextTransLimitPart = part2; |
247 | part2.prevTransLimitPart = part; |
248 | if part2.startTransLimit == nil then |
249 | part2.startTransLimit = {part.endTransLimit[1], part.endTransLimit[2], part.endTransLimit[3]}; |
250 | end |
251 | break; |
252 | end |
253 | end |
254 | end |
255 | end |
256 | end |
257 | |
258 | -- default start values to the value stored in the i3d (if not set by the end value of the previous part) |
259 | for i=1, numParts do |
260 | local part = animation.parts[i]; |
261 | if part.endRot ~= nil and part.startRot == nil then |
262 | local x,y,z = getRotation(part.node); |
263 | part.startRot = {x,y,z}; |
264 | end |
265 | if part.endTrans ~= nil and part.startTrans == nil then |
266 | local x,y,z = getTranslation(part.node); |
267 | part.startTrans = {x,y,z}; |
268 | end; |
269 | if part.endScale ~= nil and part.startScale == nil then |
270 | local x,y,z = getScale(part.node); |
271 | part.startScale = {x,y,z}; |
272 | end; |
273 | if self.isServer then |
274 | if part.endRotLimit ~= nil and part.startRotLimit == nil then |
275 | local rotLimit = part.componentJoint.rotLimit; |
276 | part.startRotLimit = {rotLimit[1], rotLimit[2], rotLimit[3]}; |
277 | end |
278 | if part.endTransLimit ~= nil and part.startTransLimit == nil then |
279 | local transLimit = part.componentJoint.transLimit; |
280 | part.startTransLimit = {transLimit[1], transLimit[2], transLimit[3]}; |
281 | end |
282 | end |
283 | end |
284 | end |
285 | |
286 | function AnimatedVehicle:delete() |
287 | |
288 | end; |
289 | |
290 | |
291 | function AnimatedVehicle:readStream(streamId, connection) |
292 | -- TODO |
293 | end; |
294 | |
295 | function AnimatedVehicle:writeStream(streamId, connection) |
296 | -- TODO |
297 | end; |
298 | |
299 | function AnimatedVehicle:readUpdateStream(streamId, timestamp, connection) |
300 | --[[if connection.isServer then |
301 | local x=streamReadFloat32(streamId); |
302 | local y=streamReadFloat32(streamId); |
303 | local z=streamReadFloat32(streamId); |
304 | local xrot=streamReadFloat32(streamId); |
305 | local yrot=streamReadFloat32(streamId); |
306 | local zrot=streamReadFloat32(streamId); |
307 | AnimatedVehicle.setAnimPos(self, animTime); |
308 | end;]] |
309 | end; |
310 | |
311 | function AnimatedVehicle:writeUpdateStream(streamId, connection, dirtyMask) |
312 | --[[if not connection.isServer then |
313 | streamWriteFloat32(streamId, self.foldAnimTime); |
314 | end;]] |
315 | end; |
316 | |
317 | function AnimatedVehicle:mouseEvent(posX, posY, isDown, isUp, button) |
318 | end; |
319 | |
320 | function AnimatedVehicle:keyEvent(unicode, sym, modifier, isDown) |
321 | end; |
322 | |
323 | function AnimatedVehicle:update(dt) |
324 | AnimatedVehicle.updateAnimations(self, dt) |
325 | end; |
326 | |
327 | function AnimatedVehicle:updateTick(dt) |
328 | -- TODO |
329 | end; |
330 | |
331 | function AnimatedVehicle:draw() |
332 | end; |
333 | |
334 | function AnimatedVehicle:onDetach() |
335 | end; |
336 | |
337 | function AnimatedVehicle:onLeave() |
338 | end; |
339 | |
340 | function AnimatedVehicle:onDeactivate() |
341 | end; |
342 | |
343 | function AnimatedVehicle:onDeactivateSounds() |
344 | end; |
345 | |
346 | function AnimatedVehicle:playAnimation(name, speed, animTime, noEventSend) |
347 | local animation = self.animations[name]; |
348 | if animation ~= nil then |
349 | if speed == nil then |
350 | speed = animation.currentSpeed; |
351 | end; |
352 | if animTime == nil then |
353 | if self:getIsAnimationPlaying(name) then |
354 | animTime = self:getAnimationTime(name); |
355 | elseif speed > 0 then |
356 | animTime = 0; |
357 | else |
358 | animTime = 1; |
359 | end; |
360 | end; |
361 | if noEventSend == nil or noEventSend == false then |
362 | if g_server ~= nil then |
363 | g_server:broadcastEvent(AnimatedVehicleStartEvent:new(self, name, speed, animTime), nil, nil, self); |
364 | else |
365 | g_client:getServerConnection():sendEvent(AnimatedVehicleStartEvent:new(self, name, speed, animTime)); |
366 | end; |
367 | end; |
368 | |
369 | self.activeAnimations[name] = animation; |
370 | animation.currentSpeed = speed; |
371 | animation.currentTime = animTime*animation.duration; |
372 | self:resetAnimationValues(animation); |
373 | end; |
374 | end; |
375 | |
376 | function AnimatedVehicle:stopAnimation(name, noEventSend) |
377 | if noEventSend == nil or noEventSend == false then |
378 | if g_server ~= nil then |
379 | g_server:broadcastEvent(AnimatedVehicleStopEvent:new(self, name), nil, nil, self); |
380 | else |
381 | g_client:getServerConnection():sendEvent(AnimatedVehicleStopEvent:new(self, name)); |
382 | end; |
383 | end |
384 | local animation = self.animations[name]; |
385 | if animation ~= nil then |
386 | animation.stopTime = nil; |
387 | end; |
388 | self.activeAnimations[name] = nil; |
389 | end; |
390 | |
391 | function AnimatedVehicle:getIsAnimationPlaying(name) |
392 | return self.activeAnimations[name] ~= nil; |
393 | end; |
394 | |
395 | function AnimatedVehicle:getRealAnimationTime(name) |
396 | local animation = self.animations[name]; |
397 | if animation ~= nil then |
398 | return animation.currentTime; |
399 | end; |
400 | return 0; |
401 | end; |
402 | |
403 | function AnimatedVehicle:setRealAnimationTime(name, animTime, update) |
404 | local animation = self.animations[name]; |
405 | if animation ~= nil then |
406 | if update == nil or update then |
407 | local currentSpeed = animation.currentSpeed; |
408 | animation.currentSpeed = 1; |
409 | if animation.currentTime > animTime then |
410 | animation.currentSpeed = -1; |
411 | end; |
412 | |
413 | self:resetAnimationValues(animation); |
414 | |
415 | local dtToUse, _ = AnimatedVehicle.updateAnimationCurrentTime(self, animation, 99999999, animTime); |
416 | AnimatedVehicle.updateAnimation(self, animation, dtToUse, false); |
417 | animation.currentSpeed = currentSpeed; |
418 | else |
419 | animation.currentTime = animTime; |
420 | end |
421 | end; |
422 | end; |
423 | |
424 | function AnimatedVehicle:getAnimationTime(name) |
425 | local animation = self.animations[name]; |
426 | if animation ~= nil then |
427 | return animation.currentTime/animation.duration; |
428 | end; |
429 | return 0; |
430 | end; |
431 | |
432 | function AnimatedVehicle:setAnimationTime(name, animTime, update) |
433 | local animation = self.animations[name]; |
434 | if animation ~= nil then |
435 | self:setRealAnimationTime(name, animTime*animation.duration, update); |
436 | end; |
437 | end; |
438 | |
439 | function AnimatedVehicle:getAnimationDuration(name) |
440 | local animation = self.animations[name]; |
441 | if animation ~= nil then |
442 | return animation.duration; |
443 | end; |
444 | return 1; |
445 | end; |
446 | |
447 | function AnimatedVehicle:setAnimationSpeed(name, speed) |
448 | local animation = self.animations[name]; |
449 | if animation ~= nil then |
450 | local speedReversed = false; |
451 | if (animation.currentSpeed > 0) ~= (speed > 0) then |
452 | speedReversed = true; |
453 | end; |
454 | animation.currentSpeed = speed; |
455 | if self:getIsAnimationPlaying(name) and speedReversed then |
456 | self:resetAnimationValues(animation); |
457 | end; |
458 | end; |
459 | end; |
460 | |
461 | function AnimatedVehicle:setAnimationStopTime(name, stopTime) |
462 | local animation = self.animations[name]; |
463 | if animation ~= nil then |
464 | animation.stopTime = stopTime*animation.duration; |
465 | end; |
466 | end; |
467 | |
468 | function AnimatedVehicle:resetAnimationValues(animation) |
469 | AnimatedVehicle.findCurrentPartIndex(animation); |
470 | for _, part in ipairs(animation.parts) do |
471 | self:resetAnimationPartValues(part); |
472 | end; |
473 | end |
474 | |
475 | function AnimatedVehicle:resetAnimationPartValues(part) |
476 | part.curRot = nil; |
477 | part.speedRot = nil; |
478 | part.curTrans = nil; |
479 | part.speedTrans = nil; |
480 | part.curScale = nil; |
481 | part.speedScale = nil; |
482 | part.curVisibility = nil; |
483 | part.curRotLimit = nil; |
484 | part.speedRotLimit = nil; |
485 | part.curTransLimit = nil; |
486 | part.speedTransLimit = nil; |
487 | end; |
488 | |
489 | function AnimatedVehicle:loadSpeedRotatingPartFromXML(superFunc, speedRotatingPart, xmlFile, key) |
490 | if superFunc ~= nil then |
491 | if not superFunc(self, speedRotatingPart, xmlFile, key) then |
492 | return false; |
493 | end |
494 | end |
495 | |
496 | speedRotatingPart.animName = getXMLString(xmlFile, key.."#animName"); |
497 | speedRotatingPart.animOuterRange = Utils.getNoNil(getXMLFloat(xmlFile, key.."#animOuterRange"), false); |
498 | speedRotatingPart.animMinLimit = Utils.getNoNil(getXMLFloat(xmlFile, key.."#animMinLimit"), 0); |
499 | speedRotatingPart.animMaxLimit = Utils.getNoNil(getXMLFloat(xmlFile, key.."#animMaxLimit"), 1); |
500 | return true; |
501 | end |
502 | |
503 | function AnimatedVehicle:getIsSpeedRotatingPartActive(superFunc, speedRotatingPart) |
504 | if speedRotatingPart.animName ~= nil then |
505 | local animTime = self:getAnimationTime(speedRotatingPart.animName); |
506 | if speedRotatingPart.animOuterRange then |
507 | if animTime > speedRotatingPart.animMinLimit or animTime < speedRotatingPart.animMaxLimit then |
508 | return false; |
509 | end |
510 | else |
511 | if animTime > speedRotatingPart.animMaxLimit or animTime < speedRotatingPart.animMinLimit then |
512 | return false; |
513 | end |
514 | end; |
515 | end; |
516 | |
517 | if superFunc ~= nil then |
518 | return superFunc(self, speedRotatingPart); |
519 | end |
520 | return true; |
521 | end; |
522 | |
523 | function AnimatedVehicle:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key) |
524 | workArea.animName = getXMLString(xmlFile, key.."#animName"); |
525 | workArea.animMinLimit = Utils.getNoNil(getXMLFloat(xmlFile, key.."#animMinLimit"), 0); |
526 | workArea.animMaxLimit = Utils.getNoNil(getXMLFloat(xmlFile, key.."#animMaxLimit"), 1); |
527 | |
528 | if superFunc ~= nil then |
529 | return superFunc(self, workArea, xmlFile, key); |
530 | end; |
531 | return true; |
532 | end; |
533 | |
534 | function AnimatedVehicle:getIsWorkAreaActive(superFunc, workArea) |
535 | if workArea.animName ~= nil then |
536 | local animTime = self:getAnimationTime(workArea.animName); |
537 | if animTime > workArea.animMaxLimit or animTime < workArea.animMinLimit then |
538 | return false; |
539 | end |
540 | end; |
541 | |
542 | if superFunc ~= nil then |
543 | return superFunc(self, workArea); |
544 | end |
545 | return true; |
546 | end; |
547 | |
548 | function AnimatedVehicle.animPartSorter(a, b) |
549 | if a.startTime < b.startTime then |
550 | return true; |
551 | elseif a.startTime == b.startTime then |
552 | return a.duration < b.duration; |
553 | end; |
554 | return false; |
555 | end; |
556 | |
557 | function AnimatedVehicle.animPartSorterReverse(a, b) |
558 | local endTimeA = a.startTime+a.duration; |
559 | local endTimeB = b.startTime+b.duration; |
560 | if endTimeA > endTimeB then |
561 | return true; |
562 | elseif endTimeA == endTimeB then |
563 | return a.startTime > b.startTime; |
564 | end; |
565 | return false; |
566 | end; |
567 | |
568 | function AnimatedVehicle.getMovedLimitedValue(currentValue, destValue, speed, dt) |
569 | local limitF = math.min; |
570 | -- we are moving towards -inf, we need to check for the maximum |
571 | if destValue < currentValue then |
572 | limitF = math.max; |
573 | elseif destValue == currentValue then |
574 | return currentValue; |
575 | end; |
576 | local ret = limitF(currentValue + speed * dt, destValue); |
577 | return ret; |
578 | end; |
579 | |
580 | function AnimatedVehicle.setMovedLimitedValues3(currentValues, destValues, speeds, dt) |
581 | |
582 | local hasChanged = false; |
583 | for i=1, 3 do |
584 | local newValue = AnimatedVehicle.getMovedLimitedValue(currentValues[i], destValues[i], speeds[i], dt); |
585 | if currentValues[i] ~= newValue then |
586 | hasChanged = true; |
587 | currentValues[i] = newValue; |
588 | end; |
589 | end; |
590 | return hasChanged; |
591 | end; |
592 | |
593 | function AnimatedVehicle.findCurrentPartIndex(animation) |
594 | if animation.currentSpeed > 0 then |
595 | -- find the first part that is being played at the current time |
596 | animation.currentPartIndex = table.getn(animation.parts)+1; |
597 | for i, part in ipairs(animation.parts) do |
598 | if part.startTime+part.duration >= animation.currentTime then |
599 | animation.currentPartIndex = i; |
600 | break; |
601 | end; |
602 | end; |
603 | else |
604 | -- find the last part that is being played at the current time (the first in partsReverse) |
605 | animation.currentPartIndex = table.getn(animation.partsReverse)+1; |
606 | for i, part in ipairs(animation.partsReverse) do |
607 | if part.startTime <= animation.currentTime then |
608 | animation.currentPartIndex = i; |
609 | break; |
610 | end; |
611 | end; |
612 | end; |
613 | end; |
614 | |
615 | function AnimatedVehicle.getDurationToEndOfPart(part, anim) |
616 | if anim.currentSpeed > 0 then |
617 | return part.startTime+part.duration - anim.currentTime; |
618 | else |
619 | return anim.currentTime - part.startTime; |
620 | end |
621 | end |
622 | |
623 | function AnimatedVehicle.getNextPartIsPlaying(nextPart, prevPart, anim, default) |
624 | if anim.currentSpeed > 0 then |
625 | if nextPart ~= nil then |
626 | return nextPart.startTime > anim.currentTime; |
627 | end |
628 | else |
629 | if prevPart ~= nil then |
630 | return prevPart.startTime + prevPart.duration < anim.currentTime; |
631 | end |
632 | end |
633 | return default; |
634 | end |
635 | |
636 | function AnimatedVehicle.updateAnimations(self, dt) |
637 | for _, anim in pairs(self.activeAnimations) do |
638 | local dtToUse, stopAnim = AnimatedVehicle.updateAnimationCurrentTime(self, anim, dt, anim.stopTime); |
639 | AnimatedVehicle.updateAnimation(self, anim, dtToUse, stopAnim); |
640 | end |
641 | end |
642 | |
643 | function AnimatedVehicle.updateAnimationByName(self, animName, dt) |
644 | local anim = self.animations[animName]; |
645 | if anim ~= nil then |
646 | local dtToUse, stopAnim = AnimatedVehicle.updateAnimationCurrentTime(self, anim, dt, anim.stopTime); |
647 | AnimatedVehicle.updateAnimation(self, anim, dtToUse, stopAnim); |
648 | end |
649 | end |
650 | |
651 | function AnimatedVehicle.updateAnimationCurrentTime(self, anim, dt, stopTime) |
652 | anim.currentTime = anim.currentTime + dt*anim.currentSpeed; |
653 | |
654 | local absSpeed = math.abs(anim.currentSpeed); |
655 | local dtToUse = dt*absSpeed; |
656 | local stopAnim = false; |
657 | if stopTime ~= nil then |
658 | if anim.currentSpeed > 0 then |
659 | if stopTime <= anim.currentTime then |
660 | dtToUse = dtToUse-(anim.currentTime-stopTime); |
661 | anim.currentTime = stopTime; |
662 | stopAnim = true; |
663 | end; |
664 | else |
665 | if stopTime >= anim.currentTime then |
666 | dtToUse = dtToUse-(stopTime-anim.currentTime); |
667 | anim.currentTime = stopTime; |
668 | stopAnim = true; |
669 | end; |
670 | end; |
671 | end; |
672 | return dtToUse, stopAnim; |
673 | end |
674 | |
675 | function AnimatedVehicle.updateAnimation(self, anim, dtToUse, stopAnim) |
676 | local name = anim.name; |
677 | |
678 | local numParts = table.getn(anim.parts) |
679 | local parts = anim.parts; |
680 | if anim.currentSpeed < 0 then |
681 | parts = anim.partsReverse; |
682 | end; |
683 | |
684 | if dtToUse > 0 then |
685 | local hasChanged = false; |
686 | local nothingToChangeYet = false; |
687 | for partI=anim.currentPartIndex, numParts do |
688 | local part = parts[partI]; |
689 | |
690 | if part.direction == 0 or ((part.direction > 0) == (anim.currentSpeed >= 0)) then |
691 | local durationToEnd = AnimatedVehicle.getDurationToEndOfPart(part, anim); |
692 | |
693 | -- is this part not playing yet? |
694 | if durationToEnd > part.duration then |
695 | nothingToChangeYet = true; |
696 | break; |
697 | end |
698 | |
699 | durationToEnd = durationToEnd+dtToUse; |
700 | |
701 | local hasPartChanged = false; |
702 | -- update the part |
703 | if part.startRot ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextRotPart, part.prevRotPart, anim, true)) then |
704 | local destRot = part.endRot; |
705 | if anim.currentSpeed < 0 then |
706 | destRot = part.startRot; |
707 | end; |
708 | if part.curRot == nil then |
709 | local x,y,z = getRotation(part.node); |
710 | part.curRot = {x,y,z}; |
711 | local invDuration = 1.0/math.max(durationToEnd, 0.001); |
712 | part.speedRot = {(destRot[1]-x)*invDuration, (destRot[2]-y)*invDuration, (destRot[3]-z)*invDuration}; |
713 | end; |
714 | if AnimatedVehicle.setMovedLimitedValues3(part.curRot, destRot, part.speedRot, dtToUse) then |
715 | setRotation(part.node, part.curRot[1], part.curRot[2], part.curRot[3]); |
716 | hasPartChanged = true; |
717 | end; |
718 | end; |
719 | if part.startTrans ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextTransPart, part.prevTransPart, anim, true)) then |
720 | local destTrans = part.endTrans; |
721 | if anim.currentSpeed < 0 then |
722 | destTrans = part.startTrans; |
723 | end; |
724 | if part.curTrans == nil then |
725 | local x,y,z = getTranslation(part.node); |
726 | part.curTrans = {x,y,z}; |
727 | local invDuration = 1.0/math.max(durationToEnd, 0.001); |
728 | part.speedTrans = {(destTrans[1]-x)*invDuration, (destTrans[2]-y)*invDuration, (destTrans[3]-z)*invDuration}; |
729 | end; |
730 | if AnimatedVehicle.setMovedLimitedValues3(part.curTrans, destTrans, part.speedTrans, dtToUse) then |
731 | setTranslation(part.node, part.curTrans[1], part.curTrans[2], part.curTrans[3]); |
732 | hasPartChanged = true; |
733 | end; |
734 | end; |
735 | if part.startScale ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextScalePart, part.prevScalePart, anim, true)) then |
736 | local destScale = part.endScale; |
737 | if anim.currentSpeed < 0 then |
738 | destScale = part.startScale; |
739 | end; |
740 | if part.curScale == nil then |
741 | local x,y,z = getScale(part.node); |
742 | part.curScale = {x,y,z}; |
743 | local invDuration = 1.0/math.max(durationToEnd, 0.001); |
744 | part.speedScale = {(destScale[1]-x)*invDuration, (destScale[2]-y)*invDuration, (destScale[3]-z)*invDuration}; |
745 | end; |
746 | if AnimatedVehicle.setMovedLimitedValues3(part.curScale, destScale, part.speedScale, dtToUse) then |
747 | setScale(part.node, part.curScale[1], part.curScale[2], part.curScale[3]); |
748 | hasPartChanged = true; |
749 | end; |
750 | end; |
751 | if part.visibility ~= nil then |
752 | if part.curVisibility == nil then |
753 | part.curVisibility = getVisibility(part.node); |
754 | end; |
755 | if part.visibility ~= part.curVisibility then |
756 | part.curVisibility = part.visibility; |
757 | setVisibility(part.node, part.visibility); |
758 | hasPartChanged = true; |
759 | end; |
760 | end; |
761 | |
762 | if self.isServer then |
763 | if part.startRotLimit ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextRotLimitPart, part.prevRotLimitPart, anim, true)) then |
764 | local destRotLimit = part.endRotLimit; |
765 | if anim.currentSpeed < 0 then |
766 | destRotLimit = part.startRotLimit; |
767 | end; |
768 | if part.curRotLimit == nil then |
769 | local x,y,z = unpack(part.componentJoint.rotLimit); |
770 | part.curRotLimit = {x,y,z}; |
771 | local invDuration = 1.0/math.max(durationToEnd, 0.001); |
772 | part.speedRotLimit = {(destRotLimit[1]-x)*invDuration, (destRotLimit[2]-y)*invDuration, (destRotLimit[3]-z)*invDuration}; |
773 | end; |
774 | for i=1, 3 do |
775 | local newRotLimit = AnimatedVehicle.getMovedLimitedValue(part.curRotLimit[i], destRotLimit[i], part.speedRotLimit[i], dtToUse); |
776 | if newRotLimit ~= part.curRotLimit[i] then |
777 | part.curRotLimit[i] = newRotLimit; |
778 | self:setComponentJointRotLimit(part.componentJoint, i, -newRotLimit, newRotLimit); |
779 | hasPartChanged = true; |
780 | end |
781 | end; |
782 | end; |
783 | if part.startTransLimit ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextTransLimitPart, part.prevTransLimitPart, anim, true)) then |
784 | local destTransLimit = part.endTransLimit; |
785 | if anim.currentSpeed < 0 then |
786 | destTransLimit = part.startTransLimit; |
787 | end; |
788 | if part.curTransLimit == nil then |
789 | local x,y,z = unpack(part.componentJoint.transLimit); |
790 | part.curTransLimit = {x,y,z}; |
791 | local invDuration = 1.0/math.max(durationToEnd, 0.001); |
792 | part.speedTransLimit = {(destTransLimit[1]-x)*invDuration, (destTransLimit[2]-y)*invDuration, (destTransLimit[3]-z)*invDuration}; |
793 | end; |
794 | for i=1, 3 do |
795 | local newTransLimit = AnimatedVehicle.getMovedLimitedValue(part.curTransLimit[i], destTransLimit[i], part.speedTransLimit[i], dtToUse); |
796 | if newRotLimit ~= part.curTransLimit[i] then |
797 | part.curTransLimit[i] = newTransLimit; |
798 | self:setComponentJointTransLimit(part.componentJoint, i, -newTransLimit, newTransLimit); |
799 | hasPartChanged = true; |
800 | end |
801 | end |
802 | end |
803 | end |
804 | |
805 | if hasPartChanged then |
806 | if self.setMovingToolDirty ~= nil then |
807 | self:setMovingToolDirty(part.node); |
808 | end |
809 | hasChanged = true; |
810 | end |
811 | end |
812 | |
813 | if partI == anim.currentPartIndex then |
814 | -- is this part finished? |
815 | if (anim.currentSpeed > 0 and part.startTime + part.duration < anim.currentTime) or |
816 | (anim.currentSpeed <= 0 and part.startTime > anim.currentTime) |
817 | then |
818 | self:resetAnimationPartValues(part); |
819 | --print("finished: "..anim.currentPartIndex); |
820 | anim.currentPartIndex = anim.currentPartIndex+1; |
821 | end |
822 | end |
823 | end; |
824 | if not nothingToChangeYet and not hasChanged and anim.currentPartIndex >= numParts then |
825 | -- end the animation |
826 | if anim.currentSpeed > 0 then |
827 | anim.currentTime = anim.duration; |
828 | else |
829 | anim.currentTime = 0; |
830 | end |
831 | stopAnim = true; |
832 | end; |
833 | end; |
834 | if stopAnim or anim.currentPartIndex > numParts or anim.currentPartIndex < 1 then |
835 | if not stopAnim then |
836 | if anim.currentSpeed > 0 then |
837 | anim.currentTime = anim.duration; |
838 | else |
839 | anim.currentTime = 0; |
840 | end |
841 | end |
842 | anim.currentTime = math.min(math.max(anim.currentTime, 0), anim.duration); |
843 | anim.stopTime = nil; |
844 | self.activeAnimations[name] = nil; |
845 | |
846 | if anim.looping then |
847 | -- restart animation |
848 | self:setAnimationTime(anim.name, math.abs((anim.duration-anim.currentTime) - 1), true); |
849 | self:playAnimation(anim.name, anim.currentSpeed, nil, true); |
850 | end; |
851 | end; |
852 | end;
|
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de