Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
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
Archives
Today
Total
관리 메뉴

인텔리킴의 Unity Studying & Game Analysis

34. 유니티 2D 종스크롤 슈팅 - 보스 구현 본문

게임 개발 일지/유니티 엔진 공부

34. 유니티 2D 종스크롤 슈팅 - 보스 구현

인텔리킴 2024. 6. 11. 01:08

기본 세팅

보스 콜라이더 지정
보스 애니메이션 지정

보스의 애니메이션을 제작하고 적용, 보스의 콜라이더 지정

 

보스 패턴

먼저 보스가 발사할 총알의 프리팹을 제작

보스 총알 A
보스 총알 B

적에게서 뿜어져 나오는 것이기 때문에 Flip Y 적용해서 위아래 반전

 

보스 총알 프리팹 오브젝트 풀링에 등록

등록

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bullet : MonoBehaviour
{
    public int bulletDamage;
    public bool isRotate;
    void Update()
    {
        if (isRotate)
        {
            transform.Rotate(Vector3.forward * 10);
        }
    }
    void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.tag == "BorderBullet")
        {
            gameObject.SetActive(false);
        }
    }
}

스스로 회전하는 총알 삽입을 위해 Bullet 스크립트에 bool 변수 삽입

** 2D 회전은 Z축만 가능**

회전은 Vector3.forward 혹은 back으로 회전

 

void Awake()
{
    spriteRenderer = GetComponent<SpriteRenderer>();
    maxHealth = health;
    if (enemyName == "B")
        animator = GetComponent<Animator>();
}
void Update()
{
    if (enemyName == "B")
        return;
    Fire();
    Reload();
}

적이 보스일 경우에 여러 예외코드 작성

 

if (enemyName == "B")
{
    //10개의 코인 아이템을 보스를 중심으로 랜덤된 위치에 배치
    for (int i = 0; i < 10; i++) {
        float ranX = Random.Range(0.0f, 1.0f);
        float ranY = Random.Range(0.0f, 1.0f);
        itemCoin[i] = objectManager.MakeObject("ItemCoin");
        itemCoin[i].transform.position = transform.position + new Vector3(ranX,ranY,0);
    }
}

적이 보스일 경우 보스를 중심으랜덤한 위치에 코인 10개를 배치

 

보스 프리팹 저장

보스 프리팹 저장

 

오브젝트 폴링 사용

 

ObjectManager

오브젝트 매니저에 보스 등록

퍼블릭

Public 변수에 등록

 

패턴 흐름

void OnEnable()
{
    health = maxHealth;

    switch(enemyName)
    {
        case "B":
            Invoke("Stop", stopTime);
            break;
    }
}

void Stop()
{
    if (!gameObject.activeSelf)
    {
        return;
    }
    Rigidbody2D rigid = GetComponent<Rigidbody2D>();
    rigid.velocity = Vector3.zero;
}

보스 출현 후 일정 시간 뒤에 멈추게 하기위해

Invoke 함수로 Stop함수 지정해서 일정 시간 후 멈추게 함

 

보스 출현

 

패턴 지정을 위해 Think 매소드 새로 제작

 

    public int patternIndex;
    public int curPatternCount;
    public int[] maxPatternCount;

Public 함수로 패턴 인덱스와

현재 패턴 몇번 반복했는지, 최대 몇번 반복할지 지정

void Think()
{
    //패턴이 3번이면 다시 0으로 초기화 아니면 +1
    patternIndex = patternIndex == 3 ? 0 : patternIndex +1;

    switch (patternIndex)
    {
        case 0:
            FireForward();
            break;
        case 1:
            FireShot();
            break;
        case 2:
            FireArc();
            break;
        case 3:
            FireAround();
            break;
    }
}

각 패턴마다 사격 패턴함수 삽입

void Think()
{
    //패턴이 3번이면 다시 0으로 초기화 아니면 +1
    patternIndex = patternIndex == 3 ? 0 : patternIndex +1;
    //다음 생각할 때마다 패턴 횟수 초기화
    curPatternCount = 0;
    switch (patternIndex)
    {
        case 0:
            FireForward();
            break;
        case 1:
            FireShot();
            break;
        case 2:
            FireArc();
            break;
        case 3:
            FireAround();
            break;
    }
}

void FireForward()
{
    Debug.Log("앞으로 4발 발사");
    curPatternCount++;

    if (curPatternCount < maxPatternCount[patternIndex])
        Invoke("FireForward", 2.0f);
    else
        Invoke("Think", 2.0f);
}
void FireShot()
{
    Debug.Log("플레이어 방향으로 샷건");
    curPatternCount++;

    if (curPatternCount < maxPatternCount[patternIndex])
        Invoke("FireShot", 2.0f);
    else
        Invoke("Think", 2.0f);
}
void FireArc()
{
    Debug.Log("부채 모양으로 발사");
    curPatternCount++;

    if (curPatternCount < maxPatternCount[patternIndex])
        Invoke("FireArc", 2.0f);
    else
        Invoke("Think", 2.0f);
}
void FireAround()
{
    Debug.Log("원 형태로 전체 공격");
    curPatternCount++;

    if (curPatternCount < maxPatternCount[patternIndex])
        Invoke("FireAround", 2.0f);
    else
        Invoke("Think", 2.0f);
}

