How to activate user animations?


#1

Continuing my battle with animations in HF…
At the end of avatar-animation.json script there are 2 fields like:

{
“id”: “userAnimA”,
“type”: “clip”,
“data”: {
“url”: “animations/idle.fbx”,
“startFrame”: 0.0,
“endFrame”: 90.0,
“timeScale”: 1.0,
“loopFlag”: true
},
“children”: []
}

They seem to be designed for user animations :slight_smile:
The question is - how can I activate the animation linked to this part of the script? The best for me would be activating the animation by pressig the keyboard key assigned.

My next problem is refreshing animation list. Do you know any tricks to make it faster? My way is to direct Avatar Animation JSON to any web address, save it, and than direct it again to the correct one and save again. Time consuming:frowning:


#2

Hey,

Lets get down to business:

Apologies beforehand, as this will be a bit long winded :slight_smile:

There are two types of Animations:

Role Animations, and Static Animations.


Static Animations are simply animations, which you may be familiar with from other worlds. Simply put it is an animation that is played back on the avatar. This is accessed using MyAvatar.overrideAnimation

Any action will not override the animation, so forexample if you dance and move, you will just keep dancing and sliding to the direction you move.

This means, it is ideal if you have a sitting animation, or “knocked back” or what ever other fun stuff you have in mind. You can restore via MyAvatar.restoreAnimation.


Role animations are animations defined as avatar-animation.json file that you load onto an Avatar. This basically defines the Animation State Machine and can be a headache to edit, but if you know what you are doing it is fantastic, but lets not dwell on that, there is an easier way:

You have two ways of replacing the animations:

Rolespecific overriding via MyAvatar.overrideRoleAnimation This is ideal if you want to allow the user to do other actions while the animation plays back. Forexample, If you want to have a limp action after an action you can

MyAvatar.overrideRoleAnimation("walkFwd", "limpUrl.fbx", 30, true, 0, 30);

To cause the avatar to play back limpUrl.fbx at 30 fps, looping, from frame 0 to 30. Blended from idle to limping every time the user walks Forward.

Which will keep until you restore the role to the state it was in avatar-animation.json

You can restore via MyAvatar.restoreRoleAnimation and MyAvatar.restoreRoleAnimations

List all available ones for your avatar via MyAvatar.getAnimationRoles


Alternatively if you want to dig in further to the avatar-animation.json:

You can permanently change the avatar-animation.json url via MyAvatar.setAnimGraphUrl() or
Override it via MyAvatar.setAnimGraphOverrideUrl(QUrl).

Note that setAnimGraphUrl should be reserved to permanent changes, while setAnimGraphOverrideUrl is for temporary changes


Further notes: on Avatar-Animation.json

All Animation Objects are defined in JSON as:

{
  “url”: “animations/idle.fbx”,
  “startFrame”: 0.0,
  “endFrame”: 90.0,
  “timeScale”: 1.0,
  “loopFlag”: true
}

In the avatar-animation.json, these animations are usually categorized under "type": "clip". The rest in the avatar-animation is state logic. Unfortunately the logic is a tad bit messy when presented as a json.


Note, Animations are loaded always locally, with the animation data being streamed to recievers, instead of users just sending animations to other users. This means you can simply load the avatar-animation.json and animations on local disk, with all files on your file system, but all the animations will get streamed to everyone else. However if you want to share this animation set with others, you have to upload the animations then…

Try using a file:// prefix and the path to file to get it working and it should auto-detect changes (unless, not, inwhich you add ?<randomText> at the end of the file.

I Hope that helps :slight_smile:


#3

You are great! Thank you very much, I will read all manuals in details today and I do hope you excuse my newbe questions.
I checked some of the solutions you mentioned and they really work, but I am too stupid to implement them in my avatar.
Lets take this example:

// An animation of the avatar clapping its hands while standing
var ANIM_URL = “https://s3.amazonaws.com/hifi-public/animations/ClapAnimations/ClapHands_Standing.fbx”;

MyAvatar.overrideAnimation(ANIM_URL, 30, true, 0, 53);

It works perfectly but everytime when I want to activate it I must go to my scripts tab and run the script of overrider. My idea is that this script will be activated by pressing e.g, letter ‘P’ on keyboard.
The thing which I am going do to is : pressing different keys on keyboard wil; make avatar perform different animations.


#4

If you want to play the animation on trigger, I suggest checking out the Controller API.

Scripts tend to play as soon as your run them sequentially,
You will have to listen to a Controller event, listening to the specific Keyboard button to grab keys, or use a update thread monitor to check what button is pressed when.

However, cleanest, and easiest way would be to use the Controller Mapping feature.

Forexample you could do one quickly by (note, I havent tested this as I am writing it during my lunch break :slight_smile: )

const PACKAGE = "unique.clap.id";
// Create a new controller map.
var clapController = Controller.newMapping(PACKAGE);

// Create function that will be called when the key is pressed
function clapKeyEvent (pressed){
  if (pressed) {
    // Turn on
  } else {
    // Turn off
  }
}
// Set the Controller to react when one presses P on the Keyboard
// Peek is just a way of saying "do not change the value to children"
clapController.from(Controller.Hardware.Keyboard.P).to(clapKeyEvent);

// Now apply the new Control rules to be active.
Controller.enableMapping(PACKAGE);

Script.scriptEnding.connect( function () {
  // Script is stopping, so lets remove the map
  Controller.disableMapping(PACKAGE);
  // And lets make sure all animations and sounds are stopped
  clapKeyEvent(false);

});



#5

Thank you very much my salvator:slight_smile:
May I bother you more, as my effords give no results.

Here is what I did as example, and it should replace idle animation with clasping hands animation when P key is pressed but itsimply does not work:frowning:
What am I doing wrong?

// Create a new controller map.
var clapController = Controller.newMapping(“unique-name-for-keyboard-clap”);
var ANIM_URL = “https://s3.amazonaws.com/hifi-public/animations/ClapAnimations/ClapHands_Standing.fbx”;

// Create function that will be called when the key is pressed
function clapKey (pressed){
if (pressed) (
MyAvatar.overrideRoleAnimation(“idleStand”, ANIM_URL, 30, true, 0, 53);
} else {
// On Release
// Stop Animation, Sound, on release
}
}
// Set the Controller to react when one presses P on the Keyboard
// Peek is just a way of saying "do not change the value to children"
clapController.from(Controller.Hardware.Keyboard.P).peek().to(clapKey);

// Now apply the new Control rules to be active.
Controller.enableMapping(clapController);

Script.scriptEnding.connect( function () {
// Script is stopping, so lets remove the map
Controller.disableMapping(clapController);
// And lets make sure all animations and sounds are stopped
clapKey(false);

});


#6

As said I hadnt tested it and as it was from memmory. I fixed the script above, use that for reference in the future :slight_smile:

Forgot that it was the Package ID you were supposed to give to the enableMapping not the controller map.


#7

Thank you! It works perfecty now.