We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpPrograms › the best strategy for "authoring" an animation
Page Index Toggle Pages: 1
the best strategy for "authoring" an animation? (Read 1960 times)
the best strategy for "authoring" an animation?
Apr 29th, 2005, 9:06am
 
Hello all

I have to build a automatic demo out of an interactive sketch that would perform a series of simple transformations linearly; for example:

- demo starts;
- object 1 rotation goes from 0 to PI in 30 frames;
then
- object 1 position moves -50 pixels;
then
- object 2 and object 3 move to 0,0;


so on, so forth; there are a zillion ways to code a linear sequence (just like a timeline), and I'm writing to ask: how would you do it?
I would write a gigantic sequence of if's, based on a counter variable;
counter 0 to 30 - object1._rotation+10;
counter 30 to 50 - object1.x+=10;
counter 0 to 45 - object2.y+=2;

once things get big and complicated (like 5 minutes), I guess this won't be a very good. Also, If I change my mind on something in the middle, I would have to remake everything.

Does anyone has experience in building coded animation sequences? any example?

Re: the best strategy for "authoring" an animation
Reply #1 - Apr 29th, 2005, 11:49am
 
OK, there's an object-oriented way to do this, and I'm going to have a go.  Additions/corrections welcome.

You could define a simple interface, say AnimationController, thus:

Code:


interface AnimationController {
boolean isActive();
void perform();
}



An interface is a special kind of class, which defines a set of methods which other classes must implement.  If several different classes all implement AnimationController, it means we can treat them all the same way, even if they perform different tasks.

So you would make an array (or a Vector) to hold all your animation controllers, and loop through them all inside the draw function.  You can also count the number of frames inside of draw().

Inside setup(), you need to create the controllers array.  Because AnimationController is just an interface, we need to implement it with actual classes which do useful things.  Here's an example program, with two animation controllers:

Code:


interface AnimationController {
boolean isActive();
void perform();
}

AnimationController controllers[];
int frames = 0;
int thingToGrow = 0;

class Grower implements AnimationController {
boolean isActive() {
return frames >= 0 && frames < 200;
}
void perform() {
thingToGrow++;
}
}

class Shrinker implements AnimationController {
boolean isActive() {
return frames >= 200 && frames < 400;
}
void perform() {
thingToGrow--;
}
}

void setup() {
size(300,300);
controllers = new AnimationController[2];
controllers[0] = new Grower();
controllers[1] = new Shrinker();
}

void draw() {
background(255);
frames++;
// quick reset
if (frames > 400) {
frames = 0;
}
for (int i = 0; i < controllers.length; i++) {
if (controllers[i].isActive()) {
controllers[i].perform();
}
}
rectMode(CENTER);
fill(thingToGrow,0,0);
rect(width/2,height/2,thingToGrow,thingToGrow);
}



That's probably how I'd do it, anyway. Essentially, there is still just a big "if" statement, but now you can have multiple animations happening at once, and you have a modular implementation.

Obviously, you can add as much or as little functionality into the perform() methods, but I would recommend creating parameters for the things you want to change (like thingToGrow) and doing all the drawing after the AnimationControllers have run.

Hope that helps.
Re: the best strategy for "authoring" an animation
Reply #2 - Apr 29th, 2005, 11:19pm
 
Hey, thanks for the response Tom. I'm going to study it -  I didn't know about the interface class...
Re: the best strategy for "authoring" an animation
Reply #3 - May 12th, 2005, 8:50am
 
Hello

I'm writing to thank again.
I haven't understood the Sun documentation on it very well (actually, it's greek to me) but your coding example was very clear, and I'll be able to use it. Thanks!



PS: maybe one day, I'll be able to develop a timeline plugin like they use for coding the assembly demos... oh yeah, maybe one day.
Re: the best strategy for "authoring" an animation
Reply #4 - May 12th, 2005, 11:20am
 
An interface is basically just a class without any data, and without implementations for any of its methods.

To implement the interface, a class must have methods with the same name as the methods in the interface.

It's just a way to treat lots of objects in the same way.

The canonical example is a "Drawable" interface.  Things which implement Drawable must have a draw method.

Code:


interface Drawable {
 void draw();
}



So you could have a circle and a square class, and then put them into an array of drawables.

Code:


interface Drawable {
 void draw();
}


class Circle implements Drawable {
 float x,y,d;
 Circle(float x, float y, float d) {
   this.x = x;
   this.y = y;
   this.d = d;
 }
 void draw() {
   ellipseMode(CENTER);
   ellipse(x,y,d,d);
 }
}

class Square implements Drawable {
 float x,y,w;
 Square(float x, float y, float w) {
   this.x = x;
   this.y = y;
   this.w = w;
 }
 void draw() {
   rectMode(CENTER);
   rect(x,y,w,w);
 }
}

Drawable[] thingsToDraw;

void setup() {
 size(300,300);
 smooth();
 thingsToDraw = new Drawable[10];
 thingsToDraw[0] = new Circle(random(width),random(height),10);
 thingsToDraw[1] = new Circle(random(width),random(height),20);
 thingsToDraw[2] = new Circle(random(width),random(height),30);
 thingsToDraw[3] = new Circle(random(width),random(height),40);
 thingsToDraw[4] = new Circle(random(width),random(height),50);
 thingsToDraw[5] = new Square(random(width),random(height),10);
 thingsToDraw[6] = new Square(random(width),random(height),20);
 thingsToDraw[7] = new Square(random(width),random(height),30);
 thingsToDraw[8] = new Square(random(width),random(height),40);
 thingsToDraw[9] = new Square(random(width),random(height),50);
 noLoop();
}

