몬스터가 캐릭터 탐지하고 추적할때 캐릭터를 바라보지 않던 문제 수정 및 CSV 코드 제거

This commit is contained in:
Mingu Kim
2025-02-12 16:22:54 +09:00
parent a8ff9955ed
commit 05abc442c9
2 changed files with 94 additions and 156 deletions

View File

@@ -32,20 +32,20 @@ namespace TON
// 공격 범위 // 공격 범위
public float attackRange; public float attackRange;
public MonsterData(int id, string name, int level, string monsterType, int hp, int attackPower, int defensivePower, int monsterSkillID, float patrolRange, float detectionRange, float chaseRange, float attackRange) public MonsterData(int a, string b, int c, string d, int e, int f, int g, string h, float i, float j, float k, float l)
{ {
id = id; id = a;
name = name; name = b;
level = level; level = c;
monsterType = monsterType; monsterType = d;
hp = hp; hp = e;
attackPower = attackPower; attackPower = f;
defensivePower = defensivePower; defensivePower = g;
monsterSkillID = monsterSkillID; monsterSkillID = h;
patrolRange = patrolRange; patrolRange = i;
detectionRange = detectionRange; detectionRange = j;
chaseRange = chaseRange; chaseRange = k;
attackRange = attackRange; attackRange = l;
} }
} }
} }

View File

