▶▷ 건축 제한 기능
CraftTable
using UnityEngine;
using UnityEngine.UI;
public class CraftTable : MonoBehaviour
{
public Button button;
public GameObject box;
public GameObject UI;
public GameObject Player;
private Camera cam;
private LayerMask layerMask;
private Ray ray;
private float Angle;
// 배치 모드 활성 여부
private bool IsSelect = false;
// 배치 가능 상태 여부
public bool CanPlace;
[SerializeField] private Build_Prefabs build_Prefabs;
private void Awake()
{
cam = FindAnyObjectByType<Camera>();
layerMask = LayerMask.GetMask("ground", "Wall");
}
private void Start()
{
button.onClick.AddListener(Craft);
}
private void Update()
{
Drop();
}
private void FixedUpdate()
{
Place();
// 화면 중앙에서 레이 생성
ray = cam.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2));
}
// 배치 모드 시작 및 아이템 프리팹 생성
private void Craft()
{
UI.gameObject.SetActive(false);
// 아이템 프리팹 생성
Instantiate(box, box.transform.position, Quaternion.identity);
IsSelect = true;
CanPlace = true;
Debug.Log("부품 선택");
}
private void Place()
{
if (IsSelect)
{
RaycastHit hit;
// 10 이내의 그라운드를 감지하고, 플레이어와의 거리가 10 미만일 때
if (Physics.Raycast(ray, out hit, 10f, layerMask) && Vector3.Distance(Player.transform.position, hit.point) < 10f)
{
if (hit.collider != null)
{
CanPlace = true;
// 배치 가능 상태 색상으로 변경
box.transform.GetChild(0).GetComponent<Build_Prefabs>().ColorChange(2);
//// 충돌면의 법선과 오른쪽 벡터의 외적으로 전방 방향 계산
//Vector3 forward = Vector3.Cross(hit.normal, Vector3.right);
// 표면의 법선에 맞춰 회전
Quaternion baseRotation = Quaternion.LookRotation(-hit.normal);
Quaternion additionalRotation = Quaternion.Euler(0, Angle, 0);
box.transform.rotation = baseRotation * additionalRotation;
// 아이템 위치를 감지된 지점으로 이동
box.transform.position = hit.point;
}
}
// 플레이어와의 거리가 10 이상이면 배치 불가
else if (Vector3.Distance(Player.transform.position, hit.point) >= 10f)
{
CanPlace = false;
// 배치 불가 상태 색상으로 변경
box.transform.GetChild(0).GetComponent<Build_Prefabs>().ColorChange(1);
Debug.Log("너무 멀음");
}
}
}
// 아이템 배치 및 회전 (클릭 계속하면 디버그 로그 계속 찍히는 현상 수정 필요)
private void Drop()
{
if (CanPlace && Input.GetMouseButtonDown(0))
{
IsSelect = false;
box.transform.GetChild(0).GetComponent<Rigidbody>().isKinematic = true;
// 배치 완료 상태 색상으로 변경
box.transform.GetChild(0).GetComponent<Build_Prefabs>().ColorChange(0);
// 배치 UI 다시 활성화
UI.gameObject.SetActive(true);
Debug.Log("배치");
}
// 우클릭: 아이템 회전
else if (Input.GetMouseButtonDown(1))
{
Angle += 90f;
}
}
}
레이캐스트가 탐지 가능한 레이어를 Ground와 Wall로 설정해두고 해당 레이캐스트가 닿는 부분에 배치할 프리팹의 프리뷰를 생성한다.
프리뷰는 탐지한 레이어를 가진 오브젝트의 법선과 맞춰 움직이도록 하여 각도를 자연스럽게 맞췄다.
좌클릭 시 배치 확정, 우클릭 시 프리뷰를 90도씩 회전시킬 수 있다.
설치 가능 여부를 판단하고 해당 결과에 맞는 색상의 정보를 아래 Build_Prefabs 스크립트에 작성한 색 변경 메서드에 전달하는 방식이다.
Build_Prefabs
using UnityEngine;
public class Build_Prefabs : MonoBehaviour
{
public Ray ray;
[SerializeField] private Material Red;
[SerializeField] private Material Green;
[SerializeField] private CraftTable craftTable;
private LayerMask layerMask;
private Material[] materials;
private MeshRenderer meshRenderer;
private void Awake()
{
meshRenderer = GetComponent<MeshRenderer>();
// 현재 메시 렌더러의 머티리얼들을 복사하여 배열에 저장
materials = new Material[meshRenderer.materials.Length];
for (int i = 0; i < materials.Length; i++)
{
materials[i] = meshRenderer.materials[i];
}
layerMask = LayerMask.GetMask("ground", "Wall");
}
private void OnTriggerStay(Collider other)
{
// 충돌한 오브젝트가 그라운드 레이어가 아니라면
if (other.gameObject.layer != LayerMask.NameToLayer("ground") && other.gameObject.layer != LayerMask.NameToLayer("Wall"))
{
// 배치 불가능 상태 머티리얼
ColorChange(1);
// CreftTable의 배치 가능 여부를 false로 설정
craftTable.CanPlace = false;
Debug.Log("배치 불가능");
}
}
public void ColorChange(int index)
{
// 원본 머티리얼 배열의 길이와 같은 새 배열 생성
Material[] NewMaterialArray = new Material[materials.Length];
// 모든 머티리얼을 인덱스에 해당하는 머티리얼로 변경
for (int i = 0; i < NewMaterialArray.Length; i++)
{
NewMaterialArray[i] = materials[index];
}
// 메시 렌더러에 새로운 머티리얼 배열 적용
meshRenderer.materials = NewMaterialArray;
}
}
머티리얼을 배열로 생성한 다음, 설치할 수 없을 경우 1번 인덱스(빨강), 설치 가능한 경우 2번 인덱스(초록), 설치를 완료했을 경우 0번 인덱스(원본)로 색상을 바꾼다.
OnTriggerStay()에서 배치 가능 여부를 판단해서 바로 메서드를 사용하려 했으나
배치 예상 거리가 멀어져서 배치 불가 상태가 되었을 경우 다시 가까이 가져오면 배치 가능 상태로 전환되어야 하는데 생각과는 다르게 구현되지 않았다.
그래서 Build_Prefabs에서는 플레이어와 너무 가까이 배치할 수 없도록 하는 로직만 넣게 되었다.
▶▷ 트러블 슈팅
막히는 점
1. 거리에 따른 설치 가능 여부 판단 및 색 변경이 제대로 이루어지지 않는 현상
2. 첫번째 프리펩을 설치 이후에 두번째 프리펩을 설치한 상태에서 플레이어와 닿을 시 경우 프리펩이 설치 불가 색상으로 변경되는 현상
시도한 점
1. bool형 변수를 추가하여 관리 시도
2. 아직 원인을 찾지 못함
해결
1. 기존의 Build_Prefabs에서 설치 가능 여부 판단과 색을 변경하는 기능까지 포함했던 방식에서 Build_Prefabs에서는 색을 변경하는 메서드만 사용하고 CraftTable에서 설치 가능 여부를 판단하여 Build_Prefabs에 전달하는 방식으로 변경
'게임 개발 공부 기록' 카테고리의 다른 글
39일차 - Path Of Survival 팀 프로젝트 마무리 (0) | 2025.03.19 |
---|---|
38일차 - 에셋 관리 (0) | 2025.03.18 |
36일차 - Path Of Survival 팀 프로젝트 3 (0) | 2025.03.14 |
35일차 - Path Of Survival 팀 프로젝트 2 (0) | 2025.03.13 |
34일차 - Path Of Survival 팀 프로젝트 1 (0) | 2025.03.12 |