본문 바로가기
🌐 유니티 (Unity)

Day 37 - 3D 건축 시스템

by shin0707 2024. 6. 4.
728x90

  • 주제

>> 플레이어가 직접 건축물을 배치하게 하기


  • 공부내용

구현 단계 1. 프리뷰 오브젝트 생성

: 특정 키를 눌렀을 때, 프리뷰용 오브젝트를 생성

-> 'CreatePreviewObject'  함수에서 프리뷰 프리팹을 인스턴스화하고 초기 색상을 초록색으로 설정

 

구현 단계 2. 마우스 위치 따라다니게 하기

: 생성된 프리뷰 오브젝트가 마우스 위치를 따라다니게 설정 

-> 'FollowMouse' 함수에서 Raycasting을 사용하여 마우스 위치를 추적하고, 프리뷰 오브젝트를 그 위치로 이동

 

구현 단계 3. 건축 가능 위치 확인

: Terrain 위인지, 다른 오브젝트와 충돌하고 있는 지 여부를 확인

-> Terrain 오브젝트에 "Terrain" 태그를 추가

 

구현 단계 4. 건축 가능 여부 표시

: 건축 가능한 위치에서는 초록색, 불가능한 위치에서는 빨간색으로 표시

-> UpdatePreviewColor 함수에서 Raycasting으로 Terrain 태그를 가진 오브젝트 위에 있는지 확인하고, 충돌 여부를 IsColliding 함수로 확인하여 색상을 변경

 

구현 단계 5. 좌클릭으로 오브젝트를 배치 및 생성

: 초록색 상태에서 좌클릭하면, 실제 오브젝트를 생성

 

BuildingSystem.cs

using UnityEngine;

public class BuildingSystem : MonoBehaviour
{
    public GameObject previewPrefab; // 프리뷰 프리팹
    private GameObject currentPreview; // 현재 프리뷰 오브젝트
    private Material previewMaterial; // 프리뷰 오브젝트의 재질

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.B))
        {
            // B키를 눌렀을 때 프리뷰 오브젝트 생성
            CreatePreviewObject();
        }

        if (currentPreview != null)
        {
            // 프리뷰 오브젝트가 마우스를 따라다니게 함
            FollowMouse();
            // 건축 가능 여부 확인 및 색상 변경
            UpdatePreviewColor();
        }

        if (Input.GetMouseButtonDown(0) && previewMaterial.color == Color.green)
        {
            // 좌클릭 및 초록색일 때 실제 오브젝트 생성
            PlaceObject();
        }
    }

    // 프리뷰 오브젝트 생성
    void CreatePreviewObject()
    {
        currentPreview = Instantiate(previewPrefab);
        previewMaterial = currentPreview.GetComponent<Renderer>().material;
        previewMaterial.color = Color.green; // 초기 색상 초록색
    }

    // 프리뷰 오브젝트가 마우스를 따라다니게 함
    void FollowMouse()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit))
        {
            currentPreview.transform.position = hit.point;
        }
    }

    // 건축 가능 여부 확인 및 색상 변경
    void UpdatePreviewColor()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit))
        {
            if (hit.collider.gameObject.CompareTag("Terrain") && !IsColliding())
            {
                previewMaterial.color = Color.green; // 건축 가능
            }
            else
            {
                previewMaterial.color = Color.red; // 건축 불가능
            }
        }
    }

    // 다른 오브젝트와 충돌 여부 확인
    bool IsColliding()
    {
        Collider[] colliders = Physics.OverlapBox(currentPreview.transform.position, currentPreview.transform.localScale / 2);
        foreach (Collider collider in colliders)
        {
            if (collider.gameObject != currentPreview)
            {
                return true;
            }
        }
        return false;
    }

    // 실제 오브젝트 생성
    void PlaceObject()
    {
        Instantiate(previewPrefab, currentPreview.transform.position, Quaternion.identity);
    }
}
728x90

loading