몬스터 스포너 테스트코드 구현

1. 몬스터 상태 Hit, Death 추가
2. 몬스터 스킬 정리
This commit is contained in:
Mingu Kim
2025-02-20 05:21:58 +09:00
parent 5f7428db4c
commit a27bb7d6d1
14 changed files with 926 additions and 709 deletions

View File

@@ -5,7 +5,7 @@
"damage": 50, "damage": 50,
"cooldown": 5, "cooldown": 5,
"range": 5, "range": 5,
"prefabName": "IceBlastPrefab" "prefabName": "IceBlast"
}, },
{ {
"skillId": 1, "skillId": 1,
@@ -13,6 +13,6 @@
"damage": 50, "damage": 50,
"cooldown": 5, "cooldown": 5,
"range": 5, "range": 5,
"prefabName": "smallFirePrefab" "prefabName": "smallFire"
} }
] ]

View File

@@ -32,7 +32,7 @@ Transform:
serializedVersion: 2 serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 9.6, y: -6.82, z: 0} m_LocalPosition: {x: 9.6, y: -6.82, z: 0}
m_LocalScale: {x: 2, y: 2, z: 2} m_LocalScale: {x: 3, y: 3, z: 2}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}

View File

@@ -2313,6 +2313,37 @@ PrefabInstance:
m_AddedGameObjects: [] m_AddedGameObjects: []
m_AddedComponents: [] m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: ab2e507b20e5dc844a1ea24b5619f656, type: 3} m_SourcePrefab: {fileID: 100100000, guid: ab2e507b20e5dc844a1ea24b5619f656, type: 3}
--- !u!1 &340342490
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 340342491}
m_Layer: 0
m_Name: Monster1
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &340342491
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 340342490}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 6.4799995, y: 2.25, z: -0.10636908}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1253934486}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &391267027 --- !u!1 &391267027
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -58772,6 +58803,59 @@ MonoBehaviour:
m_CameraActivatedEvent: m_CameraActivatedEvent:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
--- !u!1 &1253934484
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1253934486}
- component: {fileID: 1253934485}
m_Layer: 0
m_Name: Spanwer
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1253934485
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1253934484}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 481676f31fc794c4b93848b442416f2c, type: 3}
m_Name:
m_EditorClassIdentifier:
_monsterLocations:
- {fileID: 340342491}
- {fileID: 1721288851}
- {fileID: 1695686502}
_monsterId: 01000000010000000100000004000000
_spawnDistance: 10
--- !u!4 &1253934486
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1253934484}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 15.07, y: -6.5, z: 1.0991049}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 340342491}
- {fileID: 1721288851}
- {fileID: 1695686502}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1342711675 --- !u!1 &1342711675
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -84036,7 +84120,7 @@ PrefabInstance:
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 3656570700648378249, guid: f92c93d0d7d455d40b84e993e40acfca, type: 3} - target: {fileID: 3656570700648378249, guid: f92c93d0d7d455d40b84e993e40acfca, type: 3}
propertyPath: m_IsActive propertyPath: m_IsActive
value: 0 value: 1
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 8528093570479225059, guid: f92c93d0d7d455d40b84e993e40acfca, type: 3} - target: {fileID: 8528093570479225059, guid: f92c93d0d7d455d40b84e993e40acfca, type: 3}
propertyPath: m_LocalPosition.x propertyPath: m_LocalPosition.x
@@ -94630,6 +94714,68 @@ Rigidbody2D:
m_SleepingMode: 1 m_SleepingMode: 1
m_CollisionDetection: 0 m_CollisionDetection: 0
m_Constraints: 0 m_Constraints: 0
--- !u!1 &1695686501
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1695686502}
m_Layer: 0
m_Name: Monster3
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1695686502
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1695686501}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 6.25, y: 2.26, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1253934486}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1721288850
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1721288851}
m_Layer: 0
m_Name: Monster2
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1721288851
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1721288850}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 8.26, y: 3.17, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1253934486}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1906030825 --- !u!1 &1906030825
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -112802,3 +112948,4 @@ SceneRoots:
- {fileID: 535565209} - {fileID: 535565209}
- {fileID: 1423029865} - {fileID: 1423029865}
- {fileID: 1441848035} - {fileID: 1441848035}
- {fileID: 1253934486}

