Script v1_7_1_0
- AI
- Animals
- Collections
- Contracts
- Debug
- Economy
- Elements
- EnvironmentalScore
- Errors
- Events
- GUI
- Handtools
- Hud
- I3d
- Input
- Jobs
- Maps
- Materials
- Misc
- Objects
- Parameters
- Placeables
- Placement
- Player
- Shop
- Sounds
- Specialization
- Specializations
- AIConveyorBelt
- AIDrivable
- AIFieldWorker
- AIImplement
- AIJobVehicle
- AIVehicle
- AIVehicleObstacle
- AnimatedVehicle
- ArticulatedAxis
- Attachable
- AttacherJointControl
- AttacherJoints
- AutoLoader
- BaleGrab
- BaleLoader
- Baler
- BaleWrapper
- BaseMaterial
- BigBag
- BunkerSiloCompacter
- BunkerSiloInteractor
- CCTDrivable
- Combine
- ConnectionHoses
- ConveyorBelt
- Cover
- CrabSteering
- Crawlers
- CropSensor
- Cultivator
- Cutter
- Cylindered
- CylinderedFoldable
- Dashboard
- Dischargeable
- Drivable
- DynamicallyLoadedParts
- DynamicMountAttacher
- Enterable
- ExtendedAIVehicle
- ExtendedCombine
- ExtendedMotorized
- ExtendedMower
- ExtendedSowingMachine
- ExtendedSprayer
- ExtendedWearable
- FertilizingCultivator
- FertilizingSowingMachine
- FillTriggerVehicle
- FillUnit
- FillVolume
- Foldable
- FoliageBending
- ForageWagon
- FrontloaderAttacher
- FruitPreparer
- GroundAdjustedNodes
- GroundReference
- HeadlandAnimation
- Honk
- HookLiftContainer
- HookLiftTrailer
- IKChains
- InlineWrapper
- JigglingParts
- Leveler
- LicensePlates
- Lights
- LivestockTrailer
- Locomotive
- LogGrab
- ManureBarrel
- ManureSensor
- MixerWagon
- Motorized
- Mountable
- Mower
- Mulcher
- MultipleItemPurchase
- Pallet
- Pickup
- Pipe
- PlaceableAI
- PlaceableAnimatedObjects
- PlaceableBeehive
- PlaceableBeehivePalletSpa...
- PlaceableBunkerSilo
- PlaceableBuyingStation
- PlaceableCartridgePlayer
- PlaceableChargingStation
- PlaceableClearAreas
- PlaceableColorable
- PlaceableDeletedNodes
- PlaceableDoghouse
- PlaceableDynamicallyLoade...
- PlaceableFarmhouse
- PlaceableFence
- PlaceableFoliageAreas
- PlaceableGreenhouse
- PlaceableHighPressureWash...
- PlaceableHotspots
- PlaceableHusbandry
- PlaceableHusbandryAnimals
- PlaceableHusbandryFeeding...
- PlaceableHusbandryFence
- PlaceableHusbandryFood
- PlaceableHusbandryLiquidM...
- PlaceableHusbandryMilk
- PlaceableHusbandryPallets
- PlaceableHusbandryStraw
- PlaceableHusbandryWater
- PlaceableIncomePerHour
- PlaceableIndoorAreas
- PlaceableInfoTrigger
- PlaceableLeveling
- PlaceableLights
- PlaceableManureHeap
- PlaceablePlacement
- PlaceableProductionPoint
- PlaceableSellingStation
- PlaceableSilo
- PlaceableSiloExtension
- PlaceableSolarPanels
- PlaceableTipOcclusionArea...
- PlaceableTrainSystem
- PlaceableTriggerMarkers
- PlaceableVine
- PlaceableWardrobe
- PlaceableWeatherStation
- PlaceableWeighingStation
- PlaceableWindTurbine
- PlaceableWorkshop
- Plow
- PlowPacker
- PowerConsumer
- PowerTakeOffs
- PrecisionFarmingStatistic
- PushHandTool
- RandomlyMovingParts
- ReceivingHopper
- ReverseDriving
- Rideable
- RidgeMarker
- Roller
- Ropes
- RTKStation
- SaltSpreader
- SemiTrailerFront
- Shovel
- SlopeCompensation
- SmartAttach
- SoilSampler
- SowingMachine
- SpeedRotatingParts
- SplineVehicle
- Sprayer
- StonePicker
- StrawBlower
- StumpCutter
- SupportVehicle
- Suspensions
- Tedder
- TensionBeltObject
- TensionBelts
- TestAreas
- TipOccluder
- Trailer
- TreePlanter
- TreeSaplingPallet
- TreeSaw
- TurnOnVehicle
- VariableWorkWidth
- VehicleSettings
- VineCutter
- VineDetector
- VinePrepruner
- Washable
- WaterTrailer
- Wearable
- Weeder
- WeedSpotSpray
- Wheels
- WindBending
- Windrower
- Wipers
- WoodCrusher
- WoodHarvester
- WorkArea
- WorkMode
- WorkParticles
- StateMachine
- Statistics
- Tasks
- Triggers
- Utils
- Vehicles
Engine v1_7_1_0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- general
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- NoteNode
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- VoiceChat
- XML
Foundation Reference
AnimatedVehicle
DescriptionSpecialization adding support for (keyframe)animations to vehiclesFunctions
- animPartSorter
- animPartSorterReverse
- findCurrentPartIndex
- getAnimationByName
- getAnimationDuration
- getAnimationExists
- getAnimationSpeed
- getAnimationTime
- getDurationToEndOfPart
- getIsAnimationPlaying
- getIsSpeedRotatingPartActive
- getIsWorkAreaActive
- getMovedLimitedValue
- getNextPartIsPlaying
- getNumOfActiveAnimations
- getRealAnimationTime
- initializeAnimationPart
- initializeAnimationPartAttribute
- initializeAnimationParts
- initSpecialization
- loadAnimation
- loadAnimationPart
- loadSpeedRotatingPartFromXML
- loadStaticAnimationPart
- loadStaticAnimationPartValues
- loadWorkAreaFromXML
- onDelete
- onLoad
- onPostLoad
- onPreLoad
- onRegisterAnimationValueTypes
- onUpdate
- playAnimation
- postInitializeAnimationPart
- prerequisitesPresent
- registerAnimationValueType
- registerAnimationXMLPaths
- registerEventListeners
- registerEvents
- registerFunctions
- registerOverwrittenFunctions
- resetAnimationPartValues
- resetAnimationValues
- setAnimationSpeed
- setAnimationStopTime
- setAnimationTime
- setMovedLimitedValues3
- setMovedLimitedValues4
- setMovedLimitedValuesN
- setRealAnimationTime
- stopAnimation
- updateAnimation
- updateAnimationByName
- updateAnimationCurrentTime
- updateAnimationPart
- updateAnimations
animPartSorter
DescriptionReturns true if anim parts are in the right orderDefinition
animPartSorter(table a, table b)Arguments
table | a | part a to check |
table | b | part b to check |
boolean | rightOrder | returns true if parts are in right order |
1005 | function AnimatedVehicle.animPartSorter(a, b) |
1006 | if a.startTime < b.startTime then |
1007 | return true |
1008 | elseif a.startTime == b.startTime then |
1009 | return a.duration < b.duration |
1010 | end |
1011 | return false |
1012 | end |
animPartSorterReverse
DescriptionReturns true if anim parts are in the reverse right orderDefinition
animPartSorterReverse(table a, table b)Arguments
table | a | part a to check |
table | b | part b to check |
boolean | rightOrder | returns true if parts are in reverse right order |
1019 | function AnimatedVehicle.animPartSorterReverse(a, b) |
1020 | local endTimeA = a.startTime + a.duration |
1021 | local endTimeB = b.startTime + b.duration |
1022 | if endTimeA > endTimeB then |
1023 | return true |
1024 | elseif endTimeA == endTimeB then |
1025 | return a.startTime > b.startTime |
1026 | end |
1027 | return false |
1028 | end |
findCurrentPartIndex
DescriptionFind current playing partDefinition
findCurrentPartIndex(table animation)Arguments
table | animation | animation |
integer | index | of current playing part |
1090 | function AnimatedVehicle.findCurrentPartIndex(animation) |
1091 | if animation.currentSpeed > 0 then |
1092 | -- find the first part that is being played at the current time |
1093 | animation.currentPartIndex = #animation.parts+1 |
1094 | for i, part in ipairs(animation.parts) do |
1095 | if part.startTime+part.duration >= animation.currentTime then |
1096 | animation.currentPartIndex = i |
1097 | break |
1098 | end |
1099 | end |
1100 | else |
1101 | -- find the last part that is being played at the current time (the first in partsReverse) |
1102 | animation.currentPartIndex = #animation.partsReverse+1 |
1103 | for i, part in ipairs(animation.partsReverse) do |
1104 | if part.startTime <= animation.currentTime then |
1105 | animation.currentPartIndex = i |
1106 | break |
1107 | end |
1108 | end |
1109 | end |
1110 | end |
getAnimationByName
DescriptionReturns the animation by given nameDefinition
getAnimationByName(string name)Arguments
string | name | name of animation |
table | animation | animation data |
716 | function AnimatedVehicle:getAnimationByName(name) |
717 | return self.spec_animatedVehicle.animations[name] |
718 | end |
getAnimationDuration
DescriptionReturns duration of animationDefinition
getAnimationDuration(string name)Arguments
string | name | name of animation |
float | duration | duration in ms |
809 | function AnimatedVehicle:getAnimationDuration(name) |
810 | local spec = self.spec_animatedVehicle |
811 | |
812 | local animation = spec.animations[name] |
813 | if animation ~= nil then |
814 | return animation.duration |
815 | end |
816 | return 1 |
817 | end |
getAnimationExists
DescriptionReturns true if animation exitsDefinition
getAnimationExists(string name)Arguments
string | name | name of animation |
boolean | exists | animation axists |
706 | function AnimatedVehicle:getAnimationExists(name) |
707 | local spec = self.spec_animatedVehicle |
708 | |
709 | return spec.animations[name] ~= nil |
710 | end |
getAnimationSpeed
DescriptionReturns speed of animationDefinition
getAnimationSpeed(string name)Arguments
string | name | name of animation |
float | speed | speed |
843 | function AnimatedVehicle:getAnimationSpeed(name) |
844 | local spec = self.spec_animatedVehicle |
845 | |
846 | local animation = spec.animations[name] |
847 | if animation ~= nil then |
848 | return animation.currentSpeed |
849 | end |
850 | |
851 | return 0 |
852 | end |
getAnimationTime
DescriptionReturns animation timeDefinition
getAnimationTime(string name)Arguments
string | name | name of animation |
float | animTime | animation time [0..1] |
777 | function AnimatedVehicle:getAnimationTime(name) |
778 | local spec = self.spec_animatedVehicle |
779 | |
780 | local animation = spec.animations[name] |
781 | if animation ~= nil then |
782 | return animation.currentTime/animation.duration |
783 | end |
784 | return 0 |
785 | end |
getDurationToEndOfPart
DescriptionReturns duration to the end of current partDefinition
getDurationToEndOfPart(table part, table anim)Arguments
table | part | part |
table | anim | animation |
float | duration | duration to end of current part |
1117 | function AnimatedVehicle.getDurationToEndOfPart(part, anim) |
1118 | if anim.currentSpeed > 0 then |
1119 | return part.startTime+part.duration - anim.currentTime |
1120 | else |
1121 | return anim.currentTime - part.startTime |
1122 | end |
1123 | end |
getIsAnimationPlaying
DescriptionReturns true if animation is playingDefinition
getIsAnimationPlaying(string name)Arguments
string | name | name of animation |
boolean | isPlaying | animation is playing |
725 | function AnimatedVehicle:getIsAnimationPlaying(name) |
726 | local spec = self.spec_animatedVehicle |
727 | |
728 | return spec.activeAnimations[name] ~= nil |
729 | end |
getIsSpeedRotatingPartActive
DescriptionDefinitiongetIsSpeedRotatingPartActive()Code
903 | function AnimatedVehicle:getIsSpeedRotatingPartActive(superFunc, speedRotatingPart) |
904 | if speedRotatingPart.animName ~= nil then |
905 | local animTime = self:getAnimationTime(speedRotatingPart.animName) |
906 | if speedRotatingPart.animOuterRange then |
907 | if animTime > speedRotatingPart.animMinLimit or animTime < speedRotatingPart.animMaxLimit then |
908 | return false |
909 | end |
910 | else |
911 | if animTime > speedRotatingPart.animMaxLimit or animTime < speedRotatingPart.animMinLimit then |
912 | return false |
913 | end |
914 | end |
915 | end |
916 | |
917 | return superFunc(self, speedRotatingPart) |
918 | end |
getIsWorkAreaActive
DescriptionDefinitiongetIsWorkAreaActive()Code
932 | function AnimatedVehicle:getIsWorkAreaActive(superFunc, workArea) |
933 | if workArea.animName ~= nil then |
934 | local animTime = self:getAnimationTime(workArea.animName) |
935 | if animTime > workArea.animMaxLimit or animTime < workArea.animMinLimit then |
936 | return false |
937 | end |
938 | end |
939 | |
940 | return superFunc(self, workArea) |
941 | end |
getMovedLimitedValue
DescriptionReturns moved limited valueDefinition
getMovedLimitedValue(float currentValue, float destValue, float speed, float dt)Arguments
float | currentValue | current value |
float | destValue | dest value |
float | speed | speed |
float | dt | time since last call in ms |
float | ret | limited value |
1037 | function AnimatedVehicle.getMovedLimitedValue(currentValue, destValue, speed, dt) |
1038 | if destValue == currentValue then |
1039 | return currentValue |
1040 | end |
1041 | |
1042 | -- we are moving towards -inf, we need to check for the maximum |
1043 | local limitF = destValue < currentValue and math.max or math.min |
1044 | return limitF(currentValue + speed * dt, destValue) |
1045 | end |
getNextPartIsPlaying
DescriptionGet next part is playingDefinition
getNextPartIsPlaying(table nextPart, table prevPart, table anim, boolean default)Arguments
table | nextPart | next part |
table | prevPart | previous part |
table | anim | animation |
boolean | default | default value |
boolean | isPlaying | next part is playing |
1132 | function AnimatedVehicle.getNextPartIsPlaying(nextPart, prevPart, anim, default) |
1133 | if anim.currentSpeed > 0 then |
1134 | if nextPart ~= nil then |
1135 | return nextPart.startTime > anim.currentTime |
1136 | end |
1137 | else |
1138 | if prevPart ~= nil then |
1139 | return prevPart.startTime + prevPart.duration < anim.currentTime |
1140 | end |
1141 | end |
1142 | return default |
1143 | end |
getNumOfActiveAnimations
DescriptionDefinitiongetNumOfActiveAnimations()Code
1443 | function AnimatedVehicle:getNumOfActiveAnimations() |
1444 | return self.spec_animatedVehicle.numActiveAnimations |
1445 | end |
getRealAnimationTime
DescriptionReturns real animation timeDefinition
getRealAnimationTime(string name)Arguments
string | name | name of animation |
float | animTime | real animation time in ms |
735 | function AnimatedVehicle:getRealAnimationTime(name) |
736 | local spec = self.spec_animatedVehicle |
737 | |
738 | local animation = spec.animations[name] |
739 | if animation ~= nil then |
740 | return animation.currentTime |
741 | end |
742 | return 0 |
743 | end |
initializeAnimationPart
DescriptionInitialize part of animationDefinition
initializeAnimationPart(table part)Arguments
table | part | part |
598 | function AnimatedVehicle:initializeAnimationPart(animation, part, i, numParts) |
599 | for index=1, #part.animationValues do |
600 | part.animationValues[index]:init(i, numParts) |
601 | end |
602 | end |
initializeAnimationPartAttribute
DescriptionDefinitioninitializeAnimationPartAttribute()Code
945 | function AnimatedVehicle.initializeAnimationPartAttribute(self, animation, part, i, numParts, nextName, prevName, startName, endName, warningName, startName2, endName2, additionalCompareParam) |
946 | -- find next part, check for overlapping, enter dependencies and set default start value if not already set |
947 | if part[endName] ~= nil then |
948 | for j=i+1, numParts do |
949 | local part2 = animation.parts[j] |
950 | |
951 | local additionalCompare = true |
952 | if additionalCompareParam ~= nil then |
953 | if part[additionalCompareParam] ~= part2[additionalCompareParam] then |
954 | additionalCompare = false |
955 | end |
956 | end |
957 | |
958 | -- check if the animations use the same range, if not they cannot collide |
959 | local sameRequiredRange = true |
960 | if part.requiredAnimation ~= nil then |
961 | if part.requiredAnimation == part2.requiredAnimation then |
962 | for n, v in ipairs(part.requiredAnimationRange) do |
963 | if part2.requiredAnimationRange[n] ~= v then |
964 | sameRequiredRange = false |
965 | end |
966 | end |
967 | end |
968 | end |
969 | |
970 | local sameConfiguration = true |
971 | if part.requiredConfigurationName ~= nil then |
972 | if part.requiredConfigurationName == part2.requiredConfigurationName then |
973 | if part.requiredConfigurationIndex ~= part2.requiredConfigurationIndex then |
974 | sameConfiguration = false |
975 | end |
976 | end |
977 | end |
978 | |
979 | if part.direction == part2.direction and part.node == part2.node and part2[endName] ~= nil and additionalCompare and sameRequiredRange and sameConfiguration then |
980 | if part.direction == part2.direction and part.startTime + part.duration > part2.startTime+0.001 then |
981 | Logging.xmlWarning(self.xmlFile, "Overlapping %s parts for node '%s' in animation '%s'", warningName, getName(part.node), animation.name) |
982 | end |
983 | part[nextName] = part2 |
984 | part2[prevName] = part |
985 | if part2[startName] == nil then |
986 | part2[startName] = {unpack(part[endName])} |
987 | end |
988 | if startName2 ~= nil and endName2 ~= nil then |
989 | if part2[startName2] == nil then |
990 | part2[startName2] = {unpack(part[endName2])} |
991 | end |
992 | end |
993 | |
994 | break |
995 | end |
996 | end |
997 | end |
998 | end |
initializeAnimationParts
DescriptionInitialize parts of animationDefinition
initializeAnimationParts(table animation)Arguments
table | animation | animation |
583 | function AnimatedVehicle:initializeAnimationParts(animation) |
584 | local numParts = #animation.parts |
585 | |
586 | for i, part in ipairs(animation.parts) do |
587 | self:initializeAnimationPart(animation, part, i, numParts) |
588 | end |
589 | |
590 | for i, part in ipairs(animation.parts) do |
591 | self:postInitializeAnimationPart(animation, part, i, numParts) |
592 | end |
593 | end |
initSpecialization
DescriptionDefinitioninitSpecialization()Code
31 | function AnimatedVehicle.initSpecialization() |
32 | local schema = Vehicle.xmlSchema |
33 | schema:setXMLSpecializationType("AnimatedVehicle") |
34 | |
35 | AnimatedVehicle.registerAnimationXMLPaths(schema, "vehicle.animations.animation(?)") |
36 | |
37 | schema:register(XMLValueType.STRING, SpeedRotatingParts.SPEED_ROTATING_PART_XML_KEY .. "#animName", "Animation name") |
38 | schema:register(XMLValueType.BOOL, SpeedRotatingParts.SPEED_ROTATING_PART_XML_KEY .. "#animOuterRange", "Anim limit outer range", false) |
39 | schema:register(XMLValueType.FLOAT, SpeedRotatingParts.SPEED_ROTATING_PART_XML_KEY .. "#animMinLimit", "Min. anim limit", 0) |
40 | schema:register(XMLValueType.FLOAT, SpeedRotatingParts.SPEED_ROTATING_PART_XML_KEY .. "#animMaxLimit", "Max. anim limit", 1) |
41 | |
42 | schema:register(XMLValueType.STRING, WorkArea.WORK_AREA_XML_KEY .. "#animName", "Animation name") |
43 | schema:register(XMLValueType.FLOAT, WorkArea.WORK_AREA_XML_KEY .. "#animMinLimit", "Min. anim limit", 0) |
44 | schema:register(XMLValueType.FLOAT, WorkArea.WORK_AREA_XML_KEY .. "#animMaxLimit", "Max. anim limit", 1) |
45 | |
46 | schema:register(XMLValueType.STRING, WorkArea.WORK_AREA_XML_CONFIG_KEY .. "#animName", "Animation name") |
47 | schema:register(XMLValueType.FLOAT, WorkArea.WORK_AREA_XML_CONFIG_KEY .. "#animMinLimit", "Min. anim limit", 0) |
48 | schema:register(XMLValueType.FLOAT, WorkArea.WORK_AREA_XML_CONFIG_KEY .. "#animMaxLimit", "Max. anim limit", 1) |
49 | |
50 | schema:setXMLSpecializationType() |
51 | end |
loadAnimation
DescriptionDefinitionloadAnimation()Code
339 | function AnimatedVehicle:loadAnimation(xmlFile, key, animation, components) |
340 | |
341 | local name = xmlFile:getValue(key.."#name") |
342 | if name ~= nil then |
343 | animation.name = name |
344 | animation.parts = {} |
345 | animation.currentTime = 0 |
346 | animation.previousTime = 0 |
347 | animation.currentSpeed = 1 |
348 | animation.looping = xmlFile:getValue(key .. "#looping", false) |
349 | animation.resetOnStart = xmlFile:getValue(key .. "#resetOnStart", true) |
350 | animation.soundVolumeFactor = xmlFile:getValue(key .. "#soundVolumeFactor", 1) |
351 | animation.isKeyframe = xmlFile:getValue(key .. "#isKeyframe", false) |
352 | |
353 | if animation.isKeyframe then |
354 | animation.curvesByNode = {} |
355 | end |
356 | |
357 | local partI = 0 |
358 | while true do |
359 | local partKey = key..string.format(".part(%d)", partI) |
360 | if not xmlFile:hasProperty(partKey) then |
361 | break |
362 | end |
363 | |
364 | local animationPart = {} |
365 | if not animation.isKeyframe then |
366 | if self:loadAnimationPart(xmlFile, partKey, animationPart, animation, components) then |
367 | table.insert(animation.parts, animationPart) |
368 | end |
369 | else |
370 | self:loadStaticAnimationPart(xmlFile, partKey, animationPart, animation, components) |
371 | end |
372 | |
373 | partI = partI + 1 |
374 | end |
375 | |
376 | -- sort parts by start/end time |
377 | animation.partsReverse = {} |
378 | for _, part in ipairs(animation.parts) do |
379 | table.insert(animation.partsReverse, part) |
380 | end |
381 | table.sort(animation.parts, AnimatedVehicle.animPartSorter) |
382 | table.sort(animation.partsReverse, AnimatedVehicle.animPartSorterReverse) |
383 | |
384 | self:initializeAnimationParts(animation) |
385 | |
386 | animation.currentPartIndex = 1 |
387 | animation.duration = 0 |
388 | for _, part in ipairs(animation.parts) do |
389 | animation.duration = math.max(animation.duration, part.startTime + part.duration) |
390 | end |
391 | if animation.isKeyframe then |
392 | for node, curve in pairs(animation.curvesByNode) do |
393 | animation.duration = math.max(animation.duration, curve.maxTime) |
394 | end |
395 | end |
396 | |
397 | animation.startTime = xmlFile:getValue(key .. "#startAnimTime", 0) |
398 | animation.currentTime = animation.startTime * animation.duration |
399 | |
400 | if self.isClient then |
401 | animation.samples = {} |
402 | |
403 | local i = 0 |
404 | while true do |
405 | local soundKey = string.format("sound(%d)", i) |
406 | local baseKey = key .. "." .. soundKey |
407 | if not xmlFile:hasProperty(baseKey) then |
408 | break |
409 | end |
410 | |
411 | local sample = g_soundManager:loadSampleFromXML(xmlFile, key, soundKey, self.baseDirectory, components or self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) |
412 | if sample ~= nil then |
413 | sample.startTime = xmlFile:getValue(baseKey .. "#startTime", 0) |
414 | sample.endTime = xmlFile:getValue(baseKey .. "#endTime") |
415 | sample.direction = xmlFile:getValue(baseKey .. "#direction", 0) |
416 | |
417 | -- if no end time and no loop count is defined we play the sound only once |
418 | if sample.endTime == nil and sample.loops == 0 then |
419 | sample.loops = 1 |
420 | end |
421 | |
422 | sample.volumeScale = sample.volumeScale * animation.soundVolumeFactor |
423 | |
424 | table.insert(animation.samples, sample) |
425 | end |
426 | |
427 | i = i + 1 |
428 | end |
429 | |
430 | animation.eventSamples = {} |
431 | animation.eventSamples.stopTimePos = {} |
432 | animation.eventSamples.stopTimeNeg = {} |
433 | |
434 | xmlFile:iterate(key .. ".stopTimePosSound", function(index, _) |
435 | local sample = g_soundManager:loadSampleFromXML(xmlFile, key, string.format("stopTimePosSound(%d)", index - 1), self.baseDirectory, components or self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) |
436 | if sample ~= nil then |
437 | table.insert(animation.eventSamples.stopTimePos, sample) |
438 | end |
439 | end) |
440 | |
441 | xmlFile:iterate(key .. ".stopTimeNegSound", function(index, _) |
442 | local sample = g_soundManager:loadSampleFromXML(xmlFile, key, string.format("stopTimeNegSound(%d)", index - 1), self.baseDirectory, components or self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) |
443 | if sample ~= nil then |
444 | table.insert(animation.eventSamples.stopTimeNeg, sample) |
445 | end |
446 | end) |
447 | end |
448 | |
449 | return true |
450 | end |
451 | |
452 | return false |
453 | end |
loadAnimationPart
DescriptionDefinitionloadAnimationPart()Code
457 | function AnimatedVehicle:loadAnimationPart(xmlFile, partKey, part, animation, components) |
458 | local startTime = xmlFile:getValue(partKey.."#startTime") |
459 | local duration = xmlFile:getValue(partKey.."#duration") |
460 | local endTime = xmlFile:getValue(partKey.."#endTime") |
461 | local direction = MathUtil.sign(xmlFile:getValue(partKey.."#direction", 0)) |
462 | |
463 | part.components = components or self.components |
464 | part.i3dMappings = self.i3dMappings |
465 | |
466 | part.animationValues = {} |
467 | |
468 | local spec = self.spec_animatedVehicle |
469 | for _, animationValueType in pairs(spec.animationValueTypes) do |
470 | local animationValueObject = animationValueType.classObject.new(self, animation, part, animationValueType.startName, animationValueType.endName, animationValueType.name, animationValueType.initialUpdate, animationValueType.get, animationValueType.set, animationValueType.load) |
471 | if animationValueObject:load(xmlFile, partKey) then |
472 | table.insert(part.animationValues, animationValueObject) |
473 | end |
474 | end |
475 | |
476 | local requiredAnimation = xmlFile:getValue(partKey.."#requiredAnimation") |
477 | local requiredAnimationRange = xmlFile:getValue(partKey.."#requiredAnimationRange", nil, true) |
478 | |
479 | local requiredConfigurationName = xmlFile:getValue(partKey.."#requiredConfigurationName") |
480 | local requiredConfigurationIndex = xmlFile:getValue(partKey.."#requiredConfigurationIndex") |
481 | |
482 | for i=1, #part.animationValues do |
483 | part.animationValues[i].requiredAnimation = requiredAnimation |
484 | part.animationValues[i]:addCompareParameters("requiredAnimation") |
485 | |
486 | if requiredAnimationRange ~= nil then |
487 | part.animationValues[i].requiredAnimationRange = string.format("%.2f %.2f", requiredAnimationRange[1], requiredAnimationRange[2]) |
488 | part.animationValues[i]:addCompareParameters("requiredAnimationRange") |
489 | end |
490 | end |
491 | |
492 | if #part.animationValues == 0 then |
493 | return false |
494 | end |
495 | |
496 | if startTime ~= nil and (duration ~= nil or endTime ~= nil) then |
497 | if endTime ~= nil then |
498 | duration = endTime - startTime |
499 | end |
500 | part.startTime = startTime*1000 |
501 | part.duration = duration*1000 |
502 | part.direction = direction |
503 | part.requiredAnimation = requiredAnimation |
504 | part.requiredAnimationRange = requiredAnimationRange |
505 | |
506 | part.requiredConfigurationName = requiredConfigurationName |
507 | part.requiredConfigurationIndex = requiredConfigurationIndex |
508 | |
509 | return true |
510 | end |
511 | |
512 | return false |
513 | end |
loadSpeedRotatingPartFromXML
DescriptionDefinitionloadSpeedRotatingPartFromXML()Code
888 | function AnimatedVehicle:loadSpeedRotatingPartFromXML(superFunc, speedRotatingPart, xmlFile, key) |
889 | if not superFunc(self, speedRotatingPart, xmlFile, key) then |
890 | return false |
891 | end |
892 | |
893 | speedRotatingPart.animName = xmlFile:getValue(key.."#animName") |
894 | speedRotatingPart.animOuterRange = xmlFile:getValue(key.."#animOuterRange", false) |
895 | speedRotatingPart.animMinLimit = xmlFile:getValue(key.."#animMinLimit", 0) |
896 | speedRotatingPart.animMaxLimit = xmlFile:getValue(key.."#animMaxLimit", 1) |
897 | |
898 | return true |
899 | end |
loadStaticAnimationPart
DescriptionDefinitionloadStaticAnimationPart()Code
517 | function AnimatedVehicle:loadStaticAnimationPart(xmlFile, partKey, part, animation, components) |
518 | local node = xmlFile:getValue(partKey .. "#node", nil, self.components, self.i3dMappings) |
519 | if node ~= nil then |
520 | local time = xmlFile:getValue(partKey.."#time") |
521 | local startTime = xmlFile:getValue(partKey.."#startTime") |
522 | local endTime = xmlFile:getValue(partKey.."#endTime") |
523 | |
524 | if animation.curvesByNode[node] == nil then |
525 | animation.curvesByNode[node] = AnimCurve.new(linearInterpolatorTransRotScale) |
526 | end |
527 | |
528 | local curve = animation.curvesByNode[node] |
529 | |
530 | if time ~= nil then |
531 | self:loadStaticAnimationPartValues(xmlFile, partKey, curve, node, "translation", "rotation", "scale", time * 1000) |
532 | elseif startTime ~= nil or endTime ~= nil then |
533 | if startTime ~= nil then |
534 | startTime = startTime * 1000 |
535 | if curve.maxTime == 0 or curve.maxTime ~= startTime then |
536 | self:loadStaticAnimationPartValues(xmlFile, partKey, curve, node, "startTrans", "startRot", "startScale", startTime) |
537 | end |
538 | end |
539 | if endTime ~= nil then |
540 | endTime = endTime * 1000 |
541 | if curve.maxTime == 0 or curve.maxTime ~= endTime then |
542 | self:loadStaticAnimationPartValues(xmlFile, partKey, curve, node, "endTrans", "endRot", "endScale", endTime) |
543 | end |
544 | end |
545 | end |
546 | |
547 | return true |
548 | end |
549 | |
550 | return false |
551 | end |
loadStaticAnimationPartValues
DescriptionDefinitionloadStaticAnimationPartValues()Code
555 | function AnimatedVehicle:loadStaticAnimationPartValues(xmlFile, partKey, curve, node, transName, rotName, scaleName, time) |
556 | local x, y, z = xmlFile:getValue(partKey.."#"..transName) |
557 | if x == nil then |
558 | x, y, z = getTranslation(node) |
559 | else |
560 | curve.hasTranslation = true |
561 | end |
562 | |
563 | local rx, ry, rz = xmlFile:getValue(partKey.."#"..rotName) |
564 | if rx == nil then |
565 | rx, ry, rz = getRotation(node) |
566 | else |
567 | curve.hasRotation = true |
568 | end |
569 | |
570 | local sx, sy, sz = xmlFile:getValue(partKey.."#"..scaleName) |
571 | if sx == nil then |
572 | sx, sy, sz = getScale(node) |
573 | else |
574 | curve.hasScale = true |
575 | end |
576 | |
577 | curve:addKeyframe({x=x, y=y, z=z, rx=rx, ry=ry, rz=rz, sx=sx, sy=sy, sz=sz, time=time}) |
578 | end |
loadWorkAreaFromXML
DescriptionDefinitionloadWorkAreaFromXML()Code
922 | function AnimatedVehicle:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key) |
923 | workArea.animName = xmlFile:getValue(key.."#animName") |
924 | workArea.animMinLimit = xmlFile:getValue(key.."#animMinLimit", 0) |
925 | workArea.animMaxLimit = xmlFile:getValue(key.."#animMaxLimit", 1) |
926 | |
927 | return superFunc(self, workArea, xmlFile, key) |
928 | end |
onDelete
DescriptionCalled on deletingDefinition
onDelete()Code
269 | function AnimatedVehicle:onDelete() |
270 | local spec = self.spec_animatedVehicle |
271 | if self.isClient and spec.animations ~= nil then |
272 | for _, animation in pairs(spec.animations) do |
273 | g_soundManager:deleteSamples(animation.samples) |
274 | g_soundManager:deleteSamples(animation.eventSamples.stopTimePos) |
275 | g_soundManager:deleteSamples(animation.eventSamples.stopTimeNeg) |
276 | end |
277 | end |
278 | end |
onLoad
DescriptionCalled on loadingDefinition
onLoad(table savegame)Arguments
table | savegame | savegame |
222 | function AnimatedVehicle:onLoad(savegame) |
223 | local spec = self.spec_animatedVehicle |
224 | |
225 | spec.animations = {} |
226 | |
227 | local i = 0 |
228 | while true do |
229 | local key = string.format("vehicle.animations.animation(%d)", i) |
230 | if not self.xmlFile:hasProperty(key) then |
231 | break |
232 | end |
233 | |
234 | local animation = {} |
235 | |
236 | if self:loadAnimation(self.xmlFile, key, animation) then |
237 | spec.animations[animation.name] = animation |
238 | end |
239 | |
240 | i = i + 1 |
241 | end |
242 | |
243 | spec.activeAnimations = {} |
244 | spec.numActiveAnimations = 0 |
245 | spec.fixedTimeSamplesDirtyDelay = 0 |
246 | end |
onPostLoad
DescriptionCalled after loadingDefinition
onPostLoad(table savegame)Arguments
table | savegame | savegame |
251 | function AnimatedVehicle:onPostLoad(savegame) |
252 | local spec = self.spec_animatedVehicle |
253 | for name, animation in pairs(spec.animations) do |
254 | if animation.resetOnStart then |
255 | self:setAnimationTime(name, 1, true, false) |
256 | self:setAnimationStopTime(name, animation.startTime) |
257 | self:playAnimation(name, -1, 1, true, false) |
258 | AnimatedVehicle.updateAnimationByName(self, name, 9999999, true) |
259 | end |
260 | end |
261 | |
262 | if next(spec.animations) == nil then |
263 | SpecializationUtil.removeEventListener(self, "onUpdate", AnimatedVehicle) |
264 | end |
265 | end |
onPreLoad
DescriptionCalled on pre loadingDefinition
onPreLoad(table savegame)Arguments
table | savegame | savegame |
212 | function AnimatedVehicle:onPreLoad(savegame) |
213 | local spec = self.spec_animatedVehicle |
214 | spec.animationValueTypes = {} |
215 | |
216 | SpecializationUtil.raiseEvent(self, "onRegisterAnimationValueTypes") |
217 | end |
onRegisterAnimationValueTypes
DescriptionCalled on pre load to register animation value typesDefinition
onRegisterAnimationValueTypes()Code
1449 | function AnimatedVehicle:onRegisterAnimationValueTypes() |
1450 | local loadNodeFunction = function(value, xmlFile, xmlKey) |
1451 | value.node = xmlFile:getValue(xmlKey .. "#node", nil, value.part.components, value.part.i3dMappings) |
1452 | |
1453 | if value.node ~= nil then |
1454 | value:setWarningInformation("node: " .. getName(value.node)) |
1455 | value:addCompareParameters("node") |
1456 | |
1457 | return true |
1458 | end |
1459 | |
1460 | return false |
1461 | end |
1462 | |
1463 | self:registerAnimationValueType("rotation", "startRot", "endRot", false, AnimationValueFloat, loadNodeFunction, |
1464 | function(value) |
1465 | return getRotation(value.node) |
1466 | end, |
1467 | |
1468 | function(value, ...) |
1469 | setRotation(value.node, ...) |
1470 | |
1471 | SpecializationUtil.raiseEvent(self, "onAnimationPartChanged", value.node) |
1472 | end) |
1473 | |
1474 | self:registerAnimationValueType("translation", "startTrans", "endTrans", false, AnimationValueFloat, loadNodeFunction, |
1475 | function(value) |
1476 | return getTranslation(value.node) |
1477 | end, |
1478 | |
1479 | function(value, ...) |
1480 | setTranslation(value.node, ...) |
1481 | |
1482 | SpecializationUtil.raiseEvent(self, "onAnimationPartChanged", value.node) |
1483 | end) |
1484 | |
1485 | self:registerAnimationValueType("scale", "startScale", "endScale", false, AnimationValueFloat, loadNodeFunction, |
1486 | function(value) |
1487 | return getScale(value.node) |
1488 | end, |
1489 | |
1490 | function(value, ...) |
1491 | setScale(value.node, ...) |
1492 | |
1493 | SpecializationUtil.raiseEvent(self, "onAnimationPartChanged", value.node) |
1494 | end) |
1495 | |
1496 | local updateShaderParameterMask = function(xmlFile, xmlKey, mask) |
1497 | local customMask = false |
1498 | local rawValuesStr = xmlFile:getString(xmlKey) |
1499 | if rawValuesStr ~= nil then |
1500 | local rawValues = rawValuesStr:split(" ") |
1501 | for i=1, #rawValues do |
1502 | if rawValues[i] == "-" then |
1503 | mask[i] = 0 |
1504 | customMask = true |
1505 | end |
1506 | end |
1507 | end |
1508 | |
1509 | return customMask |
1510 | end |
1511 | |
1512 | self:registerAnimationValueType("shaderParameter", "shaderStartValues", "shaderEndValues", false, AnimationValueFloat, |
1513 | function(value, xmlFile, xmlKey) |
1514 | value.node = xmlFile:getValue(xmlKey .. "#node", nil, value.part.components, value.part.i3dMappings) |
1515 | value.shaderParameter = xmlFile:getValue(xmlKey.."#shaderParameter") |
1516 | value.shaderParameterPrev = xmlFile:getValue(xmlKey.."#shaderParameterPrev") |
1517 | |
1518 | if value.node ~= nil and value.shaderParameter ~= nil then |
1519 | if getHasClassId(value.node, ClassIds.SHAPE) and getHasShaderParameter(value.node, value.shaderParameter) then |
1520 | value:setWarningInformation("node: " .. getName(value.node) .. "with shaderParam: " .. value.shaderParameter) |
1521 | value:addCompareParameters("node", "shaderParameter") |
1522 | |
1523 | value.shaderParameterMask = {1, 1, 1, 1} |
1524 | value.customShaderParameterMask = updateShaderParameterMask(xmlFile, xmlKey .. "#shaderStartValues", value.shaderParameterMask) |
1525 | value.customShaderParameterMask = updateShaderParameterMask(xmlFile, xmlKey .. "#shaderEndValues", value.shaderParameterMask) or value.customShaderParameterMask |
1526 | |
1527 | if value.shaderParameterPrev ~= nil then |
1528 | if not getHasShaderParameter(value.node, value.shaderParameterPrev) then |
1529 | Logging.xmlWarning(xmlFile, "Node '%s' has no shaderParameterPrev '%s' for animation part '%s'!", getName(value.node), value.shaderParameterPrev, xmlKey) |
1530 | return false |
1531 | end |
1532 | else |
1533 | local prevName = "prev" .. value.shaderParameter:sub(1, 1):upper() .. value.shaderParameter:sub(2) |
1534 | if getHasShaderParameter(value.node, prevName) then |
1535 | value.shaderParameterPrev = prevName |
1536 | end |
1537 | end |
1538 | |
1539 | return true |
1540 | else |
1541 | Logging.xmlWarning(xmlFile, "Node '%s' has no shaderParameter '%s' for animation part '%s'!", getName(value.node), value.shaderParameter, xmlKey) |
1542 | end |
1543 | end |
1544 | |
1545 | return false |
1546 | end, |
1547 | |
1548 | function(value) |
1549 | return getShaderParameter(value.node, value.shaderParameter) |
1550 | end, |
1551 | |
1552 | function(value, x, y, z, w) |
1553 | if value.customShaderParameterMask then |
1554 | local sx, sy, sz, sw = getShaderParameter(value.node, value.shaderParameter) |
1555 | if value.shaderParameterMask[1] == 0 then x = sx end |
1556 | if value.shaderParameterMask[2] == 0 then y = sy end |
1557 | if value.shaderParameterMask[3] == 0 then z = sz end |
1558 | if value.shaderParameterMask[4] == 0 then w = sw end |
1559 | end |
1560 | |
1561 | if value.shaderParameterPrev ~= nil then |
1562 | g_animationManager:setPrevShaderParameter(value.node, value.shaderParameter, x, y, z, w, false, value.shaderParameterPrev) |
1563 | else |
1564 | setShaderParameter(value.node, value.shaderParameter, x, y, z, w, false) |
1565 | end |
1566 | end) |
1567 | |
1568 | self:registerAnimationValueType("visibility", "visibility", "", false, AnimationValueBool, loadNodeFunction, |
1569 | function(value) |
1570 | return getVisibility(value.node) |
1571 | end, |
1572 | |
1573 | function(value, ...) |
1574 | setVisibility(value.node, ...) |
1575 | end) |
1576 | |
1577 | self:registerAnimationValueType("visibilityInter", "startVisibility", "endVisibility", false, AnimationValueFloat, |
1578 | function(value, xmlFile, xmlKey) |
1579 | value.node = xmlFile:getValue(xmlKey .. "#node", nil, value.part.components, value.part.i3dMappings) |
1580 | if value.node ~= nil and value.startValue ~= nil and value.endValue ~= nil then |
1581 | value:setWarningInformation("node: " .. getName(value.node)) |
1582 | value:addCompareParameters("node") |
1583 | |
1584 | return true |
1585 | end |
1586 | |
1587 | return false |
1588 | end, |
1589 | function(value) |
1590 | if value.lastVisibilityValue ~= nil then |
1591 | return value.lastVisibilityValue |
1592 | end |
1593 | |
1594 | return getVisibility(value.node) and 1 or 0 |
1595 | end, |
1596 | |
1597 | function(value, visibility) |
1598 | value.lastVisibilityValue = visibility |
1599 | setVisibility(value.node, visibility >= 0.5) |
1600 | end) |
1601 | |
1602 | self:registerAnimationValueType("animationClip", "clipStartTime", "clipEndTime", true, AnimationValueFloat, |
1603 | function(value, xmlFile, xmlKey) |
1604 | value.node = xmlFile:getValue(xmlKey .. "#node", nil, value.part.components, value.part.i3dMappings) |
1605 | value.animationClip = xmlFile:getValue(xmlKey.."#animationClip") |
1606 | |
1607 | if value.node ~= nil and value.animationClip ~= nil then |
1608 | value.animationCharSet = getAnimCharacterSet(value.node) |
1609 | value.animationClipIndex = getAnimClipIndex(value.animationCharSet, value.animationClip) |
1610 | |
1611 | value:setWarningInformation("node: " .. getName(value.node) .. "with animationClip: " .. value.animationClip) |
1612 | value:addCompareParameters("node", "animationClip") |
1613 | |
1614 | return true |
1615 | end |
1616 | |
1617 | return false |
1618 | end, |
1619 | |
1620 | function(value) |
1621 | local oldClipIndex = getAnimTrackAssignedClip(value.animationCharSet, 0) |
1622 | clearAnimTrackClip(value.animationCharSet, 0) |
1623 | assignAnimTrackClip(value.animationCharSet, 0, value.animationClipIndex) |
1624 | |
1625 | if oldClipIndex == value.animationClipIndex then |
1626 | return getAnimTrackTime(value.animationCharSet, 0) |
1627 | end |
1628 | |
1629 | local startTime = value.startValue or value.endValue |
1630 | if value.animation.currentSpeed < 0 then |
1631 | startTime = value.endValue or value.startValue |
1632 | end |
1633 | |
1634 | return startTime[1] |
1635 | end, |
1636 | |
1637 | function(value, time) |
1638 | local oldClipIndex = getAnimTrackAssignedClip(value.animationCharSet, 0) |
1639 | if oldClipIndex ~= value.animationClipIndex then |
1640 | clearAnimTrackClip(value.animationCharSet, 0) |
1641 | assignAnimTrackClip(value.animationCharSet, 0, value.animationClipIndex) |
1642 | end |
1643 | |
1644 | enableAnimTrack(value.animationCharSet, 0) |
1645 | setAnimTrackTime(value.animationCharSet, 0, time, true) |
1646 | disableAnimTrack(value.animationCharSet, 0) |
1647 | end) |
1648 | |
1649 | self:registerAnimationValueType("dependentAnimation", "dependentAnimationStartTime", "dependentAnimationEndTime", true, AnimationValueFloat, |
1650 | function(value, xmlFile, xmlKey) |
1651 | value.dependentAnimation = xmlFile:getValue(xmlKey.."#dependentAnimation") |
1652 | |
1653 | if value.dependentAnimation ~= nil then |
1654 | value:setWarningInformation("dependentAnimation: " .. value.dependentAnimation) |
1655 | value:addCompareParameters("dependentAnimation") |
1656 | |
1657 | return true |
1658 | end |
1659 | |
1660 | return false |
1661 | end, |
1662 | |
1663 | function(value) |
1664 | return value.vehicle:getAnimationTime(value.dependentAnimation) |
1665 | end, |
1666 | |
1667 | function(value, time) |
1668 | value.vehicle:setAnimationTime(value.dependentAnimation, time, true) |
1669 | end) |
1670 | |
1671 | if self.isServer then |
1672 | self:registerAnimationValueType("rotLimit", "", "", false, AnimationValueFloat, |
1673 | function(value, xmlFile, xmlKey) |
1674 | value.startRotLimit = xmlFile:getValue(xmlKey.."#startRotLimit", nil, true) |
1675 | value.startRotMinLimit = xmlFile:getValue(xmlKey.."#startRotMinLimit", nil, true) |
1676 | value.startRotMaxLimit = xmlFile:getValue(xmlKey.."#startRotMaxLimit", nil, true) |
1677 | |
1678 | if value.startRotLimit ~= nil then |
1679 | value.startRotMinLimit = {-value.startRotLimit[1], -value.startRotLimit[2], -value.startRotLimit[3]} |
1680 | value.startRotMaxLimit = {value.startRotLimit[1], value.startRotLimit[2], value.startRotLimit[3]} |
1681 | end |
1682 | |
1683 | value.endRotLimit = xmlFile:getValue(xmlKey.."#endRotLimit", nil, true) |
1684 | value.endRotMinLimit = xmlFile:getValue(xmlKey.."#endRotMinLimit", nil, true) |
1685 | value.endRotMaxLimit = xmlFile:getValue(xmlKey.."#endRotMaxLimit", nil, true) |
1686 | |
1687 | if value.endRotLimit ~= nil then |
1688 | value.endRotMinLimit = {-value.endRotLimit[1], -value.endRotLimit[2], -value.endRotLimit[3]} |
1689 | value.endRotMaxLimit = {value.endRotLimit[1], value.endRotLimit[2], value.endRotLimit[3]} |
1690 | end |
1691 | |
1692 | local componentJointIndex = xmlFile:getValue(xmlKey.."#componentJointIndex") |
1693 | if componentJointIndex ~= nil then |
1694 | if componentJointIndex >= 1 then |
1695 | value.componentJoint = value.vehicle.componentJoints[componentJointIndex] |
1696 | end |
1697 | |
1698 | if value.componentJoint == nil then |
1699 | Logging.xmlWarning(xmlFile, "Invalid componentJointIndex for animation part '%s'. Indexing starts with 1!", xmlKey) |
1700 | return false |
1701 | end |
1702 | end |
1703 | |
1704 | if (value.endRotMinLimit ~= nil and value.endRotMaxLimit == nil) or (value.endRotMinLimit == nil and value.endRotMaxLimit ~= nil) then |
1705 | Logging.xmlWarning(xmlFile, "Incomplete end trans limit for animation part '%s'.", xmlKey) |
1706 | return false |
1707 | end |
1708 | |
1709 | if value.componentJoint ~= nil and value.endRotMinLimit ~= nil and value.endRotMaxLimit ~= nil then |
1710 | if value.startRotMinLimit ~= nil and value.startRotMaxLimit ~= nil then |
1711 | value.startValue = {value.startRotMinLimit[1], value.startRotMinLimit[2], value.startRotMinLimit[3], value.startRotMaxLimit[1], value.startRotMaxLimit[2], value.startRotMaxLimit[3]} |
1712 | end |
1713 | if value.endRotMinLimit ~= nil and value.endRotMaxLimit ~= nil then |
1714 | value.endValue = {value.endRotMinLimit[1], value.endRotMinLimit[2], value.endRotMinLimit[3], value.endRotMaxLimit[1], value.endRotMaxLimit[2], value.endRotMaxLimit[3]} |
1715 | end |
1716 | |
1717 | if value.endValue == nil then |
1718 | Logging.xmlWarning(xmlFile, "Missing end rot limit for animation part '%s'.", xmlKey) |
1719 | return false |
1720 | end |
1721 | |
1722 | value.endName = "rotLimit" -- only for comparing parts |
1723 | value:setWarningInformation("componentJointIndex: " .. componentJointIndex) |
1724 | value:addCompareParameters("componentJoint") |
1725 | |
1726 | return true |
1727 | end |
1728 | |
1729 | return false |
1730 | end, |
1731 | |
1732 | function(value) |
1733 | return value.componentJoint.rotMinLimit[1], value.componentJoint.rotMinLimit[2], value.componentJoint.rotMinLimit[3], value.componentJoint.rotLimit[1], value.componentJoint.rotLimit[2], value.componentJoint.rotLimit[3] |
1734 | end, |
1735 | |
1736 | function(value, minX, minY, minZ, maxX, maxY, maxZ) |
1737 | value.vehicle:setComponentJointRotLimit(value.componentJoint, 1, minX, maxX) |
1738 | value.vehicle:setComponentJointRotLimit(value.componentJoint, 2, minY, maxY) |
1739 | value.vehicle:setComponentJointRotLimit(value.componentJoint, 3, minZ, maxZ) |
1740 | end) |
1741 | |
1742 | self:registerAnimationValueType("transLimit", "", "", false, AnimationValueFloat, |
1743 | function(value, xmlFile, xmlKey) |
1744 | value.startTransLimit = xmlFile:getValue(xmlKey.."#startTransLimit", nil, true) |
1745 | value.startTransMinLimit = xmlFile:getValue(xmlKey.."#startTransMinLimit", nil, true) |
1746 | value.startTransMaxLimit = xmlFile:getValue(xmlKey.."#startTransMaxLimit", nil, true) |
1747 | |
1748 | if value.startTransLimit ~= nil then |
1749 | value.startTransMinLimit = {-value.startTransLimit[1], -value.startTransLimit[2], -value.startTransLimit[3]} |
1750 | value.startTransMaxLimit = {value.startTransLimit[1], value.startTransLimit[2], value.startTransLimit[3]} |
1751 | end |
1752 | |
1753 | value.endTransLimit = xmlFile:getValue(xmlKey.."#endTransLimit", nil, true) |
1754 | value.endTransMinLimit = xmlFile:getValue(xmlKey.."#endTransMinLimit", nil, true) |
1755 | value.endTransMaxLimit = xmlFile:getValue(xmlKey.."#endTransMaxLimit", nil, true) |
1756 | |
1757 | if value.endTransLimit ~= nil then |
1758 | value.endTransMinLimit = {-value.endTransLimit[1], -value.endTransLimit[2], -value.endTransLimit[3]} |
1759 | value.endTransMaxLimit = {value.endTransLimit[1], value.endTransLimit[2], value.endTransLimit[3]} |
1760 | end |
1761 | |
1762 | local componentJointIndex = xmlFile:getValue(xmlKey.."#componentJointIndex") |
1763 | if componentJointIndex ~= nil then |
1764 | if componentJointIndex >= 1 then |
1765 | value.componentJoint = value.vehicle.componentJoints[componentJointIndex] |
1766 | end |
1767 | |
1768 | if value.componentJoint == nil then |
1769 | Logging.xmlWarning(xmlFile, "Invalid componentJointIndex for animation part '%s'. Indexing starts with 1!", xmlKey) |
1770 | return false |
1771 | end |
1772 | end |
1773 | |
1774 | if (value.endTransMinLimit ~= nil and value.endTransMaxLimit == nil) or (value.endTransMinLimit == nil and value.endTransMaxLimit ~= nil) then |
1775 | Logging.xmlWarning(xmlFile, "Incomplete end trans limit for animation part '%s'.", xmlKey) |
1776 | return false |
1777 | end |
1778 | |
1779 | if value.componentJoint ~= nil and value.endTransMinLimit ~= nil and value.endTransMaxLimit ~= nil then |
1780 | if value.startTransMinLimit ~= nil and value.startTransMaxLimit ~= nil then |
1781 | value.startValue = {value.startTransMinLimit[1], value.startTransMinLimit[2], value.startTransMinLimit[3], value.startTransMaxLimit[1], value.startTransMaxLimit[2], value.startTransMaxLimit[3]} |
1782 | end |
1783 | if value.endTransMinLimit ~= nil and value.endTransMaxLimit ~= nil then |
1784 | value.endValue = {value.endTransMinLimit[1], value.endTransMinLimit[2], value.endTransMinLimit[3], value.endTransMaxLimit[1], value.endTransMaxLimit[2], value.endTransMaxLimit[3]} |
1785 | end |
1786 | |
1787 | if value.endValue == nil then |
1788 | Logging.xmlWarning(xmlFile, "Missing end trans limit for animation part '%s'.", xmlKey) |
1789 | return false |
1790 | end |
1791 | |
1792 | value.endName = "transLimit" -- only for comparing parts |
1793 | value:setWarningInformation("componentJointIndex: " .. componentJointIndex) |
1794 | value:addCompareParameters("componentJoint") |
1795 | |
1796 | return true |
1797 | end |
1798 | |
1799 | return false |
1800 | end, |
1801 | |
1802 | function(value) |
1803 | return value.componentJoint.transMinLimit[1], value.componentJoint.transMinLimit[2], value.componentJoint.transMinLimit[3], value.componentJoint.transLimit[1], value.componentJoint.transLimit[2], value.componentJoint.transLimit[3] |
1804 | end, |
1805 | |
1806 | function(value, minX, minY, minZ, maxX, maxY, maxZ) |
1807 | value.vehicle:setComponentJointTransLimit(value.componentJoint, 1, minX, maxX) |
1808 | value.vehicle:setComponentJointTransLimit(value.componentJoint, 2, minY, maxY) |
1809 | value.vehicle:setComponentJointTransLimit(value.componentJoint, 3, minZ, maxZ) |
1810 | end) |
1811 | |
1812 | self:registerAnimationValueType("componentMass", "startMass", "endMass", false, AnimationValueFloat, |
1813 | function(value, xmlFile, xmlKey) |
1814 | local componentIndex = xmlFile:getValue(xmlKey.."#componentIndex") |
1815 | if componentIndex ~= nil then |
1816 | if componentIndex >= 1 then |
1817 | value.component = value.vehicle.components[componentIndex] |
1818 | end |
1819 | |
1820 | if value.component == nil then |
1821 | Logging.xmlWarning(xmlFile, "Invalid component for animation part '%s'. Indexing starts with 1!", xmlKey) |
1822 | return false |
1823 | end |
1824 | end |
1825 | |
1826 | if value.component ~= nil then |
1827 | value:setWarningInformation("componentIndex: " .. componentIndex) |
1828 | value:addCompareParameters("component") |
1829 | |
1830 | return true |
1831 | end |
1832 | |
1833 | return false |
1834 | end, |
1835 | |
1836 | function(value) |
1837 | return getMass(value.component.node) * 1000 |
1838 | end, |
1839 | |
1840 | function(value, mass) |
1841 | setMass(value.component.node, mass * 0.001) |
1842 | end) |
1843 | |
1844 | self:registerAnimationValueType("centerOfMass", "startCenterOfMass", "endCenterOfMass", false, AnimationValueFloat, |
1845 | function(value, xmlFile, xmlKey) |
1846 | local componentIndex = xmlFile:getValue(xmlKey.."#componentIndex") |
1847 | if componentIndex ~= nil then |
1848 | if componentIndex >= 1 then |
1849 | value.component = value.vehicle.components[componentIndex] |
1850 | end |
1851 | |
1852 | if value.component == nil then |
1853 | Logging.xmlWarning(xmlFile, "Invalid component for animation part '%s'. Indexing starts with 1!", xmlKey) |
1854 | return false |
1855 | end |
1856 | end |
1857 | |
1858 | if value.component ~= nil then |
1859 | value:setWarningInformation("componentIndex: " .. componentIndex) |
1860 | value:addCompareParameters("component") |
1861 | |
1862 | return true |
1863 | end |
1864 | |
1865 | return false |
1866 | end, |
1867 | |
1868 | function(value) |
1869 | return getCenterOfMass(value.component.node) |
1870 | end, |
1871 | |
1872 | function(value, x, y, z) |
1873 | setCenterOfMass(value.component.node, x, y, z) |
1874 | end) |
1875 | |
1876 | self:registerAnimationValueType("frictionVelocity", "startFrictionVelocity", "endFrictionVelocity", false, AnimationValueFloat, loadNodeFunction, |
1877 | function(value) |
1878 | return value.lastFrictionVelocity or 0 |
1879 | end, |
1880 | |
1881 | function(value, velocity) |
1882 | setFrictionVelocity(value.node, velocity) |
1883 | value.lastFrictionVelocity = velocity |
1884 | |
1885 | if value.origTransX == nil then |
1886 | value.origTransX, value.origTransY, value.origTransZ = getTranslation(value.node) |
1887 | end |
1888 | setTranslation(value.node, value.origTransX + math.random()*0.001, value.origTransY, value.origTransZ) |
1889 | end) |
1890 | end |
1891 | |
1892 | self:registerAnimationValueType("spline", "startSplinePos", "endSplinePos", false, AnimationValueFloat, |
1893 | function(value, xmlFile, xmlKey) |
1894 | value.node = xmlFile:getValue(xmlKey .. "#node", nil, value.part.components, value.part.i3dMappings) |
1895 | value.spline = xmlFile:getValue(xmlKey .. "#spline", nil, value.part.components, value.part.i3dMappings) |
1896 | |
1897 | if value.node ~= nil and value.spline ~= nil then |
1898 | value:setWarningInformation("node:" .. getName(value.node) .. " with spline: " .. getName(value.spline)) |
1899 | value:addCompareParameters("node", "spline") |
1900 | |
1901 | return true |
1902 | end |
1903 | |
1904 | return false |
1905 | end, |
1906 | |
1907 | function(value) |
1908 | if value.lastSplineTime ~= nil then |
1909 | return value.lastSplineTime |
1910 | end |
1911 | |
1912 | local startTime = value.startValue or value.endValue |
1913 | if value.animation.currentSpeed < 0 then |
1914 | startTime = value.endValue or value.startValue |
1915 | end |
1916 | |
1917 | return startTime[1] |
1918 | end, |
1919 | |
1920 | function(value, splineTime) |
1921 | local x, y, z = getSplinePosition(value.spline, splineTime % 1) |
1922 | x, y, z = worldToLocal(getParent(value.node), x, y, z) |
1923 | setTranslation(value.node, x, y, z) |
1924 | |
1925 | value.lastSplineTime = splineTime |
1926 | |
1927 | for _, part2 in ipairs(value.animation.parts) do |
1928 | for index=1, #part2.animationValues do |
1929 | local value2 = part2.animationValues[index] |
1930 | if value2.node == value.node then |
1931 | if value2.name == value.name then |
1932 | value2.lastSplineTime = splineTime |
1933 | end |
1934 | end |
1935 | end |
1936 | end |
1937 | end) |
1938 | end |
onUpdate
DescriptionCalled on updateDefinition
onUpdate(float dt, boolean isActiveForInput, boolean isSelected)Arguments
float | dt | time since last call in ms |
boolean | isActiveForInput | true if vehicle is active for input |
boolean | isSelected | true if vehicle is selected |
285 | function AnimatedVehicle:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
286 | AnimatedVehicle.updateAnimations(self, dt) |
287 | |
288 | local spec = self.spec_animatedVehicle |
289 | if spec.fixedTimeSamplesDirtyDelay > 0 then |
290 | spec.fixedTimeSamplesDirtyDelay = spec.fixedTimeSamplesDirtyDelay - 1 |
291 | if spec.fixedTimeSamplesDirtyDelay <= 0 then |
292 | for _, animation in pairs(spec.animations) do |
293 | if spec.activeAnimations[animation.name] == nil then |
294 | if self.isClient then |
295 | for i=1, #animation.samples do |
296 | local sample = animation.samples[i] |
297 | if g_soundManager:getIsSamplePlaying(sample) then |
298 | if sample.loops == 0 then |
299 | g_soundManager:stopSample(sample) |
300 | end |
301 | end |
302 | end |
303 | end |
304 | end |
305 | end |
306 | |
307 | spec.fixedTimeSamplesDirtyDelay = 0 |
308 | end |
309 | end |
310 | |
311 | if spec.numActiveAnimations > 0 then |
312 | self:raiseActive() |
313 | end |
314 | end |
playAnimation
DescriptionPlay animationDefinition
playAnimation(string name, float speed, float animTime, boolean noEventSend)Arguments
string | name | name of animation |
float | speed | speed |
float | animTime | start time |
boolean | noEventSend | no event send |
620 | function AnimatedVehicle:playAnimation(name, speed, animTime, noEventSend, allowSounds) |
621 | local spec = self.spec_animatedVehicle |
622 | |
623 | local animation = spec.animations[name] |
624 | if animation ~= nil then |
625 | SpecializationUtil.raiseEvent(self, "onPlayAnimation", name) |
626 | |
627 | if speed == nil then |
628 | speed = animation.currentSpeed |
629 | end |
630 | |
631 | -- skip animation if speed is not set or 0 to allow skipping animations per xml speed attribute set to 0 |
632 | if speed == nil or speed == 0 then |
633 | return |
634 | end |
635 | |
636 | if animTime == nil then |
637 | if self:getIsAnimationPlaying(name) then |
638 | animTime = self:getAnimationTime(name) |
639 | elseif speed > 0 then |
640 | animTime = 0 |
641 | else |
642 | animTime = 1 |
643 | end |
644 | end |
645 | if noEventSend == nil or noEventSend == false then |
646 | if g_server ~= nil then |
647 | g_server:broadcastEvent(AnimatedVehicleStartEvent.new(self, name, speed, animTime), nil, nil, self) |
648 | else |
649 | g_client:getServerConnection():sendEvent(AnimatedVehicleStartEvent.new(self, name, speed, animTime)) |
650 | end |
651 | end |
652 | |
653 | if spec.activeAnimations[name] == nil then |
654 | spec.activeAnimations[name] = animation |
655 | spec.numActiveAnimations = spec.numActiveAnimations + 1 |
656 | SpecializationUtil.raiseEvent(self, "onStartAnimation", name, speed) |
657 | end |
658 | animation.currentSpeed = speed |
659 | animation.currentTime = animTime*animation.duration |
660 | self:resetAnimationValues(animation) |
661 | |
662 | self:raiseActive() |
663 | end |
664 | end |
postInitializeAnimationPart
DescriptionPost Initialize part of animation (normally used to set default start value if not set by the end value of the previous part)Definition
postInitializeAnimationPart(table part)Arguments
table | part | part |
607 | function AnimatedVehicle:postInitializeAnimationPart(animation, part, i, numParts) |
608 | for index=1, #part.animationValues do |
609 | part.animationValues[index]:postInit() |
610 | end |
611 | end |
prerequisitesPresent
DescriptionChecks if all prerequisite specializations are loadedDefinition
prerequisitesPresent(table specializations)Arguments
table | specializations | specializations |
boolean | hasPrerequisite | true if all prerequisite specializations are loaded |
25 | function AnimatedVehicle.prerequisitesPresent(specializations) |
26 | return true |
27 | end |
registerAnimationValueType
DescriptionDefinitionregisterAnimationValueType()Code
318 | function AnimatedVehicle:registerAnimationValueType(name, startName, endName, initialUpdate, classObject, load, get, set) |
319 | local spec = self.spec_animatedVehicle |
320 | |
321 | if spec.animationValueTypes[name] == nil then |
322 | local animationValueType = {} |
323 | |
324 | animationValueType.classObject = classObject |
325 | animationValueType.name = name |
326 | animationValueType.startName = startName |
327 | animationValueType.endName = endName |
328 | animationValueType.initialUpdate = initialUpdate |
329 | animationValueType.load = load |
330 | animationValueType.get = get |
331 | animationValueType.set = set |
332 | |
333 | spec.animationValueTypes[name] = animationValueType |
334 | end |
335 | end |
registerAnimationXMLPaths
DescriptionDefinitionregisterAnimationXMLPaths()Code
55 | function AnimatedVehicle.registerAnimationXMLPaths(schema, basePath) |
56 | schema:register(XMLValueType.STRING, basePath .. "#name", "Name of animation") |
57 | schema:register(XMLValueType.BOOL, basePath .. "#looping", "Animation is looping", false) |
58 | schema:register(XMLValueType.BOOL, basePath .. "#resetOnStart", "Animation is reseted while loading the vehicle", true) |
59 | schema:register(XMLValueType.FLOAT, basePath .. "#startAnimTime", "Animation is set to this time if resetOnStart is set", 0) |
60 | schema:register(XMLValueType.FLOAT, basePath .. "#soundVolumeFactor", "Sound volume factor that is applied for all sounds in this animation", 1) |
61 | schema:register(XMLValueType.BOOL, basePath .. "#isKeyframe", "Is static keyframe animation instead of dynamically interpolating animation (Keyframe animations only support trans/rot/scale!)", false) |
62 | |
63 | schema:addDelayedRegistrationPath(basePath .. ".part(?)", "AnimatedVehicle:part") |
64 | |
65 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".part(?)#node", "Part node") |
66 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#startTime", "Start time") |
67 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#duration", "Duration") |
68 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#endTime", "End time") |
69 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#time", "Keyframe time (only for keyframe animations)") |
70 | schema:register(XMLValueType.INT, basePath .. ".part(?)#direction", "Part direction", 0) |
71 | schema:register(XMLValueType.STRING, basePath .. ".part(?)#tangentType", "Type of tangent to be used (linear, spline, step)", "linear") |
72 | |
73 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#startRot", "Start rotation") |
74 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#endRot", "End rotation") |
75 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#startTrans", "Start translation") |
76 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#endTrans", "End translation") |
77 | schema:register(XMLValueType.VECTOR_SCALE, basePath .. ".part(?)#startScale", "Start scale") |
78 | schema:register(XMLValueType.VECTOR_SCALE, basePath .. ".part(?)#endScale", "End scale") |
79 | schema:register(XMLValueType.BOOL, basePath .. ".part(?)#visibility", "Visibility") |
80 | schema:register(XMLValueType.BOOL, basePath .. ".part(?)#startVisibility", "Visibility at start time (switched in the middle)") |
81 | schema:register(XMLValueType.BOOL, basePath .. ".part(?)#endVisibility", "Visibility at end time (switched in the middle)") |
82 | schema:register(XMLValueType.INT, basePath .. ".part(?)#componentJointIndex", "Component joint index") |
83 | |
84 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#rotation", "Rotation (only for keyframe animations)") |
85 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#translation", "Translation (only for keyframe animations)") |
86 | schema:register(XMLValueType.VECTOR_SCALE, basePath .. ".part(?)#scale", "Scale (only for keyframe animations)") |
87 | |
88 | schema:register(XMLValueType.STRING, basePath .. ".part(?)#requiredAnimation", "Required animation needs to be in a specific range to play part") |
89 | schema:register(XMLValueType.VECTOR_2, basePath .. ".part(?)#requiredAnimationRange", "Animation range of required animation") |
90 | |
91 | schema:register(XMLValueType.STRING, basePath .. ".part(?)#requiredConfigurationName", "This configuration needs to bet set to #requiredConfigurationIndex") |
92 | schema:register(XMLValueType.INT, basePath .. ".part(?)#requiredConfigurationIndex", "Required configuration needs to be in this state to activate the animation part") |
93 | |
94 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#startRotLimit", "Start rotation limit") |
95 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#startRotMinLimit", "Start rotation min limit") |
96 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#startRotMaxLimit", "Start rotation max limit") |
97 | |
98 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#endRotLimit", "End rotation limit") |
99 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#endRotMinLimit", "End rotation min limit") |
100 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#endRotMaxLimit", "End rotation max limit") |
101 | |
102 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#startTransLimit", "Start translation limit") |
103 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#startTransMinLimit", "Start translation min limit") |
104 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#startTransMaxLimit", "Start translation max limit") |
105 | |
106 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#endTransLimit", "End translation limit") |
107 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#endTransMinLimit", "End translation min limit") |
108 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#endTransMaxLimit", "End translation max limit") |
109 | |
110 | schema:register(XMLValueType.INT, basePath .. ".part(?)#componentIndex", "Component index") |
111 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#startMass", "Start mass of component") |
112 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#startCenterOfMass", "Start center of mass") |
113 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#endMass", "End mass of component") |
114 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#endCenterOfMass", "End center of mass") |
115 | |
116 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#startFrictionVelocity", "Start friction velocity applied to node") |
117 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#endFrictionVelocity", "End friction velocity applied to node") |
118 | |
119 | schema:register(XMLValueType.STRING, basePath .. ".part(?)#shaderParameter", "Shader parameter") |
120 | schema:register(XMLValueType.STRING, basePath .. ".part(?)#shaderParameterPrev", "Shader parameter (prev)") |
121 | schema:register(XMLValueType.VECTOR_4, basePath .. ".part(?)#shaderStartValues", "Start shader values") |
122 | schema:register(XMLValueType.VECTOR_4, basePath .. ".part(?)#shaderEndValues", "End shader values") |
123 | |
124 | schema:register(XMLValueType.STRING, basePath .. ".part(?)#animationClip", "Animation clip name") |
125 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#clipStartTime", "Animation clip start time") |
126 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#clipEndTime", "Animation clip end time") |
127 | |
128 | schema:register(XMLValueType.STRING, basePath .. ".part(?)#dependentAnimation", "Dependent animation name") |
129 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#dependentAnimationStartTime", "Dependent animation start time") |
130 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#dependentAnimationEndTime", "Dependent animation end time") |
131 | |
132 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".part(?)#spline", "Spline node") |
133 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#startSplinePos", "Start spline position") |
134 | schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#endSplinePos", "End spline position") |
135 | |
136 | SoundManager.registerSampleXMLPaths(schema, basePath, "sound(?)") |
137 | schema:register(XMLValueType.TIME, basePath .. ".sound(?)#startTime", "Start play time", 0) |
138 | schema:register(XMLValueType.TIME, basePath .. ".sound(?)#endTime", "End play time for loops or used on oposite direction") |
139 | schema:register(XMLValueType.INT, basePath .. ".sound(?)#direction", "Direction to play the sound (0 = any direction)", 0) |
140 | |
141 | SoundManager.registerSampleXMLPaths(schema, basePath, "stopTimePosSound(?)") |
142 | SoundManager.registerSampleXMLPaths(schema, basePath, "stopTimeNegSound(?)") |
143 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
198 | function AnimatedVehicle.registerEventListeners(vehicleType) |
199 | SpecializationUtil.registerEventListener(vehicleType, "onPreLoad", AnimatedVehicle) |
200 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", AnimatedVehicle) |
201 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", AnimatedVehicle) |
202 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", AnimatedVehicle) |
203 | SpecializationUtil.registerEventListener(vehicleType, "onUpdate", AnimatedVehicle) |
204 | SpecializationUtil.registerEventListener(vehicleType, "onRegisterAnimationValueTypes", AnimatedVehicle) |
205 | end |
registerEvents
DescriptionDefinitionregisterEvents()Code
147 | function AnimatedVehicle.registerEvents(vehicleType) |
148 | SpecializationUtil.registerEvent(vehicleType, "onRegisterAnimationValueTypes") |
149 | SpecializationUtil.registerEvent(vehicleType, "onPlayAnimation") |
150 | SpecializationUtil.registerEvent(vehicleType, "onStartAnimation") |
151 | SpecializationUtil.registerEvent(vehicleType, "onUpdateAnimation") |
152 | SpecializationUtil.registerEvent(vehicleType, "onFinishAnimation") |
153 | SpecializationUtil.registerEvent(vehicleType, "onStopAnimation") |
154 | SpecializationUtil.registerEvent(vehicleType, "onAnimationPartChanged") |
155 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
159 | function AnimatedVehicle.registerFunctions(vehicleType) |
160 | SpecializationUtil.registerFunction(vehicleType, "registerAnimationValueType", AnimatedVehicle.registerAnimationValueType) |
161 | SpecializationUtil.registerFunction(vehicleType, "loadAnimation", AnimatedVehicle.loadAnimation) |
162 | SpecializationUtil.registerFunction(vehicleType, "loadAnimationPart", AnimatedVehicle.loadAnimationPart) |
163 | SpecializationUtil.registerFunction(vehicleType, "loadStaticAnimationPart", AnimatedVehicle.loadStaticAnimationPart) |
164 | SpecializationUtil.registerFunction(vehicleType, "loadStaticAnimationPartValues", AnimatedVehicle.loadStaticAnimationPartValues) |
165 | SpecializationUtil.registerFunction(vehicleType, "initializeAnimationParts", AnimatedVehicle.initializeAnimationParts) |
166 | SpecializationUtil.registerFunction(vehicleType, "initializeAnimationPart", AnimatedVehicle.initializeAnimationPart) |
167 | SpecializationUtil.registerFunction(vehicleType, "postInitializeAnimationPart", AnimatedVehicle.postInitializeAnimationPart) |
168 | SpecializationUtil.registerFunction(vehicleType, "playAnimation", AnimatedVehicle.playAnimation) |
169 | SpecializationUtil.registerFunction(vehicleType, "stopAnimation", AnimatedVehicle.stopAnimation) |
170 | SpecializationUtil.registerFunction(vehicleType, "getAnimationExists", AnimatedVehicle.getAnimationExists) |
171 | SpecializationUtil.registerFunction(vehicleType, "getAnimationByName", AnimatedVehicle.getAnimationByName) |
172 | SpecializationUtil.registerFunction(vehicleType, "getIsAnimationPlaying", AnimatedVehicle.getIsAnimationPlaying) |
173 | SpecializationUtil.registerFunction(vehicleType, "getRealAnimationTime", AnimatedVehicle.getRealAnimationTime) |
174 | SpecializationUtil.registerFunction(vehicleType, "setRealAnimationTime", AnimatedVehicle.setRealAnimationTime) |
175 | SpecializationUtil.registerFunction(vehicleType, "getAnimationTime", AnimatedVehicle.getAnimationTime) |
176 | SpecializationUtil.registerFunction(vehicleType, "setAnimationTime", AnimatedVehicle.setAnimationTime) |
177 | SpecializationUtil.registerFunction(vehicleType, "getAnimationDuration", AnimatedVehicle.getAnimationDuration) |
178 | SpecializationUtil.registerFunction(vehicleType, "setAnimationSpeed", AnimatedVehicle.setAnimationSpeed) |
179 | SpecializationUtil.registerFunction(vehicleType, "getAnimationSpeed", AnimatedVehicle.getAnimationSpeed) |
180 | SpecializationUtil.registerFunction(vehicleType, "setAnimationStopTime", AnimatedVehicle.setAnimationStopTime) |
181 | SpecializationUtil.registerFunction(vehicleType, "resetAnimationValues", AnimatedVehicle.resetAnimationValues) |
182 | SpecializationUtil.registerFunction(vehicleType, "resetAnimationPartValues", AnimatedVehicle.resetAnimationPartValues) |
183 | SpecializationUtil.registerFunction(vehicleType, "updateAnimationPart", AnimatedVehicle.updateAnimationPart) |
184 | SpecializationUtil.registerFunction(vehicleType, "getNumOfActiveAnimations", AnimatedVehicle.getNumOfActiveAnimations) |
185 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
189 | function AnimatedVehicle.registerOverwrittenFunctions(vehicleType) |
190 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadSpeedRotatingPartFromXML", AnimatedVehicle.loadSpeedRotatingPartFromXML) |
191 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsSpeedRotatingPartActive", AnimatedVehicle.getIsSpeedRotatingPartActive) |
192 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadWorkAreaFromXML", AnimatedVehicle.loadWorkAreaFromXML) |
193 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsWorkAreaActive", AnimatedVehicle.getIsWorkAreaActive) |
194 | end |
resetAnimationPartValues
DescriptionResets animation partDefinition
resetAnimationPartValues(table part)Arguments
table | part | part to reset |
880 | function AnimatedVehicle:resetAnimationPartValues(part) |
881 | for index=1, #part.animationValues do |
882 | part.animationValues[index]:reset() |
883 | end |
884 | end |
resetAnimationValues
DescriptionResets animation valuesDefinition
resetAnimationValues(table animation)Arguments
table | animation | animation |
870 | function AnimatedVehicle:resetAnimationValues(animation) |
871 | AnimatedVehicle.findCurrentPartIndex(animation) |
872 | for _, part in ipairs(animation.parts) do |
873 | self:resetAnimationPartValues(part) |
874 | end |
875 | end |
setAnimationSpeed
DescriptionSets speed of animationDefinition
setAnimationSpeed(string name, float speed)Arguments
string | name | name of animation |
float | speed | speed |
823 | function AnimatedVehicle:setAnimationSpeed(name, speed) |
824 | local spec = self.spec_animatedVehicle |
825 | |
826 | local animation = spec.animations[name] |
827 | if animation ~= nil then |
828 | local speedReversed = false |
829 | if (animation.currentSpeed > 0) ~= (speed > 0) then |
830 | speedReversed = true |
831 | end |
832 | animation.currentSpeed = speed |
833 | if self:getIsAnimationPlaying(name) and speedReversed then |
834 | self:resetAnimationValues(animation) |
835 | end |
836 | end |
837 | end |
setAnimationStopTime
DescriptionSets animation stop timeDefinition
setAnimationStopTime(string name, float stopTime)Arguments
string | name | name of animation |
float | stopTime | stop time [0..1] |
858 | function AnimatedVehicle:setAnimationStopTime(name, stopTime) |
859 | local spec = self.spec_animatedVehicle |
860 | |
861 | local animation = spec.animations[name] |
862 | if animation ~= nil then |
863 | animation.stopTime = stopTime*animation.duration |
864 | end |
865 | end |
setAnimationTime
DescriptionSet animation timeDefinition
setAnimationTime(string name, float animTime, boolean update)Arguments
string | name | name of animation |
float | animTime | animation time [0..1] |
boolean | update | update animation |
792 | function AnimatedVehicle:setAnimationTime(name, animTime, update, playSounds) |
793 | local spec = self.spec_animatedVehicle |
794 | |
795 | if spec.animations == nil then |
796 | printCallstack() |
797 | end |
798 | |
799 | local animation = spec.animations[name] |
800 | if animation ~= nil then |
801 | self:setRealAnimationTime(name, animTime*animation.duration, update, playSounds) |
802 | end |
803 | end |
setMovedLimitedValues3
DescriptionSets moved limited values (3)Definition
setMovedLimitedValues3(table currentValues, table destValues, table speeds, float dt)Arguments
table | currentValues | current values |
table | destValues | dest values |
table | speeds | speeds |
float | dt | time since last call in ms |
1072 | function AnimatedVehicle.setMovedLimitedValues3(currentValues, destValues, speeds, dt) |
1073 | return AnimatedVehicle.setMovedLimitedValuesN(3, currentValues, destValues, speeds, dt) |
1074 | end |
setMovedLimitedValues4
DescriptionSets moved limited values (4)Definition
setMovedLimitedValues4(table currentValues, table destValues, table speeds, float dt)Arguments
table | currentValues | current values |
table | destValues | dest values |
table | speeds | speeds |
float | dt | time since last call in ms |
1082 | function AnimatedVehicle.setMovedLimitedValues4(currentValues, destValues, speeds, dt) |
1083 | return AnimatedVehicle.setMovedLimitedValuesN(4, currentValues, destValues, speeds, dt) |
1084 | end |
setMovedLimitedValuesN
DescriptionSets moved limited values on N valuesDefinition
setMovedLimitedValuesN(int n, table currentValues, table destValues, table speeds, float dt)Arguments
int | n | number of values |
table | currentValues | current values |
table | destValues | dest values |
table | speeds | speeds |
float | dt | time since last call in ms |
1054 | function AnimatedVehicle.setMovedLimitedValuesN(n, currentValues, destValues, speeds, dt) |
1055 | local hasChanged = false |
1056 | for i=1, n do |
1057 | local newValue = AnimatedVehicle.getMovedLimitedValue(currentValues[i], destValues[i], speeds[i], dt) |
1058 | if currentValues[i] ~= newValue then |
1059 | hasChanged = true |
1060 | currentValues[i] = newValue |
1061 | end |
1062 | end |
1063 | return hasChanged |
1064 | end |
setRealAnimationTime
DescriptionSet animation real timeDefinition
setRealAnimationTime(string name, float animTime, boolean update)Arguments
string | name | name of animation |
float | animTime | real animation time in ms |
boolean | update | update animation |
750 | function AnimatedVehicle:setRealAnimationTime(name, animTime, update, playSounds) |
751 | local spec = self.spec_animatedVehicle |
752 | |
753 | local animation = spec.animations[name] |
754 | if animation ~= nil then |
755 | if update == nil or update then |
756 | local currentSpeed = animation.currentSpeed |
757 | animation.currentSpeed = 1 |
758 | if animation.currentTime > animTime then |
759 | animation.currentSpeed = -1 |
760 | end |
761 | |
762 | self:resetAnimationValues(animation) |
763 | |
764 | local dtToUse, _ = AnimatedVehicle.updateAnimationCurrentTime(self, animation, 99999999, animTime) |
765 | AnimatedVehicle.updateAnimation(self, animation, dtToUse, true, true, playSounds) |
766 | animation.currentSpeed = currentSpeed |
767 | else |
768 | animation.currentTime = animTime |
769 | end |
770 | end |
771 | end |
stopAnimation
DescriptionStop animationDefinition
stopAnimation(string name, boolean noEventSend)Arguments
string | name | name of animation |
boolean | noEventSend | no event send |
670 | function AnimatedVehicle:stopAnimation(name, noEventSend) |
671 | local spec = self.spec_animatedVehicle |
672 | |
673 | if noEventSend == nil or noEventSend == false then |
674 | if g_server ~= nil then |
675 | g_server:broadcastEvent(AnimatedVehicleStopEvent.new(self, name), nil, nil, self) |
676 | else |
677 | g_client:getServerConnection():sendEvent(AnimatedVehicleStopEvent.new(self, name)) |
678 | end |
679 | end |
680 | local animation = spec.animations[name] |
681 | if animation ~= nil then |
682 | SpecializationUtil.raiseEvent(self, "onStopAnimation", name) |
683 | animation.stopTime = nil |
684 | |
685 | if self.isClient then |
686 | for i=1, #animation.samples do |
687 | local sample = animation.samples[i] |
688 | if sample.loops == 0 then |
689 | g_soundManager:stopSample(sample) |
690 | end |
691 | end |
692 | end |
693 | end |
694 | |
695 | if spec.activeAnimations[name] ~= nil then |
696 | spec.numActiveAnimations = spec.numActiveAnimations - 1 |
697 | spec.activeAnimations[name] = nil |
698 | SpecializationUtil.raiseEvent(self, "onFinishAnimation", name) |
699 | end |
700 | end |
updateAnimation
DescriptionUpdate animationDefinition
updateAnimation(table anim, float dtToUse, boolean stopAnimation, boolean fixedTimeUpdate, playSounds playSounds)Arguments
table | anim | animation |
float | dtToUse | dt to use |
boolean | stopAnimation | stop animation |
boolean | fixedTimeUpdate | is a fixed time update (e.g. from setAnimationTime) -> no sound, no looping, fixed setting between start and end values |
playSounds | playSounds | if true it still plays sounds while doing fixed time updates |
1210 | function AnimatedVehicle.updateAnimation(self, anim, dtToUse, stopAnim, fixedTimeUpdate, playSounds) |
1211 | local spec = self.spec_animatedVehicle |
1212 | local isStopTimeStop = stopAnim |
1213 | |
1214 | local numParts = #anim.parts |
1215 | local parts = anim.parts |
1216 | if anim.currentSpeed < 0 then |
1217 | parts = anim.partsReverse |
1218 | end |
1219 | |
1220 | if dtToUse > 0 then |
1221 | local hasChanged = false |
1222 | local nothingToChangeYet = false |
1223 | |
1224 | if not anim.isKeyframe then |
1225 | for partI=anim.currentPartIndex, numParts do |
1226 | local part = parts[partI] |
1227 | |
1228 | local isInRange = true |
1229 | if part.requiredAnimation ~= nil then |
1230 | local time = self:getAnimationTime(part.requiredAnimation) |
1231 | if time < part.requiredAnimationRange[1] or time > part.requiredAnimationRange[2] then |
1232 | isInRange = false |
1233 | end |
1234 | end |
1235 | |
1236 | local sameConfiguration = true |
1237 | if part.requiredConfigurationName ~= nil then |
1238 | if self.configurations[part.requiredConfigurationName] ~= nil then |
1239 | if self.configurations[part.requiredConfigurationName] ~= part.requiredConfigurationIndex then |
1240 | sameConfiguration = false |
1241 | end |
1242 | end |
1243 | end |
1244 | |
1245 | if (part.direction == 0 or ((part.direction > 0) == (anim.currentSpeed >= 0))) and isInRange and sameConfiguration then |
1246 | local durationToEnd = AnimatedVehicle.getDurationToEndOfPart(part, anim) |
1247 | |
1248 | -- is this part not playing yet? |
1249 | if durationToEnd > part.duration then |
1250 | nothingToChangeYet = true |
1251 | break |
1252 | end |
1253 | |
1254 | local realDt = dtToUse |
1255 | |
1256 | if anim.currentSpeed > 0 then |
1257 | local startT = anim.currentTime-dtToUse |
1258 | if startT < part.startTime then |
1259 | realDt = dtToUse - part.startTime + startT |
1260 | end |
1261 | else |
1262 | local startT = anim.currentTime+dtToUse |
1263 | local endTime = part.startTime + part.duration |
1264 | if startT > endTime then |
1265 | realDt = dtToUse - (startT - endTime) |
1266 | end |
1267 | end |
1268 | |
1269 | durationToEnd = durationToEnd + realDt |
1270 | |
1271 | if self:updateAnimationPart(anim, part, durationToEnd, dtToUse, realDt, fixedTimeUpdate) then |
1272 | hasChanged = true |
1273 | end |
1274 | end |
1275 | |
1276 | if partI == anim.currentPartIndex then |
1277 | -- is this part finished? |
1278 | if (anim.currentSpeed > 0 and part.startTime + part.duration < anim.currentTime) or |
1279 | (anim.currentSpeed <= 0 and part.startTime > anim.currentTime) |
1280 | then |
1281 | self:resetAnimationPartValues(part) |
1282 | anim.currentPartIndex = anim.currentPartIndex+1 |
1283 | end |
1284 | end |
1285 | end |
1286 | if not nothingToChangeYet and not hasChanged and anim.currentPartIndex >= numParts then |
1287 | -- end the animation |
1288 | anim.previousTime = anim.currentTime |
1289 | if anim.currentSpeed > 0 then |
1290 | anim.currentTime = anim.duration |
1291 | else |
1292 | anim.currentTime = 0 |
1293 | end |
1294 | stopAnim = true |
1295 | end |
1296 | else |
1297 | for node, curve in pairs(anim.curvesByNode) do |
1298 | local x, y, z, rx, ry, rz, sx, sy, sz = curve:get(anim.currentTime) |
1299 | if curve.hasTranslation then |
1300 | setTranslation(node, x, y, z) |
1301 | end |
1302 | if curve.hasRotation then |
1303 | setRotation(node, rx, ry, rz) |
1304 | end |
1305 | if curve.hasScale then |
1306 | setScale(node, sx, sy, sz) |
1307 | end |
1308 | |
1309 | SpecializationUtil.raiseEvent(self, "onAnimationPartChanged", node) |
1310 | end |
1311 | |
1312 | stopAnim = anim.currentTime <= 0 or anim.currentTime >= anim.duration |
1313 | end |
1314 | |
1315 | if spec.activeAnimations[anim.name] ~= nil or playSounds == true then |
1316 | if fixedTimeUpdate ~= true or playSounds == true then |
1317 | for i=1, #anim.samples do |
1318 | local sample = anim.samples[i] |
1319 | if g_soundManager:getIsSamplePlaying(sample) then |
1320 | if sample.endTime ~= nil then |
1321 | if anim.currentSpeed > 0 then |
1322 | if anim.currentTime > sample.endTime then |
1323 | g_soundManager:stopSample(sample) |
1324 | end |
1325 | else |
1326 | if anim.currentTime < sample.startTime then |
1327 | g_soundManager:stopSample(sample) |
1328 | end |
1329 | end |
1330 | end |
1331 | else |
1332 | if sample.direction == 0 or ((sample.direction >= 0) == (anim.currentSpeed >= 0)) then |
1333 | if sample.loops ~= 0 then |
1334 | if sample.endTime ~= nil then |
1335 | sample.readyToStart = anim.previousTime < sample.startTime or anim.previousTime > sample.endTime |
1336 | else |
1337 | if anim.currentSpeed < 0 then |
1338 | sample.readyToStart = anim.previousTime > sample.startTime |
1339 | |
1340 | else |
1341 | sample.readyToStart = anim.previousTime < sample.startTime |
1342 | end |
1343 | end |
1344 | else |
1345 | sample.readyToStart = true |
1346 | end |
1347 | |
1348 | local inRange = anim.currentTime >= sample.startTime |
1349 | if sample.endTime ~= nil then |
1350 | inRange = anim.currentTime >= sample.startTime and anim.currentTime <= sample.endTime |
1351 | else |
1352 | if anim.currentSpeed < 0 then |
1353 | inRange = anim.currentTime <= sample.startTime |
1354 | end |
1355 | end |
1356 | |
1357 | if sample.readyToStart and inRange then |
1358 | g_soundManager:playSample(sample) |
1359 | end |
1360 | end |
1361 | end |
1362 | end |
1363 | end |
1364 | |
1365 | SpecializationUtil.raiseEvent(self, "onUpdateAnimation", anim.name) |
1366 | |
1367 | if spec.activeAnimations[anim.name] == nil then |
1368 | spec.fixedTimeSamplesDirtyDelay = 2 |
1369 | end |
1370 | end |
1371 | end |
1372 | if stopAnim or (numParts > 0 and (anim.currentPartIndex > numParts or anim.currentPartIndex < 1)) then |
1373 | anim.previousTime = anim.currentTime |
1374 | if not stopAnim then |
1375 | if anim.currentSpeed > 0 then |
1376 | anim.currentTime = anim.duration |
1377 | else |
1378 | anim.currentTime = 0 |
1379 | end |
1380 | end |
1381 | anim.currentTime = math.min(math.max(anim.currentTime, 0), anim.duration) |
1382 | local allowLooping = anim.stopTime ~= anim.currentTime |
1383 | anim.stopTime = nil |
1384 | if spec.activeAnimations[anim.name] ~= nil then |
1385 | spec.numActiveAnimations = spec.numActiveAnimations - 1 |
1386 | |
1387 | if self.isClient then |
1388 | local animation = spec.activeAnimations[anim.name] |
1389 | for i=1, #animation.samples do |
1390 | local sample = animation.samples[i] |
1391 | if sample.loops == 0 then |
1392 | g_soundManager:stopSample(sample) |
1393 | end |
1394 | end |
1395 | |
1396 | if isStopTimeStop then |
1397 | if anim.currentSpeed > 0 then |
1398 | for i=1, #animation.eventSamples.stopTimePos do |
1399 | g_soundManager:playSample(animation.eventSamples.stopTimePos[i]) |
1400 | end |
1401 | else |
1402 | for i=1, #animation.eventSamples.stopTimeNeg do |
1403 | g_soundManager:playSample(animation.eventSamples.stopTimeNeg[i]) |
1404 | end |
1405 | end |
1406 | end |
1407 | end |
1408 | |
1409 | spec.activeAnimations[anim.name] = nil |
1410 | SpecializationUtil.raiseEvent(self, "onFinishAnimation", anim.name) |
1411 | end |
1412 | |
1413 | if allowLooping and fixedTimeUpdate ~= true then |
1414 | if anim.looping then |
1415 | -- restart animation |
1416 | self:setAnimationTime(anim.name, math.abs((anim.currentTime/anim.duration) - 1), true) |
1417 | self:playAnimation(anim.name, anim.currentSpeed, nil, true) |
1418 | end |
1419 | end |
1420 | end |
1421 | end |
updateAnimationByName
DescriptionUpdate animation by nameDefinition
updateAnimationByName(string animName, float dt)Arguments
string | animName | name of animation to update |
float | dt | time since last call in ms |
1161 | function AnimatedVehicle.updateAnimationByName(self, animName, dt, fixedTimeUpdate) |
1162 | local spec = self.spec_animatedVehicle |
1163 | |
1164 | local anim = spec.animations[animName] |
1165 | if anim ~= nil then |
1166 | local dtToUse, stopAnim = AnimatedVehicle.updateAnimationCurrentTime(self, anim, dt, anim.stopTime) |
1167 | AnimatedVehicle.updateAnimation(self, anim, dtToUse, stopAnim, fixedTimeUpdate) |
1168 | end |
1169 | end |
updateAnimationCurrentTime
DescriptionUpdate current animation timeDefinition
updateAnimationCurrentTime(table anim, float dt, float stopTime)Arguments
table | anim | animation |
float | dt | time since last call in ms |
float | stopTime | stop time |
float | dtToUse | dt to use |
boolean | stopAnimation | stop animation |
1178 | function AnimatedVehicle.updateAnimationCurrentTime(self, anim, dt, stopTime) |
1179 | anim.previousTime = anim.currentTime |
1180 | anim.currentTime = anim.currentTime + dt*anim.currentSpeed |
1181 | |
1182 | local absSpeed = math.abs(anim.currentSpeed) |
1183 | local dtToUse = dt*absSpeed |
1184 | local stopAnim = false |
1185 | if stopTime ~= nil then |
1186 | if anim.currentSpeed > 0 then |
1187 | if stopTime <= anim.currentTime then |
1188 | dtToUse = dtToUse-(anim.currentTime-stopTime) |
1189 | anim.currentTime = stopTime |
1190 | stopAnim = true |
1191 | end |
1192 | else |
1193 | if stopTime >= anim.currentTime then |
1194 | dtToUse = dtToUse-(stopTime-anim.currentTime) |
1195 | anim.currentTime = stopTime |
1196 | stopAnim = true |
1197 | end |
1198 | end |
1199 | end |
1200 | return dtToUse, stopAnim |
1201 | end |
updateAnimationPart
DescriptionUpdate animation partDefinition
updateAnimationPart(table anim, table part, float durationToEnd, float dtToUse, float realDt)Arguments
table | anim | animation |
table | part | part |
float | durationToEnd | duration to end |
float | dtToUse | dt to use |
float | realDt | real dt |
1430 | function AnimatedVehicle:updateAnimationPart(animation, part, durationToEnd, dtToUse, realDt, fixedTimeUpdate) |
1431 | local hasPartChanged = false |
1432 | |
1433 | for index=1, #part.animationValues do |
1434 | local valueChanged = part.animationValues[index]:update(durationToEnd, dtToUse, realDt, fixedTimeUpdate) |
1435 | hasPartChanged = hasPartChanged or valueChanged |
1436 | end |
1437 | |
1438 | return hasPartChanged |
1439 | end |
updateAnimations
DescriptionUpdate animationsDefinition
updateAnimations(float dt)Arguments
float | dt | time since last call in ms |
1148 | function AnimatedVehicle.updateAnimations(self, dt, fixedTimeUpdate) |
1149 | local spec = self.spec_animatedVehicle |
1150 | |
1151 | for _, anim in pairs(spec.activeAnimations) do |
1152 | local dtToUse, stopAnim = AnimatedVehicle.updateAnimationCurrentTime(self, anim, dt, anim.stopTime) |
1153 | AnimatedVehicle.updateAnimation(self, anim, dtToUse, stopAnim, fixedTimeUpdate) |
1154 | end |
1155 | end |