유니티 3D게임 쿼드뷰 13

유니티 3D게임 쿼드뷰 13

Summary 유니티 3D 게임 개발에 대한 내용으로, gameObject.layer를 변경하여 충돌 설정, 보스 패턴 구현, 확률 설정 및 버그 해결 방법을 다룹니다. 또한, 부모 클래스의 Awake() 메서드 문제와 해결책, 보스의 다양한 공격 메커니즘 구현에 대한 코드 예시가 포함되어 있습니다.


🎥 동영상 보기

🔥 gameObject.layer = 14; 이런느낌으로 레이어를 변경해서 특정 레이어와 충돌하게하거나 하지않게 만들어서 관리할 수 있다

🔥 상속을 받더라도 부모의 스크립트의 변수가 public 이여야만 자식 스크립트에서 사용이 가능합니다 Image

Image

🔥 보스패턴 구현 Think() 에서 랜덤한 분기점에 따라서 코루틴을 불러오고 불러온 코루틴이 끝나면 코루틴 내부에서 다시 Think()를 불러와 다시금 프로그램이 실행될 수 있도록 코드를 구현

Case를 n개 이상 겹치게하여 확률을 높임

총 5개중 40퍼확률로 미사일발사 , 돌굴러가는패턴, 20퍼확률로 점프공격

 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
//Boss.cs

IEnumerator Think()
    {
        yield return new WaitForSeconds(0.1f); //생각하는 시간 길수록 보스가 쉬워진다

        //랜덤으로 0~4값이 랜덤액션값에 들어간다
        //보스가 랜덤값에 따라 다른 패턴을 가지기 위함이다
        **int ranAction = Random.Range(0,5);
        switch (ranAction)**
        {

            case 0:
            case 1:
                //미사일 발사 패턴
                StartCoroutine(MissileShot());
                break;
            case 2:
            case 3:
                //돌 굴러가는 패턴
                StartCoroutine(RockShot());
                break;
            case 4:
                //점프 공격 패턴
                StartCoroutine(Taunt());
                break;
        }
    }

    IEnumerator MissileShot()
    {
        anim.SetTrigger("doShot");
        yield return new WaitForSeconds(2.5f);

        **StartCoroutine(Think());**
    }

    IEnumerator RockShot()
    {
        anim.SetTrigger("doBigShot");
        yield return new WaitForSeconds(3f);

        StartCoroutine(Think());
    }

    IEnumerator Taunt()
    {
        anim.SetTrigger("doTaunt");
        yield return new WaitForSeconds(3f);

        StartCoroutine(Think());
    }

🔥 근데 이렇게 짜면 어미클래스인 Enemy에서 초기화 한 컴포넌트정보가 제대로 들어가있지 않는다 왜그럴까?

이유는 자식함수의 Awake()는 자식 클래스’만’ 단독실행 하기 때문에 어미클래스의 Awake()는 제대로 실행되지 않습니다

Image

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//Enemy.cs
void Awake()
    {
        rigid = GetComponent<Rigidbody>();
        boxCollider = GetComponent<BoxCollider>();
        meshs = GetComponentsInChildren<MeshRenderer>();
        nav = GetComponent<NavMeshAgent>();
        anim = GetComponentInChildren<Animator>();
        if(enemyType != Type.D)
            Invoke("ChaseStart",2); //추격하는 함수를 2초뒤에 실행한다
    }

해결방법(택1)

  • 어미클래스의 Awake() 를 Start() 로 바꿔준다
    • 이 방법은 기존에 Awake()로 작업했던 코드들과 충돌을해 문제가 있을수도 있으니 조심
  • 어미클래스의 내용을 자식클래스에도 그대로 붙여넣는다
    • 이 방법이 제일 안전

🔥 보스 스킬들 구현

🔥 보스 미사일발사공격 매커니즘 구현

 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
//Boss.cs

