MonsterConroller

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

/// <summary>
/// 기능: 
/// 
/// </summary>
public class MonsterController : MonoBehaviour
{
    // 몬스터의 종류
    [SerializeField]
    private int _monsterIndex;
    // 몬스터의 이동속도
    private float _monsterMoveSpeed;
    // 몬스터의 현재 체력
    private float _curHp;
    // 애니메이터
    private Animator _animator;
    // 몬스터의 움직임 가능여부
    private bool _canMove = true;
    // 경험치 프리팹
    public GameObject _exePrefab;
    // 현재 플레이하는 캐릭터의 정보
    private int _playerIndex;

    //총알발사 몬스터
    private float _randomY;

    //라운드 정보
    private int _round;

    // Start is called before the first frame update
    void Start()
    {
        //DataManager를 통해 MonsterData.json의 해당 몬스터 speed 값을 가져온다.
        _monsterMoveSpeed = DataManager.instance.monsterDataList[_monsterIndex].speed;
        //DataManager를 통해 MonsterData.json의 해당 몬스터 체력 값을 가져온다.
        _curHp = DataManager.instance.monsterDataList[_monsterIndex].hp;
        _animator = GetComponent<Animator>();
        //PlayerPrefabs.PlayerIndex 값 가져오기 !! 수정 필요
        _playerIndex = PlayerPrefs.GetInt("PlayerIndex");

        //총알 몬스터 y좌표 위치 (랜덤으로 설정)
        _randomY = Random.Range(2, 5);
    }

    void Update()
    {
        //몬스터가 움직일 수 있는 상황이라면
        if (_canMove)
        {
            //몬스터 종류에 따라서 이동방식이 다르므로 해당하는 메소드 호출
            if (_monsterIndex >4) { }
            else if (_monsterIndex > 1) { ShootMonsterMove(); }
            else { BasicMonsterMove(); }
        }
        //게임 오버 상태라면 생성된 몬스터 삭제
        //DataManager를 통해 PlayData.json의 gameonver 값 가져오기
        if (DataManager.instance.playData.gameover)
        {
            Destroy(gameObject);
        }
    }

    #region monstermMove
    //총알 몬스터의 움직임
    private void ShootMonsterMove()
    {
        transform.position += new Vector3(0, (-1) * Time.deltaTime * _monsterMoveSpeed * 2f, 0);
        //몬스터의 위치가 정해진 y위치보다 아래일 경우 이동 멈춤
        if (transform.position.y <= _randomY)
        {
            _canMove = false;
        }
    }

    //기본 몬스터의 움직임
    private void BasicMonsterMove()
    {
        transform.position += new Vector3(0, (-1) * Time.deltaTime * _monsterMoveSpeed, 0);
        //몬스터의 위치가 -5f 아래일 경우 몬스터 삭제
        if (transform.position.y < -5f)
        {
            Destroy(gameObject);
        }
    }
    #endregion

    #region Trigger
    private void OnTriggerEnter2D(Collider2D collision)
    {
        //플레이어 총알에 충돌할 경우
        if (collision.CompareTag("PlayerBullet"))
        {
            //중복 충돌감지를 방지하기 위해 총알 태그 변경
            collision.gameObject.tag = "Destroy";
            //피격상태로 변환
            Attacked();
        }
    }
    private void OnTriggerExit2D(Collider2D collision)
    {
        //플레이어 총알이 부딪힌 후 사라진경우 일반 몬스터 이동가능상태로 변환
        if (collision.CompareTag("PlayerBullet"))
        {
            if (_monsterIndex < 2) { _canMove = true; }
        }
    }
    #endregion

