본문 바로가기
유니티 게임 개발

[유니티 강좌] 2D RPG 게임 만들기 - 5 / 적 공격하기

by 호일이 2020. 5. 23.

적을 공격하는 것을 크게 두 가지로 나눈다면

1. 공격 판정 정하기

2. 맞은 적의 HP 줄이기

정도가 되겠습니다.

 

공격 판정은 여러 방식으로 정할 수 있지만

이번 강좌에서는 유니티 엔진에서 제공하는 것을 사용해보겠습니다.

 

공격 방식은 판정의 영역을 정해서 그 범위 안에 있다면 맞게 할 수도 있고

아니면 판정을 무기에 붙여서 무기를 휘둘렀을 때 판정 영역에 있다면 맞게 할 수도 있습니다.

저는 후자의 방법을 택해서 진행해보도록 하겠습니다.

 

먼저 무기에 Box Collider2D를 붙입니다.

그리고 본체에도 Collider2D를 붙여줍니다.

 

적에게도 몸에 Collider를 붙여줍니다.

Collider는 물리적인 상호작용을 할 수 있게 해서 Collider들끼리 충돌하고 밀어낼 수 있습니다.

 

그리고 Rigidbody2D를 소드맨과 적에게 붙여줍니다.

Rigidbody는 오브젝트가 사실적으로 움직이게 해 줍니다. 따라서 Rigidbody가 붙으면 중력에 영향을 받게 됩니다.

 

이대로 실행하면 밑으로 쭉 떨어지기 때문에

땅을 만들어줘야 합니다.

 

아직 Tile에 대해 포스팅을 하지 않아서 임시로 체력바의 크기를 키워서 땅 대신 사용했습니다.

임시로 땅 대신 체력바 사용

 

물체를 밀 수 없게 만들기

실행해보면 땅에서 잘 움직입니다.

하지만 소드맨이 적을 쉽게 밀 수 있게 되었습니다.

미는 것을 의도한 게임이라면 상관없지만

적을 밀 수 없게 만들고 싶었을 때는 문제가 됩니다.

 

이것을 해결하기 위한 제가 알고 있는 방법은 2가지가 있습니다.

1. 미는 오브젝트의 Rigidbody의 mass(질량)값을 낮춘다.

질량 값에 따라 미는 힘의 크기가 달라집니다.

소드맨의 mass를 최솟값 0.0001로 변경하면 육안으로 보이지 않을 정도로 적이 밀리지 않습니다.

다만 소수점 단위로는 밀리고 있으므로 완벽히 밀리지 않게 하려는 경우에는 적합하지 않습니다.

 

2. 스크립트를 추가한다.

Rigidbody에 Freeze Position이 있습니다.

X를 체크하면 X축으로 밀리지 않고, Y좌표를 체크하면 Y축으로 밀리지 않습니다.

위 같은 경우는 적이 움직일 때는 체크 해제를 하고 적이 움직임을 멈췄을 때는 X를 체크해주는 스크립트를 추가해주면 적이 밀리지 않을 것입니다.

 

저는 어느 정도 미는 것은 상관없기 때문에 소드맨의 mass값을 0.1로 낮춰서 해결하겠습니다.

 

 

소드맨과 적의 스테이터스 설정

공격할 때 체력이 닳기 위해서 체력, 공격력이라는 변수가 필요합니다.

유닛마다 고유의 스텟이 있으므로 여러 변수를 만들고 값을 넣어보겠습니다.

 

소드맨 부분

Sword_Man.cs 스크립트에 추가

using UnityEngine.UI;

public int maxHp;
public int nowHp;
public int atkDmg;
public float atkSpeed = 1;
public bool attacked = false;
public Image nowHpbar;

void AttackTrue()
{
	attacked = true;
}
void AttackFalse()
{
	attacked = false;
}
void SetAttackSpeed(float speed)
{
	animator.SetFloat("attackSpeed", speed);
	atkSpeed = speed;
}

attacked는 여러번 공격 방지용으로 추가했습니다.

attacked에 대해 밑에서 자세히 설명하겠습니다.

 

Sword_Man.cs Start, Update 추가된 것

 

소드맨은 체력바를 nowHpbar에 드래그 앤 드롭으로 얻어 올 수 있게 했습니다. NowHpbar가 None이면 오류가 발생합니다. 

 

주의! SetAttackSpeed는 항상 animator = GetComponent<Animator>(); 아래에 있어야 합니다.

 

Enemy 부분

Enemy.cs 변수, 함수 추가된 것

using UnityEngine.UI; // Image 자료형을 위해 using 해줘야 함

public string enemyName;
public int maxHp;
public int nowHp;
public int atkDmg;
public int atkSpeed;

private void SetEnemyStatus(string _enemyName, int _maxHp, int _atkDmg, int _atkSpeed)
{
	enemyName = _enemyName;
	maxHp = _maxHp;
	nowHp = _maxHp;
	atkDmg = _atkDmg;
	atkSpeed = _atkSpeed;
}

