카테고리 없음

2025_03_04 TIL

chajungto0211 2025. 3. 4. 20:58
이 글은 평범한 취준생이 평범하게 자신이 당일 배운것들과 느낀점들을 쓰기 때문에 정보가 정확하지 않을 수 있습니다.

드디어 길게 느껴졌던 입문 주차 과제가 끝나고, 오늘부터 본격적인 숙련주차이다. 혹시나 해서 조금 강의의 초반부를 학습하고 오기는 했지만, 오늘 공부하면서 정말 내가 알고 넘어가는지 모르고 넘어가는지 잘 분간이 안되었고, 나중에 코드를 다시 보자니 코드가 어느새 길어져서 보기조차 막막했고, 아직 개인 과제를 어떻게 할 지도 못정한 것에 대해 답답함만 느껴졌다. 그래도 오늘 배운것들 중 그나마 지금 내 머리속에 있는 것이 날아가면 안되니까, 천천히 상기하면서 무엇을 학습했는지 써 보도록 하자.

 

1. 낮과 밤

강의 중에 낮과 밤의 사이클을 빛을 이용해서 나타나게 하는 방법을 가르쳐주었다. 일단 코드를 먼저 보자.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DayNightCycle : MonoBehaviour
{
    [Range(0f, 1f)]
    public float time;
    public float fullDayLength;
    public float startTime = 0.4f;
    private float timeRate;
    public Vector3 noon;

    [Header("Sun")]
    public Light sun;
    public Gradient sunColor;
    public AnimationCurve sunIntensity;

    [Header("Moon")]
    public Light moon;
    public Gradient moonColor;
    public AnimationCurve moonIntensity;

    [Header("Other Lighting")]
    public AnimationCurve lightIntensityMultiplier;
    public AnimationCurve reflectionIntensityMultiplier;

    private void Start()
    {
        timeRate = 1.0f / fullDayLength;
        time = startTime;
    }

    private void Update()
    {
        time = (time + Time.deltaTime * timeRate) % 1.0f;
        UpdateLight(sun, sunColor, sunIntensity);
        UpdateLight(moon, moonColor, moonIntensity);

        RenderSettings.ambientIntensity = lightIntensityMultiplier.Evaluate(time);
        RenderSettings.reflectionIntensity = reflectionIntensityMultiplier.Evaluate(time);
    }

    //각도 계산 및 색상 조정????
    void UpdateLight(Light lightSource, Gradient gradient, AnimationCurve intensityCurve)
    {
        float intensity = intensityCurve.Evaluate(time);

        lightSource.transform.eulerAngles = (time - (lightSource == sun ? 0.25f : 0.75f)) * noon * 4f;
        lightSource.color = gradient.Evaluate(time);
        lightSource.intensity = intensity;

        GameObject go = lightSource.gameObject;

        if (intensity == 0 && go.activeInHierarchy)
        {
            go.SetActive(false);
        }
        else if (intensity > 0 && !go.activeInHierarchy)
        {
            go.SetActive(true);
        }

    }
}

 

Light, Gradient, AnimationCurve로 태양 또는 달의 역할을 하는 빛의 사이클 및 색을 표현해준다. 솔직히 이걸 하면서 제일 이해하기가 까다로웠다. 빛의 각도와 하루의 주기 등등 계산할 것들이 많았고 실제로 복잡한 계산식이 들어갔기 때문이다. 그나마 내가 이해한대로 정리를 해보자면, 밤낮을 표현하려면 Update문에서 실행해주어야 하고, 실제로 UpdateLight()가 Update문에서 그 역할을 해주고 있다. 빛의 각도를 조절해 주고, 색깔은 Evaluate()를 통해 처리했으며, AnimationCurve의 수치에 따라 해당 광원의 존재여부를 처리해 주는 방식이다. 강의에서 설정한 값은 이러했다.

 

2.  delegate의 사용

