top of page

For the Spirit - RPG 유니티 포트폴리오

  • 작성자 사진: 100 powerun
    100 powerun
  • 2024년 11월 27일
  • 6분 분량

최종 수정일: 2월 20일




이동은 클릭으로 할 수 있으며 클릭한 위치로만 이동하지만 클릭 시에만 위치정보를 받아오게 코드가 짜여 있기 때문에 마우스 버튼을 누른 상태에서는 이동 위치가 갱신되진 않습니다.



Ray와 RaycastHit을 이용하여 화면을 클릭 시 클릭한 위치를 받아오고 받아온 위치를 destination이라는 이름의 변수에 Set한 뒤

받아온 위치와 현재 위치값을 빼고 나온 값의 위치로 이동합니다.

클릭한 위치와 현재 위치를 빼는 이유는 정확한 벡터 위치값과 이동 방향을 구하기 위해서고 만약 여기서 마이너스를 넣지 않을 경우 캐릭터는 엉뚱한 방향으로 향하게 됩니다.


이후, 만약 캐릭터가 이동하고자 하는 x축 값이 현재 위치보다 크다면 캐릭터가 보는 방향을 바꾸어 자연스러운 움직임을 만들기 위해 스프라이트를 뒤집어줍니다. 만약 스프라이트의 자체 기능을 사용한다면 축 뒤집기를 이용할 수 있습니다.






치트창은 ESC키, 인벤토리는 I키, 장비창은 E키로 열 수 있고 마지막 사진에선 GetMat과 GetArmor 버튼을 눌러서 아이템을 얻어온 상태입니다.


치트창은 esc를 눌렀을 때 만약 다른 창이 열려있지 않다면 열리게 되어있습니다. 별도의 정보를 가지고 있지만, SetActive로 false를 만들 시 가지고 있던 정보가 날아가는 인벤토리와 같은 다른 창과는 다르게 별도의 정보 저장이 필요 없기 때문에 SetActive를 이용해 열고 닫게 했습니다.


아래는 장비와 아이템을 불러오는 치트의 일부이다. 아이템을 불러오는 모든 함수는 GetItem함수를 이용해 가져옵니다.

위의 예시는 갑옷과 무기 아이템을 불러오며 GetItem은 무기의 타입을 먼저 불러온 뒤 스크립터블 오브젝트로 만들어놓은 아이템의 정보를 가져온다. 그 이후 가져온 리소스를 새로운 변수로 지정한 뒤 type을 지정해 주고 나서 haveItems에 추가합니다.

public List<Item> haveItems = new List<Item>();

haveItems는 위와 같은 List형식으로 이루어져 있으며

아래의 아이템 정보를 불러오는 함수인 LoadItems의 핵심 역할을 수행합니다.

LoadItems는 아이템을 인벤토리에 정보를 가져올 때에 사용되는 함수로 만약 아이템 추가 시에 위의 함수를 사용하지 않는다면 인벤토리에 추가가 되지 않습니다. 그렇기 때문에 상점 구매나 치트를 이용한 아이템 흭득 시 위의 함수를 넣어줘야 아이템이 인벤토리에 추가가 됩니다.


인벤토리는 Image형식으로 아이템의 정보를 가지고 있으며 이에따라 Slots의 [i]번째의 List에 저장합니다. List에 저장된 Image는 스프라이트 정보만 가지고 있지만 스크립터블 오브젝트로 생성된 아이템 정보를 가지고 있기에 별도의 정보 저장 없이도 모든 아이템의 정보를 가지고 있을 수 있습니다.


아래의 특수 아이템이나 소비 아이템의 경우는 스택이 가능하도록 설정했기 때문에 인벤토리 칸마다 숨겨진 텍스트에 값을 넣어 얼마나 아이템이 겹쳐 있는지를 표기합니다.


아래의 for문은 Item을 불러온 후 빈칸을 다시 초기화하는 반복문이다. 때문에 i가 haveItems의 Count량 부터 시작합니다.




위의 코드는 UseItem함수의 일부이며 무기와 방어구의 경우를 보여주는 구역으로 만약 장비칸 슬롯을 가져온 뒤 가져온 슬롯이 비어있다면 아이템을 장착하고 Null이 아닌 아이템이 장착되여있는 경우 장착된 아이템은 인벤토리로 옮기고 클릭한 장비를 장착하게 만든다.