public Sword_Man sword_man;
Image nowHpbar;

적마다 다른 스텟을 가지고 있어야 하니 편하게 스텟을 할당할 수 있게 함수를 만들었습니다.

 

Enemy.cs Start, Update 추가된 것

Start에 적마다 다른 스텟을 가지도록 이름에 따라 스텟을 설정했습니다.

nowHpbar부분은 hpBar의 fillAmount를 현재 남은 피의 양에 따라 달라지게 설정했습니다.

 

fillAmount?

fillAmount에 따라 그림의 길이가 달라짐을 이용해 현재 남은 체력을 알 수 있습니다.

 

Enemy.cs 트리거 추가

private void OnTriggerEnter2D(Collider2D col)
{
    if (col.CompareTag("Player"))
    {
        if (sword_man.attacked)
        {
            nowHp -= sword_man.atkDmg;
            Debug.Log(nowHp);
            sword_man.attacked = false;
            if (nowHp <= 0) // 적 사망
            {
                Destroy(gameObject);
                Destroy(hpBar.gameObject);
            }
        }
    }
}

OnTriggerEnter란 이 스크립트가 붙어있는 오브젝트에 Trigger가 닿았을 때 실행되는 이벤트입니다.

 

소드맨 무기의 Collider에 isTrigger체크해주셔야 Trigger가 됩니다.

태그Player로 설정해서 혹시 다른 Trigger가 닿았을 때 피가 닳지 않게 했습니다.

 

만약 무기가 닿을 때마다 트리거가 실행된다면, 공격하지 않았는데도 피가 깎이는 버그가 생기게 됩니다.

그래서 트리거에 attacked가 true일 때만 공격을 받게 설정을 해준 것이고, 이제 attacked를 공격할 때만 true가 되게 설정을 해야 합니다.

 

이것을 해결하기 위해 애니메이션에서 제공하는 이벤트 기능을 사용해보겠습니다.

 

[2021-04-22 추가설명]

Enemy스크립트에 체력바 추가할 때 헷갈릴 수도 있는 부분이 있어서 추가 설명하겠습니다.

옛날에 진행하던 프로젝트가 없어서 최신 프로젝트를 사용했습니다. 변수가 좀 더 많이 있어도 신경 쓰지 마시기 바랍니다.

Enemy 스크립트에는 에셋 창의 프리펩 체력바를 넣어서 '새로' 생성했고, 소드맨 스크립트에는 미리 생성해놨던 캔버스의 체력바를 넣게 했습니다. 제가 생각하지 못하고 이름을 동일하게 해 놔서 헷갈렸던 점 죄송합니다. 이름을 바꿔서 진행하셔도 문제없습니다.

[2021-04-22 추가설명 끝]

 

공격 한 번만 되게 설정

소드맨을 선택한 상태에서 Animation 창을 열고 Attack으로 들어갑니다.

 

Attacked를 true로 만들고 싶은 특정 지점에서 우클릭 -> Add Animation Event를 클릭합니다.

 

마찬가지로 false로 만들고 싶은 지점에서 이벤트 생성하고 AttackFalse() 설정

 

이벤트 추가한 Attack 애니메이션

이로서 공격 한 번당 한 번만공격을 받을 수 있게 되었습니다.

 

 

공격 속도 설정

공격 속도를 빠르게 하려면 Attack 애니메이션의 속도를 빠르게 하면 됩니다.

단순히 Animator창에서 Attack 애니메이션을 클릭하고 speed 값을 바꾸면 끝나지만

게임 중 아이템이나 레벨업 같은 걸로 공격 속도가 바뀌었을 때는 이렇게 하지 못합니다.

따라서 스크립트에서 바꿀 수 있어야 합니다.

 

스크립트에서 공격 속도를 제어하는 방법

attackSpeed 파라미터를 추가하고 값을 입력합니다.

Multiplier의 옆에 Parameter를 체크하고 attackSpeed를 넣습니다.

이제 Attack 애니메이션은 attackSpeed와 speed를 곱한 값이 재생속도가 되었습니다.

 

animator.SetFloat("attackSpeed", speed); 이것으로 attackSpeed의 값을 변경할 수 있습니다.

void SetAttackSpeed(float speed) 
{ 
    animator.SetFloat("attackSpeed", speed); 
    atkSpeed = speed; 
}

전 이렇게 함수를 만들어서 바꿨습니다.


마지막으로

소드맨의 공격력과 attacked를 받아오기 위해 드래그 앤 드롭 해주고 피가 다는지 테스트해봅시다.

 

계속 A키를 연타하는 것이 마음에 들지 않는다면 Input.GetKey를 사용하면 됩니다.

Input.GetKey(KeyCode.A)는 A키를 꾹 누르고만 있어도 공격이 자동으로 나가게 됩니다.

 

 

감사합니다.

 

반응형

댓글