IEnumerator MissileShot()
    {
        //애니메이션 실행
        anim.SetTrigger("doShot");

        //첫번째 미사일 발사 코드
        yield return new WaitForSeconds(0.2f);
        **//Instantiate(인스턴트할 오브젝트, 인스턴트 생성 위치, 인스턴트 생성 각도)**
        GameObject instantMissileA = **Instantiate**(missile, missilePortA.position, missilePortA.rotation);
        BossMissile bossMissileA = instantMissileA.GetComponent<BossMissile>();
        bossMissileA.target = target; //미사일의 타겟에 현재클래스의 타겟을 담는다

        //두번째 미사일 발사 코드
        yield return new WaitForSeconds(0.3f);
        //Instantiate(인스턴트할 오브젝트, 인스턴트 생성 위치, 인스턴트 생성 각도)
        GameObject instantMissileB = Instantiate(missile, missilePortB.position, missilePortB.rotation);
        BossMissile bossMissileB = instantMissileB.GetComponent<BossMissile>();
        bossMissileB.target = target; //미사일의 타겟에 현재클래스의 타겟을 담는다

        yield return new WaitForSeconds(2f);

        StartCoroutine(Think());
    }

🔥 보스 돌 발사 구현

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
//Boss.cs

IEnumerator RockShot()
    {
        //기를 모을땐 플레이어를 바라보는것을 중지시킨다
        isLook = false;
        anim.SetTrigger("doBigShot");
        //인스턴트를 생서할 오브젝트를 bullet에 저장하였고, 그 bullet의 pos값과 rotate 값을 그대로 받아오겠다는 뜻
        Instantiate(bullet, transform.position, transform.rotation);
        yield return new WaitForSeconds(3f);

				isLook = true;
        StartCoroutine(Think());
    }

🔥 보스 점프공격 구현

 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
IEnumerator Taunt()
    {
        //내려찍을 위치를 받기 위해 점프공격 위치를 변수에 저장
        //점프상태일때 타겟을 바라보면 어색하니 잠시 isLook을 끔
        //타겟의 위치와 바라보는 위치값을 더함
        tauntVec = target.position + lookVec;

        isLook = false;
        nav.isStopped = false; //네비게이션이 다시 작동합니다
        boxCollider.enabled = false; //공중에 있을때 콜라이더가 충돌하여 데미지를 입지 않게
        anim.SetTrigger("doTaunt");

        //1.5초 지나면 공격범위 활성화
        yield return new WaitForSeconds(1.5f);
        meleeArea.enabled = true;

        yield return new WaitForSeconds(0.5f);
        meleeArea.enabled = false;

        //공격이 끝났으니 다시 원래대로
        yield return new WaitForSeconds(1f);
        isLook = true;
        nav.isStopped = true; //네비게이션이 종료됩니다
        boxCollider.enabled = true; //공중에 있을때 콜라이더가 충돌하여 데미지를 입지 않게
        StartCoroutine(Think());
    }

🔥 StopAllCoroutines() = 모든 코루틴이 break되며 코드가 끝난다

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//Boss.cs

void Update()
    {
        if (isDead)
        {
            StopAllCoroutines();
						return;
        }
		}

🔥 MeleeArea와 충돌했을때 버그나는 이유는 MeleeArea에 Bullet을 넣지 않았기 때문… Image

Image

🔥 보스에게 공격당했을 때 Player 넉백구현 other.name 으로 네임태그로 오브젝트를 불러올 수 있구나

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
//player.cs

void OnTriggerEnter(Collider other)
    {
        else if(other.tag == "EnemyBullet")
        {   if(!isDamage)
            {
                Bullet_Enemy enemyBullet = other.GetComponent<Bullet_Enemy>();
                health -= enemyBullet.damage;

                bool isBossAtk = **other.name** == "Boss Melee Area";
                StartCoroutine(OnDamage(isBossAtk));
            }
        }
    }
    IEnumerator OnDamage(bool isBossAtk) //플레이어가 적의 총알의 데미지를 입었을 때
    {
        //보스공격을 맞았을땐 그냥 뒤로 넉백을 줘버리자
        if(isBossAtk)
            rigid.AddForce(transform.forward * -25, ForceMode.Impulse);

    }

💬 댓글

GitHub 계정으로 로그인하여 댓글을 남겨보세요. GitHub 로그인

🔧 댓글 시스템 설정이 필요합니다

GitHub Discussions 기반 댓글 시스템을 활성화하려면:

  1. Giscus 설정 페이지에서 설정 생성
  2. GISCUS_SETUP_GUIDE.md 파일의 안내를 따라 설정 완료
  3. Repository의 Discussions 기능 활성화

Repository 관리자만 설정할 수 있습니다. 설정이 완료되면 모든 방문자가 댓글을 남길 수 있습니다.