[Closed] Help improving a keyframe script
Okay, so I’ve got a script that looks at a selected object and drills down through its subanimations to create an array of all the object’s keyframes.
I’d like to modify it to be able to work with multiple objects, i.e. to create a single array that stores every keyframe in a specified collection exactly once.
Ideally I’d like also like to be able to do this as one function, but can’t figure out how to make that work (recursive functions always give me a headache).
Any takers?
EDIT: Just realized there is a problem with this script. It doesn’t actually quite work, but I’m having trouble figuring out why.
fn collectFrames ctrl theFrames =
(
for i = 1 to ctrl.numSubs do
(
theKeys = ctrl[i].keys
if theKeys != undefined do
(
ctrlFrames = (for k = 1 to theKeys.count collect ((theKeys[k].time as integer) / ticksPerFrame) + 1) as bitArray
theFrames += ctrlFrames
collectFrames ctrl[i]
)
catch()
)
local frameArray = theFrames as array
for f = 1 to frameArray.count do frameArray[f] -= 1
frameArray
)
fn getSelObjFrames =
(
if selection.count == 1 do
(
theFrames = #{}
frameArray = collectFrames selection[1][#transform] theFrames
theFrames = undefined
frameArray
)
)
getSelObjFrames()
I have this much working, but it requires a global variable, so I’m not sure if I’m moving forward or backward here…
frameBitArray = #{}
fn collectFrames ctrl =
(
for i = 1 to ctrl.numSubs do
(
theKeys = ctrl[i].keys
if theKeys != undefined do
(
ctrlFrames = (for k = 1 to theKeys.count collect ((theKeys[k].time as integer) / ticksPerFrame) + 1) as bitArray
frameBitArray += ctrlFrames
collectFrames ctrl[i]
)
)
local frameArray = frameBitArray as array
for f = 1 to frameArray.count do frameArray[f] -= 1
frameArray
)
collectFrames $
See if this is what you’re looking for:
(
fn collectAllKeyTimes inSubAnim =
(
local keyTimes = #()
if inSubAnim != undefined then
(
if isController inSubAnim.controller then
keyTimes = for k in inSubAnim.controller.keys collect k.time.frame
for i = 1 to inSubAnim.numSubs do
join keyTimes (collectAllKeyTimes inSubAnim[i])
keyTimes = makeUniqueArray keyTimes
)
return keyTimes
)
local allKeys = #()
for o in selection do
(
local keys = collectAllKeyTimes o
join allKeys keys
allKeys = makeUniqueArray allKeys
)
sort allKeys
print allKeys
)
cheers,
o
That seems to work! I’ll give it a closer look in a little bit when I get the chance. Thanks
It’s working really well for me, thanks for the help! Now I want to do something related but a little bit different, maybe you can point me in the right direction?
Basically, I’d like a function that will return an array of an object’s sub-animation keyframes, using the format of the sub-animation’s index followed by an array of the track’s keyframes (only for tracks that have any). Basically looking for an output like
#($objName[3][1][1], #(0,17)), #($objName[3][1][2], #(0,5)), #($objName[3][1][3], #(5,17)), #($objName[3][2][1], #(0,20)))
If that makes any sense.
do you want to make your own format to save and load animation?
do you known that the LoadSaveAnimation Core Interface at least tries to do the same? and!.. it does do it!.. and it does do it not bad.
the only thing that you need to do is the parse the data… look at an XAF file. it’s just an XML file.
read it, and get whatever you need.
Thanks, but actually, that’s not what I’m doing. I want to try and set up something to keep track of changes to sub-animations in real time, so that I can run callbacks when changes are made.
With the version of the script I am currently using, it will run callbacks when keys are added, removed, or dragged to another frame. But, that is not going to be enough. I need to it to be able to detect changes to the values of the sub-animations.
if you want to keep a controller of changes just lock it.
if you want to get a notification of any controller’s change use when construct.
I’m actually currently using a node event callback so that I can call my function with mouseUp. I was using a when construct with an earlier version of the script, and it ended up running hundreds of times while I moved objects from one place to another.
I’m also not sure if I can get even a when construct to do the things I need it to, like know which object in a group has been moved, transformed, enabled/disabled, etc., short of creating a separate handler for every single object. And then I’m trying to imagine what will happen when adjusting object A causes a transform in object B, etc.
I think I’m on the right track, just having a little trouble figuring out how to store the values the way I want them.
fn collectKeyFrames track parent: index: =
(
if index == unsupplied do index = track
if parent != unsupplied do track = parent[index]
local keyFrames = #()
if isController track.controller do (keyFrames = for k in track.controller.keys collect k.time.frame as integer)
if keyframes.count != 0 do format "%[%] (%) keyFrames: %
" parent index track keyFrames
for i = 1 to track.numSubs do collectKeyFrames track[i] index:i parent:track
)
collectKeyFrames $
Edit: Worked on it a little more. Not sure if I’m getting closer to what I want or further away though.
fn collectKeyFrames track parent: index: parentID: =
(
if index == unsupplied do index = track.name
if parent != unsupplied do track = parent[index]
if parentId == unsupplied do parentID = ""
local keyFrames = #()
if isController track.controller do (keyFrames = for k in track.controller.keys collect k.time.frame as integer)
if keyframes.count != 0 do format "%[%]: %
" parentID index keyFrames
nextParent = parentID + (if classOf index == integer then "[" + index as string + "]" else "$" + index)
for i = 1 to track.numSubs do collectKeyFrames track[i] index:i parent:track parentId:nextParent
)
collectKeyFrames $
Probably not the most efficient possible way to do this, but it’s working well enough for my needs. I’m saving the sub-animation indexes as strings to keep them from evaluating, not sure if there’s another way to do that. Obviously if anyone has any suggestions for making it better, that would be awesome.
fn getKeyVals track index: parent: parentID:"" =
(
if index == unsupplied do index = track.name
if parent != unsupplied do track = parent[index]
local keyFrames = #()
if isController track.controller do (keyFrames = for k in track.controller.keys collect k.time.frame as integer)
if keyFrames.count != 0 do
(
keyVals = #(parentID + "[" + index as string + "]")
for f in keyFrames do at time f append keyVals #(f, track.value)
append keyValArray keyVals
)
local indexString
if classOf index == integer
then indexString = "[" + index as string + "]"
else indexString = "$" + index
for i = 1 to track.numSubs do getKeyVals track[i] index:i parent:track parentID:(parentID + indexString)
keyValArray
)