Skip to content

suggestion for a different animation paradigm #2

@ratchetfreak

Description

@ratchetfreak

I've been following the development of the panim development (which unfortunately doesn't have a repo yet or I would've created a pull request there) and I believe that there is another viable and perhaps simpler way to describe animations in code.

This is based on Sebastian Lague's animation system. It uses a more immediate mode style api where every update you go over the entire animation code and decide what actually happens based on when in the animation you are.

The state required for this is:

typedef struct {
	float currentTime; // time since start of the animation preserved between frames
	float clipStartTime; // where the code is in the animation, updated by each "wait" operation, reset every update.
	float globEnd; // when the animation ends, reset every update.
} ImAnim;

Then you can get a float t from 0 to 1 based on where in the animation you are:

float clipTime(ImAnim* a, float duration) {
	long timeSinceStart = a->currentTime - a->clipStartTime;
	float animT = timeSinceStart / duration;
	if(animT < 0) //before the clip requested
		animT = 0f;
	if(animT > 1) //after the clip requested
		animT = 1f;
	
	if(a->globEnd < (a->clipStartTime + duration))
		a->globEnd = a->clipStartTime + duration;
	
	a->lastDur = duration;
	return animT;
}
void wait_for_end(ImAnim *a){
	a->clipStartTime = a->globEnd;
}

If it returns 0 then you are before the clip and should leave the animated object untouched,
if it returns 1 then the clip is finished and the animated object should be as if the clip just finished.

A lerp would do the natural thing with the result.

Your shuffle squares example would look something like: (bugs might be present)

void imanim_move_Vector2(ImAnim *a, Vector2 *from, Vector2 to, float duration){
	float t = ease_in_out(clipTime(a, duration));
	from* = lerp(from*, to, t);
}

void shuffle_squares(ImAnim* a, Square *s1, Square *s2, Square *s3){
	imanim_move_Vector2(a, &s1->position, grid(1, 1), 0.25);
	imanim_move_Vector2(a, &s2->position, grid(0, 0), 0.25);
	imanim_move_Vector2(a, &s3->position, grid(0, 1), 0.25);
	wait_for_end(a);
	
	imanim_move_Vector4(a, &s1->color, RED, 0.25);
	imanim_move_Vector4(a, &s2->color, GREEN, 0.25);
	imanim_move_Vector4(a, &s3->color, BLUE, 0.25);
	wait_for_end(a);
	
	imanim_move_Vector2(a, &s3->position, grid(1, 0), 0.25);
	wait_for_end(a);
	
	imanim_move_Vector4(a, &s1->color, FOREGROUND_COLOR, 0.25);
	imanim_move_Vector4(a, &s2->color, FOREGROUND_COLOR, 0.25);
	imanim_move_Vector4(a, &s3->color, FOREGROUND_COLOR, 0.25);
	wait_for_end(a);
	
}

void reset_ImAnim(void* v){
	ImAnim *a = (ImAnim*)v;
	
	a-> currentTime  =0;
}

bool update_ImAnim_squares(Env* env, void* v){
	ImAnim *a = (ImAnim*)v;
	
	if(a->currentTime >= a->globEnd) return true;
	
	a->currentTime += env.delta_time;
	a-> clipStartTime=0;
	a-> globEnd      =0;

	// reset squares to initial position
       reset_squares();

	Square *s1 = &p->squares[0];
	Square *s2 = &p->squares[1];
	Square *s3 = &p->squares[2];
	
	shuffle_squares(a, s1, s2, s3);
	shuffle_squares(a, s2, s3, s1);
	shuffle_squares(a, s3, s1, s2);
	wait_for(a, 1.0f);
	
	return a->currentTime >= a->globEnd;
}

no allocation or function pointers required.

In addition you can seek to any point in the animation by setting the currentTime field to which frame you want to display.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions