|
|
|
|
using DG.Tweening;
|
|
|
|
|
using LitJson;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.AI;
|
|
|
|
|
using UnityEngine.Events;
|
|
|
|
|
using UnityEngine.Serialization;
|
|
|
|
|
|
|
|
|
|
public delegate bool ItemUse(string idx, int value);
|
|
|
|
|
public delegate bool HoldingItemCheck(string idx);
|
|
|
|
|
|
|
|
|
|
[System.Serializable]
|
|
|
|
|
public class ItemUseRegister
|
|
|
|
|
{
|
|
|
|
|
public ItemUse OnItemUse;
|
|
|
|
|
public System.Action<MapDoor.Teleport> OnTeleport;
|
|
|
|
|
public System.Action<bool> OnLock;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum MapEvent { DoorNearSave, DoorConnect, DoorState, DoorInit, Register_OnItemUse }
|
|
|
|
|
public enum MapDirection { Left, Right, Down, Up }
|
|
|
|
|
public enum DoorType { Door, DoorBreak, DoorLock, Wall, WallBreak, Boss }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class MapManager : ResourcePool
|
|
|
|
|
{
|
|
|
|
|
public Transform targetCamera;
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public TiltCamera tiltCamera;
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public SoundPlayer_BGM spBGM;
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public InputController prefabPlayer;
|
|
|
|
|
public Vector3 scaleCharacter = new Vector3(1.3f, 1.3f, 1.3f);
|
|
|
|
|
[HideInInspector]
|
|
|
|
|
public InputController player;
|
|
|
|
|
public bool START_ENTER = true;
|
|
|
|
|
private void Start()
|
|
|
|
|
{
|
|
|
|
|
QualitySettings.vSyncCount = 0;
|
|
|
|
|
//Application.targetFrameRate = 60;
|
|
|
|
|
|
|
|
|
|
items_Passive = DataManager.Instance.dataItem.ListGet().FindAll(a => a.type.Equals("Passive"));
|
|
|
|
|
items_Active = DataManager.Instance.dataItem.ListGet().FindAll(a => a.type.Equals("Active"));
|
|
|
|
|
items_Weapon = DataManager.Instance.dataItem.ListGet().FindAll(a => a.type.Equals("Weapon"));
|
|
|
|
|
items_Armor = DataManager.Instance.dataItem.ListGet().FindAll(a => a.type.Equals("Armor"));
|
|
|
|
|
items_Accessory = DataManager.Instance.dataItem.ListGet().FindAll(a => a.type.Equals("Accessory"));
|
|
|
|
|
items_Use = DataManager.Instance.dataItem.ListGet().FindAll(a => a.type.Equals("Use") || a.type.Equals("Pickup"));
|
|
|
|
|
|
|
|
|
|
items_All = new List<ItemData>();
|
|
|
|
|
items_All.AddRange(items_Passive);
|
|
|
|
|
items_All.AddRange(items_Active);
|
|
|
|
|
items_All.AddRange(items_Weapon);
|
|
|
|
|
items_All.AddRange(items_Armor);
|
|
|
|
|
items_All.AddRange(items_Accessory);
|
|
|
|
|
|
|
|
|
|
EventManager.Instance.Add("PrefabCreate", PrefabCreate);
|
|
|
|
|
EventManager.Instance.Add("PrefabCreateLocal", PrefabCreateLocal);
|
|
|
|
|
|
|
|
|
|
EventManager.Instance.Add("IngameCommand", IngameCommand);
|
|
|
|
|
|
|
|
|
|
if (START_ENTER)
|
|
|
|
|
DungeonEnter("Proto");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Dictionary<MapTile.Type, List<Material>> dicMaterials = new Dictionary<MapTile.Type, List<Material>>();
|
|
|
|
|
void MaterialLoad(string dungeonName)
|
|
|
|
|
{
|
|
|
|
|
List<Material> materials = Resources.LoadAll<Material>($"Prefab/Map/{dungeonName}/Material").ToList();
|
|
|
|
|
dicMaterials.Clear();
|
|
|
|
|
int max = Util.EnumUtil<MapTile.Type>.Length();
|
|
|
|
|
for (int i = 0; i < max; i++)
|
|
|
|
|
dicMaterials.Add((MapTile.Type)i, materials.FindAll(a => a.name.Contains($"{(MapTile.Type)i}")));
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
public Dictionary<MapTile.Type, List<Material>> MaterialGet(string dungeonName)
|
|
|
|
|
{
|
|
|
|
|
if (dicMaterials.Count == 0 || this.dungeonName != dungeonName)
|
|
|
|
|
MaterialLoad(this.dungeonName = dungeonName);
|
|
|
|
|
|
|
|
|
|
return dicMaterials;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<GameObject> obstacles = new List<GameObject>();
|
|
|
|
|
void ObstacleLoad(string dungeonName)
|
|
|
|
|
{
|
|
|
|
|
obstacles = Resources.LoadAll<GameObject>($"Prefab/Map/{dungeonName}/Obstacle").ToList();
|
|
|
|
|
}
|
|
|
|
|
public List<GameObject> ObstacleGet(string dungeonName)
|
|
|
|
|
{
|
|
|
|
|
if (obstacles.Count == 0 || this.dungeonName != dungeonName)
|
|
|
|
|
ObstacleLoad(dungeonName);
|
|
|
|
|
|
|
|
|
|
return obstacles;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnDestroy()
|
|
|
|
|
{
|
|
|
|
|
EventManager.Instance.Remove("PrefabCreate", PrefabCreate);
|
|
|
|
|
EventManager.Instance.Remove("PrefabCreateLocal", PrefabCreateLocal);
|
|
|
|
|
|
|
|
|
|
EventManager.Instance.Remove("IngameCommand", IngameCommand);
|
|
|
|
|
}
|
|
|
|
|
void PrefabCreate(object value)
|
|
|
|
|
{
|
|
|
|
|
EventManager.ObjectCreate data = (EventManager.ObjectCreate)value;
|
|
|
|
|
data.create = ObjectCreate(data.prefab, data.target, data.scale, data.pos, true);
|
|
|
|
|
}
|
|
|
|
|
void PrefabCreateLocal(object value)
|
|
|
|
|
{
|
|
|
|
|
EventManager.ObjectCreate data = (EventManager.ObjectCreate)value;
|
|
|
|
|
data.create = ObjectCreateLocalPos(data.prefab, data.target, data.scale, data.pos, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static public List<Vector2> dirs = new List<Vector2>() { new Vector2(-1, 0), new Vector2(1, 0), new Vector2(0, -1), new Vector2(0, 1) };
|
|
|
|
|
List<Vector2> dirsRandom;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 다음에 생성 될 좌표의 목록을 생성합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
void DirectionIndex(bool INIT, bool SHUFFLE)
|
|
|
|
|
{
|
|
|
|
|
if (INIT)
|
|
|
|
|
{
|
|
|
|
|
dirsRandom = new List<Vector2>();
|
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
|
|
|
dirsRandom.AddRange(dirs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SHUFFLE)
|
|
|
|
|
dirsRandom = Util.ListShuffle<Vector2>.Shuffle(dirsRandom);
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 좌표 주변에 생성 가능한 좌표가 있는지 확인
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="idx"></param>
|
|
|
|
|
/// <param name="cntMax"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
bool DirectionCheck(Vector2 idx, int cntMax)
|
|
|
|
|
{
|
|
|
|
|
//cntMax = cntMax < 4 ? cntMax : 4;
|
|
|
|
|
|
|
|
|
|
int cnt = -1;
|
|
|
|
|
for(int i = 0; i < dirs.Count; i++)
|
|
|
|
|
cnt += idxsDic.ContainsKey(idx + dirs[i]) ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
return cnt < cntMax;
|
|
|
|
|
}
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public Vector2 idxMin = new Vector2(-4, -3);
|
|
|
|
|
public Vector2 idxMax = new Vector2(4, 3);
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 맵의 생성 범위 내의 좌표인지를 확인합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="idx"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool CheckIndexRange(Vector2 idx)
|
|
|
|
|
{
|
|
|
|
|
return (idxMin.x <= idx.x && idx.x <= idxMax.x) && (idxMin.y <= idx.y && idx.y <= idxMax.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventConnect ecMapEvent = new EventConnect();
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public string dungeonName = "Proto";
|
|
|
|
|
public DataDungeon dataDungeon;
|
|
|
|
|
public int floor = 0;//현재 층
|
|
|
|
|
public FloorData floorData = new FloorData();
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 던전 진입, 해당 던전의 정보 및 1층의 블럭 생성
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name">던전 이름</param>
|
|
|
|
|
public void DungeonEnter(string name)
|
|
|
|
|
{
|
|
|
|
|
dungeonName = name;
|
|
|
|
|
floor = 0;
|
|
|
|
|
dataDungeon = DataManager.Instance.dataDungeon.Load(dungeonName);
|
|
|
|
|
|
|
|
|
|
Generate_Block();//던전 입장
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 던전을 1층 내려갑니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
void FloorGoDown()
|
|
|
|
|
{
|
|
|
|
|
Fade.DOFade(1, 0.25f).SetEase(Ease.Linear).OnComplete(() =>
|
|
|
|
|
{
|
|
|
|
|
Generate_Block();//층 내려감
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 아래층이 존재하는지 확인합니다,
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="goDOWN"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
bool FloorCheck(bool goDOWN = true)
|
|
|
|
|
{
|
|
|
|
|
floor += goDOWN ? 1 : 0;
|
|
|
|
|
return floor < dataDungeon.floors.Count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public GameObject effectPortal;
|
|
|
|
|
//[Space(10)]
|
|
|
|
|
//public HPBarBoss barBoss;
|
|
|
|
|
//public void BossMonsterAppear(Character boss)
|
|
|
|
|
//{
|
|
|
|
|
// barBoss.Setting(boss);
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
[System.Serializable]
|
|
|
|
|
public class MapInitializedEvent : UnityEvent<MapManager> { }
|
|
|
|
|
[FormerlySerializedAs("onMapInitialized")]
|
|
|
|
|
[Space(10)]
|
|
|
|
|
[SerializeField]
|
|
|
|
|
private MapInitializedEvent OnMapInitialized = new MapInitializedEvent();
|
|
|
|
|
public HoldingItemCheck OnHoldingItemCheck;
|
|
|
|
|
|
|
|
|
|
public Dictionary<Vector2, MapBlock> blocks = new Dictionary<Vector2, MapBlock>();
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public CanvasGroup Fade;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 맵의 생성을 시작합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Generate_Block(string thema = "Proto")
|
|
|
|
|
{
|
|
|
|
|
floorData = dataDungeon.floors[floor];
|
|
|
|
|
floorData.LoadAll($"{thema}");
|
|
|
|
|
ecMapEvent.Invoke((int)MapEvent.DoorInit, null);
|
|
|
|
|
|
|
|
|
|
blkCurrent = null;
|
|
|
|
|
blocks.Clear();
|
|
|
|
|
ecMapEvent.Clear();
|
|
|
|
|
ObjectAllHide();
|
|
|
|
|
|
|
|
|
|
DirectionIndex(true, false);
|
|
|
|
|
|
|
|
|
|
Generate_IndexAll();
|
|
|
|
|
|
|
|
|
|
int cnt = 0;
|
|
|
|
|
//일반 블럭 생성
|
|
|
|
|
List<MapBlock.Type> types_Default = floorData.DefaultTypeGet();
|
|
|
|
|
for (int i = 0; i < all.Count; i++)
|
|
|
|
|
BlockCreate(all[i], i * 10, types_Default, ref cnt);
|
|
|
|
|
|
|
|
|
|
//특수 블럭 생성
|
|
|
|
|
MapBlock blk = null;
|
|
|
|
|
List<MapBlock.Type> specials = floorData.SpecialTypeGet();
|
|
|
|
|
if (0 < specials.Count)
|
|
|
|
|
{
|
|
|
|
|
ecMapEvent.Invoke((int)MapEvent.DoorNearSave, blocks);
|
|
|
|
|
List<MapBlock> blocksOrder = blocks.Values.ToList().FindAll(a => a.blkType <= MapBlock.Type.Monster && (0 < a.dirEmpty.Count && a.dirEmpty.Count < 4));
|
|
|
|
|
|
|
|
|
|
Debug.LogWarning($"생성해야 하는 특수 블럭 {specials.Count} 개\n특수 블럭 생성 가능한 위치 {blocksOrder.Count} 개");
|
|
|
|
|
|
|
|
|
|
MapBlock blkConnect = null;
|
|
|
|
|
Vector2 idx = Vector2.zero;
|
|
|
|
|
for (int i = 0; i < specials.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (0 == blocksOrder.Count)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"{i}/{specials} : 특수 블럭의 생성 공간이 부족합니다.");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//연결 블럭
|
|
|
|
|
blkConnect = blocksOrder[Random.Range(0, blocksOrder.Count)];
|
|
|
|
|
idx = blkConnect.NearEmptyIndex_Get();//생성될 좌표
|
|
|
|
|
|
|
|
|
|
if (blocks.ContainsKey(idx))
|
|
|
|
|
{
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//생성 블럭
|
|
|
|
|
blk = ObjectCreateLocalPos(floorData.PrefabGet(specials[i]), transform, Vector3.one, Vector3.zero).GetComponent<MapBlock>();
|
|
|
|
|
blk.OnInitialized(this, blocks.Count, idx, specials[i]);//특수블럭 초기화
|
|
|
|
|
ecMapEvent.Add(blk.OnEvent);
|
|
|
|
|
//문 연결
|
|
|
|
|
blk.Door_Connect(blkConnect);
|
|
|
|
|
blkConnect.Door_Connect(blk);
|
|
|
|
|
|
|
|
|
|
blocks.Add(idx, blk);
|
|
|
|
|
blocksOrder.Remove(blkConnect);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//맵 생성 완료, 플레이어 와 카메라를 첫 블럭으로 이동
|
|
|
|
|
blk = blocks.Values.ToList()[0];
|
|
|
|
|
|
|
|
|
|
MapDoor.Teleport tel = new MapDoor.Teleport();
|
|
|
|
|
blk.gameObject.SetActive(false);
|
|
|
|
|
tel.blk = blk;
|
|
|
|
|
tel.door = null;
|
|
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
|
player = ObjectCreateLocalPos(prefabPlayer.gameObject, null, scaleCharacter, new Vector3(-0.5f, 0, -3f)).GetComponent<InputController>();
|
|
|
|
|
OnMapInitialized.Invoke(this);
|
|
|
|
|
|
|
|
|
|
if (floor == 0)
|
|
|
|
|
player.character.OnInitialized(prefabPlayer.character.HP, prefabPlayer.character.HP_Max);//플레이어 생성
|
|
|
|
|
else
|
|
|
|
|
player.gameObject.SetActive(true);
|
|
|
|
|
player.Teleport(tel);
|
|
|
|
|
|
|
|
|
|
OnHoldingItemCheck = player.character.skill.HoldingItemCheck;
|
|
|
|
|
|
|
|
|
|
spBGM.Play();
|
|
|
|
|
|
|
|
|
|
all = null;
|
|
|
|
|
idxsDic = null;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 일반 블럭 들을 생성합니다
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="idxs">좌표 목록</param>
|
|
|
|
|
/// <param name="number">경로의 넘버링</param>
|
|
|
|
|
/// <param name="types_Default">타입 목록</param>
|
|
|
|
|
/// <param name="cnt">생성 갯수</param>
|
|
|
|
|
void BlockCreate(List<Vector2> idxs, int number, List<MapBlock.Type> types_Default, ref int cnt)
|
|
|
|
|
{
|
|
|
|
|
//연결통로, 몬스터 방 -> 보스 방 까지의 경로 생성
|
|
|
|
|
MapBlock blk = null;
|
|
|
|
|
for (int i = 0; i < idxs.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
//Debug.LogWarning($"{idxs[i]}");
|
|
|
|
|
MapBlock.Type type = i == 0 ? MapBlock.Type.None : (idxBoss == idxs[i] ? MapBlock.Type.Boss : types_Default[cnt]);
|
|
|
|
|
if (blocks.ContainsKey(idxs[i]))
|
|
|
|
|
{
|
|
|
|
|
blk = blocks[idxs[i]];
|
|
|
|
|
blk.OnInitialized(this, i + number, idxs[i], type);//블럭 초기화
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GameObject prefab = null;
|
|
|
|
|
if (i == 0 && idxs[i] == Vector2.zero)
|
|
|
|
|
prefab = floorData.PrefabGet(MapBlock.Type.Empty);
|
|
|
|
|
else
|
|
|
|
|
prefab = floorData.PrefabGet(type);
|
|
|
|
|
|
|
|
|
|
blk = ObjectCreateLocalPos(prefab, transform, Vector3.one, Vector3.zero).GetComponent<MapBlock>();
|
|
|
|
|
blocks.Add(idxs[i], blk);
|
|
|
|
|
|
|
|
|
|
blk.OnInitialized(this, i + number, idxs[i], type);//블럭 초기화
|
|
|
|
|
cnt++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ecMapEvent.Add(blk.OnEvent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ecMapEvent.Invoke((int)MapEvent.DoorConnect, blocks);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vector2 idxBoss = Vector2.zero;
|
|
|
|
|
Dictionary<Vector2, Vector2> idxsDic;
|
|
|
|
|
List<List<Vector2>> all = new List<List<Vector2>>();
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 좌표를 생성합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
void Generate_IndexAll()
|
|
|
|
|
{
|
|
|
|
|
idxsDic = new Dictionary<Vector2, Vector2>();
|
|
|
|
|
idxsDic.Add(Vector2.zero, Vector2.zero);
|
|
|
|
|
|
|
|
|
|
all = new List<List<Vector2>>();
|
|
|
|
|
int max = (int)(floorData.cntDefault * floorData.rateMax);
|
|
|
|
|
int cntRemain = floorData.cntDefault;
|
|
|
|
|
int cntFind = cntRemain <= max ? cntRemain : (cntRemain - max < 0 ? cntRemain : max);
|
|
|
|
|
|
|
|
|
|
Vector2 idxStart = Vector2.zero;
|
|
|
|
|
List<Vector2> idxSearch = new List<Vector2>();
|
|
|
|
|
idxSearch.Add(idxStart);
|
|
|
|
|
|
|
|
|
|
int cntTry = 1;
|
|
|
|
|
int cntLength = 0;
|
|
|
|
|
while (0 < cntRemain && 0 < idxSearch.Count)
|
|
|
|
|
{
|
|
|
|
|
List<Vector2> idxs = Generate_Index(idxStart, cntFind, cntTry);
|
|
|
|
|
if (idxs.Count == 1)
|
|
|
|
|
{
|
|
|
|
|
idxSearch.Remove(idxStart);
|
|
|
|
|
|
|
|
|
|
//Debug.LogWarning($"실패, 남은 목록 : {idxSearch.Count}");
|
|
|
|
|
|
|
|
|
|
if (idxSearch.Count == 0 && cntTry < 3)
|
|
|
|
|
{
|
|
|
|
|
cntTry++;
|
|
|
|
|
for (int i = 0; i < all.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
idxSearch.AddRange(all[i]);
|
|
|
|
|
idxSearch.Remove(all[i][all[i].Count - 1]);
|
|
|
|
|
}
|
|
|
|
|
idxSearch = idxSearch.Distinct().ToList();
|
|
|
|
|
|
|
|
|
|
//Debug.LogWarning($"재탐색, 목록 : {idxSearch.Count}, {cntTry}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
all.Add(idxs);
|
|
|
|
|
|
|
|
|
|
cntRemain -= idxs.Count - 1;
|
|
|
|
|
cntFind = cntRemain <= max ? cntRemain : (cntRemain - max < 0 ? cntRemain : max);
|
|
|
|
|
|
|
|
|
|
idxSearch.AddRange(idxs);
|
|
|
|
|
idxSearch.Remove(idxs[idxs.Count - 1]);
|
|
|
|
|
idxSearch = idxSearch.Distinct().ToList();
|
|
|
|
|
|
|
|
|
|
Vector2 idxChk = idxs[idxs.Count - 1];
|
|
|
|
|
int tmp = (int)(Mathf.Abs(idxChk.x) + Mathf.Abs(idxChk.y));
|
|
|
|
|
if (cntLength < tmp)
|
|
|
|
|
{
|
|
|
|
|
//Debug.LogWarning($"{cntLength}({idxBoss}) < {tmp}({idxChk})");
|
|
|
|
|
cntLength = tmp;
|
|
|
|
|
idxBoss = idxChk;
|
|
|
|
|
}
|
|
|
|
|
else if (cntLength == tmp)
|
|
|
|
|
{
|
|
|
|
|
idxBoss = Random.Range(0, 100) < 50 ? idxBoss : idxChk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Debug.LogWarning($"성공, 남은 목록 : {idxSearch.Count}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (0 < idxSearch.Count)
|
|
|
|
|
idxStart = idxSearch[Random.Range(0, idxSearch.Count)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < all.Count; i++)
|
|
|
|
|
idxSearch.AddRange(all[i]);
|
|
|
|
|
idxSearch = idxSearch.Distinct().ToList();
|
|
|
|
|
|
|
|
|
|
if (floorData.cntDefault == idxSearch.Count)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"생성 완료 결과 : {floorData.cntDefault} == {idxSearch.Count}");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError($"생성 실패 결과 : {floorData.cntDefault} == {idxSearch.Count}");
|
|
|
|
|
|
|
|
|
|
Generate_IndexAll();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// idxStart 를 시작으로 cnt 개의 좌표를 생성합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="idxStart">시작 좌표</param>
|
|
|
|
|
/// <param name="cnt">생성 갯수</param>
|
|
|
|
|
/// <param name="cntAround">생성 제한, 주변의 블럭 최소수</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
List<Vector2> Generate_Index(Vector2 idxStart, int cnt, int cntAround = 1)
|
|
|
|
|
{
|
|
|
|
|
Vector2 idx = idxStart;
|
|
|
|
|
List<Vector2> idxs = new List<Vector2>();
|
|
|
|
|
idxs.Add(idx);
|
|
|
|
|
if (!idxsDic.ContainsKey(idx))
|
|
|
|
|
idxsDic.Add(idx, idx);
|
|
|
|
|
|
|
|
|
|
Vector2 idxT;
|
|
|
|
|
bool PASS = true;
|
|
|
|
|
|
|
|
|
|
DirectionIndex(false, true);
|
|
|
|
|
|
|
|
|
|
int j = 0;
|
|
|
|
|
Vector2 dirBefore = Vector2.zero;
|
|
|
|
|
for (int i = 1; i < cnt && PASS; i++)
|
|
|
|
|
{
|
|
|
|
|
PASS = false;
|
|
|
|
|
|
|
|
|
|
if (j == dirsRandom.Count)
|
|
|
|
|
{
|
|
|
|
|
j = 0;
|
|
|
|
|
dirsRandom = Util.ListShuffle<Vector2>.Shuffle(dirsRandom);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (; j < dirsRandom.Count; j++)
|
|
|
|
|
{
|
|
|
|
|
if (dirBefore == Vector2.zero)
|
|
|
|
|
{
|
|
|
|
|
idxT = dirsRandom[j];
|
|
|
|
|
idxT = idxT + idx;//생성해야 될 위치
|
|
|
|
|
|
|
|
|
|
dirBefore = Random.Range(0, 100) < 70 ? dirsRandom[j] : Vector2.zero;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
idxT = dirBefore;
|
|
|
|
|
idxT = idxT + idx;//생성해야 될 위치
|
|
|
|
|
|
|
|
|
|
dirBefore = Random.Range(0, 100) < 70 ? dirBefore : Vector2.zero;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!idxsDic.ContainsKey(idxT) && DirectionCheck(idxT, cntAround) && CheckIndexRange(idxT))
|
|
|
|
|
{
|
|
|
|
|
//해당 위치에 생성 가능
|
|
|
|
|
idx = idxT;
|
|
|
|
|
idxsDic.Add(idx, idx);
|
|
|
|
|
idxs.Add(idx);
|
|
|
|
|
|
|
|
|
|
PASS = true;
|
|
|
|
|
j++;
|
|
|
|
|
|
|
|
|
|
Generate_Blocked_Init();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (Generate_Blocked(idxT - idx))
|
|
|
|
|
{
|
|
|
|
|
//해당 위치에 생성 불가능
|
|
|
|
|
PASS = false;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PASS = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (j + 1 == dirsRandom.Count)
|
|
|
|
|
{
|
|
|
|
|
j = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!PASS)
|
|
|
|
|
{
|
|
|
|
|
//Debug.LogWarning($"기본 위치 생성 실패, 중복된 경로 존재");
|
|
|
|
|
|
|
|
|
|
//return Generate_Index(idxStart, cnt);
|
|
|
|
|
return idxs;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return idxs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[System.Serializable]
|
|
|
|
|
public class MapClearedEvent : UnityEvent<MapManager> { }
|
|
|
|
|
[FormerlySerializedAs("onMapCleared")]
|
|
|
|
|
[Space(10)]
|
|
|
|
|
[SerializeField]
|
|
|
|
|
private MapClearedEvent OnMapCleared = new MapClearedEvent();
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 층의 클리어를 확인합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="DIE">플레이어의 죽음</param>
|
|
|
|
|
public void MapCleared(bool DIE = false)
|
|
|
|
|
{
|
|
|
|
|
if (FloorCheck() && !DIE)
|
|
|
|
|
FloorGoDown();//현재 층을 클리어
|
|
|
|
|
else
|
|
|
|
|
OnMapCleared.Invoke(this);//플레이어 죽음
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Dictionary<Vector2, bool> dicCheck = new Dictionary<Vector2, bool>();
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 주변에 생성 가능한 위치가 있었기에 확인을 위한 데이터를 초기화 합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
void Generate_Blocked_Init()
|
|
|
|
|
{
|
|
|
|
|
var list = dicCheck.Keys.ToList();
|
|
|
|
|
for (int i = 0; i < list.Count; i++)
|
|
|
|
|
dicCheck[list[i]] = false;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 주변에 생성 가능한 위치가 있는지 확인 합니다.
|
|
|
|
|
/// 사방이 막혔다면 True 를 리턴합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="dir"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
bool Generate_Blocked(Vector2 dir)
|
|
|
|
|
{
|
|
|
|
|
dicCheck[dir] = true;
|
|
|
|
|
return 4 == dicCheck.Values.Count(a => a == true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public MapBlock blkCurrent;
|
|
|
|
|
|
|
|
|
|
[System.Serializable]
|
|
|
|
|
public class MapChangedEvent : UnityEvent<MapBlock> { }
|
|
|
|
|
[FormerlySerializedAs("onMapChanged")]
|
|
|
|
|
[Space(10)]
|
|
|
|
|
[SerializeField]
|
|
|
|
|
private MapChangedEvent OnMapChanged = new MapChangedEvent();
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 생성 완료 및 플레이어의 블럭 이동시 호출 됩니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="blk"></param>
|
|
|
|
|
public void MapBlockChanged(MapBlock blk, System.Action OnEnd = null)
|
|
|
|
|
{
|
|
|
|
|
if (blkCurrent != null)
|
|
|
|
|
blkCurrent.TintFade(0.8f);
|
|
|
|
|
blk.TintFade(0);
|
|
|
|
|
|
|
|
|
|
MapBlock blkBefore = blkCurrent;
|
|
|
|
|
blkCurrent = blk;
|
|
|
|
|
blkCurrent.Setting(dungeonName);//블럭 이동
|
|
|
|
|
|
|
|
|
|
//카메라를 이동한 블럭으로 이동합니다.
|
|
|
|
|
targetCamera.DOMove(blkCurrent.transform.position, 0.5f).OnComplete(() =>
|
|
|
|
|
{
|
|
|
|
|
if (blkBefore != null)
|
|
|
|
|
blkBefore.gameObject.SetActive(false);
|
|
|
|
|
|
|
|
|
|
if (OnEnd != null)
|
|
|
|
|
OnEnd();
|
|
|
|
|
|
|
|
|
|
Fade.DOFade(0, 0.25f);
|
|
|
|
|
|
|
|
|
|
OnMapChanged.Invoke(blkCurrent);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bundle<MapTile> dicTile = new Bundle<MapTile>();
|
|
|
|
|
public MapTile CreateTile(Transform target, GameObject prefab, Vector3 scale, Vector3 pos)
|
|
|
|
|
{
|
|
|
|
|
GameObject obj = ObjectCreateLocalPos(prefab, target, scale, pos, true);
|
|
|
|
|
|
|
|
|
|
MapTile tile = dicTile.Get(obj.name);
|
|
|
|
|
if (tile == null)
|
|
|
|
|
{
|
|
|
|
|
tile = obj.GetComponent<MapTile>();
|
|
|
|
|
dicTile.Add(tile.name, tile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 플레이어가 있는 위치 이외의 블럭을 하이드 시킨다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void MapBlockHide()
|
|
|
|
|
{
|
|
|
|
|
//return;
|
|
|
|
|
|
|
|
|
|
List<MapBlock> blks = new List<MapBlock>(blocks.Values);
|
|
|
|
|
for (int i = 0; i < blks.Count; i++)
|
|
|
|
|
blks[i].gameObject.SetActive(blkCurrent == blks[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public Character mob;
|
|
|
|
|
public void MonsterCreate_Designate()
|
|
|
|
|
{
|
|
|
|
|
if (mob != null)
|
|
|
|
|
{
|
|
|
|
|
blkCurrent.CLEAR = false;
|
|
|
|
|
blkCurrent.ecMapBlock.Invoke((int)MapEvent.DoorState, false);
|
|
|
|
|
|
|
|
|
|
appear.cnt = 1;
|
|
|
|
|
appear.mobNames.Clear();
|
|
|
|
|
appear.mobNames.Add(mob.name);
|
|
|
|
|
blkCurrent.Monster_Create(appear);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public List<Character> mobs;
|
|
|
|
|
Bundle<Character> dicMonster = new Bundle<Character>();
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 몬스터를 생성합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="blk">생성될 맵 블럭</param>
|
|
|
|
|
/// <param name="prefabMonset">몬스터 프리팹</param>
|
|
|
|
|
/// <param name="pos">생성 위치</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public Character MonsterCreate(MapBlock blk, GameObject prefabMonset, Vector3 pos)
|
|
|
|
|
{
|
|
|
|
|
GameObject obj = ObjectCreate(prefabMonset, blk.transform, scaleCharacter, pos, true);
|
|
|
|
|
|
|
|
|
|
Character Monster = dicMonster.Get(obj.name);
|
|
|
|
|
if (Monster == null)
|
|
|
|
|
{
|
|
|
|
|
Monster = obj.GetComponent<Character>();
|
|
|
|
|
dicMonster.Add(Monster.name, Monster);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Monster;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bundle<DropItem> dicDrop = new Bundle<DropItem>();
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 드롭아이템을 생성합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="blk">생성될 블럭</param>
|
|
|
|
|
/// <param name="prefab">드롭아이템 프리팹</param>
|
|
|
|
|
/// <param name="pos">생성 위치</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public DropItem DropItemCreate(MapBlock blk, GameObject prefab, Vector3 pos)
|
|
|
|
|
{
|
|
|
|
|
GameObject obj = ObjectCreate(prefab, blk.transform, Vector3.one, pos, true);
|
|
|
|
|
|
|
|
|
|
DropItem drop = dicDrop.Get(obj.name);
|
|
|
|
|
if (drop == null)
|
|
|
|
|
{
|
|
|
|
|
drop = obj.GetComponent<DropItem>();
|
|
|
|
|
dicDrop.Add(drop.name, drop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return drop;
|
|
|
|
|
}
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public DropItemData dropItem;
|
|
|
|
|
public List<ItemData> items_All;
|
|
|
|
|
public List<ItemData> items_Weapon;
|
|
|
|
|
public List<ItemData> items_Armor;
|
|
|
|
|
public List<ItemData> items_Accessory;
|
|
|
|
|
public List<ItemData> items_Passive;
|
|
|
|
|
public List<ItemData> items_Active;
|
|
|
|
|
public List<ItemData> items_Use;
|
|
|
|
|
|
|
|
|
|
List<ItemData> listItems = new List<ItemData>();
|
|
|
|
|
//public void HoldinCheckList(List<ItemData> items, string idx)
|
|
|
|
|
//{
|
|
|
|
|
// ItemData item = items.Find(a => a.idx.Equals(idx));
|
|
|
|
|
|
|
|
|
|
// if(item != null)
|
|
|
|
|
// items.Remove(item);
|
|
|
|
|
//}
|
|
|
|
|
//public void HoldinCheck(string idx)
|
|
|
|
|
//{
|
|
|
|
|
// HoldinCheckList(items_Weapon, idx);
|
|
|
|
|
// HoldinCheckList(items_Equip, idx);
|
|
|
|
|
// HoldinCheckList(items_Passive, idx);
|
|
|
|
|
//}
|
|
|
|
|
//public void DropItemCreate(List<ItemData> items)
|
|
|
|
|
//{
|
|
|
|
|
// if (items.Count == 0)
|
|
|
|
|
// return;
|
|
|
|
|
|
|
|
|
|
// ItemData item = items[Random.Range(0, items.Count)];
|
|
|
|
|
// blkCurrent.OnDropItem_Create(player.transform, item);
|
|
|
|
|
// HoldinCheckList(items, item.idx);
|
|
|
|
|
//}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 현재 맵에 존재하는 모든 블럭에서 해당 아이템이 드랍되었는지 확인합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="idxItem">확인할 아이템 IDX</param>
|
|
|
|
|
/// <returns>true - 드랍되어 있음</returns>
|
|
|
|
|
bool DropCheck_All(string idxItem)
|
|
|
|
|
{
|
|
|
|
|
foreach(KeyValuePair<Vector2, MapBlock> blk in blocks)
|
|
|
|
|
{
|
|
|
|
|
if (blk.Value.HoldingItemCheck(idxItem))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 장착중인 아이템 및 드랍된 아이템 의 중첩드랍을 확인 하며
|
|
|
|
|
/// 어느쪽에도 해당하지 않는 아이템을 넘깁니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="items">드랍 리스트</param>
|
|
|
|
|
/// <param name="tierMin">최소 티어</param>
|
|
|
|
|
/// <param name="tierMax">최대 티어</param>
|
|
|
|
|
/// <param name="target">생성 위치</param>
|
|
|
|
|
/// <param name="CREATE">생성 유무</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public ItemData DuplicateItemCheck(List<ItemData> items, int tierMin = 0, int tierMax = 999, Transform target = null, bool CREATE = true)
|
|
|
|
|
{
|
|
|
|
|
listItems.Clear();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < items.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (tierMin <= items[i].tier && items[i].tier <= tierMax)
|
|
|
|
|
{
|
|
|
|
|
if (items[i].type.Equals("Use") || items[i].type.Equals("Pickup"))
|
|
|
|
|
{
|
|
|
|
|
listItems.Add(items[i]);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
//if (!OnHoldingItemCheck(items[i].idx) && !blkCurrent.HoldingItemCheck(items[i].idx))
|
|
|
|
|
if (!OnHoldingItemCheck(items[i].idx) && !DropCheck_All(items[i].idx))
|
|
|
|
|
listItems.Add(items[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (listItems.Count < 1)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
ItemData data = listItems[Random.Range(0, listItems.Count)];
|
|
|
|
|
if (0 < listItems.Count && CREATE)
|
|
|
|
|
blkCurrent.OnDropItem_Create(target == null ? player.transform : target, data.idx);
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
//public void DropItemCreate()
|
|
|
|
|
//{
|
|
|
|
|
// blkCurrent.OnDropItem_Create(player.transform, dropItem);
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
AppearList appear = new AppearList();
|
|
|
|
|
void Update()
|
|
|
|
|
{
|
|
|
|
|
if (Input.GetKeyDown(KeyCode.F8))
|
|
|
|
|
{
|
|
|
|
|
//ecMapEvent.Invoke((int)MapEvent.DoorInit, null);
|
|
|
|
|
blkCurrent.CLEAR = false;
|
|
|
|
|
blkCurrent.ecMapBlock.Invoke((int)MapEvent.DoorInit, false);
|
|
|
|
|
|
|
|
|
|
appear.cnt = 1;
|
|
|
|
|
appear.mobNames.Clear();
|
|
|
|
|
appear.mobNames.Add(mobs[Random.Range(0, mobs.Count)].name);
|
|
|
|
|
blkCurrent.Monster_Create(appear);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.GetKeyDown(KeyCode.F1))
|
|
|
|
|
DuplicateItemCheck(items_Use);
|
|
|
|
|
if (Input.GetKeyDown(KeyCode.F2))
|
|
|
|
|
DuplicateItemCheck(items_Weapon);
|
|
|
|
|
if (Input.GetKeyDown(KeyCode.F3))
|
|
|
|
|
DuplicateItemCheck(items_Accessory);
|
|
|
|
|
if (Input.GetKeyDown(KeyCode.F4))
|
|
|
|
|
DuplicateItemCheck(items_Armor);
|
|
|
|
|
if (Input.GetKeyDown(KeyCode.F5))
|
|
|
|
|
DuplicateItemCheck(items_Passive);
|
|
|
|
|
if (Input.GetKeyDown(KeyCode.F6))
|
|
|
|
|
DuplicateItemCheck(items_Active);
|
|
|
|
|
|
|
|
|
|
//if (Input.GetKeyDown(KeyCode.F12))
|
|
|
|
|
// Generate_Block();//치트, 맵 재설정
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void IngameCommand(object value)
|
|
|
|
|
{
|
|
|
|
|
string command = (string)value;
|
|
|
|
|
|
|
|
|
|
string[] split = command.Split(':');
|
|
|
|
|
switch(split[0])
|
|
|
|
|
{
|
|
|
|
|
case "Monster":
|
|
|
|
|
{
|
|
|
|
|
blkCurrent.CLEAR = false;
|
|
|
|
|
blkCurrent.ecMapBlock.Invoke((int)MapEvent.DoorInit, false);
|
|
|
|
|
|
|
|
|
|
appear.cnt = 1;
|
|
|
|
|
appear.mobNames.Clear();
|
|
|
|
|
appear.mobNames.Add(split[1]);
|
|
|
|
|
blkCurrent.Monster_Create(appear);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case "Item":
|
|
|
|
|
{
|
|
|
|
|
ItemData itemData = DataManager.Instance.dataItem.Search(split[1]);
|
|
|
|
|
if(itemData != null)
|
|
|
|
|
blkCurrent.OnDropItem_Create(player.transform, itemData.idx);
|
|
|
|
|
else
|
|
|
|
|
Debug.LogWarning($"Can't Find Item IDX : {split[1]}");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"Wrong input : {command}");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|