[Unity] Knife Hit (9)

suhan0304·2024년 9월 3일

유니티 - Knife Hit

목록 보기
9/9
post-thumbnail

Boss Rotate

보스 회전을 패턴화해보자. Target 클래스를 상속받은 Boss 클래스를 상속해서 보스별로 패턴 스크립트를 작성해주려고 했는데, 좀 비약적이긴 한데 보스가 100마리 넘게 구현하려면 100개가 넘는 스크립트가 필요하고 이를 컴파일하고, 실행하는데 시간이 너무 소요될 거 같아서 그냥 Boss 클래스를 상속받은 BossInstance 스크립트 하나를 작성하기로 했다.

회전 패턴화를 어떻게 구현하고자 했냐면 현재 Target의 회전을 담당하는 Target 클래스의 RotateTargetObject가 아닌 보스 별로 별도의 회전 메소드를 만들어 보스 타입별로 해당 회전을 실행하도록 구현하고자 했다.

먼저 보스별로 타입을 주어서 어떤 보스인지 구분하게 하자.

Boss.cs

[TabGroup("Boss","Settings")] public int bossType = -1;

BossInstance.cs

using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.UIElements;

public class BossInstance : Boss
{
    protected override void Start() {
        gameObject.transform.position = GameManager.Instance.targetSpawnPosition;

        StartTargetAnimation();

        if(bossType == -1) {
            Debug.LogError($"[Boss.cs] bossType is not assigned.");
        }
        else {
            RotateBossObject();
        }
    }

    public void RotateBossObject() {
        bossSequence?.Kill();

        bossSequence = DOTween.Sequence();

        switch(bossType) {
            case 0:
                bossSequence.Append(transform.DORotate(new Vector3(0f, 0f, transform.eulerAngles.z + 60f), 1f, RotateMode.FastBeyond360)
                    .SetEase(Ease.InOutSine))
                    .AppendInterval(1f);
                break;
            case 1:
                break;
            case 2:
                break;
            case 3:
                break;
            case 4:
                break;
            case 5:
                break;
        }

        bossSequence.SetLoops(-1); 
    }
}

그리고 bossSequnce.Kill()를 Target.cs에 업데이트 해주어야 보스의 애니메이션도 잘 종료된다.

Target.cs

using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.UIElements;

public class BossInstance : Boss
{

    protected override void Start() {
        gameObject.transform.position = GameManager.Instance.targetSpawnPosition;

        StartTargetAnimation();

        if(bossType == -1) {
            Debug.LogError($"[Boss.cs] bossType is not assigned.");
        }
        else {
            RotateBossObject();
        }
    }

    public void RotateBossObject() {
        float delayTime = 0.5f;

        bossSequence?.Kill();

        bossSequence = DOTween.Sequence();

        switch(bossType) {
            case 0:
                bossSequence.Append(transform.DORotate(new Vector3(0f, 0f, 60f), 0.5f, RotateMode.FastBeyond360)
                        .SetEase(Ease.InOutSine))
                    .AppendInterval(delayTime);
                break;
            case 1:
                break;
            case 2:
                break;
            case 3:
                break;
            case 4:
                break;
            case 5:
                break;
        }

        bossSequence.SetLoops(-1, LoopType.Incremental); 
    }
}

LoopType을 Incremental로 해야 종료된 시점을 시작 지점으로 모션이 다시 시작된다.

이제 보스 스프라이트를 저번 Boss Orange를 만들었을때와 동일한 방법으로 여러개 만들고 여러 패턴을 적용시켜 보스 프리팹을 여러 개 만들어보려했으나, 스프라이트 하나를 3개로 복사해서 다시 Polygon으로 바꿔서 설정해주고 하면 너무나 오랜 시간이 걸리고, 결국 스프라이트의 개수 자체도 많아지다보니 힘들거 같아서 다른 방식으로 해결했다.

Sprite Mask

Sprite Mask를 써서 테두리만 미리 잡아주고, 스프라이트만 바꿔주면 알아서 조각이 되도록 바꿔보자. 먼저 Sprite Renderer에서 Mask InteractionVisible Inside Mask로 해줘서 Mask 내부가 보이도록 해준다.

그 다음 자식 오브젝트로 SpriteMask를 추가해보자.