    //체력 감소, 피격 애니 실행
    private void Attacked()
    {
        //일반 몬스터는 피격 시 위로 조금 이동
        if (_monsterIndex < 2)
        {
            transform.position += new Vector3(0, 0.2f, 0);
        }

        //체력감소 (몬스터의 현재체력에서 플레이어의 공격력만큼 차감)
        _curHp -= DataManager.instance.playerStatDataList[_playerIndex].str;

        //감소된 체력이 0이상이 경우 피격 상태
        if (_curHp > 0)
        {
            //피격 애니
            _animator.SetTrigger("Attacked");
            Invoke(nameof(CanMove),0.5f);
        }
        //체력이 고갈되었으면 죽음
        else
        {
            //일반몬스터는 이동중인 상태이므로 움직일수 없는 상태로 바꿔줌
            if (_monsterIndex < 2) { _canMove = false; }
            _animator.SetTrigger("Die");
            gameObject.tag = "Destroy";
            //점수 가산 
            DataManager.instance.playData.score += 100 + _monsterIndex * 50;
            //업적에 죽인몬스터 수 가산
            DataManager.instance.achieveData.killMonsterCnt[_monsterIndex]++;

            _round = DataManager.instance.playData.round;
            //라운드 정보에 처치해야하는 몬스터 수 차감
            DataManager.instance.roundDataList[_round - 1].monsterCount[_monsterIndex]--;
            //경험치 오브젝트 생성
            Instantiate(_exePrefab, transform.position, Quaternion.identity);
            //일정확률로 아이템 드랍
            CloneItem();
            //피격애니메이션 클립 실행 시간이 끝난 후 오브젝트 파괴
            Destroy(gameObject, 0.5f);
        }
    }

    //움직일 수 없는 상태일 경우 호출
    private void CanMove(){
        _canMove =true;
    }

    //아이템 생성 메소드
    private void CloneItem(){

        int _itemDropPercent = Random.Range(0,1001);
        if(_itemDropPercent >950){
        //ItemSpawner의 _itemSpawner를 호출하여 아이템 생성
        ItemSpawner _itemSpawner = new ItemSpawner();
        _itemSpawner.CloneItem(transform); 
        }
    }
}

[SerializeField]

Unity가 Private Field를 직렬화하여 Private를 노출한다.
다른 class에서는 접근하지 못하게 해당 Field의 private를 감추면서, 직렬화를 통해 unity 에디터의 인스펙터를 통한 값을 입력 및 수정할 수 있도록 만들기 위해 사용한다.

  • Unity에서 public Field만 직렬화한다. SerializeField를 사용하여 private Field 또한 직렬화 한다.
  • Unity 내 모든 구성 요소를 직렬화하여 다시 생성한다.
  • SerializeField의 직렬화는 Unity 내부 직렬화 시스템이다. .NET의 직렬화 기능이 아니다.

직렬화 시스템의 역할
1) 직렬화 가능 유형의 Private Field를 직렬화
2) SerializeField 속성으로 표시된 Private Field만 직렬화 가능
3) Static Field(정적 필드)를 직렬화할 수 없다.
4) Serialize 속성을 직렬화할 수 없다.

직렬화 가능 유형

  • Unity의 Object에서 상속되는 모든 Class
    : GameObject, Component, MonoBehaviour, Texture2D, AnimaitonClip
  • int, string, float, bool
  • Vector2, Vector3, Vector4, Quatemion, Matrix4x4, Color, Rect, LayerMask와 같은 일부 내장 유형
  • 직렬화 가능한 유형의 배열
  • 직렬화 가능 유형 목록
  • Enum(열거형)
  • Struct(구조체)

주의해야 할 점

  • struct Field를 직렬화하려면 struct에 System.Serialized 특성을 제공해야 한다.
  • Unity에서 Dictionary를 직렬화 하지 않지만 Key와 값에 대해서 List<>로 저장할 수 있다.

Script serialization

serialization(직렬화)는 데이터 구조나 GameObject 상태를 Unity가 나중에 저장하고 재구성할 수 있는 형식으로 변환하는 자동 프로세스이다. Unity 프로젝트 진행 시 프로젝트 내 데이터를 구성하는 방식은 Unity가 해당 데이터를 직렬화하는 방식에 영향을 미친다.

