프리팹을 활용하면 게임오브젝트를 원하는 만큼 언제든 팍팍 뽑아서 사용할 수 있어서 편합니다.
하지만 프리팹을 다시 풀 순 없을까요?
저는 푸는 방법을 몰라서 이상한짓을 하다가 대장님께 SOS 보냈습니다.
🕹️ 프리팹을 게임오브젝트로 변경하는 방법
1. 기존에 만들어 둔 프리팹을 Hierarchy창에 드래그 앤 드롭! 이러면 씬에 배치됩니다.
2. 해당 game object를 우클릭 > Prefab > Unpcak
3. 프리팹 풀린 것을 확인
프리팹이 풀리면 해당 game object를 아무리 수정해도 prefab에는 영향이 없습니다.
🕹️ 해당하는 식재료 위에 아이콘 배치하기
제가 프리팹을 언팩한 이유는 테스트를 위해서입니다.
1. 해당하는 재료와 재료 아이콘을 연결 후 재료위에 재료 아이콘 표시하기
2. 재료가 접시에 올려지면 해당하는 재료 아이콘 연결하기
3. 완료됐다면 테스트했던 자료들 정리하고 스크립트와 재료 아이콘 깃헙에 병합하기
우선 1번부터 진행 해봅시다.
1. 해당하는 재료와 재료 아이콘을 연결 후 재료위에 재료 아이콘 표시하기
모든 재료 위에 아이콘이 표시되는 것이 아닙니다.
접시에 올릴 수 있는 재료. 즉 다듬어진 재료만 아이콘이 표시될 수 있게 해줘야합니다.
재료 아이콘 리스트를 만들어서, 해당하는 재료 인덱스를 찾아 아이콘을 리턴하는 방식으로 생각해봤습니다.
재료 아이콘 리스트 = [양배추, 토마토, 오이];
재료 리스트 = [양배추, 토마토, 오이]
만약 양배추가 다듬어졌다면 재료 아이콘에서도 양배추를 가져오는 방식으로(편의를 위해 인덱스 맞춤)
다듬어진 재료의 정보는 대장님이 넘겨주셨으니 저는 넘겨주신 인덱스를 바탕으로 재료 아이콘을 유니티 씬에 출력하는 스크립트를 작성했습니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
// 재료 아이콘 UI 리스트를 만들고
// 재료가 0(썰기 전)에서 1(썰기 후)로 변경되면
// 알맞는 재료의 머리 위에 재료 아이콘 UI가 표시되게 만든다.
public class IngredientUI : MonoBehaviour
{
// 재료 아이콘 UI 프리팹을 담을 리스트
public List<GameObject> ingredientIconList;
public GameObject iconUI;
public GameObject canvas;
Ingredient ingredient;
void Update()
{
// 현재 상태 인덱스
// 재료에 올라갈 아이콘인지 접시에 올라갈 아이콘인지 판별
if (gameObject.CompareTag("Ingredient"))
{
// get
int curFormIdx = ingredient.CUR_FORM_INDEX;
// 재료가 다듬어졌다면
if (curFormIdx == 1)
{
// 아이콘 UI를 활성화
iconUI.SetActive(true);
}
else
{
// 아이콘 UI를 비활성화
iconUI.SetActive(false);
}
}
}
스크립트를 작성하고 리스트에 프리팹을 넣어주면 위와같이 썰려진 재료 위에 아이콘이 뜨는걸 확인할 수 있습니다.
아무래도 팀플이기 때문에 제 스크립트로만 동장하는 것이 아니기에 만약 누군가 이 글을 본다면 코드 자체가 도움이 될 수 있을진 미지수라는 생각이 들기시작했다.
2. 해당하는 재료와 재료 아이콘이 연결하기
3. 재료가 접시에 올려지면 해당하는 재료 아이콘 연결하기
저는 NomalPlate에 연결 된 스크립트에서 Plate Ingredients ID List들을 가져와야합니다.
해당 리스트에는 접시에 올라간 재료의 정보가 들어옵니다.
저는 재료의 정보를 읽어서 일치하는 아이콘을 가져와서 접시 위에 나란히 배치하면 됩니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
// 재료 아이콘 UI 리스트를 만들고
// 재료가 0에서 1로 변경되면
// 알맞는 재료의 머리 위에 재료 아이콘 UI가 표시되게 만든다.
public class IngredientUI : MonoBehaviour
{
// 재료 아이콘 UI 리스트
public List<GameObject> ingredientIconList;
public GameObject iconUI;
public GameObject canvas;
PlateIngredient plateIngredient;
Ingredient ingredient;
// 버튼 눌렸는지 아닌지
bool isKeyBtnDown;
private void Start()
{
if (gameObject.CompareTag("Plate"))
{
plateIngredient = GetComponent<PlateIngredient>();
}
else if (gameObject.CompareTag("Ingredient"))
{
ingredient = GetComponent<Ingredient>();
}
//iconUI.SetActive(false);
bool isKeyBtnDown = false;
}
// Update is called once per frame
void Update()
{
// 현재 상태 인덱스
// 재료에 올라갈 아이콘인지 접시에 올라갈 아이콘인지 판별
if (gameObject.CompareTag("Ingredient"))
{
// get
int curFormIdx = ingredient.CUR_FORM_INDEX;
if (Input.GetKeyDown(KeyCode.Alpha9) || curFormIdx == 1)
{
//if (isKeyBtnDown == false)
iconUI.SetActive(true);
isKeyBtnDown = true;
}
else
{
iconUI.SetActive(false);
isKeyBtnDown = false;
}
}
else if (gameObject.CompareTag("Plate"))
{
// 접시에 놓여진 식재료 리스트를 가져와서
// 리스트에 놓인 재료의 번호를 확인하고
// 번호와 일치하는 재료를 Ingredient Ui List에서 가져와서
// 접시 상단에 배치하라
if(iconList.Count >= plateIngredient.platedIngredientsIDList.Count)
{
return;
}
// count가 0이 아니면 for문 시작
if (plateIngredient.platedIngredientsIDList.Count != 0 && iconList.Count <= plateIngredient.platedIngredientsIDList.Count)
{
foreach(GameObject ingUI in iconList)
{
Destroy(ingUI);
}
iconList.Clear();
for (int i = 0; i < plateIngredient.platedIngredientsIDList.Count; i++)
{
int id = plateIngredient.platedIngredientsIDList[i];
GameObject currentIdIconGameObject = Instantiate(ingredientIconList[id], canvas.transform);
currentIdIconGameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(0.5f, 0.5f);
iconList.Add(currentIdIconGameObject);
}
}
}
}
//아이콘 UI 리스트
public List<GameObject> iconList;
}
해당 스크립트를 작성해주면, 접시위에 올라간 재료를 반복문으로 확인해서 리턴해줍니다.
3.1. 문제점 : UI 크기가 너무 크고 게임 오브젝트가 무한히 생성된다.
처음에 문제점이 있었습니다.
접시에 재료를 올리면 굉장히 큰 UI 나타나서 화면 전체를 가리고, 그 UI들이 무한으로 생성되는 것이었습니다.
아무래도 Update문에 Instantiate를 사용하여 프레임마다 UI가 계속 생성된 거 같았습니다.
그래서 조건을 달았습니다.
else if (gameObject.CompareTag("Plate"))
{
// 접시에 놓여진 식재료 리스트를 가져와서
// 리스트에 놓인 재료의 번호를 확인하고
// 번호와 일치하는 재료를 Ingredient Ui List에서 가져와서
// 접시 상단에 배치하라
if(iconList.Count >= plateIngredient.platedIngredientsIDList.Count)
{
return;
}
// count가 0이 아니면 for문 시작
if (plateIngredient.platedIngredientsIDList.Count != 0 && iconList.Count <= plateIngredient.platedIngredientsIDList.Count)
{
foreach(GameObject ingUI in iconList)
{
Destroy(ingUI);
}
iconList.Clear();
for (int i = 0; i < plateIngredient.platedIngredientsIDList.Count; i++)
{
int id = plateIngredient.platedIngredientsIDList[i];
GameObject currentIdIconGameObject = Instantiate(ingredientIconList[id], canvas.transform);
currentIdIconGameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(0.5f, 0.5f);
iconList.Add(currentIdIconGameObject);
}
}
}
}
//아이콘 UI 리스트
public List<GameObject> iconList;
}
아래 코드를 보면
첫 if문에서 iconList.Count가 접시에 올라간 재료의 개수보다 많아지면 return하도록 만들었습니다.
이렇게 된다면 실제 접시에 올라간 재료보다 아이콘 리스트가 많아지면 instantiate가 실행되지 않아서
gameobjec 무한 생성 사건이 멈추겠죠?
다음 if문을 보면, 접시에 재료가 없을때도 Update문이 실행 될 필요가 있을까요?
없으니까 빈접시가 아닐때에만 반복문이 발생하도록 조건을 걸었습니다.
그리고 foreach를 해준 후 밑에 Destroy로 gameObject를 파괴한 이유는
만약 접시에 토마토가 들어왔다면? 토마토를 출력
그런데 토마토 뒤에 오이가 또 들어왔다면?
기존 토마토 삭제하고 다시 토마토와 오이 올리기
그 뒤에 양배추가 들어왔다면?
기존에 있던 토마토와 오이를 삭제하고 다시 토마토, 오이 양배추 배치
아래 for문에서는 ui크기 문제를 sizeDelata = new Vector2(x, y);로 해결했고
최종적으로 접시에 노출되는 아이콘 리스트를 생성하는 것으로 마무리했습니다.
(병합 후 사진 추가 할 예정)
3. 완료됐다면 테스트했던 자료들 정리하고 스크립트와 재료 아이콘 깃헙에 병합하기
(오늘 19시에 병합하고 플레이 화면 올릴 예정)
'동식이 취업시키기 작전' 카테고리의 다른 글
[백준] 10866 덱(c#) (0) | 2024.01.22 |
---|---|
[융합 프로젝트] 포톤 입장한 플레이어 닉네임 가져오기, 플레이어가 입장하면 알림해주기, 입장한 플레이어 UI로 나타내기(실패ㅠㅠ) (1) | 2023.11.11 |
[UNITY] DestroyZone에 Player가 닿으면 게임 종료되기 (0) | 2023.07.20 |