이제 기존 Segment에는 원형의 Sprite를 그대로 넣어주고 Mask에 Polygon의 CustomOutline으로 쪼개준 모양을 넣어주면 아래와 같이 잘 나온다.

이제 보스를 똑같이 프리팹을 복사해주고 각 Segment 오브젝트의 Sprite Renderer에 원형의 스프라이트를 그대로 넣어주면?

Pivot과 Position은 초기화해줬다. 물론 방향 로직 스크립트도 수정해주었다.

이제 보스 별로 패턴을 한 번 만들어주자.

switch(bossType) {
    case 0:
        bossSequence
            .Append(transform.DORotate(new Vector3(0f, 0f, 35f), 0.25f, RotateMode.FastBeyond360)
                .SetEase(Ease.InOutSine))
            .AppendInterval(0.25f)
            .SetLoops(-1, LoopType.Incremental); 
        break;
    case 1:
        bossSequence
            .Append(transform.DORotate(new Vector3(0f, 0f, 70f), 0.5f, RotateMode.FastBeyond360).SetEase(Ease.InOutCubic))
            .Append(transform.DORotate(new Vector3(0f, 0f, -140f), 1f, RotateMode.FastBeyond360).SetEase(Ease.InOutCubic).SetLoops(-1, LoopType.Yoyo));
        break;
    case 2:
        bossSequence
            .Append(transform.DORotate(new Vector3(0f, 0f, 360f), 2f, RotateMode.FastBeyond360).SetEase(Ease.Linear))
            .SetLoops(-1, LoopType.Incremental); 
        break;
    case 3:
        bossSequence
            .Append(transform.DORotate(new Vector3(0f, 0f, Random.Range(180f, 240f) * (Random.value > 0.5f ? 1f : -1f)), 1f, RotateMode.FastBeyond360)
                .SetEase(Ease.InOutSine))
            .AppendInterval(0.5f)
            .SetLoops(-1, LoopType.Incremental); 
        break;
    case 4:
        bossSequence
            .Append(transform.DORotate(new Vector3(0f, 0f, -360f * 4.3f), 4.5f, RotateMode.FastBeyond360).SetEase(Ease.InOutSine))
            .AppendInterval(0.5f)
            .SetLoops(-1, LoopType.Incremental); 
        break;
    case 5:
        bossSequence
            .Append(transform.DORotate(new Vector3(0f, 0f, Random.Range(60f, 100f) * (Random.value > 0.5f ? 1f : -1f)), 0.5f, RotateMode.FastBeyond360)
                .SetEase(Ease.Linear)
                .SetLoops(Random.Range(1,5), LoopType.Yoyo))
            .SetLoops(-1, LoopType.Incremental);
        break;
}

이 정도로 만들고 프리팹에서 boss Type과 이름을 수정해주자.

이제 Boss Prefab 리스트를 만들고 보스 스폰 시 랜덤한 보스를 스폰하도록 해보자.

[TabGroup("Tab","Prefabs")] public List<GameObject> bossPrefabs;

[Button("SpawnBoss")]
public void SpawnBoss() {
    currentTarget = Instantiate(bossPrefabs[Random.Range(0, bossPrefabs.Count - 1)]);
    RemainKnives = currentTarget.GetComponent<Target>().knivesToDestroy;
}

이제 보스가 랜덤하게 스폰된다.

연이어 똑같은 보스가 스폰돼지 않도록 아래와 같이 수정했다.

[Button("SpawnBoss")]
public void SpawnBoss() {
    int bossNum;
    do
    {
        bossNum = Random.Range(0, bossPrefabs.Count - 1);
    } while (bossNum == lastBossIndex);
    
    Debug.Log($"[GameManager.cs] SpawnBoss : {bossNum} Boss");
    currentTarget = Instantiate(bossPrefabs[bossNum]);
    RemainKnives = currentTarget.GetComponent<Target>().knivesToDestroy;
}

기타 버그 수정

  • Score 초기화 오류 수정
  • Ground 보스 패턴 오류 수정
  • Tire 보스 패턴 부자연스러움 수정
  • 보스 스폰 미작동 오류 수정
  • 동일한 보스 스폰 방지
profile
Be Honest, Be Harder, Be Stronger

0개의 댓글