<aside> 💡 Notion 팁: 새 페이지를 만들고 템플릿 목록에서 데일리 일기를 선택해 매일 아래 양식을 자동으로 생성할 수 있어요.

</aside>

오늘은 무엇을 배웠나요

  1. 최종 팀 과제

이야깃거리

<aside> 🔢 27. MonoBehaviour 클래스의 주요 메서드와 그 기능에 대해 설명해주세요.

Initialization 부분에서는 Awake(), OnEnable(), Start()가 있습니다. Awake()는 스크립트가 실행될 때 1번만 호출되며, 오브젝트가 비활성화일 경우 호출되지 않지만 스크립트가 비활성화일 경우 호출됩니다. 주로 게임의 상태 또는 변수 초기화로 사용합니다. OnEable()은 오브젝트 또는 스크립트가 활성화될 때마다 호출됩니다. Start()는 스크립트가 활성화될 때 1번만 호출됩니다. Awake()와의 차이점은 Start()는 오브젝트 또는 스크립트가 비활성화일 경우 호출되지 않습니다.

Physics 부분에서는 Update(), FixedUpdate(), LateUpdate()가 있습니다. Update()는 매 프레임마다 호출되는 함수로, 기기 성능에 따라 프레임이 변하여 함수 호출 시간이 매번 달라집니다. FixedUpdate()는 Update()와 달리 함수 호출 간격이 일정하여, 같은 주기로 연산을 처리해야 하는 물리 계산에 주로 사용됩니다. LateUpdate()는 모든 Update()가 호출된 후 호출되고, 주로 카메라 움직임에 사용됩니다. 예를 들어 Update()에서 캐릭터 이동을 처리하면, LateUpdate()에서는 캐릭터 이동 이후 카메라 움직임을 처리합니다. OnTrigger류와 OnCollision류의 함수는 두 오브젝트의 충돌 체크를 하는 함수입니다. Trigger는 물리 연산을 하지 않고 통과하며, Collision은 물리 영향을 받는다는 차이점이 존재합니다.

Decommissioning에서는 OnApplicationQuit(), OnDisable(), OnDestroy()가 있습니다. OnApplicationQuit()는 프로그램 종료 전 모든 오브젝트에서 호출됩니다. OnDisable은 오브젝트 또는 스크립트가 비활성화될때마다 호출됩니다. OnDestroy()는 오브젝트가 파괴되기 직전 마지막 프레임이 업데이트된 후 실행됩니다.

</aside>

MapIlluminator의 Initialize()에서 3중 for문을 2중 for문으로 줄이는 데에는 성공했다!

using System;
using UnityEngine;

[Serializable]
public struct VerticesArray
{
    public Vector3[] Verticearray;
}

[Serializable]
public struct ColorsArray
{
    [SerializeField]
    public Color[] Colorarray;
}

public class MapIlluminator : MonoBehaviour
{
    private GameObject _shadowPlanePrefab;
    private GameObject[] _shadowPlanes;
    private Transform _player;
    private Mesh[] _meshes;
    private LayerMask _shadowLayer;
    private VerticesArray[] _verticesArray;
    [SerializeField] private ColorsArray[] _colorsArray;

    private float _shadowRadius = 250f;
    private int _numPlanesX = 11;
    private int _numPlanesZ = 3;
    private float _radiusCircle { get { return _shadowRadius; } }

    private void Awake()
    {
        Initialize();
    }

    private void Initialize()
    {
        _shadowPlanePrefab = Managers.Resource.GetCache<GameObject>("ShadowPlane.prefab");
        _shadowPlanes = new GameObject[_numPlanesX * _numPlanesZ];
        _meshes = new Mesh[_shadowPlanes.Length];
        _shadowLayer = LayerMask.GetMask("ShadowLayer");
        _verticesArray = new VerticesArray[_shadowPlanes.Length];
        _colorsArray = new ColorsArray[_shadowPlanes.Length];

        GameObject shadowPlanesParent = new GameObject("ShadowPlanes");

        for (int i = 0; i < _shadowPlanes.Length; i++)
        {
            int row = i / _numPlanesZ;
            int col = i % _numPlanesZ;

            Vector3 spawnPosition = new Vector3(row * 100 - 500, 40, col * -100 + 100);

            _shadowPlanes[i] = Instantiate(_shadowPlanePrefab, spawnPosition, Quaternion.Euler(90, 0, 0));
            _shadowPlanes[i].transform.parent = shadowPlanesParent.transform;

            _meshes[i] = _shadowPlanes[i].GetComponent<MeshFilter>().mesh;
            _verticesArray[i] = new VerticesArray { Verticearray = _meshes[i].vertices };
            _colorsArray[i] = new ColorsArray { Colorarray = new Color[_verticesArray[i].Verticearray.Length] };

            for (int k = 0; k < _colorsArray[i].Colorarray.Length; k++)
            {
                _colorsArray[i].Colorarray[k] = Color.black;
            }
        }
    }

    ...
}

Update()의 2중 for문은 어떻게 줄여야 하는지 고민이다. 🤔

진영님이 bfs를 써보라고 하셨다. bfs,, 이론만 알고 한번도 응용해본 적이 없는데 🥲

플레이어가 shadowplane에 레이를 쏘면 맞은 shadowplane을 받아와서 반지름만큼 그 주변 값만

private void Update()
{
    Ray ray = new Ray(_player.position, Vector3.up);
    RaycastHit hit;

    if (Physics.Raycast(ray, out hit, 1000, _shadowLayer, QueryTriggerInteraction.Collide))
    {
        int planeIndex = FindPlaneIndex(hit.collider.gameObject);

        if (planeIndex != -1)
        {
            for (int j = 0; j < _verticesArray[planeIndex].Verticearray.Length; j++)
            {
                Vector3 vector3 = _shadowPlanes[planeIndex].transform.TransformPoint(_verticesArray[planeIndex].Verticearray[j]);
                var temp = vector3 - hit.point;
                temp.y = 0;
                float distance = Vector3.SqrMagnitude(temp);

                if (distance < _radiusCircle * _radiusCircle)
                {
                    float alpha = Mathf.Min(_colorsArray[planeIndex].Colorarray[j].a, distance / _radiusCircle);
                    _colorsArray[planeIndex].Colorarray[j].a = alpha;
                }
            }

            UpdateColors(planeIndex);
        }
    }
}

private int FindPlaneIndex(GameObject plane)
{
    for (int i = 0; i < _shadowPlanes.Length; i++)
    {
        if (_shadowPlanes[i] == plane)
        {
            return i;
        }
    }

    return -1; // 해당하는 shadowplane을 찾지 못한 경우
}

Untitled

지도를 보면 이런 식으로 해당 shadowplane까지만 검사를 해서 인접한 shadowplane의 경계에 와도 색이 변하지 않는다.