@@ -14,45 +14,45 @@ namespace TON
{ {
public class MonsterBase : MonoBehaviour, IDamage public class MonsterBase : MonoBehaviour, IDamage
{ {
public int id; // 적 고유 ID public int id; // 몬스터의 ID
public float currentHP = 100; // HP public float currentHP = 100; // 몬스터의 현재 체력
// public string name; // 몬스터 명 or 프리팹 명 // public string name; // 몬스터 이름
public string monsterType; // 몬스터 타입 ex : melee, ranged public string monsterType; // 몬스터 타입 (예: melee, ranged)
// public int damage; // 공격력 // public int damage; // 공격력
public float speed = 2; // 이동속도 public float speed = 2; // 몬스터의 이동 속도
[SerializeField] [SerializeField]
private SpriteRenderer _spriteRenderer; private SpriteRenderer _spriteRenderer; // 몬스터의 스프라이트 렌더러
private Animator _animator; private Animator _animator; // 몬스터 애니메이터
private Vector3 _direction; private Vector3 _direction; // 몬스터의 이동 방향
private bool _isWalking; private bool _isWalking; // 몬스터가 걷고 있는지 여부
private bool _isHit; private bool _isHit; // 몬스터가 맞았는지 여부
private bool _isDetect; private bool _isDetect; // 몬스터가 대상을 인식했는지 여부
private float _currentTime; private float _currentTime; // 현재 시간
[SerializeField] [SerializeField]
private int _idleTime = 2; private int _idleTime = 2; // 대기 시간
[SerializeField] [SerializeField]
private int walkingTime = 2; private int walkingTime = 2; // 걷기 시간
[SerializeField] [SerializeField]
private GameObject _target; private GameObject _target; // 몬스터의 타겟
[SerializeField] [SerializeField]
private Collider2D _collider; private Collider2D _collider; // 몬스터의 콜라이더
public float defencePower; public float defencePower; // 몬스터의 방어력
// 애니메이션 관련 선언 // 애니메이션 관련 선언
private string currentState; private string currentState; // 현재 애니메이션 상태
const string AniIdle = "Idle"; const string AniIdle = "Idle"; // 대기 애니메이션
const string AniWalk = "Walk"; const string AniWalk = "Walk"; // 걷기 애니메이션
const string AniAttack = "Attack"; const string AniAttack = "Attack"; // 공격 애니메이션
public bool IsWalking public bool IsWalking
{ {
@@ -66,136 +66,77 @@ namespace TON
set => _isDetect = value; set => _isDetect = value;
} }
public Dictionary<string, Monster> dicMonster = new Dictionary<string, Monster>(); // 초기화 // 첫 번째 프레임 전에 호출됩니다.
[System.Serializable]
public class Monster
{
public int id;
public string name;
public int level;
public int hp;
public int attackPower;
public int defencePoser;
}
// Start is called before the first frame update
void Start() void Start()
{ {
// 몬스터 데이터 로드 (테스트용, 첫 번째 몬스터 데이터만 로드)
MonsterData monsterData = MonsterDataManager.Singleton.monstersData[0];
Debug.Log(monsterData.name); // 몬스터 ID 출력
ReadCsv(); _currentTime = Time.realtimeSinceStartup; // 시작 시간 기록
// dicMonster 사용 예시 _animator = GetComponent<Animator>(); // 애니메이터 컴포넌트 초기화
if (dicMonster.ContainsKey("1")) // 키 존재 확인
{
// Debug.Log(dicMonster["1"].name);
}
_currentTime = Time.realtimeSinceStartup; _direction = new Vector3(1, 0, 0); // 초기 이동 방향 (x 축 양의 방향)
_animator = GetComponent<Animator>(); _spriteRenderer.flipX = !(_direction.x > 0); // 이동 방향에 따라 스프라이트 플립
_direction = new Vector3(1, 0, 0); _collider = GetComponent<Collider2D>(); // 콜라이더 컴포넌트 초기화
_spriteRenderer.flipX = !(_direction.x > 0); // 몬스터 방어력 임시값 설정
_collider = GetComponent<Collider2D>();
// TODO: 몬스터 방어력 임시값
defencePower = 10f; defencePower = 10f;
} }
// 애니메이션 상태를 변경하는 메서드
void ChangeAnimationState(string newState) void ChangeAnimationState(string newState)
{ {
// 현재 상태와 동일한 상태일 경우, 애니메이션을 변경하지 않음
if(currentState == newState) return; if(currentState == newState) return;
_animator.Play(newState); _animator.Play(newState); // 새로운 애니메이션 상태 실행
} }
private void ReadCsv() // 매 프레임 호출됩니다.
{
TextAsset csvFile = Resources.Load<TextAsset>("Monster");
if (csvFile == null)
{
Debug.LogError("CSV 파일 로드 실패: Monster");
return;
}
StringReader reader = new StringReader(csvFile.text);
string line;
bool isFirstLine = true; // 첫 번째 줄은 헤더로 건너뛰기
while ((line = reader.ReadLine()) != null)
{
if (isFirstLine)
{
isFirstLine = false;
continue; // 헤더 건너뛰기
}
var splitData = line.Split(',');
Monster monster = new Monster();
// int.TryParse를 사용하여 안전하게 정수형으로 변환
if (int.TryParse(splitData[0], out monster.id)) { }
else { Debug.LogError("id 필드 정수 변환 실패: " + splitData[0]); }
monster.name = splitData[1];
if (int.TryParse(splitData[2], out monster.level)) { }
else { Debug.LogError("level 필드 정수 변환 실패: " + splitData[2]); }
if (int.TryParse(splitData[3], out monster.hp)) { }
else { Debug.LogError("hp 필드 정수 변환 실패: " + splitData[3]); }
if (int.TryParse(splitData[4], out monster.attackPower)) { }
else { Debug.LogError("attackPower 필드 정수 변환 실패: " + splitData[4]); }
if (int.TryParse(splitData[5], out monster.defencePoser)) { }
else { Debug.LogError("defencePoser 필드 정수 변환 실패: " + splitData[5]); }
dicMonster.Add(monster.id.ToString(), monster); // id를 키로 사용
}
}
// Update is called once per frame
void Update() void Update()
{ {
// todo : 시야를 벗어났으면 idle 전환 // TODO: 시야를 벗어났으면 idle 상태로 전환하는 기능 추가 예정
// 몬스터가 걷고 있는 경우
if (_isWalking) if (_isWalking)
{ {
transform.Translate(_direction * speed * Time.deltaTime); transform.Translate(_direction * speed * Time.deltaTime); // 몬스터를 이동시킴
// 걷기 시간을 초과하면 대기 상태로 전환
if (Time.realtimeSinceStartup - _currentTime >= walkingTime) if (Time.realtimeSinceStartup - _currentTime >= walkingTime)
{ {
_isWalking = false; _isWalking = false;
ChangeAnimationState(AniIdle); ChangeAnimationState(AniIdle); // 애니메이션을 Idle로 변경
_currentTime = Time.realtimeSinceStartup; _currentTime = Time.realtimeSinceStartup; // 시간 갱신
} }
} }
else else
{ {
// 대기 시간이 초과되면 걷기 시작
if (Time.realtimeSinceStartup - _currentTime >= _idleTime) if (Time.realtimeSinceStartup - _currentTime >= _idleTime)
{ {
_currentTime = Time.realtimeSinceStartup; _currentTime = Time.realtimeSinceStartup;
// 걷기 상태가 아니라면 방향을 반대로 바꿔서 걷기 시작
if (_isWalking == false) if (_isWalking == false)
{ {
_direction *= -1; _direction *= -1; // 이동 방향 반전
_spriteRenderer.flipX = !(_direction.x > 0); _spriteRenderer.flipX = !(_direction.x > 0); // 스프라이트 방향 반전
} }
_isWalking = true; _isWalking = true;
ChangeAnimationState(AniWalk); ChangeAnimationState(AniWalk); // 애니메이션을 Walk로 변경
} }
} }
// Detect 및 공격 처리 // 대상을 인식하고 있으면 공격 또는 추적 처리
if (_isDetect && _target != null) if (_isDetect && _target != null)
{ {
// 플레이어와 몬스터 간의 거리 계산 // 몬스터와 타겟 간의 거리 계산
float distance = Vector3.Distance(transform.position, _target.transform.position); float distance = Vector3.Distance(transform.position, _target.transform.position);
if (distance < 1.5f) // 일정 거리 이내에서 공격 if (distance < 1.5f) // 일정 거리 이내에서 공격
@@ -204,65 +145,62 @@ namespace TON
} }
else else
{ {
Detect(_target); // 플레이어가 가까이 오면 추적 Detect(_target); // 타겟이 멀어지면 추적
} }
} }
// 걷기 애니메이션으로 변경
// ChangeAnimationState(AniWalk);
// _animator.SetBool("Walk", _isWalking); // 걷기 애니메이션
} }
// 피해를 적용하는 메서드
public void ApplyDamage(float damage) public void ApplyDamage(float damage)
{ {
// 몬스터 피해 값 코드 // 몬스터의 체력을 감소시키고, 죽었을 경우 파괴 처리
// 체력이 감소되는 부분
// 몬스터 죽고 파괴되는 부분
// 피격됐을때 애니메이션
float prevHP = currentHP; float prevHP = currentHP;
currentHP -= damage; currentHP -= damage;
if (prevHP > 0 && currentHP <= 0) if (prevHP > 0 && currentHP <= 0)
{ {
// _animator.SetBool("Die", true); // 몬스터 죽는 애니메이션 트리거 // 몬스터었을 때 처리 (죽는 애니메이션은 주석 처리됨)
Destroy(gameObject); // 몬스터 파괴 Destroy(gameObject); // 몬스터 파괴
} }
else if (prevHP > 0 && currentHP > 0) else if (prevHP > 0 && currentHP > 0)
{ {
// _animator.SetBool("Hit", true); // 피격 애니메이션 // 피격 애니메이션은 주석 처리됨 (필요시 활성화)
} }
} }
// 타겟을 공격하는 메서드
public void Attack(GameObject player) public void Attack(GameObject player)
{ {
ChangeAnimationState(AniAttack); ChangeAnimationState(AniAttack); // 공격 애니메이션으로 변경
// 임시 반영 수정 예정 // 데미지 계산 (현재 임시 값)
DamageCalculator damageCalculator = new DamageCalculator(); DamageCalculator damageCalculator = new DamageCalculator();
float baseAttack = 30f; float baseAttack = 30f; // 기본 공격력
float equipmentAttack = 10f; float equipmentAttack = 10f; // 장비 공격력
float defense = 0.1f; float defense = 0.1f; // 방어력 비율
// 기본 데미지 계산 (치명타 없음) // 기본 데미지 계산 (치명타 없음)
float damage = damageCalculator.CalculateBaseDamage(baseAttack, equipmentAttack, defense); float damage = damageCalculator.CalculateBaseDamage(baseAttack, equipmentAttack, defense);
Debug.Log($" 몬스터 공격! 최종 데미지: {damage}"); Debug.Log($" 몬스터 공격! 최종 데미지: {damage}"); // 데미지 출력
} }
// 타겟을 추적하는 메서드
public void Detect(GameObject target) public void Detect(GameObject target)
{ {
if (target == null) return; if (target == null) return; // 타겟이 없으면 리턴
UnityEngine.Vector2 direction = target.transform.position - transform.position; UnityEngine.Vector2 direction = target.transform.position - transform.position; // 타겟과의 방향 계산
if (direction.magnitude > 0) if (direction.magnitude > 0) // 타겟이 존재하면 이동
{ {
transform.Translate(direction.normalized * speed * Time.deltaTime); transform.Translate(direction.normalized * speed * Time.deltaTime); // 타겟 방향으로 이동
ChangeAnimationState(AniWalk); ChangeAnimationState(AniWalk); // 걷기 애니메이션으로 변경
_spriteRenderer.flipX = direction.x < 0;
}
}
}
// 타겟 방향에 따라 스프라이트 방향 즉시 변경
_spriteRenderer.flipX = direction.x < 0; // 타겟이 왼쪽에 있으면 반전, 오른쪽에 있으면 정방향
}
}
}
} }