View File

@@ -1,82 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TON
{
public class AttackPattern
{
protected MonsterBase _monsterBase;
public AttackPattern(MonsterBase monsterBase)
{
_monsterBase = monsterBase;
}
public virtual void Attack()
{
}
}
public class Monster1AttackPattern : AttackPattern
{
public Monster1AttackPattern(MonsterBase monsterBase) : base(monsterBase)
{
}
public override void Attack()
{
Skill1();
MeleeAttack();
}
private void Skill1()
{
_monsterBase.MonsterSkillLaunch();
}
private void MeleeAttack()
{
_monsterBase.PlayerAttack();
}
}
public class Monster2AttackPattern : AttackPattern
{
public Monster2AttackPattern(MonsterBase monsterBase) : base(monsterBase)
{
}
public override void Attack()
{
Skill1();
Skill2();
MeleeAttack();
}
private void Skill1()
{
}
private void Skill2()
{
}
private void MeleeAttack()
{
_monsterBase.PlayerAttack();
}
}
}

View File

@@ -0,0 +1,22 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TON
{
public partial class MonsterBase
{
private void OnGUI()
{
if (GUILayout.Button("Hit"))
{
ApplyDamage(1);
}
if (GUILayout.Button("Dead"))
{
ApplyDamage(1000000000);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: be351d22396005d4bbcd8a3e72592f75
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,22 +1,13 @@
using System; using TMPro;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Numerics;
using Assets.PixelFantasy.PixelMonsters.Common.Scripts;
using Unity.VisualScripting;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using DamageCalculator = TON.DamageCalculator;
using Vector2 = UnityEngine.Vector2; using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3; using Vector3 = UnityEngine.Vector3;
namespace TON namespace TON
{ {
public class MonsterBase : MonoBehaviour, IDamage public partial class MonsterBase : MonoBehaviour, IDamage
{ {
[SerializeField] [SerializeField]
public int id; // 몬스터의 ID public int id; // 몬스터의 ID
public float defencePower; public float defencePower;
@@ -30,14 +21,15 @@ namespace TON
StateMachine _stateMachine; StateMachine _stateMachine;
private AttackPattern _attackPattern; private SkillPattern _skillPattern;
// [SerializeField] private TextMeshProUGUI _textState;
private Vector3 _direction; // 몬스터의 이동 방향 private Vector3 _direction; // 몬스터의 이동 방향
public bool IsDetect { get; set; } // 몬스터가 대상을 인식했는지 여부 public bool IsDetect { get; set; } // 몬스터가 대상을 인식했는지 여부
public bool IsAttacking { get; set; } // 몬스터가 공격했는지 여부 public bool IsAttacking { get; set; } // 몬스터가 공격했는지 여부
public bool IsFisnishAttack { get; set; } // 몬스터 공격 모션이 끝났는지 여부 public bool IsFisnishAttack { get; set; } // 몬스터 공격 모션이 끝났는지 여부
public bool IsHit { get; set; } // 몬스터 공격 모션이 끝났는지 여부 public bool IsSkillAttackable => _skillPattern.IsAttackable;
public bool IsDead { get; set; } // 몬스터 공격 모션이 끝났는지 여부
[SerializeField] private GameObject _target; // 몬스터의 타겟 [SerializeField] private GameObject _target; // 몬스터의 타겟
@@ -47,37 +39,23 @@ namespace TON
private string currentAnimationState; // 현재 애니메이션 상태 private string currentAnimationState; // 현재 애니메이션 상태
// hp바 // hp바
[SerializeField] private Image _hpBarImage; // HP 바 이미지 public GameObject _hpBarImage; // HP 바 이미지
private float _maxHP; private float _maxHP;
private float currentHP; private float currentHP;
private float hpMaxWidth;
// 몬스터 스킬 프리팹
public GameObject smallFirePrefab;
public GameObject DragonBreathPrefab;
public GameObject IceBlastPrefab;
public GameObject PumpkinCrashPrefab;
public GameObject TrollChargePrefab;
public GameObject TrollCrashPrefab;
public GameObject TrollThundePrefab;
public GameObject WolfEnergyWavePrefab;
public GameObject WolfPunchPrefab;
public GameObject DragonShockWavePrefab;
public GameObject FireImpactPrefab;
// 첫 번째 프레임 전에 호출됩니다. // 첫 번째 프레임 전에 호출됩니다.
private void Start() private void Start()
{ // 전략 패턴 {
// TODO : 수정중
// _attackPattern = new Monster1AttackPattern();
// _attackPattern = new Monster2AttackPattern();
_animator = GetComponent<Animator>(); // 애니메이터 컴포넌트 초기화 _animator = GetComponent<Animator>(); // 애니메이터 컴포넌트 초기화
// _stateMachine = new StateMachine(new IdleState(), this, _textState);
_stateMachine = new StateMachine(new IdleState(), this); _stateMachine = new StateMachine(new IdleState(), this);
// 몬스터 데이터 로드 및 적용 // 몬스터 데이터 로드 및 적용
InitializeMonsterData(); InitializeMonsterData();
InitializeMonsterSkillData();
_skillPattern = new Monster1SkillPattern(_monsterData, this);
id = _monsterData.id; id = _monsterData.id;
@@ -86,6 +64,8 @@ namespace TON
_spriteRenderer.flipX = !(_direction.x > 0); // 이동 방향에 따라 스프라이트 플립 _spriteRenderer.flipX = !(_direction.x > 0); // 이동 방향에 따라 스프라이트 플립
_collider = GetComponent<Collider2D>(); // 콜라이더 컴포넌트 초기화 _collider = GetComponent<Collider2D>(); // 콜라이더 컴포넌트 초기화
// hpMaxWidth = _hpBarImage.GetComponent<RectTransform>().sizeDelta.x;
} }
// TODO : 불러온 값 변수에 대응하게 수정 // TODO : 불러온 값 변수에 대응하게 수정
@@ -95,9 +75,7 @@ namespace TON
if (_monsterData != null) if (_monsterData != null)
{ {
_maxHP = _monsterData.hp; currentHP = _monsterData.hp;
currentHP = _maxHP;
defencePower = _monsterData.defencePower; defencePower = _monsterData.defencePower;
Debug.Log($"몬스터 {_monsterData.name} 데이터 로드 완료"); Debug.Log($"몬스터 {_monsterData.name} 데이터 로드 완료");
@@ -108,29 +86,6 @@ namespace TON
} }
} }
// TODO : 불러온 값 변수에 대응하게 수정
private void InitializeMonsterSkillData()
{
_monsterSkillData = MonsterSkillDataManager.Singleton.GetMonsterSkillData(_monsterData.monsterSkillID);
if (_monsterData.monsterSkillIDTwo > -1)
{
_monsterSkillDataTwo = MonsterSkillDataManager.Singleton.GetMonsterSkillData(_monsterData.monsterSkillIDTwo);
}
if (_monsterSkillData != null && _monsterSkillDataTwo != null)
{
Debug.Log($"몬스터 {_monsterSkillData.skillName} 데이터 로드 완료");
Debug.Log($"몬스터 {_monsterSkillDataTwo.skillName} 데이터 로드 완료");
}
else
{
Debug.LogError($"몬스터 스킬 ID {_monsterSkillData.skillId}에 대한 데이터를 찾을 수 없습니다.");
Debug.LogError($"몬스터 스킬 ID {_monsterSkillDataTwo.skillId}에 대한 데이터를 찾을 수 없습니다.");
}
}
// 애니메이션 상태를 변경하는 메서드 // 애니메이션 상태를 변경하는 메서드
public void ChangeAnimationState(string newState) public void ChangeAnimationState(string newState)
{ {
@@ -143,7 +98,7 @@ namespace TON
private void Update() private void Update()
{ {
_stateMachine.Update(); _stateMachine.Update();
_skillPattern.Update();
} }
public void FinishAttack() public void FinishAttack()
@@ -163,13 +118,11 @@ namespace TON
if (prevHP > 0 && currentHP <= 0) if (prevHP > 0 && currentHP <= 0)
{ {
// 몬스터가 죽었을 때 처리 (죽는 애니메이션은 주석 처리됨) _stateMachine.SetTransition(new DeathState());
// Destroy(gameObject); // 몬스터 파괴
DestroyMonster();
} }
else if (prevHP > 0 && currentHP > 0) else if (prevHP > 0 && currentHP > 0)
{ {
// 피격 애니메이션은 주석 처리됨 (필요시 활성화) _stateMachine.SetTransition(new HitState());
} }
} }
@@ -178,9 +131,10 @@ namespace TON
{ {
if (_hpBarImage != null) if (_hpBarImage != null)
{ {
// 현재 체력 비율 계산 (0.0 ~ 1.0) float minHPBarWidth = 5f; // 최소 HP 바 길이 (원하는 값으로 설정)
float hpRatio = currentHP / _maxHP; float hpBarWidth = Mathf.Max(currentHP / _maxHP * hpMaxWidth, minHPBarWidth); // 최소 길이 적용
_hpBarImage.fillAmount = hpRatio; // 이미지 크기를 체력 비율에 맞게 조절
_hpBarImage.GetComponent<RectTransform>().sizeDelta = new Vector2(hpBarWidth, _hpBarImage.GetComponent<RectTransform>().sizeDelta.y);
} }
} }
@@ -231,25 +185,12 @@ namespace TON
public void MonsterSkillLaunch() public void MonsterSkillLaunch()
{ {
// _spriteRenderer.flipX = target.transform.position.x < transform.position.x;
// newSkill.transform.position = transform.position + new Vector3(0, 1f, 0);
// newSkill.GetComponent<MonsterSkill>().Direction = new Vector2(0, 1);
var target = GameObject.FindGameObjectWithTag("Player"); var target = GameObject.FindGameObjectWithTag("Player");
_spriteRenderer.flipX = target.transform.position.x < transform.position.x; _skillPattern.Attack(target);
// TODO : 몬스터가 가지고 있는 스킬에 따라 분기되는 조건 추가
// GameObject newSkill = Instantiate(smallFirePrefab);
// GameObject newSkill = Instantiate(DragonBreathPrefab);
GameObject newSkill = Instantiate(IceBlastPrefab);
// GameObject newSkill = Instantiate(PumpkinCrashPrefab);
// GameObject newSkill = Instantiate(TrollChargePrefab);
// GameObject newSkill = Instantiate(TrollCrashPrefab);
// GameObject newSkill = Instantiate(TrollThundePrefab);
// GameObject newSkill = Instantiate(WolfEnergyWavePrefab);
// GameObject newSkill = Instantiate(WolfPunchPrefab);
// GameObject newSkill = Instantiate(DragonShockWavePrefab);
// GameObject newSkill = Instantiate(FireImpactPrefab);
newSkill.transform.position = transform.position + new Vector3(0, 1f, 0);
newSkill.GetComponent<MonsterSkill>().Direction = new Vector2(0, 1);
} }
public void DestroyMonster() public void DestroyMonster()

View File

@@ -0,0 +1,153 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TON
{
public class MonsterSpawner : MonoBehaviour
{
[SerializeField]
private List<Transform> _monsterLocations = new List<Transform>();
[SerializeField]
private List<int> _monsterId = new List<int>();
[SerializeField]
private float _spawnDistance = 10f;
private CharacterBase _player;
private List<MonsterBase> _spawnedMonsters = new List<MonsterBase>();
private Dictionary<Transform, bool> _spawnPoints = new Dictionary<Transform, bool>();
private void Start()
{
InitializeSpawner();
}
private void InitializeSpawner()
{
// 플레이어 찾기
GameObject playerObj = GameObject.FindGameObjectWithTag("Player");
if (playerObj != null)
{
_player = playerObj.GetComponent<CharacterBase>();
Debug.Log("플레이어 찾음: " + playerObj.name);
}
// 스폰 포인트 초기화
foreach (var location in _monsterLocations)
{
if (location != null)
{
_spawnPoints[location] = false;
Debug.Log($"스폰 포인트 초기화: {location.name}");
}
}
}
private void Update()
{
if (_player == null) return;
CheckSpawnConditions();
}
private void CheckSpawnConditions()
{
for (int i = 0; i < _monsterLocations.Count; i++)
{
Transform spawnPoint = _monsterLocations[i];
if (spawnPoint == null || _spawnPoints[spawnPoint]) continue;
float distance = Vector2.Distance(_player.transform.position, spawnPoint.position);
if (distance <= _spawnDistance)
{
SpawnMonster(i);
_spawnPoints[spawnPoint] = true;
}
}
}
private void SpawnMonster(int index)
{
if (index >= _monsterId.Count)
{
Debug.LogError($"유효하지 않은 인덱스: {index}");
return;
}
try
{
int monsterId = _monsterId[index];
// MonsterDataManager에서 데이터 가져오기
MonsterData monsterData = MonsterDataManager.Singleton.GetMonsterData(monsterId);
if (monsterData == null)
{
Debug.LogError($"몬스터 ID {monsterId}에 대한 데이터를 찾을 수 없습니다.");
return;
}
// 몬스터 프리팹 경로 결정
string prefabPath = GetMonsterPrefabPath(monsterData);
// 프리팹 로드
MonsterBase monsterPrefab = Resources.Load<MonsterBase>(prefabPath);
if (monsterPrefab == null)
{
Debug.LogError($"몬스터 프리팹을 찾을 수 없습니다: {prefabPath}");
return;
}
// 몬스터 생성
Vector3 spawnPosition = _monsterLocations[index].position;
MonsterBase newMonster = Instantiate(monsterPrefab, spawnPosition, Quaternion.identity);
// 몬스터 초기화
newMonster.id = monsterId;
_spawnedMonsters.Add(newMonster);
Debug.Log($"몬스터 생성 완료: ID {monsterId}, 위치 {spawnPosition}");
}
catch (System.Exception e)
{
Debug.LogError($"몬스터 생성 중 오류 발생: {e.Message}");
}
}
private string GetMonsterPrefabPath(MonsterData monsterData)
{
// 몬스터 데이터에 따른 프리팹 경로 결정
string basePath = "MonsterPrefabs/";
// 일반 몬스터인 경우
if (monsterData.id == 6)
{
return basePath + "Nomal/BlackTroll";
}
// 기타 몬스터들
Dictionary<int, string> monsterNames = new Dictionary<int, string>
{
{ 1, "BlueDragon" },
{ 2, "BrownWerewolf" },
{ 3, "GreenDragon" },
{ 4, "PurpleOgre" },
{ 5, "RedWerewolf" }
};
if (monsterNames.TryGetValue(monsterData.id, out string monsterName))
{
return basePath + monsterName;
}
throw new System.Exception($"알 수 없는 몬스터 ID: {monsterData.id}");
}
public void OnMonsterDestroyed(MonsterBase monster)
{
if (_spawnedMonsters.Contains(monster))
{
_spawnedMonsters.Remove(monster);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 481676f31fc794c4b93848b442416f2c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,133 @@
using System.Collections;
using System.Collections.Generic;
using Assets.PixelFantasy.PixelMonsters.Common.Scripts;
using UnityEngine;
namespace TON
{
public abstract class SkillPattern
{
protected MonsterData _monsterData;
protected MonsterBase _monsterBase;
protected SkillPattern(MonsterData monsterData, MonsterBase monsterBase)
{
_monsterData = monsterData;
_monsterBase = monsterBase;
}
public bool IsAttackable { get; set; }
public abstract void Attack(GameObject target);
public abstract void Update();
}
public class Monster1SkillPattern : SkillPattern
{
private float _skill1CoolTime;
private float _skill2CoolTime;
private MonsterSkillData _monsterSkillData;
private MonsterSkillData _monsterSkillDataTwo;
private MonsterSkill _skill1;
private MonsterSkill _skill2;
private Vector3 _skillOffset = new Vector3(0, -0.5f, 0); // 스킬 생성 위치 조정값
public Monster1SkillPattern(MonsterData monsterData, MonsterBase monsterBase) : base(monsterData, monsterBase)
{
_monsterSkillData = MonsterSkillDataManager.Singleton.GetMonsterSkillData(_monsterData.monsterSkillID);
if (_monsterData.monsterSkillIDTwo > -1)
{
_monsterSkillDataTwo = MonsterSkillDataManager.Singleton.GetMonsterSkillData(_monsterData.monsterSkillIDTwo);
}
if (_monsterSkillData != null && _monsterSkillDataTwo != null)
{
Debug.Log($"몬스터 {_monsterSkillData.skillName} 데이터 로드 완료");
Debug.Log($"몬스터 {_monsterSkillDataTwo.skillName} 데이터 로드 완료");
// 프리팹을 연결한 코드
_skill1 = Resources.Load<MonsterSkill>($"MonsterSkillPrefabs/{_monsterSkillData.skillName}");
_skill2 = Resources.Load<MonsterSkill>($"MonsterSkillPrefabs/{_monsterSkillDataTwo.skillName}");
}
else
{
Debug.LogError($"몬스터 스킬 ID {_monsterSkillData.skillId}에 대한 데이터를 찾을 수 없습니다.");
Debug.LogError($"몬스터 스킬 ID {_monsterSkillDataTwo.skillId}에 대한 데이터를 찾을 수 없습니다.");
}
_skill1CoolTime = Time.realtimeSinceStartup;
_skill2CoolTime = Time.realtimeSinceStartup;
}
public override void Attack(GameObject target)
{
if (target == null) return;
// 스킬 스프라이트 방향 플레이어 바라보게
_monsterBase.GetComponent<SpriteRenderer>().flipX = target.transform.position.x < _monsterBase.transform.position.x;
// 몬스터의 현재 위치에서 offset만큼 아래에 스킬 생성
Vector3 spawnPosition = _monsterBase.transform.position - _skillOffset;
// 프리팹을 지정된 위치에 생성
Object.Instantiate(_skill1, spawnPosition, Quaternion.identity);
}
public override void Update()
{
if (Time.realtimeSinceStartup - _skill1CoolTime >= _monsterSkillData.cooldown)
{
// TODO : 범위 체크
IsAttackable = true;
}
if (Time.realtimeSinceStartup - _skill2CoolTime >= _monsterSkillDataTwo.cooldown)
{
// TODO : 범위 체크
IsAttackable = true;
}
}
}
// public class Monster2AttackPattern : AttackPattern
// {
//
//
// public Monster2AttackPattern(MonsterBase monsterBase) : base(monsterBase)
// {
//
// }
//
// public override void Attack()
// {
//
// Skill1();
//
// Skill2();
//
// MeleeAttack();
//
// }
//
// private void Skill1()
// {
//
// }
//
// private void Skill2()
// {
//
// }
//
// private void MeleeAttack()
// {
// _monsterBase.PlayerAttack();
// }
// }
}

View File

@@ -1,3 +1,4 @@
using TMPro;
using UnityEngine; using UnityEngine;
namespace TON namespace TON
@@ -8,6 +9,9 @@ namespace TON
private IState _state; private IState _state;
private MonsterBase _monsterBase; private MonsterBase _monsterBase;
private TextMeshProUGUI _textState;
// public StateMachine(IState state, MonsterBase monsterBase, TextMeshProUGUI textState)
public StateMachine(IState state, MonsterBase monsterBase) public StateMachine(IState state, MonsterBase monsterBase)
{ {
// 초기 상태 객체 생성 // 초기 상태 객체 생성
@@ -15,6 +19,9 @@ namespace TON
_state = state; _state = state;
_state.Enter(_monsterBase); _state.Enter(_monsterBase);
// _textState = textState;
// _textState.text = _state.ToString();
} }
public void Update() public void Update()
@@ -30,13 +37,13 @@ namespace TON
} }
} }
private void SetTransition(IState state) public void SetTransition(IState state)
{ {
// 다음음 상태로 전환 // 다음음 상태로 전환
_state = state; _state = state;
_state.Enter(_monsterBase); _state.Enter(_monsterBase);
Debug.Log($"State : {_state}"); // _textState.text = _state.ToString();
} }
} }
@@ -168,6 +175,11 @@ namespace TON
if(_monsterBase.IsDetect== false) if(_monsterBase.IsDetect== false)
return new IdleState(); return new IdleState();
if (_monsterBase.IsSkillAttackable)
{
return new MonsterSkillState();
}
// Attack으로 변경 // Attack으로 변경
if (_monsterBase.IsAttacking) if (_monsterBase.IsAttacking)
return new AttackState(); return new AttackState();
@@ -178,8 +190,6 @@ namespace TON
} }
} }
// 몬스터 1의 어택(스킬 1개를 가진 중보스)
// 몬스터 2의 어택(스킬 2개를 가진 보스)
public class AttackState : IState public class AttackState : IState
{ {
private const string AniAttack = "Attack"; // 공격 애니메이션 private const string AniAttack = "Attack"; // 공격 애니메이션
@@ -188,7 +198,6 @@ namespace TON
private float _lastAttackTime; // 마지막 공격 시간 private float _lastAttackTime; // 마지막 공격 시간
private float _attackAnimationDuration = 0.5f; // 공격 애니메이션 지속 시간 private float _attackAnimationDuration = 0.5f; // 공격 애니메이션 지속 시간
private bool _isAttacking = false; private bool _isAttacking = false;
private bool _completAttck;
public void Enter(MonsterBase monsterBase) public void Enter(MonsterBase monsterBase)
{ {
@@ -215,7 +224,6 @@ namespace TON
if (_isAttacking && Time.time >= _lastAttackTime + _attackAnimationDuration) if (_isAttacking && Time.time >= _lastAttackTime + _attackAnimationDuration)
{ {
_isAttacking = false; _isAttacking = false;
_completAttck = true;
} }
} }
@@ -238,11 +246,9 @@ namespace TON
return this; return this;
} }
} }
// TODO : HIT, Death 상태 추가
public class MonsterSkillState : IState public class MonsterSkillState : IState
{ {
private const string AniAttack = "Attack"; // 공격 애니메이션 private const string AniAttack = "Attack"; // 공격 애니메이션
private const string AniIdle = "Idle"; // 대기 애니메이션
private MonsterBase _monsterBase; private MonsterBase _monsterBase;
private float _skillAttackAnimationDuration = 0.5f; // 공격 애니메이션 지속 시간 private float _skillAttackAnimationDuration = 0.5f; // 공격 애니메이션 지속 시간
private float _skillAttackDelayTime = 2f; // 공격 딜레이 시간 private float _skillAttackDelayTime = 2f; // 공격 딜레이 시간
@@ -269,7 +275,6 @@ namespace TON
if (_isSkillAttacking && Time.time >= _lastSkillAttackTime + _skillAttackAnimationDuration) if (_isSkillAttacking && Time.time >= _lastSkillAttackTime + _skillAttackAnimationDuration)
{ {
_isSkillAttacking = false; _isSkillAttacking = false;
_monsterBase.ChangeAnimationState(AniIdle);
} }
} }
@@ -288,6 +293,10 @@ namespace TON
public IState CheckTransition() public IState CheckTransition()
{ {
if(_isSkillAttacking == false)
return new IdleState();
return this; return this;
} }
} }
@@ -308,10 +317,7 @@ namespace TON
public void Update() public void Update()
{ {
if (Time.time >= _hitStartTime + _hitDuration)
{
_monsterBase.IsHit = false;
}
} }
public void Exit() public void Exit()
@@ -320,12 +326,6 @@ namespace TON
public IState CheckTransition() public IState CheckTransition()
{ {
if (_monsterBase.IsHit)
return new HitState();
if (_monsterBase.IsDead)
return new DeathState();
if (Time.time >= _hitStartTime + _hitDuration) if (Time.time >= _hitStartTime + _hitDuration)
return new IdleState(); return new IdleState();