Scriptable Object : 대량의 공유데이터를 저장할 수 있는 클래스
확장자 .asset으로 생성
특징
컴포넌트가 아님
일반적인 대부분의 이벤트 함수가 없음
다른 게임 오브젝트나 프리팹에 추가할 수 없음
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "RifleGunData" , menuName ="ScriptableObjects/RifleGunData" , order =1)]
// 파일명, 메뉴 이름, 순서
public class PlayerRifleData : ScriptableObject
{
public AudioClip shotClip;
public AudioClip reloadClip;
public float fireRate = 0.1f; // 발사 속도
public float reloadTime = 2.0f; // 재장전 시간
}

* 스크립터블 오브젝트로 세이브 / 로드
[CreateAssetMenu(fileName = "GameDataSO" , menuName = "ScriptableObjects/GameDataSO" , order = 2)]
//Scriptable Object로 세이브 / 로드
public class GameDataObject :ScriptableObject
{
public int killCnt = 0;
public float hp = 120;
public float damage = 25;
public float speed = 6f;
public List<Item> equipItem = new List<Item>();
}

만든다
void LoadGameData()
{
//KillCnt = PlayerPrefs.GetInt("KillCnt", 0);//PlayerPrefs : 플레이어 Preferences
//gameData = this.dataManager.Load();
if(gameData.equipItem.Count > 0)
{
this.InventorySetUp();
}
this.killCntTxtUi.text = $"Kill : <color=#ff0000>{this.gameData.killCnt.ToString("000")}</color>";
//.asset 파일에 데이터 저장
UnityEditor.EditorUtility.SetDirty(gameData);
}
private void SaveGameData()
{
//this.dataManager.Save(this.gameData);
UnityEditor.EditorUtility.SetDirty(gameData);
}
아이템 추가랑 제거 부분에도 저거 추가
수치 활용은 저 gameData로 하고,
나머지 data관리하던 부분을 UnityEditor.EditorUtility.SetDirty(gameData) 해놓으면 알아서 전역으로 처리 가능
단, 저렇게 두고 빌드하면 에러가 나서 안된다
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(gameData);
#endif
이렇게 넣어서 에디터에서만 동작하게 해놓아야 빌드된다
하지만 이러면 빌드에선 저장이 안된다.
빌드에서 저장되는법은 따로 있다
__________________________________________________________
rayCast로 총 발사
RaycastHit hit;
if (Physics.Raycast(this.firePos.position, firePos.forward, out hit, 20f, this.layerMask))
{
isFire = (hit.collider.CompareTag(enemyTag));
}
else
isFire = false;
if (!isReload && isFire)
{
if (Time.time > this.prevFire)
this.Shot();
this.prevFire = Time.time + this.autiFireRate;
}
_______________________________________________________________
Drop(장비창) -> 자신이 가지고있는 장비, 이 효과를 적용할 플레이어
Drag(장비) -> 지가 올리는 스텟
장비창에 장비를 올려두면 Drop이 장비 정보를 갖게되고,
그 장비의 효과를 플레이어한태 적용
빼면 Drop이 가지고있던 장비가 사라지고, 효과 또한 제거
player(유저) -> 장비창 data 를 가지고있어야함, 한두개가 아닐테니, 그 리스트를 data로써
가지고 있으면 됨
기초 스탯 Data도 가지고 있어야함
그 후 기초스탯, 장비창 변동 내용만 들고있으면 게임 부팅시 알아서 적용되는 형태
DataManager -> Player가 본인의 data를 Save하거나
게임을 킬때 Load하는 기능만 있어도 됨
이를 Scriptable object를 이용해서 DataManager없이 저장
Scriptable IO
//------------------------------------------------------------------------------
// <auto-generated>
// 이 코드는 도구를 사용하여 생성되었습니다.
// 런타임 버전:4.0.30319.42000
//
// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
// 이러한 변경 내용이 손실됩니다.
// </auto-generated>
//------------------------------------------------------------------------------
using System.Collections.Generic;
using UnityEditor.Search;
using UnityEngine;
[CreateAssetMenu(fileName ="GameDataSO",menuName ="Create GameData" ,order = 1)]
public class GameDataSO:ScriptableObject
{
public int hp = 10;
public int speed = 1;
public int granade = 1;
public int damage = 1;
public ItemData[] items = new ItemData[4];
}
code 생성으로 만든 코드를 따로 수정해서 사용
Player
this.InitStats();
for(int i = 0; i < slots.Length; i++)
{
slots[i].itemEquipAction += (idx) =>
{
this.gameData.items[idx] = slots[idx].item;
this.StatUpdate(this.slots[idx].item ,(CharValue, ItemValue) =>
{
return CharValue + ItemValue;
});
UnityEditor.EditorUtility.SetDirty(this.gameData);
};
slots[i].itemRemoveAction += (idx) =>
{
this.StatUpdate(this.slots[idx].item, (CharValue, ItemValue) =>
{
return CharValue - ItemValue;
});
this.gameData.items[idx] = null;
UnityEditor.EditorUtility.SetDirty(this.gameData);
};
if (gameData.items[i].Idx != ItemData.eItemIdx.None)
{
Debug.Log(this.gameData.items[i].Idx);
this.slots[i].item = this.gameData.items[i];
}
}
this.hp = this.maxhp;
private void StatUpdate(ItemData item, Func<int,int,int> op) // 아이템이 갱신됐을때 스탯 적용용 함수
{
switch (item.Idx)
{
case ItemData.eItemIdx.None:
break;
case ItemData.eItemIdx.Hp:
this.maxhp =op(this.maxhp, item.Value); // 식을 전달해서 함수 하나로 이용 가능 하도록
break;
case ItemData.eItemIdx.Speed:
this.speed =op(this.speed, item.Value);
break;
case ItemData.eItemIdx.Shock:
this.B_damage = op(this.B_damage, item.Value);
break;
case ItemData.eItemIdx.Granade:
this.granade = op(this.granade, item.Value);
break;
}
}
private void InitStats() //저장된 게임 정보 로드할때 스탯과 장비창 적용 부분
{
this.maxhp = gameData.hp;
this.speed = gameData.speed;
this.B_damage = gameData.damage;
this.granade = gameData.granade;
for (int i = 0; i < gameData.items.Length; i++)
{
if (gameData.items[i].Idx != ItemData.eItemIdx.None)
this.items[(int)gameData.items[i].Idx - 1].transform.SetParent(this.slots[i].transform);
switch (gameData.items[i].Idx)
{
case ItemData.eItemIdx.None:
break;
case ItemData.eItemIdx.Hp:
this.maxhp += gameData.items[i].Value;
break;
case ItemData.eItemIdx.Speed:
this.speed += gameData.items[i].Value;
break;
case ItemData.eItemIdx.Granade:
this.granade += gameData.items[i].Value;
break;
case ItemData.eItemIdx.Shock:
this.B_damage += gameData.items[i].Value;
break;
}
}
}
Slot(장비창)
public class Drop : MonoBehaviour,IDropHandler
{
//슬롯: 장비 데이터를 얘가 가지고있음
//그걸 플레이어쪽에 적용
bool isEquiped = false;
public ItemData item;
public int idx;
public Action<int> itemEquipAction; //아이템 낄때 플레이어쪽에서 실행할 액션
public Action<int> itemRemoveAction; // 아이템 뺄때 플레이어쪽에서 실행할 액션
//public Player player;
public void OnDrop(PointerEventData eventData)
{
if (isEquiped)
{
return;
}
Drag.draggingItem.transform.SetParent(this.transform, false);
this.item = Drag.draggingItem.GetComponent<ItemInfo>().data;
this.itemEquipAction(this.idx);
//
//DataManager.instance.AddItem(item);
}
private void OnTransformChildrenChanged()
{
if (!isEquiped)
{
isEquiped = true;
}
else
{
isEquiped = false;
this.itemRemoveAction(this.idx);
//this.item.Idx = ItemData.eItemIdx.None;
}
}
}
OnDrop의 실행 순서가 OnTransformChildrenChanged 보다 느리기때문에,
아이템을 빼는건 ChildrenChanged쪽에서 해도 되지만, 끼는건 Drop쪽에서 해야
아이템 정보를 가진 상태에서 실행 시킬 수 있다.
아이템(장비)
public class Drag : MonoBehaviour,IDragHandler,IBeginDragHandler,IEndDragHandler
{
public static GameObject draggingItem = null;
public GameObject inventory;
public GameObject itemSlot;
CanvasGroup cvGroup;
void Start()
{
this.cvGroup = GetComponent<CanvasGroup>();
}
public void OnBeginDrag(PointerEventData eventData)
{
draggingItem = this.gameObject;
this.transform.SetParent(this.inventory.transform);
this.cvGroup.blocksRaycasts = false; // 드래그가 시작되면 다른 UI 이벤트를 받지 않도록 설정
}
public void OnDrag(PointerEventData eventData)
{
this.transform.position = Input.mousePosition;
}
public void OnEndDrag(PointerEventData eventData)
{
draggingItem = null;
this.cvGroup.blocksRaycasts = true;
if (this.transform.parent == this.inventory.transform)
{
this.transform.SetParent(this.itemSlot.transform);
}
}
}
___________________________________________
//------------------------------------------------------------------------------
// <auto-generated>
// 이 코드는 도구를 사용하여 생성되었습니다.
// 런타임 버전:4.0.30319.42000
//
// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
// 이러한 변경 내용이 손실됩니다.
// </auto-generated>
//------------------------------------------------------------------------------
[System.Serializable]
public class ItemData
{
public enum eItemIdx
{
None,Hp,Speed,Granade,Shock
}
public eItemIdx Idx;
public int Value;
}
_________________________________________________
public class ItemInfo : MonoBehaviour
{
public ItemData data;
}
Drag는 그저 ui적인 내용만 수행함, 드래그해서 슬롯(장비창)에 붙이면 붙고,
이상한곳에 드래그되면 원래 위치로 돌아오는 내용
아이템 수치적인 내용은 ItemData를 가지고있는 ItemInfo에서 수행
'2025유니티수업' 카테고리의 다른 글
| 0701 유니티(NavMeshObstacle, 라이트맵, 씬 합치기) (5) | 2025.07.01 |
|---|---|
| 0630 깃허브 데스크톱(Branch), 유니티(적 인공지능(AI)) (0) | 2025.06.30 |
| 0626 깃허브 , 데이터 저장/불러오기 (1) | 2025.06.26 |
| 0625 비주얼 스튜디오 코드, 깃허브, 유니티(오쿨루전 컬링) , 유니티 button navigation (0) | 2025.06.25 |
| 0624 유니티(시네머신에 쉐이크 적용, UI 동적할당) (0) | 2025.06.24 |