Project - Flip Pad Animator

Hi all,

I’ve begun working on this project in order to teach myself about classes and tweens and to try and achieve bringing together of a full set of application elements; screens, UI elements, user interactions, data handling, etc, etc. After trying, and failing, to implement classes in another project, I looked for an idea that I thought I could implement within a reasonable timeframe, say a couple of months (given limited time available to code). Very much in awe of Luatee’s demos in his building project showing slick interfaces for users to add objects to the screen (I wish I could code that!), learning that tweens do not animate objects per se, rather they interpolate over ranges of values, and then seeing an animation flip book on a desk at work, the idea for the project was born!

Anyway, cut to the chase… I would appreciate any and all advice on how to proceed.

The basic tenet is for a user to be able to add objects to an animation; I’m sticking at first to straight lines, ellipses and rectangles, all black outlines on a white canvas to start with. Similar to PowerPoint, once a “frame” is drawn, it can be copied and the objects can be moved about and resized so that a transition occurs. Each frame has a time period, over which the objects are moved from their positions in the previous frame to those in this frame on a linear path (again, at first, I can’t handle too much complexity). The user repeats adding frames as needed, and moves/sizes objects in any frame, checking the animation works. Ideally, they can record the video and export it at the end. Animations can be saved, edited, copied, deleted, etc.

So, I think I should I have an animation class and a frame sub class, with object positions varying between frame instances. Is this sensible? I have begun storing the objects’ positions per frame in tables, but should I use a mesh per frame? How best to store/retrieve values to pass to the tween functions to display the animations? Can mesh rects be tweened? Any other thoughts, limitations of the idea, suggestions, advice to give?

Many thanks in advance, I am already indebted to many of you.

Rob.

@time_trial you have set yourself a very ambitious project. Have you seen my XFC project? It has many similarities with what you want to do, in terms of functionnalities, at least in the principles, but is much less difficult than what you want to do. And i’ve been working for 6 months on it, and it is not finished… If i were you i would start very simple, making it more complex step by step, and be prepared to rewrite everthing about 10 times, as you progress in your understanding of what you can do / want to do. You cant really know what class you need before you know how you chose to do it… Good luck!

Thanks @Jmv38, I wasn’t aware of XFC. I will watch the video in your post. It looks stunning!

I have created the animation and frame classes, and instantiated a couple of animations each with a few frames. Had to learn to deep copy the frame objects! I call a couple of ugly functions with hard coded values to change the animation’s objects, and call a function to loop through the object tables and store tween calls in another table, which I then unpack in a tween.sequence function.

This does actually animate. Before I go any further, I thought it wise to ask if I was heading down the wrong path.

I am not a total newbie, but still at the stage where I struggle to understand things. I am a slow(ish) learner, with a haphazard trial-and-error approach to coding. Meshes are still mysterious, and shaders, well…

Just treat meshes like anything else. A good side project to get meshes down is dynamicaly creat 10x10 grid, start with them as seperate meshes. Then move on to having each row being a seperate mesh and finally move on to textures.

Something I had to find out the hard way–I’m sure a quick post here woild have fixed it, but I like to try to solve my problems first.-- You need sequential numbers for the mesh id or it will not texture but still draw.

Thanks, @Thwapp. Do you recommend using meshes instead of tables of coordinates? I will certainly give your suggestion a go.

@time_trial he’s recommending you use meshes with a table of coordinates, play with mesh:addRect to create a quad (rectangle) you need to assign it to a variable and use setRect which is the same function layout except the first argument is the variable of your mesh:addRect. If you don’t understand I can write you an example.

@Luatee, thanks for the offer. I have found your Spline class in your Splinerider discussion. That looks like the same set up as you are proposing, so I will try to replicate that in my project.

If I get this project to work as planned, I’d like to try and use the Spline class to let the user define a non-linear path for an object’s movement between frames. But that’s an upgrade for version 2!

