[System.Serializable]
추가했음public class InventoryModel
{
// weapon정보들 키(int)는 슬롯의 index와 같다.
public Dictionary<int, WeaponInfo> weaponDatas { get; private set; } = new ();
// 장비가 아닌 아이템 인벤토리. 키(int)는 슬롯의 index와 같습니다.
public Dictionary<int, GenericItemInfo> itemDatas { get; private set; } = new ();
// 아이템 인벤토리의 아이템 개수입니다. 키(int)는 아이템 슬롯의 index와 같습니다.
public Dictionary<int, int> itemCounts { get; private set; } = new ();
//인벤토리 업데이트 콜백
public Action OnInventoryUpdated;
//현재 생성된 슬롯의 개수
public int curSlotCounts;
}
using System.Collections.Generic;
[System.Serializable]
public class SerializableInventoryModel
{
public List<WeaponData> weaponDatas = new List<WeaponData>();
public List<ItemData> itemDatas = new List<ItemData>();
public int curSlotCounts;
[System.Serializable]
public class WeaponData
{
public int slotIndex;
public WeaponInfo weaponInfo;
}
[System.Serializable]
public class ItemData
{
public int slotIndex;
public GenericItemInfo itemInfo;
public int itemCount;
}
}
public void LoadPlayerDataBase()
{
if (FileExists() == false)
{
Logger.Log("저장된 파일 없음");
LoadGameDatas<PlayerDataBase, PlayerData>();
LoadGameDatas<PlayerDataBase, PlayerStatData>();
existFile = false;
}
else
{
Logger.Log("저장된 파일 로드");
Logger.Log(PlayerDataFilePath);
string json = File.ReadAllText(PlayerDataFilePath);
Managers.Data.PlayerDataBase = JsonUtility.FromJson<PlayerDataBase>(json);
existFile = true;
}
}
/// <summary>
/// InventoryModel -> SerializableInventoryModel 변환해주는 함수 입니다.
/// </summary>
/// <param name="inventoryModel">직렬화 되기전 인벤정보</param>
/// <returns>직렬화된 인벤정보</returns>
private SerializableInventoryModel ConvertToSerializable(InventoryModel inventoryModel)
{
var serializableModel = new SerializableInventoryModel();
serializableModel.curSlotCounts = inventoryModel.curSlotCounts;
foreach (var invenWeapon in inventoryModel.weaponDatas)
{
serializableModel.weaponDatas.Add(new SerializableInventoryModel.WeaponData
{
slotIndex = invenWeapon.Key,
weaponInfo = invenWeapon.Value
});
}
foreach (var invenItem in inventoryModel.itemDatas)
{
serializableModel.itemDatas.Add(new SerializableInventoryModel.ItemData
{
slotIndex = invenItem.Key,
itemInfo = invenItem.Value,
itemCount = inventoryModel.itemCounts[invenItem.Key]
});
}
return serializableModel;
}
/// <summary>
/// InventoryModel 저장하는 함수입니다.
/// </summary>
/// <param name="inventoryModel">인벤 저장 정보</param>
public void SaveInventoryModel(InventoryModel inventoryModel)
{
var serializableModel = ConvertToSerializable(inventoryModel);
string json = JsonUtility.ToJson(serializableModel, true);
System.IO.File.WriteAllText(InvenDataFilePath, json);
Debug.Log($"InventoryModel 저장 완료: {InvenDataFilePath}");
}
/// <summary>
/// SerializableInventoryModel -> InventoryModel 변환 해주는 함수입니다.
/// </summary>
/// <param name="serializableModel">직렬화된 인벤 정보</param>
/// <returns>변환된 인벤토리 정보</returns>
private InventoryModel ConvertToInventoryModel(SerializableInventoryModel serializableModel)
{
var inventoryModel = new InventoryModel();
inventoryModel.InitDic(serializableModel.curSlotCounts);
foreach (var weaponData in serializableModel.weaponDatas)
{
if (weaponData.weaponInfo.ID == 0)
continue;
if (weaponData.weaponInfo.isEquip)
weaponData.weaponInfo.isEquip = false;
inventoryModel.weaponDatas[weaponData.slotIndex] = weaponData.weaponInfo;
}
foreach (var itemData in serializableModel.itemDatas)
{
if(itemData.itemCount == 0)
continue;
inventoryModel.itemDatas[itemData.slotIndex] = itemData.itemInfo;
inventoryModel.itemCounts[itemData.slotIndex] = itemData.itemCount;
}
return inventoryModel;
}
/// <summary>
/// 저장된 InventoryModel를 불러오는 함수입니다.
/// </summary>
/// <returns>변환된 인벤토리 정보</returns>
public InventoryModel LoadInventoryModel()
{
if (!System.IO.File.Exists(InvenDataFilePath))
{
Debug.LogWarning("저장된 인벤토리가 없습니다.");
return null;
}
string json = System.IO.File.ReadAllText(InvenDataFilePath);
var serializableModel = JsonUtility.FromJson<SerializableInventoryModel>(json);
Debug.Log("InventoryModel 불러오기 완료");
return ConvertToInventoryModel(serializableModel);
}
public class InventoryPresenter : MonoBehaviour
{
#region 변수
// 뷰어
[SerializeField] private UIInventory inventoryViewer;
// 슬롯의 우클릭할 시 나오는 작은 메뉴창
[SerializeField] private UIItemActionPopup actionPopup;
// 판매 팝업
[SerializeField] private PurchasePopup sellPopup;
//모델
private InventoryModel inventoryModel;
//드래그했을때 나오는 무기의 아이콘
private Image followImage;
//현재 인벤토리에서 보이고 있는 창
public InventoryView curView = InventoryView.Equip;
//툴팁패널
private UITooltipPanel tooltipPanel;
#endregion
#region Unity함수
/// <summary>
/// 초기화 및 이벤트 연결
/// </summary>
private void Awake()
{
inventoryModel = new InventoryModel();
//인벤저장&로드 관련 이벤트 연결
Managers.SaveLoad.saveFileInvenData += SaveInvenData;
if (Managers.SaveLoad.FileExists())
{
Logger.Log("인벤저장 불러오기");
inventoryModel = Managers.SaveLoad.LoadInventoryModel();
}
else
{
inventoryModel.InitDic(inventoryViewer.totalSlotCount);
}
// 모델 업데이트 시 뷰를 갱신
inventoryModel.OnInventoryUpdated += UpdateView;
}
System.Threading
네임스페이스를 사용하여 일반적인 스레드를 구현할 수 있음using System.Threading;
void Start()
{
Thread thread = new Thread(HeavyTask);
thread.Start();
}
void HeavyTask()
{
// 시간이 오래 걸리는 작업 수행
Debug.Log("Heavy task running on a separate thread.");
}
async void Start()
{
await PerformHeavyTaskAsync();
Debug.Log("Task completed on the main thread.");
}
async Task PerformHeavyTaskAsync()
{
await Task.Run(() => {
// 오래 걸리는 작업
Thread.Sleep(2000);
});
}
using Unity.Jobs;
using Unity.Collections;
using UnityEngine;
public class JobSystemExample : MonoBehaviour
{
void Start()
{
NativeArray<int> numbers = new NativeArray<int>(10, Allocator.TempJob);
MyJob job = new MyJob { Numbers = numbers };
JobHandle handle = job.Schedule();
handle.Complete();
for (int i = 0; i < numbers.Length; i++)
{
Debug.Log(numbers[i]);
}
numbers.Dispose();
}
struct MyJob : IJob
{
public NativeArray<int> Numbers;
public void Execute()
{
for (int i = 0; i < Numbers.Length; i++)
{
Numbers[i] = i * i;
}
}
}
}
Unity ECS (Entity Component System)와 결합 :
주의 사항
요약 : CPU는 복잡한 단일 작업을 처리하는 데 적합하며, GPU는 많은 단순 작업을 동시에 처리하는 데 특화되어 있습니다. 현대 컴퓨팅 환경에서는 CPU와 GPU가 서로 보완적인 역할을 수행 합니다.
CPU (Central Processing Unit)
CPU는 컴퓨터의 "중앙 처리 장치"로, 다양한 작업을 처리할 수 있는 범용 프로세서입니다.
코어 구조:
처리 능력:
속도와 캐시:
유형별 작업:
- 운영 체제 관리, 애플리케이션 로직 실행, 일반 계산 처리 등 범용적인 역할.
GPU (Graphics Processing Unit)
CPU와 GPU의 비교
실제 사용 사례
Unity에서 월드 스페이스와 로컬 스페이스는 게임 오브젝트의 위치, 회전, 스케일을 표현할 때 사용하는 두 가지 좌표 체계입니다. 두 스페이스의 차이는 주로 참조 기준에 따라 달라집니다.
월드 스페이스 (World Space)
// 월드 스페이스에서 오브젝트 이동
transform.position = new Vector3(5, 10, 3);
로컬 스페이스 (Local Space)
// 로컬 스페이스에서 오브젝트 이동
transform.localPosition = new Vector3(1, 0, 0);
Unity에서 벡터의 내적(Dot Product)과 외적(Cross Product)은 게임 개발에서 방향 계산, 충돌 감지, 회전, 정렬 등의 작업에 자주 사용됩니다.
내적(Dot Product)
A ⋅ B = ∣A∣ ⋅ ∣B∣ ⋅ cosθ
Vector3 forward = transform.forward; // 오브젝트의 전방 벡터
Vector3 toTarget = (target.position - transform.position).normalized;
float dot = Vector3.Dot(forward, toTarget);
if (dot > 0.9f) // 0.9 이상이면 거의 같은 방향
{
Debug.Log("Target is in front of the object.");
}
A × B = ∣A∣ ⋅ ∣B∣ ⋅ sinθ ⋅ n
Vector3 normal = Vector3.Cross(vectorA, vectorB).normalized;
Vector3 cross = Vector3.Cross(forward, toTarget);
if (cross.y > 0)
{
Debug.Log("Target is on the left.");
}
else
{
Debug.Log("Target is on the right.");
}
내적과 외적의 차이 요약
실제 게임 개발에서의 응용
Unity에서 쿼터니언을 사용하는 이유는 안정성, 효율성, 정확성 때문입니다. 특히 짐벌 락 문제를 해결하고, 매끄러운 회전 및 효율적인 연산을 제공하므로 게임 개발에서 필수적인 도구로 자리 잡았습니다. Unity는 쿼터니언과 오일러 각도를 모두 제공하지만, 복잡한 회전 계산에서는 쿼터니언이 기본적으로 사용됩니다.
쿼터니안
(상세)유니티에서 쿼터니언을 사용하는 이유
짐벌 락(Gimbal Lock) 방지
매끄러운 회전(Smooth Interpolation)
Quaternion.Slerp()
를 사용하여 두 회전 간의 부드러운 전환을 구현할 수 있습니다.효율적인 연산
축과 각도로 회전 표현 가능
Quaternion.AngleAxis()
를 사용하여 축과 각도로 회전을 생성할 수 있습니다.회전의 누적 오류 감소
Unity에서 쿼터니언 사용 예제
// 특정 각도로 회전 설정
transform.rotation = Quaternion.Euler(45, 30, 60);
// Y축을 기준으로 90도 회전
Quaternion rotation = Quaternion.AngleAxis(90, Vector3.up);
transform.rotation = rotation;
// A와 B 사이를 부드럽게 보간
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime);
쿼터니언과 오일러 각도의 비교
IP (Internet Protocol)
TCP (Transmission Control Protocol)
UDP (User Datagram Protocol)
종합적으로 본 네트워크 프로토콜의 역할
TCP와 UDP는 전송 계층에서 데이터를 송수신하는 데 사용되는 두 가지 주요 프로토콜입니다. 이 두 프로토콜은 데이터 전송 방식과 특성이 다르며, 용도에 따라 선택적으로 사용됩니다.
개념
주요 단계
Unity의 렌더링 파이프라인
렌더링 파이프라인의 최적화