SerializeField
serialization의 추가자료


PlayerPrefs

Unity 내부의 class로 플레이어 기본 설정을 저장하는 기능을 가지고 있다.
로컬 레지스터에 string, float, interger values(정수 값)을 저장합니다.
다만, 중요 데이터는 PlayerPrefs을 사용하지 않는 것이 좋다.

PlayerPrefs


OnTriggerEnter2D()

다른 객체가 이 객체에 연결된 트리거 충돌체에 들어갈 때 전송된다.
다른 충돌체에 대한 추가 정보는 호출 중에 전달된 Collider2D 매개변수에 보고된다. 이 보고되는 메세지는 Tigger Collider2D와 Tigger Collider2D가 속한 Rigidbody2D, Tigger에 닿는 Rigidbody2D(Rigidbody2D가 없는 경우 Collider2D)로 전송된다.

MonoBehaviour.OnTriggerEnter2D(Collider2D)

  • 매개 변수 = 충돌과 관련되 다른 collider2D
  • Tigger는 Collider 중 하나가 Rigidbody2D가 연결된 경우에만 전송된다.
  • OnTriggerEnter2D 외, OnTriggerExit2DOnTriggerStay2D가 있다.

OnTriggerEnter2D()


Component.CompareTag

bool GameObject에 동일한 Tag가 있으면 true를 반환합니다. 그렇지 않으면 false를 반환합니다.

public bool CompareTag(string tag);

  • 매개변수 = 비교할 태그

CompareTag


Animator.SetTrigger

지정된 Tigger의 매개변수의 값을 설정합니다.
애니메이션 Tigger 설정하여 애니메이터 컨트롤러 상태에서 흐름을 변경할 수 있습니다.

public void SetTrigger(string name);
public void SetTrigger(int id);

ex)

 if (_curHp > 0)
 {
     //피격 애니
     _animator.SetTrigger("Attacked");
     Invoke(nameof(CanMove),0.5f);
 }

SetTrigger

Invoke

Invoke는 MonoBehaviour에 속해있으며 시간(초) 단위로 메서드를 호출합니다. 시간을 0으로 설정하면 다음 Update에 실행된다.
Invoke는 시간 딜레이를 주고 실행합니다.

public void Invoke(string methodName, float time);

  • Invoke는 해당 GameObject가 비활성화되어도 계속 동작되기 때문에 컴퓨터 사양에 영향을 미친다. 이를 해결하기 위해서는 Invoke를 멈추는 CancelInvoke()를 사용하는 것이 좋다.

Invoke

InvokeRepeating()

메서드를 반복해서 호출한다.
주기적으로 실행되는 로직을 구현할 때 사용된다.

public void InvokeRepeating(string methodName, float time, float repeatRate);

매개변수

  • methodName = 호출할 메소드 이름
  • time = n초 후에 호출을 시작
  • repeatRate = n초마다 반복

InvokeRepeating

CancelInvoke()

해당 이름을 가진 메서드의 모든 Invoke 호출을 취소한다.

public void CancelInvoke(strioing methodName);

CancelInvoke

Instantiate

GameObject를 복제하여 생성한다.

  • public static Object Instantiate(Object original);
  • public static Object Instantiate(Object original, Transform parent);
  • public static Object Instantiate(Object original, Transform parent, bool instantiateInWorldSpace);
  • public static Object Instantiate(Object original, Vector3 position, Quaternion rotation);
  • public static Object Instantiate(Object original, Vector3 position, Quaternion rotation, Transform parent);

매개변수

  • orignal = 복사본을 만들 기존 객체
  • position = 새로운 객체의 위치
  • rotation = 새로운 객체의 방향
  • parent = 새 객체에 할당될 상위 객체
  • bool instantiateInWorldSpace = 상위 객체 할당 때 true > 새 객체를 WolrdSpace에 직접 배치 / flase > 새 부모를 기준으로 객체의 위치 설정

Instantiate

0개의 댓글