@time_trial this uses individual quads for each segment of the spline and each spline has its own mesh. It could be a lot faster now but it’s an old project. Free to use it as you like :slight_smile:

Great, thanks. It looks plenty fast enough for me and gives me a good example of what you both have recommended I use.

Hi all,

Brief progress update. I have managed to create some functions that will replicate the line and rect Codea primitives for meshes. Also using the setRect call in touch function to move the end of one line.

Haven’t been able to tween anything yet. When I have multiple animation frames, each with its own mesh holding objects, could/should I draw each frame and tween between frames? Or draw a copy of the first frame’s mesh, then tween that mesh’s objects by their positions in each other mesh?

Next steps are to draw ellipses, detect touches to select/move/resize objects, then move the code into my project classes (rather than using the functions here).

-- Mesh Add/Change Function Test
-- 
function setup()
    parameter.action("Animate!",fnAnimate)
    ex,ey = 500,500
    parameter.watch("ex")
    parameter.watch("ey")
    ellipseMode(CENTER)
    m = mesh()
    tblObjects = {}
    tblObjects[1] = fnAddRect(m,vec2(550,201),60,200,2,color(0,255))
    tblObjects[2] = fnAddLine(m,vec2(100,550),vec2(150,550),2,color(0,255))
    tblObjects[3] = fnAddRect(m,vec2(350,151),40,100,2,color(0,255))
    tblObjects[4] = fnAddRect(m,vec2(150,201),60,200,2,color(0,255))
    tblObjects[5] = fnAddLine(m,vec2(60,100),vec2(650,100),2,color(0,255))
    tblObjects[6] = fnAddLine(m,vec2(150,550),vec2(125,600),2,color(0,255))
    tblObjects[7] = fnAddLine(m,vec2(125,600),vec2(100,550),2,color(0,255))

    tblObjects[99] = fnAddLine(m,vec2(350,201),vec2(500,500),2,color(255,0,0,255))
    fill(255,0,0,255)
end
function fnAnimate()
    --tblObject = {objSelf,objVec,objLength,objAng,objT,objCol}
    
end
function draw()
    background(255)
    m:draw()
    ellipse(ex,ey,10,10)
end
function fnAddRect(pMesh,p,pW,pH,pT,pC)
    --Mimics rectMode(CENTER); the coords of vector p are the centre point
    local obj = {}
    obj[1] = pMesh:addRect(p.x,p.y+pH/2,pW,pT,0) --Top "line" rectangle
    obj[2] = pMesh:addRect(p.x,p.y-pH/2,pW,pT,0) --Bottom "line" rectangle
    obj[3] = pMesh:addRect(p.x-pW/2,p.y,pT,pH,0) --Left "line" rectangle
    obj[4] = pMesh:addRect(p.x+pW/2,p.y,pT,pH,0) --Right "line" rectangle
    for i=1, #obj do
        pMesh:setRectColor(obj[i],pC) --Loop through each "line" rectangle setting its color
    end
    return obj
end
function fnGetLineVars(p1,p2)
    local mp = vec2(((p1.x+p2.x)/2),((p1.y+p2.y)/2)) --midpoint
    local length = p1:dist(p2) -- distance between p1 and p2
    local ang = math.atan2(p2.x-p1.x,p2.y-p1.y)
    return mp, length, ang
end
function fnMoveLine(pObj,pMesh,p1,p2,pT,pC)
    local mp,length,ang = fnGetLineVars(p1,p2)
    local object
    pMesh:setRect(pObj,mp.x,mp.y,pT,length,-ang) --Line
    local obj = {objSelf=pObj,objVec=mp,objLength=length,objAng=ang,objT=pT,objCol=pC}
    return obj
end
function fnAddLine(pMesh,p1,p2,pT,pC)
    local mp,length,ang = fnGetLineVars(p1,p2)
    local object
    object = pMesh:addRect(mp.x,mp.y,pT,length,-ang) --Line
    pMesh:setRectColor(object,pC)
    local obj = {objSelf=object,objVec=mp,objLength=length,objAng=ang,objT=pT,objCol=pC}
    return obj
