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);
}
}
}
Unity가 Private Field를 직렬화하여 Private를 노출한다.
다른 class에서는 접근하지 못하게 해당 Field의 private를 감추면서, 직렬화를 통해 unity 에디터의 인스펙터를 통한 값을 입력 및 수정할 수 있도록 만들기 위해 사용한다.
직렬화 시스템의 역할
1) 직렬화 가능 유형의 Private Field를 직렬화
2) SerializeField 속성으로 표시된 Private Field만 직렬화 가능
3) Static Field(정적 필드)를 직렬화할 수 없다.
4) Serialize 속성을 직렬화할 수 없다.
직렬화 가능 유형
주의해야 할 점
serialization(직렬화)는 데이터 구조나 GameObject 상태를 Unity가 나중에 저장하고 재구성할 수 있는 형식으로 변환하는 자동 프로세스이다. Unity 프로젝트 진행 시 프로젝트 내 데이터를 구성하는 방식은 Unity가 해당 데이터를 직렬화하는 방식에 영향을 미친다.
Unity 내부의 class로 플레이어 기본 설정을 저장하는 기능을 가지고 있다.
로컬 레지스터에 string, float, interger values(정수 값)을 저장합니다.
다만, 중요 데이터는 PlayerPrefs을 사용하지 않는 것이 좋다.
다른 객체가 이 객체에 연결된 트리거 충돌체에 들어갈 때 전송된다.
다른 충돌체에 대한 추가 정보는 호출 중에 전달된 Collider2D 매개변수에 보고된다. 이 보고되는 메세지는 Tigger Collider2D와 Tigger Collider2D가 속한 Rigidbody2D, Tigger에 닿는 Rigidbody2D(Rigidbody2D가 없는 경우 Collider2D)로 전송된다.
MonoBehaviour.OnTriggerEnter2D(Collider2D)
- 매개 변수 = 충돌과 관련되 다른 collider2D
bool GameObject에 동일한 Tag가 있으면 true를 반환합니다. 그렇지 않으면 false를 반환합니다.
public bool CompareTag(string tag);
- 매개변수 = 비교할 태그
지정된 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는 MonoBehaviour에 속해있으며 시간(초) 단위로 메서드를 호출합니다. 시간을 0으로 설정하면 다음 Update에 실행된다.
Invoke는 시간 딜레이를 주고 실행합니다.
public void Invoke(string methodName, float time);
메서드를 반복해서 호출한다.
주기적으로 실행되는 로직을 구현할 때 사용된다.
public void InvokeRepeating(string methodName, float time, float repeatRate);
매개변수
해당 이름을 가진 메서드의 모든 Invoke 호출을 취소한다.
public void CancelInvoke(strioing methodName);
CancelInvoke
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);
매개변수