인텔리킴의 Unity Studying & Game Analysis
34. 유니티 2D 종스크롤 슈팅 - 보스 구현 본문
기본 세팅
보스의 애니메이션을 제작하고 적용, 보스의 콜라이더 지정
보스 패턴
먼저 보스가 발사할 총알의 프리팹을 제작
적에게서 뿜어져 나오는 것이기 때문에 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개를 배치
보스 프리팹 저장
오브젝트 폴링 사용
오브젝트 매니저에 보스 등록
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으로 생성해서 원형으로 발사가 됨
'게임 개발 일지 > 유니티 엔진 공부' 카테고리의 다른 글
37. 3D 쿼터뷰 게임 제작 - 플레이어 이동 (1) | 2024.06.18 |
---|---|
35. 메인 메뉴 제작 - 옵션 (1) (0) | 2024.06.13 |
33. 유니티 2D 종스크롤 슈팅 - 따라다니는 보조무기 만들기 (1) | 2024.06.09 |
32. 유니티 2D 종스크롤 슈팅 - 텍스트 파일로 적 배치하기 (1) | 2024.06.05 |
31. 유니티 2D 종스크롤 슈팅 - 오브젝트 폴링 (0) | 2024.06.05 |