void draw() {
 background(0);
 stroke(255);
 strokeWeight(2.0);
 fill(255,0,0,100);
 for (int i = 0; i < thingsToDraw.length; i++) {
   thingsToDraw[i].draw();
 }
}




Note that you could do this without the interface.  Instead, you would have a common base class for Drawable, with an empty draw method.  The Circle and Square would say extends Drawable instead, and they would implement draw in the same way.

Code:

class Drawable {
 void draw() {
   // do nothing
 }
}
class Circle extends Drawable {
 void draw() {
   // do something...
 }
}


Once you understand the difference between implementing interfaces and extending classes you might want to look up abstract classes, which are halfway between the two.
Re: the best strategy for "authoring" an animation
Reply #5 - May 12th, 2005, 7:00pm
 
Thanks for the explanation. I've been wondering about the differences and uses of interfaces and extending/implementing. This helps a lot.

steve
Re: the best strategy for "authoring" an animation
Reply #6 - May 13th, 2005, 3:10am
 
Quote:
Once you understand the difference between implementing interfaces and extending classes you might want to look up abstract classes


woa
I guess I'm already abstracting enough.
Thanks for all the explanation Tom, really nice and really helpful.  I'm very grateful.
Re: the best strategy for "authoring" an
Reply #7 - May 25th, 2005, 10:45am
 
Thanks for this, Tom. Yep! it certainly makes sense. I looked at your code and have had a go using abstract classes. I've got a procedural programming hangover and so this kind of jargon cutting-type example has been useful to me. I know it's probably beyond the scope of this board to look to indepth at OOP concepts, but it can be bloody helpful!

Anyhow, here's my attempt at a timeline using your original example as a kind of blueprint.

On the question of animation, you just slot.add() your images where and when you want them to appear in the sequence and bob's your uncle. A better way would be to write an animation element that dealt with iter. But this'll should do it in lieu of something better.

Code:

// ToDo:
// Add mini controller and on/off flag.
// mini controller will provide an offset from master head

// Generates a timeline Vector() of elements.
public abstract class Timeline {

float  head;
int stageLength;
Vector slot;

  public Timeline(int stageLength) {
 
    this.stageLength = stageLength;
    slot = new Vector();
  }
 
 void perform() {
     
   for(int i=0; i<slot.size(); i++) {
       TimelineElement element = (TimelineElement)slot.elementAt(i);
        if(element.isActive((int)head)) {
          element.display((int)head);
        }
    }
 }  
} // class Timeline


// Timeline slots contain elements derived from this class.
public abstract class TimelineElement {

int begin, end;

 TimelineElement (int begin, int end) {
 
 this.begin = begin;
 this.end = end;  
 }
 
 boolean isActive(int head) {
   return head >= begin && head <= end;
 }
 
 abstract void display(int head);
} // class





Timeline timelines[];   // array to hold timelines.
float head;

void setup() {

 size(200, 200);
     
 timelines = new Timeline[2];
 timelines[0] = new tLine1(width);       // insert timeline length and pass to constructor and imbed headpos
 timelines[1] = new tLine2(width);       // insert timeline length and pass to constructor and imbed headpos
}

void draw() {
 background(255);
   
 for (int i = 0; i < timelines.length; i++) {

   head = mouseX*(timelines[i].stageLength/width%timelines[i].stageLength);

   timelines[i].head = head;  //*timelines[i].stageLength;
   timelines[i].perform();
 }
}


// User defined timelines and contents
// Uses vectors to increase future flexibility
// Any defined element can exist on any timeline

class tLine1 extends Timeline{

 tLine1(int stageLength) {
   super(stageLength);
   
   slot.add(new Timeline_FadeImage(20,110,"t1.gif",0,0,200,200));
   slot.add(new Timeline_FadeImage(90,180,"t2.gif",0,0,200,200));

 }
} // class Visual


class tLine2 extends Timeline{

 tLine2(int stageLength) {
   super(stageLength);
   
   slot.add(new Timeline_FadeImage(20,190,"t3.gif",0,0,200,200));
 }
} // class Visual




// Timeline element definitions.
// ToDo:
// backgroundTask(); maintain element method


// Display a static image with no effects
class Timeline_Image extends TimelineElement {

PImage img;
int x,y;
int xsize, ysize;

Timeline_Image(int begin, int end, String _filename, int x, int y, int xsize, int ysize) {

 super(begin, end);
 img=loadImage(_filename);
 this.x = x;
 this.y = y;
 this.xsize = xsize;
 this.ysize = ysize;
}

 void display(int head) {
   
   noTint();
   image(img,x,y,xsize,ysize);
 }
} // Class



// Display image with proportional fade using the tint() method
class Timeline_FadeImage extends TimelineElement {

PImage img;
int x,y;
int xsize, ysize;

Timeline_FadeImage(int begin, int end, String _filename, int x, int y, int xsize, int ysize) {

 super(begin, end);
 img=loadImage(_filename);
 this.x = x;
 this.y = y;
 this.xsize = xsize;
 this.ysize = ysize;
}

void display(int head) {

 int span = abs(begin-end);   // time available for this slot
 int headoffset = abs(head-begin);  // current heads postion 0'ed to this time slice.
 int distance = (abs(-span/2+headoffset));  // calculate the distance from middle
 
 tint(255,255-(distance*2)*255/span);
 
 image(img,x,y,xsize,ysize);
}

} // Class



Page Index Toggle Pages: 1