각각의 섬들을 탐험하면서 자원을 채집하세요.
다양한 장비를 제작해서 최대한 오래 생존하세요.
밤 마다 몰려오는 몬스터의 공격에 대비하세요.
다양한 설치 아이템들을 배치해서 나만의 공간을 만들어보세요.
보스 몬스터를 사냥해서, 강력함을 뽐내세요.
각 섬의 영향력 속에서 생존하세요.
오브젝트 투명화
public class ChangeMaterials : MonoBehaviour
{
public Material[] fadeMaterials = new Material[2];
public Material[] originMaterials = new Material[2];
private Material[] _materials;
private MeshRenderer _meshRenderer;
private void Awake()
{
_meshRenderer = GetComponentInChildren<MeshRenderer>();
_materials = _meshRenderer.materials;
}
public void ChangeFadeMaterials()
{
for (int i = 0; i < _materials.Length; i++)
{
_materials[i] = fadeMaterials[i];
}
_meshRenderer.materials = _materials;
}
public void ReturnMaterials()
{
for (int i = 0; i < _materials.Length; i++)
{
_materials[i] = originMaterials[i];
}
_meshRenderer.materials = _materials;
}
}
public class RaycastToChangeMaterials : MonoBehaviour
{
[SerializeField]
private LayerMask _layerMask;
[SerializeField]
private Camera _camera;
[SerializeField]
private Transform _player;
private RaycastHit[] _hits = new RaycastHit[10];
private HashSet<ChangeMaterials> _prevChangeMaterials = new();
private HashSet<ChangeMaterials> _curruentChangeMaterials = new();
private void Start()
{
StartCoroutine(CheckPlayer());
}
private IEnumerator CheckPlayer()
{
while (Managers.Game.Player == null)
{
yield return null;
}
_player = Managers.Game.Player.ViewPoint;
}
private void FixedUpdate()
{
if (_player != null)
{
CheckForObjects();
}
}
private void CheckForObjects()
{
_prevChangeMaterials = _curruentChangeMaterials;
_curruentChangeMaterials = new();
int hits = Physics.RaycastNonAlloc(_camera.transform.position, (_player.transform.position - _camera.transform.position).normalized, _hits,
Vector3.Distance(_camera.transform.position, _player.transform.position), _layerMask);
if (hits >= 0)
{
// hashset
for (int i = 0; i < hits; i++)
{
ChangeMaterials changeMaterials = _hits[i].transform.gameObject.GetComponentInParent<ChangeMaterials>();
_curruentChangeMaterials.Add(changeMaterials);
changeMaterials.ChangeFadeMaterials();
}
_prevChangeMaterials.ExceptWith(_curruentChangeMaterials);
foreach (var hit in _prevChangeMaterials)
hit.transform.gameObject.GetComponentInParent<ChangeMaterials>().ReturnMaterials();
}
}
}
방어구 시스템
이전 코드
public class UIArmorSlot : UIItemSlot
{
enum Images
{
Icon,
}
public ItemParts part;
public override void Initialize()
{
Bind<Image>(typeof(Images));
Get<Image>((int)Images.Icon).gameObject.SetActive(false);
Get<Image>((int)Images.Icon).raycastTarget = false;
}
private void Awake()
{
Initialize();
Managers.Game.Player.ToolSystem.OnEquip += EquipArmor;
Managers.Game.Player.ToolSystem.OnUnEquip += UnEquipArmor;
Managers.Game.Player.ArmorSystem.UnEquipArmor += UnEquipArmor;
}
public void EquipArmor(QuickSlot quickSlot)
{
int parts = GetPart(quickSlot);
if (parts == 0)
{
switch (part)
{
case ItemParts.Head:
Set(quickSlot.itemSlot);
break;
}
}
else if (parts == 1)
{
switch (part)
{
case ItemParts.Body:
Set(quickSlot.itemSlot);
break;
}
}
}
public void UnEquipArmor(QuickSlot quickSlot)
{
int parts = GetPart(quickSlot);
if (parts == 0)
{
switch (part)
{
case ItemParts.Head:
Clear();
break;
}
}
else if (parts == 1)
{
switch (part)
{
case ItemParts.Body:
Clear();
break;
}
}
}
public override void Set(ItemSlot itemSlot)
{
Get<Image>((int)Images.Icon).sprite = itemSlot.itemData.iconSprite;
Get<Image>((int)Images.Icon).gameObject.SetActive(true);
}
public override void Clear()
{
Get<Image>((int)Images.Icon).gameObject.SetActive(false);
}
private int GetPart(QuickSlot slot)
{
var itemData = slot.itemSlot.itemData as EquipItemData;
if (itemData == null) return -1;
return (int)itemData.part;
}
}
public class ArmorSystem : MonoBehaviour
{
public int _defense;
public QuickSlot[] _linkedSlots;
public event Action<QuickSlot> UnEquipArmor;
private void Awake()
{
_linkedSlots = new QuickSlot[2];
Managers.Game.Player.ToolSystem.OnEquip += DefenseOfTheEquippedArmor;
Managers.Game.Player.ToolSystem.OnUnEquip += DefenseOfTheUnEquippedArmor;
Managers.Game.Player.OnHit += Duration;
}
private void Start()
{
Managers.Game.Player.Inventory.OnUpdated += OnInventoryUpdated;
}
public void DefenseOfTheEquippedArmor(QuickSlot quickSlot)
{
EquipItemData toolItemData = ArmorDefense(quickSlot);
_defense += toolItemData.defense;
Managers.Game.Player.playerDefense = _defense;
if ((int)toolItemData.part == 0 || (int)toolItemData.part == 1)
{
_linkedSlots[(int)toolItemData.part] = quickSlot;
}
}
public void DefenseOfTheUnEquippedArmor(QuickSlot quickSlot)
{
EquipItemData toolItemData = ArmorDefense(quickSlot);
_defense -= toolItemData.defense;
Managers.Game.Player.playerDefense = _defense;
if ((int)toolItemData.part == 0 || (int)toolItemData.part == 1)
{
_linkedSlots[(int)toolItemData.part] = null;
}
}
public void Duration() // Player Hit에서 호출
{
for (int i = 0; i < _linkedSlots.Length; i++)
{
if (_linkedSlots[i] != null && _linkedSlots[i].targetIndex != -1)
{
Managers.Game.Player.Inventory.UseToolItemByIndex(_linkedSlots[i].targetIndex, 1);
}
}
}
public void OnInventoryUpdated(int inventoryIndex, ItemSlot itemSlot)
{
for (int i = 0; i < 2; i++)
{
if (_linkedSlots[i] != null)
{
if (_linkedSlots[i].targetIndex == inventoryIndex)
{
if (itemSlot.itemData == null)
{
EquipItemData toolItemData = ArmorDefense(_linkedSlots[i]);
_defense -= toolItemData.defense;
Managers.Game.Player.playerDefense = _defense;
UnEquipArmor?.Invoke(_linkedSlots[i]);
_linkedSlots[i].Clear();
Managers.Game.Player.ToolSystem.UnEquipArmor(_linkedSlots[i]);
}
}
}
}
}
private EquipItemData ArmorDefense(QuickSlot quickSlot)
{
ItemData armor = quickSlot.itemSlot.itemData;
EquipItemData toolItemDate = (EquipItemData)armor;
return toolItemDate;
}
}
문제점
수정 코드
public class ArmorSystem : MonoBehaviour
{
private Player _player;
private int _defense;
private QuickSlot[] _equippedArmors;
public event Action<QuickSlot> OnEquipArmor;
public event Action<QuickSlot> OnUnEquipArmor;
private void Awake()
{
_player = GetComponentInParent<Player>();
_equippedArmors = new QuickSlot[2];
for (int i = 0; i < _equippedArmors.Length; i++)
{
_equippedArmors[i] = new QuickSlot();
}
GameManager.Instance.Player.OnHit += OnUpdateDurabilityOfArmor;
Load();
GameManager.Instance.OnSaveCallback += Save;
}
private void Start()
{
_player.Inventory.OnUpdated += OnInventoryUpdated;
}
public void Equip(int index, ItemSlot itemSlot)
{
var part = GetPart(itemSlot);
UnEquip(part);
itemSlot.SetEquip(true);
_equippedArmors[(int)part].Set(index, itemSlot);
AddDefenseOfArmor(_equippedArmors[(int)part]);
OnEquipArmor?.Invoke(_equippedArmors[(int)part]);
}
public void UnEquip(ItemParts part)
{
if (_equippedArmors[(int)part].itemSlot.itemData == null) return;
SubtractDefenseOfArmor(_equippedArmors[(int)part]);
_equippedArmors[(int)part].itemSlot.SetEquip(false);
OnUnEquipArmor?.Invoke(_equippedArmors[(int)part]);
_equippedArmors[(int)part].Clear();
}
private void AddDefenseOfArmor(QuickSlot quickSlot)
{
EquipItemData toolItemData = GetArmorItemData(quickSlot);
_defense += toolItemData.defense;
}
private void SubtractDefenseOfArmor(QuickSlot quickSlot)
{
EquipItemData toolItemData = GetArmorItemData(quickSlot);
_defense -= toolItemData.defense;
}
public void OnUpdateDurabilityOfArmor()
{
for (int i = 0; i < _equippedArmors.Length; i++)
{
if (_equippedArmors[i] != null && _equippedArmors[i].targetIndex != -1)
{
_player.Inventory.TrySubtractDurability(_equippedArmors[i].targetIndex, 1);
}
}
}
private EquipItemData GetArmorItemData(QuickSlot quickSlot)
{
EquipItemData toolItemDate = quickSlot.itemSlot.itemData as EquipItemData;
return toolItemDate;
}
private ItemParts GetPart(ItemSlot slot)
{
var itemData = slot.itemData as EquipItemData;
return itemData.part;
}
public int GetDefense()
{
return _defense;
}
public QuickSlot[] GetEquippedArmorsArray()
{
return _equippedArmors;
}
public void OnInventoryUpdated(int inventoryIndex, ItemSlot itemSlot)
{
if (itemSlot.itemData != null) return;
for (int i = 0; i < _equippedArmors.Length; i++)
{
if (_equippedArmors[i] != null)
{
if (_equippedArmors[i].targetIndex == inventoryIndex && itemSlot.itemData == null)
{
SubtractDefenseOfArmor(_equippedArmors[i]);
OnUnEquipArmor?.Invoke(_equippedArmors[i]);
_equippedArmors[i].Clear();
}
}
}
}
private void Load()
{
if (SaveGame.TryLoadJsonToObject(this, SaveGame.SaveType.Runtime, "ArmorSystem"))
{
for (int i = 0; i < _equippedArmors.Length; ++i)
{
_equippedArmors[i].itemSlot.LoadData();
}
}
}
private void Save()
{
var json = JsonUtility.ToJson(this);
SaveGame.CreateJsonFile("ArmorSystem", json, SaveGame.SaveType.Runtime);
}
}
개선 사항
public class UIArmorSlotContainer : MonoBehaviour
{
private List<UIArmorSlot> _armorSlots = new List<UIArmorSlot>();
private void Awake()
{
GameManager.Instance.Player.ArmorSystem.OnEquipArmor += EquipArmor;
GameManager.Instance.Player.ArmorSystem.OnUnEquipArmor += UnEquipArmor;
}
public void CreatArmorSlots<T>(GameObject slotPrefab, int count) where T : UIArmorSlot
{
for (int i = 0; i < count; i++)
{
var armorSlotPrefab = Instantiate(slotPrefab, this.transform);
var armorSlotUI = armorSlotPrefab.GetComponent<T>();
SetParts(armorSlotUI, i);
_armorSlots.Add(armorSlotUI);
}
}
public void Init<T>(QuickSlot[] quickSlot) where T : UIArmorSlot
{
foreach (var armor in quickSlot)
{
EquipArmor(armor);
}
}
private void SetParts(UIArmorSlot armorSlotUI, int index)
{
armorSlotUI.SetPart((ItemParts)index);
}
public void EquipArmor(QuickSlot quickSlot)
{
if (quickSlot.itemSlot.itemData == null) return;
int parts = GetPart(quickSlot);
_armorSlots[parts].Set(quickSlot.itemSlot);
}
public void UnEquipArmor(QuickSlot quickSlot)
{
int parts = GetPart(quickSlot);
_armorSlots[parts].Clear();
}
private int GetPart(QuickSlot slot)
{
var itemData = slot.itemSlot.itemData as EquipItemData;
if (itemData == null) return -1;
return (int)itemData.part;
}
}
개선 사항
public class UIArmorSlot : UIItemSlot
{
public Sprite[] sprites;
public Color emptyState;
enum Images
{
Icon,
}
public ItemParts part;
public override void Initialize()
{
Bind<Image>(typeof(Images));
Clear();
Get<Image>((int)Images.Icon).raycastTarget = false;
}
private void Awake()
{
Initialize();
}
public void SetPart(ItemParts part)
{
this.part = part;
Clear();
}
public override void Set(ItemSlot itemSlot)
{
if (itemSlot.itemData == null)
{
Clear();
return;
}
Get<Image>((int)Images.Icon).color = Color.white;
Get<Image>((int)Images.Icon).sprite = itemSlot.itemData.iconSprite;
Get<Image>((int)Images.Icon).gameObject.SetActive(true);
}
public override void Clear()
{
Get<Image>((int)Images.Icon).sprite = sprites[(int)part];
Get<Image>((int)Images.Icon).color = emptyState;
}
}
개선 사항