end
function touched(touch)
    ex,ey = CurrentTouch.x, CurrentTouch.y
    tblObjects[99] = fnMoveLine(tblObjects[99].objSelf,
        m,vec2(350,201),vec2(ex,ey),2,color(255,255))
end

@time_trial - I would assume that when you have several tweens going at the same time, they will not necessarily be synchronised together. So it is probably best to have a separate tween per object, or maybe a separate tween for all objects starting at the same time with the same tween duration. This gives you more flexibility.

Tweens are not very complicated, and all they do is interpolate numbers. What might work for you is setting up a simple tween class, but if you haven’t done this before, you will probably need some help.

@Ignatz, hadn’t considered a tween per object. You’re right, it might be necessary. I had made one tween per object type (ellipse, rect, line) in my non-mesh based first attempt.

So, a tween class would enable defining tweens, which would be started by a function call. As opposed to defining tweens and storing in a table and then trying to stop them all starting (at slightly different times!) with a tween.sequence call. Seems the right way to go, thanks.

If all your tweens have the same duration, then you can set up one per draw (assuming at least one mesh needs it) and assign that tween to each mesh that needs it. That cuts down on the number of tweens needed.

The way I had imagined it, each frame would have its own duration to allow for smaller movements to allow smoother animation, and longer durations for easy, large movements.

Set up something like: Frame class has duration property and object collections (object is a class with rect, line, ellipse sub classes). Each object has its position/size tweened over each frame’s duration to each frame’s position/size values for each object.

I think this means all tweens have the same duration, because there is one tween per object sub class per frame.

So, one month in and I’ve made progress, rewritten things, hit some roadblocks and perhaps most significantly, discovered the export to video will need to be written in Objective C…

My main problem at the moment is getting my class hierarchy right. I have an animation class, which has a collection of pages, each of which represents a scene in the animation. I did have the drawn objects (lines, ellipses, rectangles) each being instantiated per page, as the user sets position, size and visibility of them per page. This seemed logical to me, until I realised I wasn’t linking objects between pages and that each page could have a different number of objects. I can tween the mesh rectangles of page one to the position buffer of each subsequent page’s mesh, but there is no continuity between rectangle IDs; the effect is that rectangles move between drawn objects and the animation is a mess!

I realise this is a difficult question, but can anyone provide some ideas on how to set this up? I can’t determine if I will need an animation to have collections of objects and pages, or if an animation should just have objects each of which has a number of positions/sizes/colours (for visibility). If the latter, how do I manage the duration of tweens between pages?

I appreciate any help or advice. Even if the advice is go and build something easier instead.

@time_trial - I would probably go for objects that have a number of positions/sizes/colours, as you suggest, because that is not only logical but probably easiest to test.

I imagine you could keep a table of tweens and just store the id of the relevant tween along with each object, so you know which one to use.

Thanks, @Ignatz. I imagine this is suitable?

self.Positions = {}
self.Colors = {}
...
self.Positions[#self.Positions+1] = vec2(x,y)
self.Colors[#self.Colors+1] = colour (r,g,b,a)
...

I think it was the page class that confused me. I’ll do away with that and also store tween durations for each object position, colour, etc.

@time_trial - without seeing the rest of the code, that looks ok to me

Cheers!

After some rewriting of the object classes, I might finally have the tracking I need between the meshes in each page. Here is my first video:

http://youtu.be/66v2JQU4i5w

Before I move on to the add object menu (might use a Cider tray on the right hand side), I’d appreciate any thoughts or opinions anyone has. Resizing and rotating objects is next on my list, but lines can be small, so touch points on either end are a bit fiddly. Would two finger pinch/expand/rotate outside the move touch points, which scales and rotates the object seem intuitive?

I plan to create a splash screen animation assembling the stick man piece by piece, with him pressing the start button at the end to move to the main menu screen.