ETH官方钱包

前往
大廳
主題

【Unity】連續動作的處理

微笑的貘 | 2023-04-20 12:32:47 | 巴幣 12 | 人氣 1078

我覺得這是一個很難發現卻很重要的問題。
很多人試玩了我的遊戲後反應動作有延遲。
本來以為是動作或碰撞判定的問題,後來才發現是 Animator 對連續輸入的反應所致。

一般來說,玩家輸入幾次,Animator Trigger 就會觸發幾次。
舉例來說,如果玩家按三下攻擊,Animator 就會演出三次攻擊動畫。
這聽起來很合理。
但是假如攻擊動畫有一秒,玩家手速超快,在一秒之內按了十次,你就會看到在接下來的十秒角色都在攻擊。
然而玩家心理預期的是手一放開,角色就該停止動作。
那這要怎辦咧?

首先先做一張表
以這張表為例,移動之後可以接任何動作。
普攻之後只能接移動,其他的都不行。
然後把它寫成txt,或是任何程式可以讀的檔案。
然後是程式的部分

protected override void Update()
{
    base.Update();

    //將輸入的 keycode 塞進 queue 中
    KeyCode keyCode = KeyCode.Escape;
    if (Input.GetKeyDown(KeyCode.X))
    {
        keyCode = KeyCode.X;
    }
    if (Input.GetKeyDown(KeyCode.A))
    {
        keyCode = KeyCode.A;
    }
    if (Input.GetKeyDown(KeyCode.C))
    {
        keyCode = KeyCode.C;
    }
    if (Input.GetKeyDown(KeyCode.Z))
    {
        keyCode = KeyCode.Z;
    }

    if (keyCode != KeyCode.Escape)
    {
        _actionQueue.Enqueue(keyCode);

        //如果 queue 中只有一個 keycode,就立刻執行動畫
        if (_actionQueue.Count == 1)
        {
            _lastKeyCode = keyCode;
            SetAnimation(keyCode);
        }
    }
}

private void SetAnimation(KeyCode keyCode)
{
    //X是普攻,會根據目前是否有輸入向上或向下來判斷是向上、向下、或向前的攻擊
    if (keyCode == KeyCode.X)
    {
        if (Input.GetKey(KeyCode.UpArrow))
        {
            AttackUp();
        }
        else if (Input.GetKey(KeyCode.DownArrow))
        {
            AttackDown();
        }
        else
        {
            Attack();
        }
    }
    
    //其他的動作指令
    if (keyCode == KeyCode.A)
    {
        SkillA();
    }
    if (keyCode == KeyCode.C)
    {
        Dash();
    }
    if (keyCode == KeyCode.Z)
    {
        Jump();
    }
}

void Attack()
{
    Animator.SetTrigger("Attack");
}

在這些動作的動畫的最後一幀加入 Event,執行 OnActionEnd

OnAnimationEnd 的程式

public void OnActionEnd() //動作結束的時候
{
    if (_actionQueue.Count > 0)
    {
        _actionQueue.Dequeue();
        if (_actionQueue.Count > 0)
        {
            KeyCode currentKeyCode = _actionQueue.Peek();
            ContinueActionData.ActionEnum currentActionEnum = KeyCodeToActionEnum(currentKeyCode);
            ContinueActionData.ActionEnum lastActionEnum = KeyCodeToActionEnum(_lastKeyCode);

            //判斷是否為可連續的動作
            if (ContinueActionData.Data[(int)lastActionEnum, (int)currentActionEnum])
            {
                _lastKeyCode = currentKeyCode;
                SetAnimation(currentKeyCode);
            }
            else
            {
                _actionQueue.Clear();
            }
        }
    }
}
舉例來說,玩家在攻擊結束前輸入了衝刺,這個衝刺的指令就會被塞進 queue 中
攻擊動作結束時 dequeue
根據上面那張表來判斷攻擊之後可不可以接衝刺,答案是不行。
所以衝刺的指令會被忽略。
反之,如果是可連續的動作就會執行該動作。

還有一個問題是 Animatio Exit Time
舉例來說,角色的普通攻擊有兩段動作。
第一下普通攻擊結束後一段時間內再次進行的普通攻擊會不一樣。
這段時間就是 Exit Time
以我的遊戲為例,X之後0.5內再次按X就會進行 SecondAttack
這個 0.5 的單位好像不是秒,而是動畫長度的 normalized time

大概就是這樣...
這個問題超坑爹的。我就是玩了幾十年的遊戲都沒發現這個問題。
卻會一直讓人覺得"手感怪怪的"
多虧了專精動作遊戲的小夥伴才終於發現了這個問題。
希望這篇文章可以讓其他人避免被坑。
追蹤 創作集

作者相關創作

相關創作

更多創作