From 648452a153aea273d0e8f1791a2ec88e876f76c5 Mon Sep 17 00:00:00 2001 From: Mingu Kim Date: Sat, 15 Feb 2025 02:17:46 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AA=AC=EC=8A=A4=ED=84=B0=20=EC=8A=A4?= =?UTF-8?q?=ED=82=AC=20json=20=EB=A1=9C=EB=93=9C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Gameton/Scripts/GameData/MonsterData.cs | 5 +- .../Scripts/GameData/MonsterSkillData.cs | 17 +++ .../Scripts/GameData/MonsterSkillData.cs.meta | 11 ++ .../Assets/Gameton/Scripts/Monster/Attack.cs | 17 +++ .../Gameton/Scripts/Monster/MonsterBase.cs | 112 +++++++++++--- .../Monster/MonsterSkillDataManager.cs | 54 +++++++ .../Monster/MonsterSkillDataManager.cs.meta | 11 ++ .../Gameton/Scripts/Monster/StateMachine.cs | 142 +++++++++++++++++- 8 files changed, 345 insertions(+), 24 deletions(-) create mode 100644 Gameton-06/Assets/Gameton/Scripts/GameData/MonsterSkillData.cs create mode 100644 Gameton-06/Assets/Gameton/Scripts/GameData/MonsterSkillData.cs.meta create mode 100644 Gameton-06/Assets/Gameton/Scripts/Monster/MonsterSkillDataManager.cs create mode 100644 Gameton-06/Assets/Gameton/Scripts/Monster/MonsterSkillDataManager.cs.meta diff --git a/Gameton-06/Assets/Gameton/Scripts/GameData/MonsterData.cs b/Gameton-06/Assets/Gameton/Scripts/GameData/MonsterData.cs index 19d14baa..e1ccfda4 100644 --- a/Gameton-06/Assets/Gameton/Scripts/GameData/MonsterData.cs +++ b/Gameton-06/Assets/Gameton/Scripts/GameData/MonsterData.cs @@ -20,15 +20,16 @@ namespace TON // 기본 공격력 public int attackPower; // 기본 방어력 - public int defensivePower; + public int defencePower; // 몬스터 스킬 ID - public string monsterSkillID; + public int monsterSkillID; // 패트롤 범위 public float patrolRange; // 인식 범위 public float detectionRange; // 추적 범위 public float chaseRange; + public float moveSpeed; // 공격 범위 public float attackRange; diff --git a/Gameton-06/Assets/Gameton/Scripts/GameData/MonsterSkillData.cs b/Gameton-06/Assets/Gameton/Scripts/GameData/MonsterSkillData.cs new file mode 100644 index 00000000..20e30a5d --- /dev/null +++ b/Gameton-06/Assets/Gameton/Scripts/GameData/MonsterSkillData.cs @@ -0,0 +1,17 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace TON +{ + [System.Serializable] + public class MonsterSkillData + { + public int skillId; // 스킬 ID + public string skillName; // 스킬 이름 + public float damage; // 스킬 데미지 + public float cooldown; // 스킬 쿨다운 + public float range; // 스킬 범위 + public string animationName; // 스킬 애니메이션 이름 + } +} \ No newline at end of file diff --git a/Gameton-06/Assets/Gameton/Scripts/GameData/MonsterSkillData.cs.meta b/Gameton-06/Assets/Gameton/Scripts/GameData/MonsterSkillData.cs.meta new file mode 100644 index 00000000..f56be2ab --- /dev/null +++ b/Gameton-06/Assets/Gameton/Scripts/GameData/MonsterSkillData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e7674986391c77044bbc330f14711e86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Gameton-06/Assets/Gameton/Scripts/Monster/Attack.cs b/Gameton-06/Assets/Gameton/Scripts/Monster/Attack.cs index 008d13d7..5f679014 100644 --- a/Gameton-06/Assets/Gameton/Scripts/Monster/Attack.cs +++ b/Gameton-06/Assets/Gameton/Scripts/Monster/Attack.cs @@ -15,7 +15,24 @@ namespace TON if (other.CompareTag("Player")) { _monsterBase.SetTransition(new AttackState()); + // _monsterBase.SetTransition(new MonsterSkillState()); } + + // if (!_monsterBase.monsterSkillID) + // { + // if (other.CompareTag("Player")) + // { + // // 일정 확률로 스킬 사용 + // if (Random.value < 0.3f) // 30% 확률 + // { + // _monsterBase.SetTransition(new SkillState()); + // } + // else + // { + // _monsterBase.SetTransition(new AttackState()); + // } + // } + // } } private void OnTriggerExit2D(Collider2D other) diff --git a/Gameton-06/Assets/Gameton/Scripts/Monster/MonsterBase.cs b/Gameton-06/Assets/Gameton/Scripts/Monster/MonsterBase.cs index ddcbab2f..d602351c 100644 --- a/Gameton-06/Assets/Gameton/Scripts/Monster/MonsterBase.cs +++ b/Gameton-06/Assets/Gameton/Scripts/Monster/MonsterBase.cs @@ -7,21 +7,28 @@ using System.Numerics; using Assets.PixelFantasy.PixelMonsters.Common.Scripts; using Unity.VisualScripting; using UnityEngine; +using UnityEngine.UI; using DamageCalculator = TON.DamageCalculator; +using Vector2 = UnityEngine.Vector2; using Vector3 = UnityEngine.Vector3; namespace TON { public class MonsterBase : MonoBehaviour, IDamage { + [SerializeField] public int id; // 몬스터의 ID + public string monsterName; // 몬스터 이름 + public int level; public float currentHP = 100; // 몬스터의 현재 체력 - - // public string name; // 몬스터 이름 - public string monsterType; // 몬스터의 타입 (예: melee, ranged) - - // public int damage; // 공격력 + public int attackPower; // 공격력 + public int defensePower; + public int monsterSkillID; + public float patrolRange; + public float detectionRange; + public float chaseRange; public float speed = 2; // 몬스터의 이동 속도 + public float attackRange; [SerializeField] private SpriteRenderer _spriteRenderer; // 몬스터의 스프라이트 렌더러 private Animator _animator; // 몬스터 애니메이터 @@ -49,16 +56,18 @@ namespace TON // 추적 관련 선언 private float _detectStartTime; // 추적 시작 시간 private bool _isTracking; // 추적 중인지 여부 - - private const float DETECT_DURATION = 5f; // 추적 지속 시간 - + // hp바 + [SerializeField] private Image _hpBarImage; // HP 바 이미지 + private float _maxHP; - public bool IsDetect - { - get => _isDetect; - set => _isDetect = value; - } + // 스킬 + public int skillId; // 스킬 ID + public string skillName; // 스킬 이름 + public float damage; // 스킬 데미지 + public float cooldown; // 스킬 쿨다운 + public float range; // 스킬 범위 + public string animationName; // 스킬 애니메이션 이름 // 첫 번째 프레임 전에 호출됩니다. private void Start() @@ -67,9 +76,13 @@ namespace TON _stateMachine = new StateMachine(new IdleState(), this); - // 몬스터 데이터 로드 (테스트용, 첫 번째 몬스터 데이터만 로드) - MonsterData monsterData = MonsterDataManager.Singleton.monstersData[0]; - Debug.Log(monsterData.name); // 몬스터 ID 출력 + // // 몬스터 데이터 로드 (테스트용, 첫 번째 몬스터 데이터만 로드) + // MonsterData monsterData = MonsterDataManager.Singleton.monstersData[0]; + // Debug.Log(monsterData.name); // 몬스터 ID 출력 + + // 몬스터 데이터 로드 및 적용 + InitializeMonsterData(); + InitializeMonsterSkillData(); _direction = new Vector3(1, 0, 0); // 초기 이동 방향 (x 축 양의 방향) @@ -80,6 +93,57 @@ namespace TON // 몬스터 방어력 임시값 설정 defencePower = 10f; } + + private void InitializeMonsterData() + { + MonsterData monsterData = MonsterDataManager.Singleton.GetMonsterData(id); + if (monsterData != null) + { + id = monsterData.id; + monsterName = monsterData.name; + level = monsterData.level; + currentHP = monsterData.hp; + attackPower = monsterData.attackPower; + defencePower = monsterData.defencePower; + monsterSkillID = monsterData.monsterSkillID;; + patrolRange = monsterData.patrolRange; + detectionRange = monsterData.detectionRange; + chaseRange = monsterData.chaseRange; + speed = monsterData.moveSpeed; + attackPower = monsterData.attackPower; + + _maxHP = monsterData.hp; + currentHP = _maxHP; + + Debug.Log($"몬스터 {monsterData.name} 데이터 로드 완료"); + } + else + { + Debug.LogError($"몬스터 ID {id}에 대한 데이터를 찾을 수 없습니다."); + } + } + + private void InitializeMonsterSkillData() + { + MonsterSkillData monsterSkillData = MonsterSkillDataManager.Singleton.GetMonsterSkillData(monsterSkillID); + + if (monsterSkillData != null) + { + skillId = monsterSkillData.skillId; + skillName = monsterSkillData.skillName; + damage = monsterSkillData.damage; + cooldown = monsterSkillData.cooldown; + range = monsterSkillData.range; + animationName = monsterSkillData.animationName; + + Debug.Log($"몬스터 {monsterSkillData.skillName} 데이터 로드 완료"); + } + else + { + Debug.LogError($"몬스터 스킬 ID {id}에 대한 데이터를 찾을 수 없습니다."); + } + } + // 애니메이션 상태를 변경하는 메서드 public void ChangeAnimationState(string newState) @@ -102,7 +166,10 @@ namespace TON // 몬스터의 체력을 감소시키고, 죽었을 경우 파괴 처리 float prevHP = currentHP; currentHP -= damage; - + + // HP 바 업데이트 + UpdateHPBar(); + if (prevHP > 0 && currentHP <= 0) { // 몬스터가 죽었을 때 처리 (죽는 애니메이션은 주석 처리됨) @@ -113,6 +180,17 @@ namespace TON // 피격 애니메이션은 주석 처리됨 (필요시 활성화) } } + + // HP 바 업데이트 + private void UpdateHPBar() + { + if (_hpBarImage != null) + { + // 현재 체력 비율 계산 (0.0 ~ 1.0) + float hpRatio = currentHP / _maxHP; + _hpBarImage.fillAmount = hpRatio; // 이미지 크기를 체력 비율에 맞게 조절 + } + } // 타겟을 공격하는 메서드 public void Attack(GameObject player) diff --git a/Gameton-06/Assets/Gameton/Scripts/Monster/MonsterSkillDataManager.cs b/Gameton-06/Assets/Gameton/Scripts/Monster/MonsterSkillDataManager.cs new file mode 100644 index 00000000..d0e293ba --- /dev/null +++ b/Gameton-06/Assets/Gameton/Scripts/Monster/MonsterSkillDataManager.cs @@ -0,0 +1,54 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace TON +{ + using System.Collections.Generic; + using System.IO; + using UnityEngine; + + public class MonsterSkillDataManager : SingletonBase + { + // 전체 몬스터 스킬 데이터 리스트 + public List monstersSkillData { get; private set; } + + // 현재 선택된 몬스터 스킬 데이터 + public MonsterSkillData currentMonsterSkill { get; private set; } + + protected override void Awake() + { + base.Awake(); + LoadMonsterSkillData(); + } + + private void LoadMonsterSkillData() + { + monstersSkillData = JSONLoader.LoadFromResources>("MonsterSkills"); + if (monstersSkillData == null) + { + monstersSkillData = new List(); + Debug.LogError("몬스터 스킬 데이터 로드 실패"); + } + } + + public MonsterSkillData GetMonsterSkillData(int monsterSkillId) + { + if (monsterSkillId >= 0 && monsterSkillId < monstersSkillData.Count) + { + currentMonsterSkill = monstersSkillData[monsterSkillId]; + return currentMonsterSkill; + } + else + { + Debug.LogError($"유효하지 않은 몬스터 SkillID입니다: {monsterSkillId}"); + return null; + } + } + + public List GetAllMonsterSkillData() + { + return monstersSkillData; + } + } +} diff --git a/Gameton-06/Assets/Gameton/Scripts/Monster/MonsterSkillDataManager.cs.meta b/Gameton-06/Assets/Gameton/Scripts/Monster/MonsterSkillDataManager.cs.meta new file mode 100644 index 00000000..b982368b --- /dev/null +++ b/Gameton-06/Assets/Gameton/Scripts/Monster/MonsterSkillDataManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 517b06d480f28194b830fa1520a0a395 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Gameton-06/Assets/Gameton/Scripts/Monster/StateMachine.cs b/Gameton-06/Assets/Gameton/Scripts/Monster/StateMachine.cs index 7dc4595f..382d8a73 100644 --- a/Gameton-06/Assets/Gameton/Scripts/Monster/StateMachine.cs +++ b/Gameton-06/Assets/Gameton/Scripts/Monster/StateMachine.cs @@ -147,26 +147,48 @@ namespace TON public class AttackState : State { private const string AniAttack = "Attack"; // 공격 애니메이션 - private MonsterBase _monsterBase; - // private float _attackDelayTime = 2f; + private const string AniIdle = "Idle"; // 대기 애니메이션 - // private StateMachine _stateMachine; + private MonsterBase _monsterBase; + private float _attackDelayTime = 2f; // 공격 딜레이 시간 + private float _lastAttackTime; // 마지막 공격 시간 + private float _attackAnimationDuration = 0.5f; // 공격 애니메이션 지속 시간 + private bool _isAttacking = false; public void Enter(MonsterBase monsterBase) { _monsterBase = monsterBase; + _lastAttackTime = -_attackDelayTime; // 처음 진입시 바로 공격하도록 설정 + Attack(); } public void Update() + { + // 현재 공격 중이 아니고, 쿨다운이 지났다면 공격 + if (!_isAttacking && Time.time >= _lastAttackTime + _attackDelayTime) + { + Attack(); + } + + // 공격 애니메이션 종료 체크 + if (_isAttacking && Time.time >= _lastAttackTime + _attackAnimationDuration) + { + _isAttacking = false; + _monsterBase.ChangeAnimationState(AniIdle); + } + } + + private void Attack() { _monsterBase.ChangeAnimationState(AniAttack); - _monsterBase.PlayerAttack(); + _lastAttackTime = Time.time; + _isAttacking = true; } public void Exit() { - + _isAttacking = false; } public void CheckTransition() @@ -177,4 +199,114 @@ namespace TON // } } } + + public class HitState : State + { + private const string AniHit = "Hit"; // 피격 애니메이션 + private MonsterBase _monsterBase; + private float _hitStunDuration = 0.5f; // 피격 경직 시간 + private float _hitStartTime; + + public void Enter(MonsterBase monsterBase) + { + _monsterBase = monsterBase; + _hitStartTime = Time.time; + _monsterBase.ChangeAnimationState(AniHit); + + Debug.Log($"피격 상태 진입! 현재 HP: {_monsterBase.currentHP}"); + } + + public void Update() + { + // 피격 경직 시간이 지나면 이전 상태로 복귀 + if (Time.time >= _hitStartTime + _hitStunDuration) + { + // HP가 0 이하면 죽음 상태로 전환 + if (_monsterBase.currentHP <= 0) + { + _monsterBase.SetTransition(new DeadState()); + } + else + { + // 플레이어가 공격 범위 내에 있으면 공격 상태로, 아니면 추적 상태로 + var target = GameObject.FindGameObjectWithTag("Player"); + if (target != null) + { + float distanceToTarget = + Vector2.Distance(_monsterBase.transform.position, target.transform.position); + if (distanceToTarget <= _monsterBase.attackRange) + { + _monsterBase.SetTransition(new AttackState()); + } + else + { + _monsterBase.SetTransition(new ChasingState()); + } + } + } + } + } + + public void Exit() + { + } + + public void CheckTransition() + { + } + } + + public class DeadState : State + { + private const string AniDead = "Death"; // 죽음 애니메이션 + private MonsterBase _monsterBase; + private float _deathAnimationDuration = 1f; // 죽음 애니메이션 재생 시간 + private float _deathStartTime; + private bool _hasTriggeredDeath = false; + + public void Enter(MonsterBase monsterBase) + { + _monsterBase = monsterBase; + _deathStartTime = Time.time; + _monsterBase.ChangeAnimationState(AniDead); + + // 죽음 처리 시작 + StartDeathProcess(); + } + + private void StartDeathProcess() + { + if (_hasTriggeredDeath) return; + + _hasTriggeredDeath = true; + + // 콜라이더 비활성화 + if (_monsterBase.GetComponent() != null) + { + _monsterBase.GetComponent().enabled = false; + } + + Debug.Log($"몬스터 사망: {_monsterBase.name}"); + + // 여기에 경험치 드롭, 아이템 드롭 등의 로직 추가 가능 + } + + public void Update() + { + // 죽음 애니메이션이 끝나면 오브젝트 제거 + if (Time.time >= _deathStartTime + _deathAnimationDuration) + { + GameObject.Destroy(_monsterBase.gameObject); + } + } + + public void Exit() + { + } + + public void CheckTransition() + { + // 죽음 상태에서는 다른 상태로 전환되지 않음 + } + } }