Jump to content

Последовательность включения анимации.


photo

Recommended Posts

Всем привет!

Уважаемые разработчики, подскажите пожалуйста). Не могу понять, как заставить работать анимацию последовательно, без рывков.

Есть простые клипы анимации сделанные в блендере: 

1. Достаём топор. 2. Движение топора когда стоим. 3. Движение когда идём. 4. Убираем топор. 5. Удар топором.

С помощью клавиш F1 - F3, Input.MOUSE_BUTTON.LEFT , включаю анимации по отдельности. Работает это хорошо. Но,  теперь вопрос - как мне заставить их работать слитно, как единое целое? Хорошо тут работают только 2 анимации - это когда стоишь и когда идёшь. 

Что бы включить после первой анимации: [Достаём топор] вторую: [Движение топора когда стоим], надо задать условие окончания 1-й анимации, а в нем это равенство:            STATE = ANIM_STATE.AXE_OFF; но как понять когда закончится первая анимация? Пробовал использовать переменную _main_character.Time но это не сработало. 

Надеюсь, понятно объяснил. Код и скриншот (как обычно), прилагаю:

public class hand_axe : Component
{
    [ShowInEditor][ParameterAsset (Filter = ".anim")]
    private string axe_on, axe_off, axe_idle, axe_attak, axe_step;
 
    ObjectMeshSkinned _main_character;
    float _weight = 0;
    bool _is_weight_charget = false;
 
    enum ANIM_STATE {PROCEDURAL  = 0, AXE_ON, AXE_OFF, AXE_IDLE, AXE_ATTAK, AXE_STEP, COUNT}
    ANIM_STATE STATE = ANIM_STATE.PROCEDURAL, PREV_STATE;
 
    private void Init()
    {
        _main_character = node as ObjectMeshSkinned;
        _main_character.NumLayers = (int)ANIM_STATE.COUNT;
 
        int _a_on = _main_character.AddAnimation(axe_on);
        int _a_off = _main_character.AddAnimation(axe_off);
        int _a_idle = _main_character.AddAnimation(axe_step);//  поменял местами для корректной работы  
        int _a_attak = _main_character.AddAnimation(axe_attak);
        int _a_step = _main_character.AddAnimation(axe_idle);// поменял местами для корректной работы
 
        _main_character.SetAnimation((int)ANIM_STATE.AXE_ON, _a_on);//1
        _main_character.SetAnimation((int)ANIM_STATE.AXE_OFF, _a_off);//2
        _main_character.SetAnimation((int)ANIM_STATE.AXE_IDLE, _a_idle);//3
        _main_character.SetAnimation((int)ANIM_STATE.AXE_ATTAK, _a_attak);//4
        _main_character.SetAnimation((int)ANIM_STATE.AXE_STEP, _a_step);//5        
    }
   
    private void Update()
    {
        _main_character.SetFrame((int)ANIM_STATE.PROCEDURAL, Game.Time * 30);
        _main_character.SetFrame((int)ANIM_STATE.AXE_ON, Game.Time * 30);
        _main_character.SetFrame((int)ANIM_STATE.AXE_OFF, Game.Time * 30);
        _main_character.SetFrame((int)ANIM_STATE.AXE_IDLE, Game.Time * 30);
        _main_character.SetFrame((int)ANIM_STATE.AXE_ATTAK, Game.Time * 30);
        _main_character.SetFrame((int)ANIM_STATE.AXE_STEP, Game.Time * 30);
       
        //достаём топор
        if(Input.IsKeyDown(Input.KEY.F1))
            STATE = ANIM_STATE.AXE_ON;
        //убираем топор
        if(Input.IsKeyDown(Input.KEY.F2))
            STATE = ANIM_STATE.AXE_OFF;
        //анимация простоя
        if(Input.IsKeyDown(Input.KEY.F3))
            STATE = ANIM_STATE.AXE_IDLE;            
        //атака топором
        if(Input.IsMouseButtonDown(Input.MOUSE_BUTTON.LEFT) && (STATE == ANIM_STATE.AXE_IDLE || STATE == ANIM_STATE.AXE_STEP))
            STATE = ANIM_STATE.AXE_ATTAK;  
 
        AnimCharger();
 
        _weight = MathLib.Clamp(_weight + Game.IFps, 0f, 1f);      
    }
 
