본문 바로가기

Unity/로봇 체스 개발 일지

[Unity] 스킬 구현(2) : 데미지 판정, 스킬 알고리즘

요약

로봇을 제거하는 방법으로 총알을 실제로 날리는 방법과 데미지 판을 만들어 생성하는 방법으로 나뉜다. 다만 데미지 판을 만들게 되면 총을 발사할 때 총알이 나가지 않으므로 가짜 총알을 만들어 실제 발사되는 것처럼 하였다. 이때 가짜 총알은 처음 발사된 곳에서 목적지까지 거리가 현재 지점보다 작다면 사라지도록 하였다.

스킬 알고리즘은 대부분 유사한 모습의 코드를 가지고 있으나 총알과 데미지 판 중 어느것을 사용한지에 따라 달라진다.


총알

Bullet.cs

public class Bullet : MonoBehaviour
{
    float speed = 10;
    public bool isMonster = true;
    void Update()
    {
        transform.Translate(speed * Time.deltaTime, 0,0);
    }
    public void OnCollisionEnter2D(Collision2D collision)
    {
        if (!isMonster)
        {
            try
            {
                if (collision.gameObject.GetComponent<Monster>() != null)
                {
                    collision.gameObject.GetComponent<Monster>().Hp -= 1;
                    GetComponent<MyObject>().Destroy();

                }
            }
            catch { }
        }
        if (isMonster)
        {
            if (collision.gameObject.GetComponent<Player>() != null)
            {
                collision.gameObject.GetComponent<Player>().Hp -= 1;
                GetComponent<MyObject>().Destroy();
            }
        }
    }
}

총알이 실제로 날아가 부딪혀 데미지를 입히는 방법이다. 다만 플레이어가 사용하는지 몬스터가 사용하는지 구분하기 위해 isMonster변수를 통해 지정해야 한다.

 


데미지판

CrashBoxObject.cs

public class CrashBoxObject : MonoBehaviour
{
    private void OnCollisionEnter2D(Collision2D collision)
    {
        if(collision != null && collision.transform.GetComponent<Monster>() != null)
        {
            collision.transform.GetComponent<Monster>().Hp -= 1;
            GetComponent<MyObject>().Destroy();
        }
        if (collision != null && collision.transform.GetComponent<Player>() != null)
        {
            collision.transform.GetComponent<Player>().Hp -= 1;
            GetComponent<MyObject>().Destroy();
        }
    }
}

총알과 유사한 코드를 가지고 있다. 다만 판은 이동하지 않으므로 Collision 관련 함수만 존재한다.

 

FakeBullet.cs

public class FakeBullet : MonoBehaviour
{
    public Vector3 targetPos;

    private Vector3 previousPosition;
    bool start = true;
    void FixedUpdate()
    {
        transform.Translate(15 * Time.fixedDeltaTime, 0, 0);
    }
    void Update()
    {
        if (start)
        {
            previousPosition = transform.position;
            start = false;
        }
        Vector3 currentPosition = transform.position;

        float previousDistance = Vector3.Distance(previousPosition, targetPos);
        float currentDistance = Vector3.Distance(currentPosition, targetPos);

        if (previousDistance < currentDistance)
        {
            start = true;
            GetComponent<MyObject>().Destroy();
        }
        previousPosition = currentPosition;
    }
}

총인 만큼 실제로 총알이 날아가는 것처럼 보이기 위해 가짜 총알을 만들었다. 처음에는 목적지에 도착하면 사라지도록 구현하였지만, 미세한 오차로 목적지를 지나가면 사라지지 않았다. 그래서 처음 생성된 지점과 목적지 거리가 현재보다 작다면 사라지도록 하였다.


스킬 알고리즘

배치 알고리즘과 데미지 판정 알고리즘을 활용하면 하나의 스킬을 만들 수 있다. 

Pistol.cs

public class Pistol : IState
{
    bool start = false;
    bool skillUse = false;
    float accuracy = 0.001f;
    public override int UsageLimit { get => 4; set { } }

    public void Entry()
    {
        UnifiedAttackRange(2, AttackType.Normal);
    }

초반 Entry 부분에서는 특별히 수정하는 것은 없다. 배치 알고리즘에 맞는 타입을 선택하고 범위를 지정하면 된다.

 

Pistol.cs / Sniper.cs

    public void IStateUpdate()
    {
        if (UpdateSelectionCheck())
        {
            skillUse = true;
            start = true;
        }

        if (start)
        {
            if (!Instance.action.UpdateLookAtTarget(Instance.MyHit.positionInt, transform, accuracy, 7f))
            {
                Shoot(PoolManager.Prefabs.AK47Bullet);
                start = false;
                Usage++;
            }
        }
        else if (skillUse)
        {
            if (Instance.action.TurnAngle(Vector3.zero, transform, 7f))
            {
                Instance.playerState = State.Idle;
                CheckUsage();
            }
        }
    }

총알을 사용하는 경우 스크립트가 같다. 다만 데미지 판을 사용하는 칼이면 조금 달라진다.

 

Knife.cs

public void IStateUpdate()
{
    MyObject crashBoxObject;
    if (UpdateSelectionCheck())
    {
        crashBoxObject = Instance.poolManager.SelectPool(PoolManager.Prefabs.CrashBoxObject).Get();
        crashBoxObject.transform.position = new Vector3Int(Instance.MyHit.positionInt.x, Instance.MyHit.positionInt.y, 0);
        skillUse = true;
        start = true;
    }
    if (start)
    {
        if (!Instance.action.UpdateLookAtTarget(Instance.MyHit.positionInt, transform, 0.001f, 7f))
        {
            start = false;
        }
    }
    else if (skillUse)
    {
        if (Instance.action.TurnAngle(new Vector3(0,0, Instance.action.LeftAbj(transform, 90)), transform,7f))
        {
            Instance.playerState = State.Idle;
            CheckUsage();
        }
    }
}

칼인 경우 실제로 투사체가 없기에 데미지 판을 이용하여 적을 제거한다.

 

Knife.cs / Pistol.cs / Sniper.cs / Schrotflinte.cs / LaserGun.cs

    public bool Exit()
    {
        if (skillUse)
        {
            skillUse = false;
            return true;
        }
        return false;
    }
}

마지막에 스킬을 취소하지 않고 사용 했는지 아닌지를 판단하기 위해 작성된 스크립트이다. 스킬 스크립트에는 대부분 사용되고 있다.