I got a request a little while ago about playing animation in custom fps with pure code, so I came here to share it.
It took time to be finished since it was quite a headache
So, here we go...
First of all, we need to define the variables.
Write this on global code.
- Code: Select all
#define FrameRate 30 //Store game's frame rate
//Check Config -> Game Properties -> Frame rate
//We use this manual configuration due to unstable "real_fps" value
//Unstable "real_fps" value will affect the animation smoothness
//Animation List
int AnimationList[5][5]=
{
//animation1, animation2, animation3, animation4, fps
2,8,2,8,3, //Stop Left
3,9,3,9,3, //Stop Right
0,4,0,6,10, //Run Left
1,5,1,7,10, //Run Right
//add other animation sequence here
};
//The number of the animation sequence is taken from the "animpos" of the player's animation
//And make sure the player has only one big animation, which contain all the animation it needs
//In correlation to the animation set, we need to define the facing direction as well
int direct=0; //To store Player's facing direction
int walk=0; //To store Player's walking state
int AnimationIndex=0; //To store Player's animation index
int AnimationFps=0; //To store Player's animation fps
And the PlayAnimation() function.
- Code: Select all
void PlayAnimation(char Name[256], int animIndex, int fps)
{
Actor *check=getclone(Name); //Get actor by it's name
int i,anim1,anim2,currentframe; //Define temporary variables
float PlayEachFrame,tmp_framerate; //Define temporary variables
int FrameList[FrameRate]; //Use to store the frame playing list
fps=max(1,min(fps,FrameRate)); //Limit the "fps" to avoid illegal operation
tmp_framerate=FrameRate; //Copy the global "FrameRate" value to a decimal form
PlayEachFrame=max(1,tmp_framerate/fps); //Get the frame count to play animation
for(i=0;i<fps;i++)
{
FrameList[i]=round(i*PlayEachFrame); //Store the playing sequence into array
}
for(i=0;i<fps;i++)
{
currentframe=frame%FrameRate; //Get the current frame and loop it
if(FrameList[i]==currentframe) //Check if any of the frame list value matches "currentframe"
{
anim2=anim1%4; //Loop the "anim1" value from 0 to 3 forever and store it to "anim2"
check->animpos=AnimationList[animIndex][anim2]; //Set the actor animation
anim1++; //Add the "anim1" value to play the next animation sequence
}
}
}
Now, let's code the Player actor.
Player -> Create Actor -> Script Editor:
- Code: Select all
//Prevent the animation from auto playing
ChangeAnimationDirection("Event Actor", STOPPED);
Player -> Draw Actor -> Script Editor:
- Code: Select all
AnimationIndex=direct+walk*2; //Get the animation index
AnimationFps=AnimationList[AnimationIndex][4]; //Get the animation fps
//"direct+walk*2" is the animation index formula (check the AnimationList[5][4])
//if "direct" is 0 and "walk" is 0, you will get 0 as index, which is "Stop Left"
//if "direct" is 1 and "walk" is 0, you will get 1 as index, which is "Stop Right"
//if "direct" is 0 and "walk" is 1, you will get 2 as index, which is "Run Left"
//if "direct" is 1 and "walk" is 1, you will get 3 as index, which is "Run Right"
//PlayAnimation("actor_name", animation_index, animation_fps);
PlayAnimation("player", AnimationIndex, AnimationFps); //Play the animation
That's the main code you need.
The following code are just custom configuration.
Player -> Keydown "Right" -> Script Editor:
- Code: Select all
walk=1; //walk
direct=1; //face right
Player -> Keydown "Left" -> Script Editor:
- Code: Select all
walk=1; //walk
direct=0; //face left
Player -> Keyup "Any key" -> Script Editor:
- Code: Select all
walk=0; //stop
That's all.
The main idea about the custom fps is we play the animation by a certain duration.
Say the game has 30 of frame rate, and we give the animation 15 fps, that means we have to play / change the animation once for each 2 frames.
Say the game has 30 of frame rate, and we give the animation 10 fps, that means we have to play / change the animation once for each 3 frames.
Etc etc...
If we have to play / change the animation once for each 2 frames, that means we have to change the animation at the following frame:
0 - 2 - 4 - 6 - 8 - 10 - etc
We store this frame sequence to an array.
While playing the animation, we check the current frame to the array.
If any of the value matches, play the next animation. Otherwise, don't play it.
And this process is looping over time.
To see the final result, here's the demo
P.S.: Advantage of using this method is that you don't need to load a long list of animations with their own fps to your actor.
You just need a single animation sheet, which you can configure the sequence as well as it's fps with pure code. So that you can change them anytime you want
The disadvantage probably it requires even number of animation to display properly and easy to manage. Also, it's only for looping animation.
Needs more workaround to play animation only for once. Other than that, you tell me...