다음은 소비아이템의 사용이며 소비 아이템은 클릭 시 수량을 줄이고 사용 함수를 이용해 사용하며 만약 수량이 0개가 된다면 인벤토리 칸에서 없앱니다.

그리고 모든 if문을 돈 후 맨 아래의 LoadItems() 함수를 이용해 장착하거나 사용한 아이템의 정보를 실시간으로 변경시켜 줍니다.


위의 코드는 Consume의 함수이며 현재는 회복 아이템밖에 존재하지 않기 때문에 사용 함수에서는 heal만 존재합니다. 우선 아이템의 회복력을 나타내는 heal을 가져온 뒤


위의 Heal함수에서 n이라는 변수로 정보를 가져오고 플레이어의 체력을 가져온 n만큼 회복합니다.

만약 플레이어의 체력이 최대체력을 넘어간다면 최대 hp로 만들어준 뒤 CanvasMansger에 SetHp함수를 통해 Canvas에 보여지는 플레이어의 체력바의 정보를 변경해줍니다.




위의 스크린 샷은 아이템 장착기능과 장착시 스탯 변화를 보여줍니다.

아이템 장착 시 스탯 변화가 일어나게 만들어주는 코드는 위와 같습니다.


우선 장비한 아이템의 정보를 불러옵니다.


Equipment의 haveItems의 코드는 아래와 같습니다.

[SerializeField] public Item[] haveItems = new Item[5] { null,null,null,null,null};

총 길이 5로 이루어져 있으며 투구, 갑옷, 건틀랫, 부츠, 무기 순서이고

방어구는 public int slotNum;의 변수를 가지고 있어 방어구가 무작위 또는 장착 순서로 변경되지 않고 고정된 위치에만 장착되게 만들어줍니다.


만약 장비 아이템을 장착할 때 for문을 통해 모든 방어구의 스탯을 현재 플레이어의 스탯에 +해주고, 무기의 경우는 무기만의 스탯을 플레이어의 스탯에 영향을 끼치게 해줍니다.


맨 아래의 DataSet은 장비창을 열었을 때 표시되는 플레이어의 스탯 텍스트를 바꿔줍니다. DataSet이 없다면 장비를 장착해도 스탯은 변화하지만 플레이어가 이를 확인할 수 없게 됩니다.





맵에있는 모루에 가까이 다가가면 강화 창이 열립니다.

강화 창은 인벤토리를 불러오는 것이 아닌 플레이어가 장착하고 있는 아이템의 정보를 가져옵니다. 때문에 인벤토리에 있는 장비를 강화할 수는 없습니다.



Upgrade의 clickSlot은 대부분 slotNum을 가져옵니다. 만약 현재 장착된 아이템이 없는 경우에는 모든 업그래이드 칸의 정보를 초기화 시켜 아이템이 장착돼 있지 않다는 걸 보여줍니다.


만일 장비가 장착돼 있는 경우 아이템의 정보를 이미지만 불러오지만 위에서 설명한 대로 스크립터블 오브젝트로 만든 데이터이기 때문에 모든 정보를 불러옵니다.

방어구는 최대 15강까지 있으며 6개의 속성을 가지고 있습니다.

순서대로 hp, mp, 힘, 지능, 물리방어, 마법방어 입니다.

위에 표기되는 강화에 필요한 아이템의 수량은 위의 정보에서 가져옵니다. 현재 게임에서는 0티어와 1티어의 아이템으로 분류되어 있습니다.

만약 아이템의 티어가 0이라면 위의 코드에서 보이는 0번 배열의 정보를 가져오고, 만일 1티어라면 1번 배열의 정보를 가져옵니다. 아래의 배열은 각각{일반 재료, 상위 재료}의 정보를 가지고 있습니다.


강화하고자 하는 아이템 클릭 시 나타나는 재료의 정보는 위의 코드를 이용해 가져옵니다

우선 일반재료와 상위재료의 정보를 인벤토리에서 가져오고 재료 정보 출력 주석이 달린 아래의 코드를 이용해 현재 가지고 있는 재료의 수와 필요한 재료의 수를 나타냅니다.