    float _t;
 
    void AnimCharger()
    {
        switch (STATE)
        {
            //достаём топор
            case ANIM_STATE.AXE_ON:
                ResetWeight(); PREV_STATE = ANIM_STATE.AXE_ON;
                _main_character.LerpLayer((int)ANIM_STATE.PROCEDURAL, (int)PREV_STATE, (int)ANIM_STATE.AXE_ON, _weight);            
            break;
            //анимация во время простоя
            case ANIM_STATE.AXE_IDLE:
            if(!Input.IsKeyPressed(Input.KEY.W)){ ResetWeight(); STATE = ANIM_STATE.AXE_STEP; PREV_STATE = ANIM_STATE.AXE_IDLE;}
                _main_character.LerpLayer((int)ANIM_STATE.PROCEDURAL, (int)PREV_STATE, (int)ANIM_STATE.AXE_IDLE, _weight );
            break;
            //анимация во время ходьбы
            case ANIM_STATE.AXE_STEP:
            if(Input.IsKeyPressed(Input.KEY.W)) {ResetWeight(); STATE = ANIM_STATE.AXE_IDLE; PREV_STATE = ANIM_STATE.AXE_STEP;}
                _main_character.LerpLayer((int)ANIM_STATE.PROCEDURAL, (int)PREV_STATE, (int)ANIM_STATE.AXE_STEP, _weight );
            break;
            //убираем топор
            case ANIM_STATE.AXE_OFF:
                if(!Input.IsKeyPressed(Input.KEY.W)) {ResetWeight(); PREV_STATE = ANIM_STATE.AXE_IDLE;}
                if(Input.IsKeyPressed(Input.KEY.W)) {ResetWeight(); PREV_STATE = ANIM_STATE.AXE_STEP;}
                _main_character.LerpLayer((int)ANIM_STATE.PROCEDURAL, (int)PREV_STATE, (int)ANIM_STATE.AXE_OFF, 1);
            break;
            //атакуем топором
            case ANIM_STATE.AXE_ATTAK:
                _main_character.LerpLayer((int)ANIM_STATE.PROCEDURAL, (int)PREV_STATE, (int)ANIM_STATE.AXE_ATTAK, _weight);
            break;
 
            default:
                break;
        }
    }
 
    void ResetWeight()
    {
        _is_weight_charget = true;
        if(_is_weight_charget){ _weight = 0; _is_weight_charget = false;}
    }
}

Ну и скрин:

image.thumb.png.f4857276cf2269803fc877fbdc759d0f.png

 

 

Link to comment

Что бы узнать когда заканчивается анимация нужно узнать какой кадр сейчас утановлен. Это можно посчитать отстатком от деления текущего кадра на количество кадров анимации:

_main_character.GetFrame(0) % _main_character.GetNumFrames(0)

Рывок анимации может быть из-за того что, при переключении анимации вес слоя сбрасывается резко в 0. Лучше сделать плавное уменьшения веса:

 _weight = MathLib.Clamp(_weight - Game.IFps, 0f, 1f);

  • Thanks 1
Link to comment

yingaz

Спасибо за ответ!  Кое-что стало получаться, думаю допилю переходы. Сильно помогла эта строчка: 

_main_character.GetFrame(0) % _main_character.GetNumFrames(0)

Правда, попутно, назрел еще один вопрос: как к костям (или заскиненным мешам) привязать ноду?  Например, у меня на руках висят наручные часы. Они показывают время суток. Скрипт для движения стрелок готов. Но как привязать наручные часы к предплечью?  Я вижу что можно нодами управлять костью,  используя Create Dummy Hierarchy. А наоборот? Или я что-то недопонял? Любая наводка пригодиться! 

Спасибо! 

Link to comment
×
×
  • Create New...