본문 바로가기
게임 제작/뉴진스 파워퍼프걸 팬게임

뉴진스 파워퍼프걸 팬게임 제작 (14)_ Stage1_보스 패턴(1) (New jeans Powerpuff girls fangame)

by 나는반딧불 2023. 9. 1.
반응형

뉴진스 파워퍼프걸 팬게임 제작 (14)_ Stage1_보스 패턴(1)

이번 글에서는 Stage1의 보스인 거대 토끼의 등장과

두 가지 종류의 공격패턴을 구현할 계획이다.

 

이번글의 목표

Wave3 등장 구현

거대 토끼 공격  패턴 구현

 

 

 

1. Wave3 제작

빈 오브젝트를 생성하고 좌표를 0으로 전부 맞춘다음 Wave3(BOSS)라고 이름을 바꿔주었다.

그리고 해당 오브젝트 하위에 보스 전투에 필요한 오브젝트들을 배치해 주었다.

 

1.1 거대 토끼(BOSS)

거대토끼는 응원봉을 자식 오브젝트로 가지고 있고

응원봉은 3가지 Pos 오브젝트를 자식으로 가지고 있다.

추후 저 Pos의 위치에서 거대 토끼의 공격 탄환들이 발사될 예정이다.

 

1.2 RIGHTWALL&BOXCOLLIDER

플레이어가 거대 토끼 오른쪽으로 이동해 공격을 피하지 못하게 만들기 위해

게임 화면 중앙에 RIGHTWALL을 배치했다.

RIGHTWALL이 있으면 캐릭터는 오른쪽이동을 할 수 없지만 

만약 플레이어가 보스 등장 전부터 오른쪽에 있었다면 이것만으로는 

플레이어를 왼쪽으로 몰아낼 수 없기에 예전에 파이프 및 랜덤박스에 추가했던것처럼

물리충돌을 담담하는 BOXCOLLIDER 오브젝트를 하나 더 생성해주고 

MASS를 100 IsTrigger를 False로 바꿔준다.

이것으로 보스 전투가 시작되면 플레이어는 무조건 화면의 절반왼쪽에서만 움직일 수 있게 되었다.

 

 

1.3 Wave3Ctrl 스크립트 작성

public class Wave3Ctrl : MonoBehaviour
{
    public float speed=-3;
    private Transform tr;
    public float goalX=-9.69f;
    public GameObject boss;

    void Start()
    {
        tr = gameObject.GetComponent<Transform>();
    }

    void Update()
    {
        if (tr.position.x > goalX) // 목적 위치에 도달하기 전까지 이동
        {
            tr.Translate(speed * Time.deltaTime, 0, 0);
        }
        else
        {
            boss.GetComponent<Boss1Ctrl>().StartBossAction();  //보스 액션 시작 함수 호출
        }
    }
}

Wave3은 다른 Wave와 달리 끝까지 이동하면 안되고 일정 위치에서 멈춰야만한다.

그래서 특정 위치에 도달하기 전까지만 움직이는 스크립트를 작성했다.

그리고 목적지 도착하는 순간 거대 토끼의 공격이 시작되도록 함수를 호출하게 만들었다.

Boss1Ctrl에 대해서는 밑에서 설명할 예정이다. 

 

 

2. 거대 토끼 공격 스킬 프리팹 제작

 

2.1 당근 애너지볼

당근 애너지볼은 일반 토끼의 탄환과 다를바가 거의 없다.

차이가 있다면 Box Collider 대신 Circle Collider를 썼다는 점이다.

 

 

2.2 당근 유도 미사일

당근 유도 미사일은 만드는데 조금 시간이 걸렸다.

한 스크립트에서는 현재 각도대로 이동하게 만들면

자연스럽게 타겟을 향해 날아가는 유도미사일이 완성된다.

플레이어를 계속 쳐다보며 회전하게 만들어야 하는데

3D였다면 단순히 LOOKAT함수를 쓰면 되지만 2D에선 따로 수식을 써줘야한다.

한 스크립트에서는 오브젝트가 계속 타겟을 따라 회전하게 만들고

 

 

LookatonTime 스크립트

 private Transform target;

    public float StartTime = 0.3f;//타겟을 따라 회전 시작하는 시각
    public float EndTime = 1.0f; //타켓을 따라 회전 종료하는 시각
    private float time = 0;

    private bool lookatMod = false;
    float angle;

당근 유도 미사일이 처음부터 끝까지 플레이어를 추적한다면 

플레이어는 절대 피할 수 없기에 일정시간 동안만

