(3D RPG) 플레이어 기능
포스트
취소

(3D RPG) 플레이어 기능

구르기 (회피)

몬스터의 공격이나 보스의 공격 패턴을 피하기 위해 구르기를 추가했다.

연속 공격

처음에 연속 공격은 생각보다 구현이 헷갈려서 해맸지만 구현은 성공했다..!

[ 연속 공격이 되는 과정 ]
공격키 입력 -> 공격 진행 -> 공격 중에 공격키 입력하는지 계속 확인 -> 공격키를 누르면 다음 공격 진행 || 안누르면 Idle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
float _attackCloseTime = 0;
// State가 Attack면 UpateAttack 계속 호출
protected override void UpdateAttack()
{
    _attackCloseTime += Time.deltaTime;

    // 공격이 시간이 끝나면 종료 || 공격이 끝났는데 다른 애니메이션에 있다면 종료
    if ((anim.GetCurrentAnimatorStateInfo(0).IsTag("Attack") == true &&
        _attackCloseTime > 0.94f && _onComboAttack == false) || 
        (anim.GetCurrentAnimatorStateInfo(0).IsTag("Attack") == false &&
        _attackCloseTime > 0.99f && _onComboAttack == false))
    {
        StopAttack();
        State = Define.State.Idle;
        return;
    }

    dir = _destPos - transform.position;
    transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(dir), 20f * Time.deltaTime);
}

bool _onAttack = false;
bool _onComboAttack = false;
int attackClipNumber = 0;
string[] _attackClipList = new string[] {"ATTACK1", "ATTACK2"};
// 공격키를 누르면 호출
void OnAttack()
{
    // 콤보 체크
    if (_onAttack &&
        anim.GetCurrentAnimatorStateInfo(0).IsTag("Attack") &&
        anim.GetCurrentAnimatorStateInfo(0).normalizedTime >= 0.3f)
    {
        _onComboAttack = true;
    }

    // 공격!
    if (!_onAttack)
    {
        anim.CrossFade(_attackClipList[attackClipNumber], 0.1f, -1, 0);
        State = Define.State.Attack;

        _onAttack = true;
    }
}

// [ Anim Event ] 공격 애니메이션이 끝나면 호출
public void ExitAttack()
{
    // 공격 중에 공격 키를 눌렀나?
    if (_onComboAttack == true)
    {
        if (attackClipNumber == 1)
            attackClipNumber = 0;
        else if (attackClipNumber == 0)
            attackClipNumber = 1;

        anim.CrossFade(_attackClipList[attackClipNumber], 0.1f, -1, 0);
        _onComboAttack = false;
    }
}

void StopAttack()
{
    _onAttack = false;
    _onComboAttack = false;
    _stopAttack = true;
    _attackCloseTime = 0;
    attackClipNumber = 0;
}

💻 BaseController.cs

컨트롤이 필요한 캐릭터는 모두 BaseController.cs를 상속받는다. (Player, Monster, NPC,…)

BaseController.cs는 상태(State)에 관련한 기본 기능을 가지고 있다.

애니메이션 코드

애니메이션을 코드로 관리하기 위해 CrossFade를 사용했으며

애니메이션(CrossFade)은 캐릭터의 상태(State)가 바뀌면 호출되도록 구현했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
int number = 1;

[SerializeField]
protected Define.State _state = Define.State.Idle;

public virtual Define.State State
{
    get { return _state; }
    set {
        _state = value;

        // anim.CrossFade(재생 클립 이름, 바뀌는데에 지연 시간, 레이어, 재생 시작 시점)
        switch (_state)
        {
            case Define.State.Moving:
                anim.CrossFade("RUN", 0.1f);
                break;
            case Define.State.Idle:
                anim.CrossFade("WAIT", 0.4f);
                break;
            case Define.State.DiveRoll:
                anim.CrossFade("DIVEROLL", 0.1f, -1, 0);
                break;
            case Define.State.Attack:
                // 플레이어는 공격 상황이 바뀔 수 있으니 Monster만 사용
                if (WorldObjectType == Define.WorldObject.Monster)
                {
                    anim.CrossFade("ATTACK"+number, 0.1f, -1, 0);

                    // 기본 공격 방법은 두가지로 번갈아도록 함.
                    if (number == 1)
                        number = 2;
                    else if (number == 2)
                        number = 1;
                }
                break;
            case Define.State.Hit:
                {
                    anim.CrossFade("HIT", 0.1f, -1, 0);
                }
                break;
            case Define.State.Die:
                {
                    anim.CrossFade("DIE", 0.1f, -1, 0);
                }
                break;
        }
    }
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.