Wednesday, June 5, 2013

[TUT] Animations

Animations can give another look to an modification. In this tutorial i will show what i know about animations in GTA IV, you can download the code of this tutorial here and download the list of GTA IV animation here.

We have an big list of animations to use and thanks to the people involved in OpenIV development we can see those animations without the game running, it's very useful, you can find this option in the OpenIV menu Tools > Animation Viewer:


In the next screen we can choose what kind of animation we want preview:


Clicking in Ped animations (anim.img) we will be redirected to an screen that organizes the animations by their categories:


Clicking in one of the categories we will see an new screen with an Ped in center and the list of animations in the left side, if we click one of the animations the OpenIV will start playing the animation in loop mode:



Now to make this happen in game we can do with basically two ways:
  • Using scripthook classes
  • Using native method calls


Using Scripthook classes to play animations

To play animations using the scripthook we need:
  • An animation set: This object will determine the category of the animation
  • The Animation object that each Ped have, or the Ped's Task.PlayAnimation object
Simple example:


Here I'm declaring the animation set of the category swimming, then playing the animation idle from this category, the number 8 represents the speed of the playback, this param don't seems to affect the playback all the time, seems to work only in the start.

Result:


Before use an animation it's interesting request the animations of the category, we can do this using this native call:


Now let's improve this, as we can see the player plays the animation until the animation reaches the end then go back to normal animation, but what we need to do to make it automatically loop this animation? We need to use animation flags, based on this site the animation flags that we have are:
  • Unknown01 - Don't come back to initial position after animation ends, we use this for animations that result in position change for the ped, for example the land and roll animation
  • Unknown04 - Based on translation it will make ped return to original position, in my tests don't change anything
  • Unknown05 - We use this flag to loop the animation
  • Unknown06 - We use this to stop the ped in the last animation position, ped will play animation then stop frozen in the last frame of the animation
  • Unknown07 - Seems that makes player reset to Standing idle animation after the animation ends
  • Unknown09 - This one will make the animation be played only in ped's upper body, legs wont be affected, it's interesting to be used while the ped is inside an vehicle (Nevitro tip).
  • Unknown10 - Remove the possible sound of the animation, some animations has sounds others don't
  • Unknown09 combined with Unknown11 (Unknown09 Or Unknown11) - Tip sent by Giovafr Giova, this will result in the play of the animation only in the upper body with the possibility to walk while the anim is being played.

We have other flags but they seems to result in nothing like the Unknown04.

So, to make our player repeat the animation we should use the flag Unknown05:


We can combine flags with the Or operator, for example, if we want play the run animation of the swimming category we can use the flags: Unknown01 to don't come back to initial positionUnknown05 to repeat and Unknown10 to remove the animation sound:


Sometimes this play method fails when we try to put together the flags (after some reloadscripts command calls), so if the things are not happening as expected, reload the game and test again.

This video shows the result with and without the flags:


To stop the animation I'm using this:



Other interesting methods of the Animation class

  • isPlaying - This method returns True when the animation is being played
  • GetCurrentAnimationTime - This method return the current time of the animation



Detecting animations

We can use the isPlaying or the GetCurrentAnimationTime to determine if the ped is playing an determined animation, but to make sure that we can detect the anim we need to call the method REQUEST_ANIMS to load the animations of that animation category before we try to detect the animation play:





Using native methods to play animations

To play animations using the native calls we have this methods:

  • TASK_PLAY_ANIM
  • TASK_PLAY_ANIM_FACIAL
  • TASK_PLAY_ANIM_NON_INTERRUPTABLE
  • TASK_PLAY_ANIM_READY_TO_BE_EXECUTED
  • TASK_PLAY_ANIM_SECONDARY
  • TASK_PLAY_ANIM_SECONDARY_IN_CAR
  • TASK_PLAY_ANIM_SECONDARY_NO_INTERRUPT
  • TASK_PLAY_ANIM_SECONDARY_UPPER_BODY
  • TASK_PLAY_ANIM_UPPER_BODY
  • TASK_PLAY_ANIM_WITH_ADVANCED_FLAGS
  • TASK_PLAY_ANIM_WITH_FLAGS

The more interesting here is the TASK_PLAY_ANIM_SECONDARY_UPPER_BODY because that method will play the animation only in the upper body of the ped, it's useful when we need to play an animation while the player is walking or running, example:


First param is the ped, second is the animation name, then comes the category name, number 8.0 represents the playback speed, I declared p1_Repeat and p4_... to make clear of what is the function of that parameter in the method call, if we set those params to one or true we will enable them, they act like flags, the last param determine the time in milliseconds that the animation will be played, if we set an time smaller than the total animation time the animation will end before reach final frame, this time is not precise because it is affected by game FPS.

The TASK_PLAY_ANIM_SECONDARY_IN_CAR it's interesting too because we can use this to play animations while the ped is in an vehicle, the params are same of the TASK_PLAY_ANIM_SECONDARY_UPPER_BODY method.

I don't will talk about the other anim methods because they have similar results of the Scripthook methods.



Other interesting methods related to animations

  • HAVE_ANIMS_LOADED - We can use to check if the REQUEST_ANIMS call finished the loading of the animations of the category, params: category name
  • IS_CHAR_PLAYING_ANIM - To check if player is playing an animation, params: ped, category name and animation name
  • GET_CHAR_ANIM_CURRENT_TIME - Get the animation time, params: ped, category name, animation name and a pointer to an variable (of type Single) to store the time:


SET_CHAR_ALL_ANIMS_SPEED - This one will set an new playback speed for all animations that the pPed is playing, params: ped and new speed multiplier (float number). For example, to set player anims to 150% the normal we can do:


SET_CHAR_ANIM_SPEED - This one is similar to the one above, the difference is that this one will affect one animation only, params: ped, category name, animation name and speed multiplier


SET_CHAR_ANIM_CURRENT_TIME - We can use this method to set the animation time, 1.0 is 100%, the end, 0 is the start, very useful to control the animation, we can make and fake reverse playback reducing the percent number, params: ped, category name, animation name and playback percent/100 (from 0 to 1.0)


Demonstration of reverse playbackhttp://www.facebook.com/photo.php?v=355430167913263, in this video i play grenade_throw_overarm from 0.3 (30%) to 0.6 (60%) and back to 0.3, also i use SET_CHAR_ANIM_SPEED and set it to 0.1 to make the movement more smooth.


SET_CHAR_MOVE_ANIM_SPEED_MULTIPLIER - This one changes only the ped movement animations speed, params: ped and speed multiplier

SET_ANIM_GROUP_FOR_CHAR - This one changes the ped animations group, will affect his walk, run, idle animation, etc., params: ped and animation group

To use this last one we need to call the REQUEST_ANIMS to load the animations of the chosen movement category before use the method:


We need to be careful with this native call because if we set an invalid movement group we crash the game :)
Generally the names of the groups starts with move_, for example: move_player, move_melee, move_rifle, etc.. You can download the list of animations and see the categories that start with move_ here.
pernas
//propaganda YT float style='display:none;'