delegate에 대해서는 공부해 본 적은 있지만, 사실 나는 아직도 delegate를 잘 알지 못한다. 예시로는 보면 "아~ 그렇구나"라는 말이 나오면서 이해한 듯 보여도, 막상 delegate를 쓰면 좋은 상황일 때는 어떻게 써야 할지를 모르며, 심지어 그런 상황인지도 인지를 못할 때가 상당수이다. 그래서 지금 오늘 강의에서 delegate가 쓰였던 곳을 한번 되짚어보고자 한다.

using System;
using UnityEngine;

public class Player : MonoBehaviour
{
    public PlayerController controller;
    public PlayerCondition condition;

    public ItemData itemData;
    public Action addItem;

    public Transform dropPosition;

    private void Awake()
    {
        CharacterManager.Instance.Player = this;
        controller = GetComponent<PlayerController>();
        condition = GetComponent<PlayerCondition>();
    }
}
// UIInventory.cs 중



private void Start()
 {
     controller = CharacterManager.Instance.Player.controller;
     condition = CharacterManager.Instance.Player.condition;
     dropPosition = CharacterManager.Instance.Player.dropPosition;

     controller.inventory += Toggle;
     CharacterManager.Instance.Player.addItem += AddItem;

     inventoryWindow.SetActive(false);
     slots = new ItemSlot[slotPanel.childCount];

     for (int i = 0; i < slots.Length; i++)
     {
         slots[i] = slotPanel.GetChild(i).GetComponent<ItemSlot>();
         slots[i].index = i;
         slots[i].inventory = this;

     }
     ClearSelectedItemWindow();
 }
 
 ////....
 
 void AddItem()
{
    ItemData data = CharacterManager.Instance.Player.itemData;

    if (data.canStack)
    {
        ItemSlot slot = GetItemStack(data);
        if (slot != null)
        {
            slot.quantity++;
            UpdateUI();
            CharacterManager.Instance.Player.itemData = null;
            return;
        }
    }

    ItemSlot emptySlot = GetEmptySlot();

    if (emptySlot != null)
    {
        emptySlot.item = data;
        emptySlot.quantity++;
        UpdateUI();
        CharacterManager.Instance.Player.itemData = null;
        return;
    }

    ThrowItem(data);
    CharacterManager.Instance.Player.itemData = null;

}
    // ItemObject 중
    
    public void OnInteract()
    {
        CharacterManager.Instance.Player.itemData = data;
        CharacterManager.Instance.Player.addItem?.Invoke();
        Destroy(gameObject);
    }

위의 코드를 보면 Player에서 addItem이라는 Action을 선언해주었다. 그리고 Charactermanager가 싱글톤으로 설정되어 있어서, UIInventory.cs에서도 불러올 수 있다. 그리고 UIInventory.cs에서는 그 점을 이용해 AddItem()이라는 함수를 addItem에 구독했다. 그리고 실제 실행은 ItemObject.cs의 OnInteract에서 한다. 

솔직히 말하자면, 이미 강의를 듣고 코드를 작성하고 어떻게 돌아가는지를 아니까 어느정도 해설을 보고 이해가 가는 정도이지, 나는 아직도 어떻게 하면 "Player에게 아이템을 얻는 행동을 Player.cs에 delegate로 선언하고, UIInventory가 인벤토리의 관한 UI를 관리해주니 실질적인 행동을 저기서 정의하고, ItemObject의 OnInteract를 실행할 때 불러오자"라는 생각을 어떻게 하는지 앚기도 잘 이해가 안간다. 

 

오늘 한 것을 복습하려고 했으나, 그냥 내가 몰랐던 부분을 한번더 깨닫고 답은 잘 모르는 그런 깨림칙한 기분만 들었다. 내 생각으로는 저런 부분들을 직접 코드를 작성하고 경험함으로써 늘리면 자연스레 늘것 같지만, 혹시나 팁이 있을지 모르니 내일은 강의를 다 듣고 튜터님께 어떻게 이해해야하는지 방법을 한번 물어봐야겠다. 오늘은 이런 찝찝함 때문에 잠을 잘 잘수있을지 모르겠으나, 내일을 위해서라면 자야 하므로 오늘은 여기서 마친다.