마지막 글을 쓴 이후로 무려 4일이나 경과했다.
아이템과 인벤토리 시스템 구현이 생각보다 복잡하고 어려워서 시간이 좀 많이 걸렸다.
인벤토리를 구현하기 위해서는 아이템이 구현되어있어야 하기 때문에 두 작업을 모두 마치는 데에 시간이 상당히 오래 걸린 것 같다. 이전에 다뤄본 아이템과 인벤토리 시스템을 활용했지만 구현하는 방식이 기존 방식과 상당히 동떨어져있어 구조를 뜯어고치는 등 복잡한 작업이 필요했다.
목요일에는 아이템의 전반적인 기능들을 구현했다.
금요일에는 루나모바일 게임 내에서 인벤토리와 아이템 등 UI를 가져왔고, Static / Dynamic 등 인벤토리 스크립트를 구현했다. (각각 플레이어 장비창, 아이템창)
토요일에는 아이템이 인벤토리에 추가되거나, 아이템의 등급과 감정하는 기능 등 아이템과 인벤토리 전반적인 기능 구현을 마쳤고, 인벤토리를 여닫을 때 카메라의 위치를 수정했다.
오늘인 일요일에는 아이템 장착, 해제와 더불어 플레이어의 스탯 시스템을 구현했다. 또한 플레이어와 적의 체력바 등 UI도 구현하였으며, 적을 클릭하거나 공격하여 적을 선택하고 테두리를 강조하는 기능도 구현했다. 아이템을 장착하거나 해제할 때 인벤토리에 빈 공간이 생기지 않도록 정렬 기능까지 구현했다. 클릭이나 공격, 피격, 장착, 해제, 움직임 등에 사용되는 효과음도 적용하였다.
이렇게 정리하고나니 굉장히 많은 것을 한 것 같다. 조금씩 정리했으면 좋았을 것 같은데, 전체적으로 기능이 부족하고, 체계적으로 작동하지 않는 것 같아서 정리를 미뤄뒀던 것 같다. 이 구조들을 정리하려고 하니 벌써부터 머리가 아파오는 것 같다. 우선은 처음부터 순서대로 정리해보겠다.
Flowchart Maker & Online Diagram Software
Flowchart Maker and Online Diagram Software draw.io is free online diagram software. You can use it as a flowchart maker, network diagram software, to create UML online, as an ER diagram tool, to design database schema, to build BPMN online, as a circuit d
app.diagrams.net
프로그램 구조도를 그리는 데에 꽤나 괜찮은 사이트가 있어 이곳에서 구조도를 작성해보았다.
먼저 Item 시스템의 구조도이다. ItemDatabaseObject와 ItemObejct는 ScriptableObject를 상속받아 구현하였다. ItemDatabaseObject는 하나만 존재하고, 이 안에 ItemObject들이 저장되어있다. ItemObject는 아이템을 생성하는 틀이며, 실제 플레이어에게 드롭되는 아이템은 ItemData 형식으로 저장된다. itemDatabaseObject에 등록될 때 ItemObject의 ItemData 내의 ItemObject마다 id가 중복되지 않도록 id를 부여한다. ItemData에는 ItemStat이라는, 아이템의 능력치 정보가 여럿 저장되어있다. 아이템의 등급, 성급, 강화 수치에 따라 최종 수치가 결정된다.
IModifier는 플레이어의 스탯 시스템을 구현하기 위한 인터페이스로, ItemStat이 상속받아 AddValue라는 함수를 구현한다. 또한, 게임 내에 강화석을 옵션석을 장착하는 슬롯이 있어 생성은 해놓았지만 아직 구현하지 않았다. ItemRank, CharacterClass, ItemType, AttributeType은 enum으로 각종 기능시 체크할 떄 사용된다.
다음은 Inventory 시스템의 구조도이다. InventoryObject라는 ScriptableObject가 있으며, 이를 생성하여 플레이어의 장비창과 인벤토리를 구현하였다. InventoryObject는 ItemDatabaseObject를 통해 아이템의 각종 비교에 사용한다. 또한 인벤토리 각각의 슬롯의 정보를 저장한 InventorySlot을 여러 개 가진 Inventory를 가지고 있다. InventorySlot은 해당 슬롯에 저장된 ItemData를 저장한다. 하나의 InventoryObject는 각각 장비창, 인벤토리 등 하나의 인벤토리 창의 정보를 가지고 있다.
InventoryUI는 InventoryObject를 가지며 인벤토리에 아이템이 추가되거나 제거될 때 UI를 갱신한다.
이를 상속받아 구현하는 StaticInventory는 고정적인 인벤토리 창을 갖는 장비창에 등록되는 스크립트로, 등록된 GameObject들인 staticSlots를 InventoryObject의 Inventory 안에 저장된 slots의 slotUI에 순서대로 저장해준다. 마찬가지로 InventoryUI를 상속받아 구현하는 DynamicInventory는 크기가 변하는 인벤토리 창을 갖는 플레이어 인벤토리에 등록되는 스크립트로, 최초에 인벤토리들을 생성하고 아이템을 정렬하는 등의 기능을 수행한다.
마지막으로 스탯 시스템의 구조도이다. 마찬가지로 ScriptableObject인 StatObject가 있다. 이를 생성하여 플레이어의 스탯을 관리하는 PlayerStat에 등록하였다. StatObject에는 현재 레벨과 경험치, 체력, 마나, attributes가 저장되어있다. Attribute는 플레이어의 각 스탯들의 타입과 값을 저장하고 있다. 값은 ModifiableFloat의 형태로 저장되어 있는데, 기본 값인 baseValue에 아이템을 장착할 때마다 스탯별로 modifiers가 추가되어 최종 능력치로 modifiedValue를 반환한다.
막상 이렇게 정리를 하니까 생각보다 그렇게 복잡하진 않은 것 같다. 구조도를 그리는 데에 2시간 정도 소요되긴 했지만.
EnemyController나 전투 시스템도 이렇게 구조도를 그리면 좋을 것 같기도 하다.
이외에는 대부분 기능을 UIManager에서 처리한다. 화면의 버튼을 누르는 기능들, 플레이어의 체력바를 업데이트하며 현재 주시 중인 적의 정보를 업데이트한다. 적의 정보를 업데이트하는 것은 적을 클릭하거나 적에게 피해를 주었을 때 작동한다.
그리고 처음 다뤄보는 것이 두 가지 정도 있었다. 먼저 ScrollView다. 일정 범위 내에서 스크롤을 하면 해당 범위 내에서만 데이터가 수평, 혹은 수직 방향으로 움직이며 많은 데이터를 한 곳에서 볼 수 있게끔 해준다. 사용법은 인터넷에 자세히 나와있어서 해당 부분을 참조했다. 게임에서 이전 대화 기록을 볼 때 해당 기능을 사용하면 될 것 같다.
Unity UGUI 스크롤뷰(ScrollView) 사용법 간단 정리 : 네이버 블로그 (naver.com)
Unity UGUI 스크롤뷰(ScrollView) 사용법 간단 정리
Unity에서 UI 작업시 가장 까다로우면서도 손이 많이 가는 작업으로 스크롤뷰( ScrollView ) 작업을 ...
blog.naver.com
두 번째로 다뤄본 것은 테두리이다. Shader를 이용하는데, 아무래도 각기 다른 에셋을 사용해서 그런지 테두리가 일정하고 균일하게 표시되진 않았으나 Shader에 대해서도 간단하게 다뤄본 것 같다. 이것도 마찬가지로 인터넷을 찾다보니 참고할만한 예제가 있어서 약간 변형하여 사용하였다.
유니티 - 오브젝트를 선택된 상태로 만들기 : (3) Shader Outline (tistory.com)
유니티 - 오브젝트를 선택된 상태로 만들기 : (3) Shader Outline
Unity 전체 링크 오브젝트를 선택된 상태로 만들기 : (1) bool 오브젝트를 선택된 상태로 만들기 : (2) 이미지로 만들기 오브젝트를 선택된 상태로 만들기 : (3) Shader Outline 오브젝트를 선택된 상태로
bloodstrawberry.tistory.com
using System.Collections.Generic;
using UnityEngine;
namespace SingletonPattern
{
public class OutlineManager : Singleton<OutlineManager>
{
private Material _outline;
private GameObject _target;
private Renderer _renderer;
private List<Material> _materialList = new();
public void OnDrawOutline(GameObject target)
{
if (target == null) return;
if (_outline == null) _outline = new Material(Shader.Find("Draw/OutlineShader"));
DisableOutline();
_target = target;
_renderer = target.GetComponent<Renderer>();
_materialList.Clear();
_materialList.AddRange(_renderer.sharedMaterials);
_materialList.Add(_outline);
_renderer.materials = _materialList.ToArray();
Debug.Log("Here");
}
private void DisableOutline()
{
if (_target == null || _renderer == null) return;
_materialList.Clear();
_materialList.AddRange(_renderer.sharedMaterials);
_materialList.Remove(_outline);
_renderer.materials = _materialList.ToArray();
}
}
}
나는 이런식으로 선택한 적이 바뀔 때마다 기존의 테두리를 없애주고 새로운 적에게 테두리를 생성해주었다. OnDrawOutline은 적을 클릭하거나 적을 공격할 때 호출된다.
이외에는 전투 시스템을 약간 수정했는데, 스탯을 가져와서 공격력을 계산하는 부분만 약간 바꾸었다.
지난 4일간에 걸쳐 구현된 부분은 다음과 같다.
UI와 사운드가 추가되니 훨씬 봐줄만한 게임이 된 것 같다. 무기가 나와야 적을 빨리 잡아서 아이템 파밍을 빨리 할텐데, 무기가 좀처럼 나오지 않아서 녹화가 약간 길어졌다. 너무 길어져서 중간에 끊었는데, 생각해보니 무기를 장착하면 데미지가 더 강해지는 것을 담지 못한 것 같다. 다음 번 녹화때는 전부 담을 수 있도록 해야겠다.
사실 이렇게 녹화하고보니 모든 내용을 다 정리하진 못한 것 같다. 아이템 등급은 짧게 통계를 내보고 추측하여 아이템이 드랍되도록 하였고, 성급은 표기된 확률대로 구현했다. 아이템 도감이 있어서 이미지나 등급/성급별 수치 변화도 쉽게 찾아볼 수 있었다. 아이템 스탯도 스크롤 뷰를 사용해서 구현했는데 해당 부분도 담지 못한 것 같다. 아직 구현할 것들이 조금 남아있기도 하니 내일 구현을 마무리한 후에 구현한 모든 내용들을 담을 수 있게끔 정리하고 녹화해야겠다. 또, 포트폴리오로 사용할 것이니 더 깔끔하게 잘 정리할 필요가 있을 것 같다. 지금 남은 것은 전투 부분의 UI 개선 정도이다. 데미지 텍스트, 공격 이펙트 정도만 추가하면 계획했던 기능들을 거의 구현한 것 같다. 사실 이 부분도 꼭 필요하지는 않은 것 같은데, 아무래도 전투가 밋밋해보여서 추가하는 게 좋을 것 같다. 게임에서 시각적인 부분도 꽤나 중요하기도 하고 말이다. 아이템을 더 추가해야하나 싶기도 한데, 이 부분은 일단 보류해야겠다. 내일 개발을 마무리하고 나머지 부분들을 정리하여 글을 써야겠다.
'개발 > 개발일지' 카테고리의 다른 글
3D RPG 개발 6 - exe/apk 빌드 관련 오류 수정 (0) | 2023.04.24 |
---|---|
3D RPG 개발 5 - 데미지 텍스트 UI, 아이템 추가 (1) | 2023.04.24 |
3D RPG 개발 3 - 적 캐릭터 AI, 전투, 필드 구현 (8) | 2023.04.20 |
3D RPG 개발 2 - 캐릭터 연속 공격 모션, 사망 상태 구현 등 (0) | 2023.04.19 |
3D RPG 개발 1 - 조이스틱을 이용한 캐릭터 이동, 대기 모션, 카메라 구현 (1) | 2023.04.18 |