들어가며
생각보다 쉬운 거 같으면서도... 구조 짜기 어려워서 빨리 할 수 있을까 걱정입니다.
빨리빨리 열심히 해야죠!
개발할 시스템
아래 2줄로 재료가 정렬되어 있고 위에 유닛에 맞는 공식이 적혀있습니다.
재료들을 드래그 앤 드랍으로 공식에 놓아 다 놓으면 업그레이드가 되면 됩니다.
오늘은 소환 및 정렬, 개수 조건에 따른 들기 정도만 하였습니다.
개발 시작
우선 재료를 만들겠습니다.
using UnityEngine;
/// <summary>
/// 재료 아이템 종류 타입
/// </summary>
public enum ResourceType
{
none,a,b,c,x,y,pie,squ,l,r,number
}
/// <summary>
/// 재료 아이템 정보 SO
/// </summary>
[CreateAssetMenu(menuName = "SO/Resource/Data")]
public class ResourceDataSO : ScriptableObject
{
public Sprite sprite; // 아이템 스프라이트
public ResourceType type; // 아이템 타입
public int count; //아이템 개수
}
재료의 타입을 구분하기 쉽게 enum으로 선언해 주고,
재료 데이터에 필요한 3가지를 변수로 선언하여 넣어줍니다.
enum에서 보시다시피 너무 많은 양의 재료 종류가 존재하니 관리하기 쉽게
리스트 SO도 만들어줍니다.
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 리소스 SO 리스트
/// </summary>
[CreateAssetMenu(menuName = "SO/Resource/List")]
public class ResourceSOList : ScriptableObject
{
public List<ResourceDataSO> dataList;
}
SO를 인스펙터 창에서 보면 이렇게 됩니다.
이 데이터들을 적용시킬 재료 본체를 만들어 봅시다.
using UnityEngine;
using UnityEngine.EventSystems;
/// <summary>
/// 재료 주 컴포넌트
/// </summary>
public class Resource : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler
{
public NotifyValue<int> count = new NotifyValue<int>();//재료 개수 ui 갱신을 위한 노티파이
private ResourceUI _uiCompo;
public ResourceDataSO resourceData;
public void Initalized(ResourceDataSO data)
{
resourceData = data;
count.Value = data.count;
_uiCompo = GetComponentInChildren<ResourceUI>();
_uiCompo.Initialize(this);
}
public void OnPointerEnter(PointerEventData eventData)
{
ResourceManager.Instance.EnterPointer(resourceData.type);
}
public void OnPointerExit(PointerEventData eventData)
{
ResourceManager.Instance.ExitPointer();
}
}
뭔가 길어 보이지만 별거 없습니다.
이따 소개할 매니저에서 초기화(initalized)를 통해
데이터를 받아오고 세팅한 이후, 포인터의 인식을 받아 함수 호출을 하는 클래스입니다.
_uiCompo 변수의 클래스 ResourceUI는 이러합니다.
using TMPro;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 재료 아이템 Ui 총관리
/// </summary>
public class ResourceUI : MonoBehaviour
{
private Image _imageCompo;
private TextMeshProUGUI _countText;
private Color _fullColor = new Color(255, 255, 255, 255);
private Color _emptyColor = new Color(255, 255, 255, 100);
public void Initialize(Resource resouce)
{
_imageCompo = GetComponentInChildren<Image>();
_countText = GetComponentInChildren<TextMeshProUGUI>();
resouce.count.OnValueChanged += HandleCountChangeEvent;
HandleCountChangeEvent(0, resouce.count.Value);
_imageCompo.sprite = resouce.resourceData.sprite;
}
private void HandleCountChangeEvent(int prev, int next)
{
_countText.text = $"{next}";
if (next > 0)
_imageCompo.color = _fullColor;
else
_imageCompo.color = _emptyColor;
}
}
이 역시 Resource에서 초기화해 주면 텍스트, 이미지를 세팅해 주는 클래스입니다.
왜인지 컬러 부분은 작동을 안 하지만..ㅜ
이를 통해 프리팹은 이렇게 만들어졌습니다. (임시입니다.. 제가 미적감각이 좀 떨어집니다.)
리소스 매니저
이제 매니저에서 재료를 소환 후 관리 해주면 됩니다.
[SerializeField] private ResourceSOList dataList;
[SerializeField] private Resource _resourcePrefab;
아까 만든 것들 받아오고,
private void Awake()
{
foreach (var data in dataList.dataList)
{
Resource resource = Instantiate(_resourcePrefab, transform);
resource.Initalized(data);
_spriteDic.Add(data.type,resource);
}
}
이런 식으로 재료를 소환 후, 초기화를 해줍니다.
(딕셔너리는 추후 관리를 위한 추가)
이제 게임을 실행시키면 재료가 소환이 됩니다.
이후 아까 Resource클래스에 있던 함수 두 가지 추가해 줍니다.
private ResourceType _keyType;
private bool _isCursor=false;
public void ExitPointer()
{
_isCursor = false;
_keyType = ResourceType.none;
}
public void EnterPointer(ResourceType keyType)
{
_isCursor = true;
_keyType = keyType;
}
들어왔는지 안 들어왔는지를 bool값에,
키값을 같이 저장해 주는 함수입니다.
이후 업데이트에서 마우스 클릭 인풋을 받아줍니다.
public bool _isSelect=false;
[SerializeField] private Piece piecePrefab;
private void Update()
{
if (Input.GetMouseButtonDown(0) && _isCursor)
{
if (_spriteDic[_keyType].count.Value > 0) // 개수가 0개 초과인지
{
_isSelect = true; // 선택됨
Piece piece = Instantiate(piecePrefab);
piece.Initialize(_spriteDic[_keyType].resourceData.sprite);
_spriteDic[_keyType].count.Value--;
}
}
else if (Input.GetMouseButtonUp(0) && _isSelect)
{
//조각을 놓는 작업
}
}
아까 만들었던 딕셔너리가 빛을 보는 시간입니다.
키값을 통해 개수, 이미지를 가져와 소환하여 세팅해 주는 코드입니다. 조각 놓는 작업은 나중에..
이후 Piece 클래스를 선언해 줍니다.
using UnityEngine;
/// <summary>
/// 재료 조각 클래스
/// </summary>
public class Piece : MonoBehaviour
{
private Vector2 MousePos;
public void Initialize(Sprite sprite)
{
SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
spriteRenderer.sprite = sprite;
}
private void Update()
{
InputMouse();
transform.position = MousePos;
}
private void InputMouse()
{
Vector2 inputPos = Input.mousePosition;
MousePos = Camera.main.ScreenToWorldPoint(inputPos);
}
}
선택한 재료의 스프라이트를 받아 마우스 포지션을 따라오는 컴포넌트입니다.
최종 ResourceManager 클래스
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 재료 총괄 매니저
/// </summary>
public class ResourceManager : MonoSingleton<ResourceManager>
{
[SerializeField] private ResourceSOList dataList;
[SerializeField] private Resource _resourcePrefab;
[SerializeField] private Piece piecePrefab;
private ResourceType _keyType;
private bool _isCursor=false;
public bool _isSelect=false;
private Dictionary<ResourceType,Resource> _spriteDic = new Dictionary<ResourceType, Resource>();
private void Awake()
{
foreach (var data in dataList.dataList)
{
Resource resource = Instantiate(_resourcePrefab, transform);
resource.Initalized(data);
_spriteDic.Add(data.type,resource);
}
}
private void Update()
{
if (Input.GetMouseButtonDown(0) && _isCursor)
{
if (_spriteDic[_keyType].count.Value > 0) // 개수가 0개 초과인지
{
_isSelect = true; // 선택됨
Piece piece = Instantiate(piecePrefab);
piece.Initialize(_spriteDic[_keyType].resourceData.sprite);
_spriteDic[_keyType].count.Value--;
}
}
else if (Input.GetMouseButtonUp(0) && _isSelect)
{
//조각 놓는 작업
}
}
public void ExitPointer()
{
_isCursor = false;
_keyType = ResourceType.none;
}
public void EnterPointer(ResourceType keyType)
{
_isCursor = true;
_keyType = keyType;
}
}
이렇게 해서 이번 개발 분량은 끝냈습니다.
마치며
대충... 이제야 한걸음 온 거 같은데 나머지 얼른 힘내서 해보겠습니다.
'개발일기 > 수학공모전게임' 카테고리의 다른 글
[개발일지] 수학 공모전 개발 일지 중단 #ㅠㅠ (1) | 2024.09.27 |
---|---|
[개발일기]수학 공모전 업그레이드 시스템 #02 (3) | 2024.09.15 |
[개발일지] 수학 공모전 게임 개발 시작 #00 (2) | 2024.09.11 |