Pondering Keyframe Animation

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Candall
Prole
Posts: 19
Joined: Sat Oct 31, 2009 1:09 pm

Pondering Keyframe Animation

Post by Candall »

Okay, folks. I've never programmed anything like this before, so I'd like to make sure that I'm on a sensible track before I get too many lines of useless code written.

I'm trying to set up a keyframe animation system. I already have a class set up for characters that will be using this system, and each character on the screen can and usually will have a different animation playing, so I have already come to the conclusion that the table of keyframes is going to need to be stored somewhere within the character class (my character class is called "yarnie").

And so, I have added the following to the "yarnie" table:

Code: Select all

yarnie.keylist={}
Now, my animation editor is basically an array of sliders. Adjusting each slider should create a new key inside the keylist table, but since the keyframe data contains both a frame number and a rotation amount, the new key must also be a table. So, if I were to go to frame 30 and adjust the head by 45 degrees and then go to frame 50 and adjust the front bicep by 90 degrees, I would end up with something like this:

Code: Select all

yarnie.keylist= {
     fbicep= {
          1 {
               frame=50
               position=90
          }
     }
     head= {
          1= {
               frame=30
               position=45
          }
     }
}
After a couple of additional keyframes, it might look more like this:

Code: Select all

yarnie.keylist= {
     fbicep= {
          1= {
               frame=50
               position=90
          }
          2= {
               frame=60
               position=80
          }
     }
     head= {
          1= {
               frame=30
               position=45
          }
          2= {
               frame=90
               position=90
          }
     }
}
Since I'm planning to keep the animation system at a smooth 30 fps, the above represents a short but strange three-second animation.

However, there's no way for the character to keep up with which keyframe he's on at any given moment, so I add:

Code: Select all

yarnie.keylist= {
     fbicep= {
          1= {
               frame=50
               position=90
          }
          2= {
               frame=60
               position=80
          }
          index=1
     }
     head= {
          1= {
               frame=30
               position=45
          }
          2= {
               frame=90
               position=90
          }
          index=1
     }
}
Now... having a table with numerical indexes (which are equal to tables) and named keys (which are equal to integers) is okay, right?

If this system works, it would allow me to have the character work toward the next keyframe by calling the body part's index using the index key inside the same table. Does that make sense? Does that work? Can that many tables be nested within one another, or should I go back to the drawing board and start over?

Does anybody have any suggestions on how I'd go about getting the indexes containing tables for frame and position to arrange themselves in order from smallest frame value to largest?

Any questions, comments, criticisms and concerns will be deeply appreciated.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Pondering Keyframe Animation

Post by Robin »

This is a difficult project you're doing, good luck. :)
Candall wrote:Now... having a table with numerical indexes (which are equal to tables) and named keys (which are equal to integers) is okay, right?
Short answer: yes. Longer answer: different types are mostly transparent to you when using Lua. You can toss tables and functions around just like you can toss strings and numbers around. It would be good for you to understand table keys and values can be anything (except you can't have a nil key).

Code: Select all

t = {[true] = false} -- works
t2 = {nil, 5, "aha", t} -- works as well, note that ipairs will behave strangely with this: it stops directly because t2[1] == nil
-- but it is completely legal, and sometimes even useful
String keys have a shortcut:

Code: Select all

t = {}
t["hello"] = "world"
print(t.hello) --prints world
This only works if the key is a valid identifier in Lua, so "Hello", "james_007" and "i386" are okay, but "053", "Rock & Roll" and " " are not. To use those, you have to use the "long" version: t["053"], t["Rock & Roll"] etc.

So let me repeat that: you can use any type for table keys and values (but no table1[nil] = ...)

This means you can even have functions inside tables. That's what love.load() etc. is in LÖVE 0.6.0.
Candall wrote:Does anybody have any suggestions on how I'd go about getting the indexes containing tables for frame and position to arrange themselves in order from smallest frame value to largest?
I'm not sure what you mean, but if you want t[1] to come before t[2]: that's always the case. Try this:

Code: Select all

t = {}
t[1] = 'a'
t[3] = 'useless'
t[2] = 'example'
for index,value in ipairs(t) do
    print(index, value)
end
Help us help you: attach a .love.
Candall
Prole
Posts: 19
Joined: Sat Oct 31, 2009 1:09 pm

Re: Pondering Keyframe Animation

Post by Candall »

Robin wrote:This is a difficult project you're doing, good luck. :)
Heh, I'm getting that impression more and more clearly as I progress :?
Robin wrote: Short answer: yes. Longer answer: different types are mostly transparent to you when using Lua. You can toss tables and functions around just like you can toss strings and numbers around. It would be good for you to understand table keys and values can be anything (except you can't have a nil key).
Yeah, I'm concerned with nil tables getting garbage collected and choking up the works, but unless I'm mistaken, it won't be a huge issue so long as I make sure that the key being checked is not nil. Any numerical indexes are going to be called from a function argument, and any named keys are going to be called explicitly (and as long as the table exists, the keys are going to exist as well).
Robin wrote:I'm not sure what you mean, but if you want t[1] to come before t[2]: that's always the case.
Yeah, and that works out as long as all of the keyframes are placed in sequential order from start to finish, but let's say I were to put a keyframe at frame 30, and one at frame 90, but then I decide that I want one at frame 60. The simplified version, then, would be:

Code: Select all

part= {
     1= {
          frame=30
     }
     2= {
          frame=90
     }
     3= {
          frame=60
     }
}
This would result in the character seeking frame 30, then 90, then 60, because 60 is the frame value in index 3. And just now I'm realizing that deleting keyframes may wreak the same sort of havock.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Pondering Keyframe Animation

Post by Robin »

Luckily we have a very cool table.sort().
When you call it with two arguments, the table to sort and a function, that function will be used instead of < to determine the order of keys.
So you would do:

Code: Select all

function sort_frames(a, b)
    return a.frame < b.frame
end

(...)

table.sort(<choose one :P>, sort_frames) -- call this whenever you insert or remove a key frame
Help us help you: attach a .love.
Candall
Prole
Posts: 19
Joined: Sat Oct 31, 2009 1:09 pm

Re: Pondering Keyframe Animation

Post by Candall »

You're a man among men, Robin. Thanks a million.

I'm not 100% clear on how that works, but I'll look into it and get all the ins and outs... now that I know what to look for.
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: Pondering Keyframe Animation

Post by bartbes »

What about using the frame argument as a key, then you could do something like:

Code: Select all

counter = counter + 1
if part[counter] then
--apply it
end
--loop at 30 Hz
Candall
Prole
Posts: 19
Joined: Sat Oct 31, 2009 1:09 pm

Re: Pondering Keyframe Animation

Post by Candall »

Bahah! It worked at last!

The table setup worked perfectly; it was writing an algorithm to actually read it that took a while. Now I need to plan out my animation format and write/load it and I'll have a functional but unpolished animation mode!
Post Reply

Who is online

Users browsing this forum: Majestic-12 [Bot] and 90 guests