플레이어를 추적하도록 시작시간과 종료시간을 선언해 두었다.

void Start()
    {
        target = GameObject.Find("Player").GetComponent<Transform>();  //타겟을 플레이어로 지정
    }

시작과 동시에 FIND로 알아서 타겟인 플레이어를 찾을 수 있게 작성했다.

 

void Timer()
    {
        time += Time.deltaTime;

        if(time>StartTime&&time<EndTime)
        {
            lookatMod = true;
        }
        else
        {
            lookatMod = false;
        }
    }

처음에는 플레이어를 추적하지 않다가 일정시간동안 플레이어를 추적하고

다시 추적이 풀리게끔 작성했다.

 

void Update()
    {
        Timer();

        if (lookatMod)  //타겟을 쳐다보는 함수 처리
        {
            angle = Mathf.Atan2(target.position.y - transform.position.y, target.position.x - transform.position.x) * Mathf.Rad2Deg;
            transform.rotation = Quaternion.AngleAxis(angle - 90, Vector3.forward);
        }
    }

대망의 타겟을 계속 쳐다보게하는 함수 

타겟의 위치값과 현재 오브젝트의 객체값의 차이를 계산해 삼각함수로 각도를 도출해내는 방법같은데

사실 정확하게는 모르고 다른 사람들이 작성한 코드를 살짝 수정만 했다.

 

 

3. 거대 토끼 공격 패턴 스크립트 작성

먼저 보스인 거대토끼의 공격 패턴을 정리하자면

일정 위치에 도달하면 응원봉을 상하로 휘두르면서

당근 애너지볼을 일정시간동안 발사한다.

이후 특정한 각도로 응원봉을 든뒤

응원봉 양 귀쪽에서 일정시간 동안

당근 유도 미사일을 발사한다.

2개의 공격패턴이 지나가면 잠까동안 멈췄다가

다시 똑같은 행동을 반복한다.

 

    public GameObject weapon; //응원봉
    private Transform tr; //응원봉의 위치값을 대입할 변수

    public GameObject bullet1; //당근 애너지볼
    public GameObject bullet2;// 당근 유도미사일

    public Transform bullet1Pos;//당근 애너지볼 발사 위치
    public Transform bullet2Pos1;//당근 유도미사일1 발사 위치
    public Transform bullet2Pos2;//당근 유도미사일2 발사 위치

    public float rotBot=95.2f;  //응원봉 좌측 최대 회전각
    public float rotTop=19.5f;  //응원봉 우측 최대 회전각
    public float rotMid = 60f;  //당근 유도 미사일 발사시 각도
    public float rotSpeed = 100f; //회전 속도

    public float time = 0;
    public float cooltime1 = 0.35f; //당근 애너지볼 쿨타임
    public float cooltime2 = 2.0f;// 당근 유도미사일 쿨타임

    public bool swingmod = false; // down=false, up = true;
    public bool idlemod = true; //true= stop, flase= move;
    private bool corutine = true; //코루틴 중복 발동 방지용 변수
    private bool ActionStart = false; //액션 시작 함수 호출용 변수

    public int Attackmod; //0= 대기상태, 1=애너지볼 공격, 2=당근 유도 미사일

선언은 위와 같이 작성했다.

 

 void Start()
    {
        tr = weapon.GetComponent<Transform>();
    }

Start함수는 응원봉의 Transform만 대입해주면 끝난다.

 

 public void Swingmod1() //attack1의 swing ctrl
    {
        if (tr.rotation.eulerAngles.z < rotTop)  //eulerAngles를 붙여주지 않으면 쿼터니언값이 나와서 1보다 작은수만 나온다.
        {
            swingmod = false; //내려간다   
        }
        else if (tr.rotation.eulerAngles.z > rotBot)
        {
            swingmod = true; //올라간다
        }
    }

attack1의 응원봉 휘두르기 설정 함수이다.

특정 각도 구간을 계속 반복해서 회전하는 함수이다.

rotatin값을 불러올때 eulerAngles를 붙여주지 않으면  각도값이 1보다 작은 숫자로 치환되어 나오기 때문에

직관적으로 판단하기가 어려워서 eulerAngles를 붙여주었다.

eulerAngles를 붙여주면 0~360사이로 나와서 직관적으로 알아보기 쉽다.

 

 

  public void Swingmod2() //attack2의 swing ctrl
    {
        if (tr.rotation.eulerAngles.z < rotMid-1f)  //eulerAngles를 붙여주지 않으면 쿼터니언값이 나와서 1보다 작은수만 나온다.
        {
            swingmod = false;  //내려간다.
        }
        else if (tr.rotation.eulerAngles.z > rotMid+1f)
        {
            swingmod = true;  // 올라간다.
        }
        else if (tr.rotation.eulerAngles.z > rotMid-1f&& tr.rotation.eulerAngles.z < rotMid + 1f) //==으로 하면 제대로 값맞추기가 힘들어서 범위로 설정
        {
            idlemod = true;
        }
    }