맨 아래의 Slots[7]의 경우는 본편에서는 사용되지 않고 개인용으로 사용됩니다.


만약 가지고 있는 아이템의 수량이 강화가 가능한 상태라면 강화 버튼을 활성화 시킵니다.


만약 무기일 경우에는 훨씬 복잡해집니다. 우선 만약 강화 단계가 최대라면 버튼을 비활성화 시키고 만약 물리 데미지가 0이라면 마법 공격력의 텍스트를 변화시키는데, 이 이유는 현재 만든 게임에서는 물리 공격력을 가진 무기는 오로지 물리 공격력만을 가지기 때문에, 마법 공격력이 설정된 무기라면 오로지 마법 공격력만을 가진다는 뜻이기에 한쪽 속성의 공격력만 표시하는 것입니다.


위의 코드는 방어구 처럼 클릭 시 보여주는 현재 장비 스탯과 업그래이드 후 장비의 스탯을 보여주는 코드입니다.

아래는 무기의 강화 데이터이며 물리 공격력과 마법 공격력이 따로 설정돼 있지 않기에 위에 설명한 대로 물리면 물리, 마법이면 마법만 설정할 수 있었습니다.


무기의 경우는 1레벨, 5레벨, 15레벨, 25레벨 제한으로 나뉘어져 있으며 그에 따라 불러오는 강화 재료 아이템 정보를 다르게 만듭니다.


현재는 1레벨 무기만 구현되여 있기 때문에 무기강화에 필요한 재료는 다음과 같이 고정돼 있습니다.


Try버튼을 누르면 아이템을 강화할 수 있고 아이템 강화는 확률에 따라 강화에 성공할 수 있고, 실패할 수 있습니다.

강화 확률은 배열로 미리 저장되어 있습니다.


강화의 경우는 위의 코드에서 진행됩니다. 만약 강화시 랜덤값인 r이 위에 올라와 있는 강화 확률 안에 안착한다면 강화가 진행됩니다.

위의 코드는 방어구 내에 있는 강화 함수이며 강화시 이 함수를 통해 현재 아이템의 스탯을 올려줍니다.


각 data배열은 위에 올려놨던 강화 정보를 가져옵니다.


강화를 마치고 장비창을 열어보면 상태창이 바뀐것을 확인할 수 있습니다.



지금 보이는 것은 상점의 구매 창 입니다.


상점은 Trigger를 이용해 플레이어가 가까이 온다면 상점을 열도록 했습니다.

상점은 Active On/Off로 키고 끄지만, 판매 패이지의 경우는 제 2의 인벤토리로 되여있기 때문에 Scene에 보이듯이 화면보다 위에 위치해 있다가 sell키를 누를 시 내려오는 형태로 되어있습니다.

위의 코드가 바로 그 예시입니다. 구매 페이지는 별도의 사라지는 정보가 존재하지 않기에 SetActive로 끄고 켜줍니다.


상점도 Image로 되여있지만, 인벤토리와 같이 이벤트 트리거를 통해 위의 함수를 통해 상점 아이템의 정보를 가져오게 만든 후 상점에 정보를 출력하게 합니다.


위의 코드는 아이템 구매 버튼을 눌렀을 때 반응을 보여주는 함수입니다. 만약 아이템을 살 돈이 충분하다면 구매한 아이템의 정보를 inven과 SellSlot에 저장한다. 아래의 UpgradeSlot은 테스트용으로 만들었지만 현재는 사용하지 않는 함수입니다.


이후에 상점 로그 텍스트를 나타나게 만들고 로그 텍스트를 이용해 상점의 아이템이 구매되었는지, 실패했는지를 보여줍니다.

위의 텍스트 플러그는 텍스트가 영구적으로 머무는 것이 아닌, 잠깐 머무르게 만듭니다. 혹시라도 텍스트가 나타나지 않았을 때의 혼란을 막기 위해서이기도 하고 일부 연출적인 이유도 있습니다.


만약 돈이 없다면 구매할 수 없다고 아래에 메세지가 나타납니다.

치트를 이용해 돈을 얻은 뒤 구매를 하여 인벤토리에 아이템이 생긴 모습입니다.


