일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 유니티공부
- c#코테
- unity3d
- unity3dservival
- 유니티게임만들기
- c# 백준
- Console.WriteLine
- 스파르타코딩클럽
- 스파르타
- c#프로그래머스기초문법
- Unity
- c#
- 시샵문법
- c#기초문법
- unity게임
- 유니티3dui
- unity게임만들기
- c# c#프로그래머스
- 유니티
- 오블완
- 시샵
- c#코딩기초트레이닝
- C#문법
- 유니티서바이벌게임만들기
- unity공부
- 티스토리챌린지
- 유니티상호작용
- c#문제
- c#기본문법
- unity3d게임만들기
- Today
- Total
나 개발자 진짜 되냐?
[ Unity 3D 서바이벌 게임 만들기 5 ] 아이템 상호작용 본문
자자!
이제
아이템을 만들어보고 상호작용을 해보자!
아이템을 만들고 상호작용하는것은 인터페이스를 활용 할 예정이다.
인터페이스에 대한 개념은
을 참고하자!!
먼저!
레이어 하나 추가해주자
7에다가 Interactable를 추가해주자.
다음 우리는 에임을 만들어주어야한다.
물건을 집든, 뭐 상호작용에 있어서
카메라 가운데에 에임은 필수적이다.
캠버스 안에 점을 하나 만들어보자!
이 점을 기준으로 Ray를 쏴서
닿는친구들과 상호작용 할 수 있게 만들어보자!
자 아이템을 만들어보자
빈옵젝을 만들고
Item_Wood 만들기
프리팹에서 Log를 찾아서
넣어주고
Log는 3가지가 나오는데
꼭 프리팹 모양으로 고르자!\
맨 오른쪽 꺼!
다음에 프리팹을 언팩해주고,
Log 안에있는 캡슐 콜라이더도 지워준다.
다음에 상위 옵젝으로 올라가서
( Item_Wood )에
box Collider을 넣어주자.
사이즈를 아이콘에 맞게
Edit Collider을 통해서 바꿔주자.
다음에는 아이템오브젝트 스크립트를 미리 넣어주자
그 이유는 이친구를 4개 더 복사할 예정..ㅎ
중력도 추가해주고!
Wood
0 // 0.15 // 0
2 // 0.3 // 0.3
Carrot
0 // 0.1 // 0
0.1 // 0.9 // 0.1
( 오브젝트 크기를 2 2 2로 키워줘야한다. )
Rock
0 // 0.05 // 0
0.3 // 0.3 // 0.3
Ax
- 0.1 // 0.2 // 0
0.3 // 0.8 // 0.1
Sword
0 // 0.5 // 0
0.2 // 1 // 0.1
5개 다 이렇게
진행하자!
자 실행해보면
이상하게
콜라이더가 뚝 하고 땅으로 떨어졌는데
아이콘은 그대로 있다..
그 이유는
여기 스태틱에 채크가 되어있어서 이다.
이 스태틱은 움직이지 않게 묶어주는 친구인데
이친구가 묶여있어서 하늘에 붕 떠있었던것이다.
이 친구를 채크 해제해주면 된다!
우리는 이제
이 아이템들을
프리팹이라는 폴더에 넣어주고,
ScriptableObject로
아이템들의 데이터를 세팅해주자!
< ItemData.cs >
using UnityEngine;
public enum ItemType // 아이템 타입
{
Resource, // 자원, 돌 나무 등등
Equipable, // 도끼 + 무기
Consumable // 당근 등 먹을것 사용될것
}
public enum ConsumableType
{
Hunger,
Health
}
[System.Serializable]
public class ItemDataConsumable
{
public ConsumableType type;
public float value;
}
[CreateAssetMenu(fileName = "Item", menuName = "New Item")]
public class ItemData : ScriptableObject
{
[Header("Info")]
public string displayName; // 아이템 이름
public string description; // 아이템 설명
public ItemType type; // 아이템 타입, 뭐 음식, 무기 등등
public Sprite icon; // 아이콘 정보
public GameObject dropPrefab; //프리팹 정보도 가지고 와본다.
[Header("Stacking")] // 아이템은 여러개 들고 있을 수 있다.
public bool canStack; // 여러개 아이템인가? 아닌가?
public int maxStackAmount; // 얼마나 많이 가지고 있을지
[Header("Consumable")] // 소비하는 아이템 중
public ItemDataConsumable[] consumables; // 체력회복이냐 배고픔 회복이냐 구분
[Header("Equip")]
public GameObject equipPrefab;
}
상속이
MonoBehaviour 이 아니라
스크립트오브젝트로 해줘야한다!
여기 보면 아이템 타입이 있다.
이 타입에는
우리가 5개를 만들면서
자원 두개 무기 두개 먹을것 하나로 만들었다.
이 아이템 타입은 우리가 열거형
Enum으로 정의해보자
클래스 나와서 맨 위에 적어보자!!
다시 내려와서
아이템은 갯수를 하나만 하기엔 ..아쉽다
변수로 몇개를 받아올지
여러개 아이템이 되는지 안되는지 체크해주자!
무기는 뭐 같은걸 10개 들고다닐 필요가 없기 때문!
소비아이템을 보면
음식 중에서도
체력을 회복해주는 체력물약과
배고픔을 잊게해주는 음식
두종류 이다.
이 또한 타입으로 구분되며 Enum으로 해주자
다음에
밑에서
클래스를 하나 만들어주고
위에 저 타입들과
얼만큼 회복시킬 value를 적어준다.
이렇게 해주었으면!
유니티로 돌아가보자
자 먼저
SO파일 안에
Data 폴더 생성
폴더 들어가서
새로 만들어보면
위에 New Item 이 있다.
해줘서 5개 만들어준다.
값을 하나하나 채워준다.
아이콘은 어디있냐!
여기 있습니다.
이렇게 하나하나 채워보자!
당근이다.
아까와의 차이점은
CanStack이다
위에는 한개만 가지고 있을 수 있게 해서
false해주기 위해 채크를 뺐고
당근의 경우
여러개 가지고 있을 수 있게 해주기위해
true 해주고
12개 가지고 있을 수 있게 해주었다.
이렇게 5개 다 해주고
마지막으로
프리팹으로 가서
Data에 SO를 넣어주면 된다!
만약 비활성화 되어있다?
data를 받아오면 된다!
옵젝 눌러서
apply all 여기 눌러줘서
프리팹까지 오버레이 해준다
자,이제
스크립트 폴더 안에
아이템 폴더만들어서
아이템 폴더안에
Item Object 스크립트 생성
이 스크립트를 작성해서
상호작용을 만들어보자
< ItemObject.cs >
using UnityEngine;
public class ItemObject : MonoBehaviour, IInteractable // 인터페이스 구현
{
public ItemData data; //상호작용 할때 필요한 기능들
public string GetInteractPrompt()
{ // IInteractable 이라는 컴포넌트를 찾았다면 그 인터페이스 안에 내용( 2개 ) 을 쓸 수 있다.
string str = $"{data.displayName}\n{data.description}"; // 프롬프트에 띄울 정보 ( 이름과 설명 )
return str; // 문자열 반환
}
public void OnInteract()
{ //정보를 player로 넘겨줘야하는데 직접적으로 넘길 수 없다.
CharacterManager.Instance.Player.itemData = data; // 내가 가진 데이터 넣어주기
CharacterManager.Instance.Player.addItem?.Invoke(); // 실행시키게 한다.
Destroy(gameObject); // 아이템을 인벤토리에 넣었으니 맵에서 지우기
}
}
public interface IInteractable
{
public string GetInteractPrompt(); // 화면에 띄워줄 프롬프트
public void OnInteract(); // 인터렉트 됐을때 어떻게 할건지
}
지금은 data만 넣어주었지만
타입의 갯수도
또 그 아이템의 개수도 엄청 많으면
그만큼 조건문도 많아진다.
그러면 엄청 복잡해질테니
인터페이스를 하나 만들어보자
인터페이스는 I를 앞에 붙여서
인터페이스 사용
그리고 IInteractable에 빨간줄에서
ctrl . 해주면
인터페이스 구현이라고 뜬다
엔터 해주고
값을 넣어준다.
Get을 통해
컴포넌트를 찾게하고
찾았다면
아이템 이름과 설명을 문자열에 넣어서 출력해준다.
만약 못찾았다면 고대로 나가준다.
다음에 상호작용이 될 때!
내가가진 데이터를
player에 넣어주고
실행시켜준다.
그 다음에 아이템을 먹었으니
맵에서 템들을 지워준다.
OnInteract에는
player.itemData와 addItem 이 있는데
이친구들은 지금 우리가 player로 가서
추가시켜주자!
해주면 오류가 없다!
자 Interaction.cs도 player 폴더 안에 만들어주자
< Interaction.cs >
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
public class Interaction : MonoBehaviour
{ // 카메라를 기준으로 Ray를 쏠 것이다.
public float checkRate = 0.05f; // 얼마나 자주 업데이트 될 것인가.
private float lastCheckTime; // 마지막 채크시간
public float maxCheckDistance; // 얼마나 멀리 있는지 채크
public LayerMask layerMask; // 레이어마스크 어떤 레이어마스크를 추출할건지
public GameObject curInteractGameObject; // 현재 상호작용 된 오브젝트를 가지고 있을 것이다.
private IInteractable curInteractable; // 인터페이스 캐싱된 정보가 여기 담긴다.
public TextMeshProUGUI promptText; // 프롬포트에 보이게 하기
private Camera camera;
void Start()
{ // 카메라는 메인카메라 값을 넣어준다.
camera = Camera.main;
}
void Update()
{ // 계속 상호작용 할 수 있게끔 Ray를 쏴줘야한다.
if (Time.time - lastCheckTime > checkRate) // 얼마나 자주 검사해줄건지,
{
lastCheckTime = Time.time; // 마지막시간을 여기 넣어주고,
// Ray는 카메라에서 쏜다. 정중앙에서 쏘기 위해 /2를 해준다.
Ray ray = camera.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2));
RaycastHit hit; // 부딪히면 여기 데이터가 담기게끔
if (Physics.Raycast(ray, out hit, maxCheckDistance, layerMask)) // 충돌이 됐을때
{
if (hit.collider.gameObject != curInteractGameObject) // 상호작용인 오브젝트가 없다면
{
curInteractGameObject = hit.collider.gameObject; // 새로운 오브젝트 넣어주기
curInteractable = hit.collider.GetComponent<IInteractable>(); // 컴포넌트 가져오기
SetPromptText(); // 이 정보를 담아뒀다면 프롬포트에 출력해주라
}
}
else
{ //빈공간에 쐈다면 정보를 암것도 없게 비워둬야한다. 새로 넣을 자리도 만들 겸,
curInteractGameObject = null;
curInteractable = null;
promptText.gameObject.SetActive(false); // 프롬포트 꺼주기
}
}
}
private void SetPromptText() // 프롬포트에 출력해주기
{
promptText.gameObject.SetActive(true); // 프롬포트 보이게 하기
promptText.text = curInteractable.GetInteractPrompt(); // ItemObject.cs에 있는 함수가 실행된다.
}
public void OnInteractInput(InputAction.CallbackContext context)
{ // e 키를 눌렀을때 작동하게끔 해주는 엑션
if (context.phase == InputActionPhase.Started && curInteractable != null)
{ // 버튼이 눌렸을때, 허공에 아이템을 눌리지 않았을때 ( = 물건을 바라볼때 )
curInteractable.OnInteract(); // 상호작용한다.
curInteractGameObject = null; // 상호작용하고나서 꺼주기
curInteractable = null;
promptText.gameObject.SetActive(false); // 프롬포트 꺼주기
}
}
}
주석에도 써놨지만 여기서는
상호작용 되는 친구들에 대해 써주는 친구들이다.
이제 ray를 지속적으로 쏘기 위해
update문에 작성해준다.
맨 위에 if Time는 뭐냐
update로 해주면 매프레임마다 검사해주면 최적화가 떨어지기 때문에
지금 시간에서 마지막 검사한 시간을 빼준게
0.05f 초가 넘어가면
마지막 시간을 지금시간으로 해줘서
이 로직을 한번 더 실행하게 끔 한다.
마지막쯤에 SetPromptText가 누구냐면
바로
이 친구
프롬포트를 보여주고
정보를 가져와서 text에 넣어준다.
가져오는건 어디냐..!!
curInteractable.GetInteractPrompt();
앞에
curInteractable 이 부분은
인터페이스 상속 해주었던
여기 이다.
이 인터페이스로 가보면
여기 GetInteractPrompt에 의해
str이 리턴된다.
마지막으로 엑션을 켜줘서
진짜 눌렸을때, 작동하게 끔 되는 함수를 적어준다.
자!
유니티에가서 확인해보자
Ray를 해줄거니까
Layer를 Interactable로 해주고
Player가서
먼저
Interaction스크립트를 드래그 드롭 해준 후
Player Input에 이벤트를 눌러서
Player 옵젝 붙여넣고
OnInteractInput을 넣어주면 끝!
이제 TextMashPro를 만들어준다.
캠버스에 하나 만들어주면
임포트 메시지가 뜬다.
위에꺼만 import해준다.
Window > TextMashPro > Font Asset Creator
에 들어가서
이렇게 설정하고
Generate 해준다.
다음에
Save가 뜨면
폰트라는 폴더 만들어서
그 안에다가 저장하고
Text로가서 드래그 해주면 끝!
진짜 끝!
자 이제 이 아이템들을
상호작용해주는거까지 성공했다.
이제 이 템을 가져다대고 버튼을 눌렀을때 사라지게되면
인벤토리로 이동하게끔 정보를 줘보자!
긴 내용이 될 듯하다..!!
화이팅!!
'유니티를 공부해봐요! > 중급이에요!' 카테고리의 다른 글
[ Unity 3D 서바이벌 게임 만들기 7 ] 아이템 장착 그리고 공격 (1) | 2024.10.29 |
---|---|
[ Unity 3D 서바이벌 게임 만들기 6 ] 인벤토리 & 아이템 사용 (0) | 2024.10.29 |
[ Unity 3D 서바이벌 게임 만들기 4 ] 낮과 밤 구현 (2) | 2024.10.28 |
[ Unity 3D 서바이벌 게임 만들기 3 ] 플레이어 대미지 처리 (1) | 2024.10.28 |
[ Unity 3D 서바이벌 게임 만들기 2 ] UI 만들기 (1) | 2024.10.27 |