attack2의 응원봉 휘두르기 설정 함수이다.

특정 각도가 아니면 특정 각도 구간에 도달할때까지 해당 각도 방향으로 회전하게 작성했다.

특정 각도 구간에 도달하면 응원봉의 회전 움직임을 멈춘다.

마지막 비교를 할때 ==을 쓰지 않고 굳이 위아래로 플러스 마이너스 1을 준 이유는

정확하게 목표값에 일치하지 않을때 버그가 나는 것을 방지하기 위해서이다.

 

 

  void SwingCtrl()
    {
        if (!swingmod)
        {
            tr.Rotate(Vector3.forward, rotSpeed * Time.deltaTime);
        }

        else if (swingmod)
        {
            tr.Rotate(Vector3.forward, -rotSpeed * Time.deltaTime);
        }
    }

위에서 작성한 각 패턴에 따른 각도 조절 함수에 따라

bool변수가 조절되면 그에 따라 회전을 진행하는 함수이다.

 public void idle()   //아무것도 안하는 기본상태
    {
        idlemod = true;
    }

    public void Attack1() //애너지볼 공격
    {
        idlemod = false;
        Swingmod1();
        Attack1timer();
    }
    public void Attack2() //당근미사일 공격
    {
        Swingmod2();
        if (idlemod)
        {
            Attack1timer2();
        }
    }

거대 토끼의 행동에 대한 함수들이다.

응원봉을 휘두를 때는 idlemod가 false고 siwngmod가 true가 된다.

휘두르지 않을때는 반대로 설정된다.

 

public void StartBossAction()
    {
        ActionStart = true;
    }

위에서 작성한 Wave3Ctrl에서 호출하는 함수이다.

 

 

void Attack1timer()
    {
        time += Time.deltaTime;
        if (time >= cooltime1)
        {
            Instantiate(bullet1, bullet1Pos.position, bullet1Pos.rotation);
            time = 0;
        }

    }
    void Attack1timer2()
    {  
        time += Time.deltaTime;
        if (time >= cooltime2)
        {
            Instantiate(bullet2, bullet2Pos1.position, bullet2Pos1.rotation);
            Instantiate(bullet2, bullet2Pos2.position, bullet2Pos2.rotation);
            time = 0;
        }
    }

각각의 공격 패턴일때 일정시간동안 애너지볼과 당근 유도미사일을 생성하는 함수이다.

 

IEnumerator BossAction()
    {
        corutine = false;
        Attackmod = 0;
        yield return new WaitForSeconds(1f);
        Attackmod = 1;
        time = 0;
        yield return new WaitForSeconds(6f);
        Attackmod = 2;
        time = 0.5f;
        yield return new WaitForSeconds(7f);
        corutine = true;
    }

앞서 말한 패턴대로 거대 토끼의 행동 모드를 일정시간마다 변경 시켜주는 코루틴 함수이다.

 

 void Update()
    {
        if (!idlemod)  //멈춤상태가 아니라면
        {
            SwingCtrl();  //응원봉 회전
        }

        if (ActionStart)  //wave3Ctrl에서 함수를 호출해 ActionStart를 true로 만들면
        {
            if (corutine)
            {
                StartCoroutine("BossAction"); //보스의 공격  패턴 시작
            }
        }

        if(Attackmod==1)
        {
            Attack1();
        }
        else if (Attackmod == 2)
        {
            Attack2();
        }
        else if (Attackmod == 0)
        {
            idle();
        }
    }

방금까지 만든 함수들을 Update에 넣어 작동할 수 있게 만들었다.

 

 

스크립트 작성이 다되었으면 보스 오브젝트에 추가해주고

만들어놨던 Pos와 프리팹들을 드래그해서 넣어준다.

 

 

 

4. 결과물

 

거대 토끼 전투 화면

보스인 거대 토끼의 공격 패턴을 확인할 수있다.

 

 

 

글이 너무 길어질 것 같아서 2개로 나눠서 썼는데

이것조차도 글이 너무 길어진 것 같다.

 

다음 글에서는 보스의 체력관리와 보스 사망후

획득 아이템 처리를 구현할 예정이다.

 

 

 

 

 

 

 

반응형