코인 추가는 위처럼 치트를 활성화 할 시 1000코인을 지급하게 되어있고, LosingCoin의 경우는 EarningCoin의 반대 역할을 수행합니다.



만약 마을 밖으로 나갈 경우 플레이어는 공격이 가능해집니다.


raycastHit을 통해 플레이어가 마을에 있는지를 파악하고, 만약 마을에 있으면 isTown을 true로 만들어 공격을 불가능 하게 만들어 줍니다.


마우스 좌클릭이 공격으로 할당되어 있습니다.


공격은 위의 함수로 작동한다 함수에서는 int n 을 가져오게 되여있지만 현재 구현된 기능은 case 0밖에 없습니다.


공격은 마우스를 클릭한 위치로 공격 발사체를 발사하는 형식으로 만약 공격하고자 하는 위치를 클릭하여 공격 진행 시 Ray와 RaycastHit으로 공격 위치를 가져옵니다.

만약 공격이 시작된다면 공격 발사체인 프리팹을 목표하고자 하는 위치로 발사시킵니다. 발사체는 공격 포인트를 앞으로 설정하고 회전합니다. 구현된 공격은 구 형태라 회전 상태를 구별하기 매우 힘듭니다. 만약 발사체가 5초가 적에게 맞히지 않고 지나갈 시 파괴하도록 설계했습니다.


공격 발사체는 start없이 Update를 통해 계속해서 움직이게 만들고 만약 몬스터와 접속 시 몬스터의 Dead 함수를 이용해 몬스터를 처치하게 됩니다.


몬스터를 처치 시 일정 확률을 주어 아이템이 떨어질 확률을 확인한 뒤 확률에 맞는 아이템을 드랍하게 설정되여있고, 아이템은 연출적인 이유를 위해 잠깐 위에 떠올랐다가 떨어지게끔 만들었습니다. 아이템 이외에도 코인과 경험치를 플레이어에게 주고 맨 아래의 MonsterCount의 Remove를 통해 현재 스폰되여있는 몬스터 수가 줄었다는 것을 인지시켜 주고 몬스터가 랜덤한 위치에 스폰하게 만듭니다.


몬스터는 만약 스폰되여있는 몬스터의 수가 개발자가 설정하고자 하는 수보다 적다면 몬스터가 출현하는 맵의 랜덤한 위치에 몬스터를 스폰하게 만들었습니다.


위의 사진은 몬스터 처치시 아이템이 드롭한 걸 보여주는 스크린샷으로 구현된 게임에서는 강화 소재만 드랍하게 만들었습니다.



바닥에 떨어진 아이템 가까이 가면 아이템을 얻을 수 있으며 이 정보는 인벤토리에 저장됩니다.


필드에 떨어진 아이템은 별도의 스크립트를 가지며 스크립터블 오브젝트의 정보를 받아와 정보를 가지게 됩니다.


그리고 OnTriggerEnter를 이용해 플레이어가 다가올 경우 아이템을 얻고 바닥에 떨어진 오브젝트를 파괴시킵니다.




개인수행


개인 수행으로는 강화의 방법의 변화를 주었습니다.

우선 본편에는 없던 확률 표시가 나타나있으며 확률 옆에는 보조 아이템의 사용 수를 나타내는 이미지와 텍스트가 있습니다.



인벤토리를 열어 보조 아이템을 이용하면 확률이 올라가게 되고 올라가는 %는 1%로 설정하였습니다.


아이템 사용 시 위의 코드를 통해 강화 확률이 올라가게 설정하게 되어있습니다.

아이템의 강화 확률은 배열에 저장되어 있기 때문에 만약 강화 확률을 올릴 경우 배열 자체의 데이터를 건드리기 때문에 모든 해당 등급의 강화 확률이 올라가게 되는 상황이 만들어져 있습니다.



위의 스크린샷은 그 문제점을 보여주는 상황으로 0강의 확률을 올리면 다른 장비를 불러올 때도 강화 확률이 같은 것을 볼 수 있습니다. 위에서는 투구의 확률을 올렸으나 여기에선 같은 방어구의 확률을 공유하는 갑옷까지 확률이 올라간 것이 보입니다.



그리고 구현 한계로 보조재료 사용 수는 다른 강화를 불러와도 바뀌지 않는다는 문제점이 있습니다.





Comentários


bottom of page