각 패턴 별로 일정 횟수 실행하고 다음 패턴으로 넘어가도록 구현

 

******주의 : 보스 엑티브를 디엑티브하지 않고 오브젝트 풀링에 넣으면 오류가 날 수 있음 미리 비활성화하기******

 

보스 패턴 발사

 

패턴 구현

void FireForward()
{
    //앞으로 4발 발사
    Debug.Log("1. 앞으로 4발 발사");
    GameObject bulletL = objectManager.MakeObject("BulletBossB");
    bulletL.transform.position = transform.position + new Vector3(1.0f, 0);
    GameObject bulletLL = objectManager.MakeObject("BulletBossB");
    bulletL.transform.position = transform.position + new Vector3(2.0f, 0);
    GameObject bulletR = objectManager.MakeObject("BulletBossB");
    bulletR.transform.position = transform.position + new Vector3(-1.0f, 0);
    GameObject bulletRR = objectManager.MakeObject("BulletBossB");
    bulletR.transform.position = transform.position + new Vector3(-2.0f, 0);

    Rigidbody2D rigidL = bulletL.GetComponent<Rigidbody2D>();
    Rigidbody2D rigidLL = bulletLL.GetComponent<Rigidbody2D>();
    Rigidbody2D rigidR = bulletR.GetComponent<Rigidbody2D>();
    Rigidbody2D rigidRR = bulletRR.GetComponent<Rigidbody2D>();

    Vector3 fireDir = Vector2.down;
    rigidL.AddForce(fireDir * 8, ForceMode2D.Impulse);
    rigidLL.AddForce(fireDir * 8, ForceMode2D.Impulse);
    rigidR.AddForce(fireDir * 8, ForceMode2D.Impulse);
    rigidRR.AddForce(fireDir * 8, ForceMode2D.Impulse);

    curPatternCount++;
    if (curPatternCount < maxPatternCount[patternIndex])
        Invoke("FireForward", 1.0f);
    else
        Invoke("Think", 3.0f);
}

 

첫 패턴 : Fire 변수를 참고해 일직선 아래로 4발을 발사하게 함

 

void FireShot()
{
    Debug.Log("2. 플레이어 방향으로 샷건");
    //앞으로 4발 발사
    for(int i=0; i< 5; i++)
    {
        GameObject bullet = objectManager.MakeObject("BulletBossA");
        bullet.transform.position = transform.position;
        Rigidbody2D rigid = bullet.GetComponent<Rigidbody2D>();

        float randX = Random.Range(-1.0f, 1.0f);
        float randY = Random.Range(0, 2.0f);
        Vector3 fireDir = player.transform.position - transform.position + new Vector3(randX, randY, 0);
        rigid.AddForce(fireDir.normalized * 6, ForceMode2D.Impulse);
    }

    curPatternCount++;

    if (curPatternCount < maxPatternCount[patternIndex])
        Invoke("FireShot", 2.0f);
    else
        Invoke("Think", 3.0f);
}

2번째 패턴 : 랜덤 변수를 이용하여 플레이어를 향해 5발을 동시에 방사형으로 발사

void FireArc()
{
    Debug.Log("3. 부채 모양으로 발사");

        GameObject bullet = objectManager.MakeObject("BulletEnemyB");
        bullet.transform.position = transform.position;
        bullet.transform.rotation = Quaternion.identity;
        Rigidbody2D rigid = bullet.GetComponent<Rigidbody2D>();

        Vector3 fireDir = new Vector3(Mathf.Cos(Mathf.PI* 8 *curPatternCount/ maxPatternCount[patternIndex]), -1, 0);
        rigid.AddForce(fireDir.normalized * 6, ForceMode2D.Impulse);

    curPatternCount++;

    if (curPatternCount < maxPatternCount[patternIndex])
        Invoke("FireArc", 0.15f);
    else
        Invoke("Think", 3.0f);
}

3번째 패턴 Math함수를 이용하여 방사형으로 발사

* Math.Sin() : 삼각함수 Sin

* Math.Cos() 으로도 시작 방향만 다를뿐 같은 패턴 재현 가능

* Quaternion.identity : 회전 0

* Math.PI : 원주율

 

4번째 패턴 주변에 원형으로 총알 발사

생성되는 총알의 순번을 이용해 방향을 결정

X축 하나는 Sin, 하나는 Cos으로 생성해서 원형으로 발사가 됨

 

1번째 패턴
2번째패턴
3번째 패턴
4번째 패턴

 

사망