<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>SCC - StudyCodingClub</title>
        <link>https://velog.io/</link>
        <description>개발 공부 블로그</description>
        <lastBuildDate>Tue, 11 Jun 2024 02:54:21 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>SCC - StudyCodingClub</title>
            <url>https://velog.velcdn.com/images/purangi_code/profile/d1f37114-fc96-4730-b62f-3a139b224ff5/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. SCC - StudyCodingClub. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/purangi_code" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[이후는 이전보다] 리마스터링 - 1]]></title>
            <link>https://velog.io/@purangi_code/%EC%9D%B4%ED%9B%84%EB%8A%94-%EC%9D%B4%EC%A0%84%EB%B3%B4%EB%8B%A4-%EB%A6%AC%EB%A7%88%EC%8A%A4%ED%84%B0%EB%A7%81-1</link>
            <guid>https://velog.io/@purangi_code/%EC%9D%B4%ED%9B%84%EB%8A%94-%EC%9D%B4%EC%A0%84%EB%B3%B4%EB%8B%A4-%EB%A6%AC%EB%A7%88%EC%8A%A4%ED%84%B0%EB%A7%81-1</guid>
            <pubDate>Tue, 11 Jun 2024 02:54:21 GMT</pubDate>
            <description><![CDATA[<p>📝 24.06.11</p>
<p>🔗 : <a href="https://github.com/purangi/BTB_Refactor">https://github.com/purangi/BTB_Refactor</a></p>
<p>2022년 진행했던 이후는 이전보다(Better Than Before, 약칭 BTB)의 스크립트를 일부 리팩토링 하던 도중 차라리 리마스터링이 더 낫겠다는 생각이 들었고, 새로운 프로젝트를 만들어 리마스터링을 시작했다. (24.05.31)</p>
<p>자소서 작성 및 지원과 병행하다보니 작업 속도가 빠르진 않지만 천천히 변경점에 대해서 작성해두려고 한다.</p>
<h3 id="1-맵-구조물-ui-button---2d-sprite로-변경">1. 맵 구조물 UI Button -&gt; 2D Sprite로 변경</h3>
<blockquote>
<p>메인 맵의 구조물들은 UI에 속하지 않는 <strong>게임 그래픽 요소</strong>이므로 UI를 사용하는 것은 부적합하다 판단하여 변경</p>
</blockquote>
<p>기존에는 UI Button에 PointerEvent 구현
<img src="https://velog.velcdn.com/images/purangi_code/post/c7373a17-947b-4731-979e-c0ad13552045/image.png" alt=""></p>
<p><strong><code>HouseClick.cs</code></strong></p>
<pre><code class="language-cs">public void OnPointerEnter(PointerEventData eventData)
{
    ChangeImage();
}

public void OnPointerExit(PointerEventData eventData)
{
    BasicImage();
}</code></pre>
<p>리마스터링 버전에는 2D Sprite에 Collider를 추가하여 PointerEvent 구현함</p>
<p><img src="https://velog.velcdn.com/images/purangi_code/post/5cb86f3b-61e1-4318-b0ec-decfb436f832/image.png" alt=""></p>
<p>부모 클래스인 <code>SpriteInteraction</code>를 상속받아 ClickMethod를 재정의하여 메인 맵 요소들에 대한 함수를 구현했다.</p>
<p><strong><code>SpriteInteraction.cs</code></strong></p>
<pre><code class="language-cs">public class SpriteInteraction : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        ClickMethod();
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        EnterMethod();
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        ExitMethod() ;
    }

    protected virtual void ClickMethod()
    {

    }

    protected virtual void EnterMethod()
    {

    }

    protected virtual void ExitMethod()
    {

    }
}</code></pre>
<p><strong><code>MainMapSprites.cs</code></strong></p>
<pre><code class="language-cs">public class MainMapSprites : SpriteInteraction
{
    [SerializeField] SpriteRenderer spriteRenderer;

    Sprite basicSprite;
    [SerializeField] Sprite lineSprite;
    [SerializeField] Sprite exitSprite;

    [SerializeField] int spriteIndex;

    private void Start()
    {
        basicSprite = spriteRenderer.sprite;
    }

    protected override void ClickMethod()
    {
        Vector3 targetPosition = new Vector3(transform.position.x, transform.position.y, -1);
        float targetSize = 2f;

        CameraController.Instance.ZoomCamera(targetPosition, targetSize, spriteIndex);
    }

    protected override void EnterMethod()
    {
        spriteRenderer.sprite = lineSprite;
    }

    protected override void ExitMethod()
    {
        spriteRenderer.sprite = basicSprite;
    }
}</code></pre>
<p>만약 Sprite 요소에 다른 클릭 이벤트를 실행하는 스크립트를 구현할 것이라면 위와 같이 <code>SpriteInteraction</code> 클래스를 상속받아 사용하면 된다.</p>
<h3 id="2-스프라이트-클릭-시-카메라-확대-효과-추가">2. 스프라이트 클릭 시 카메라 확대 효과 추가</h3>
<p><code>BetterThanBefore</code>
<img src="https://velog.velcdn.com/images/purangi_code/post/4b28cf19-7201-40f1-82cc-bf797bf4594b/image.gif" alt=""></p>
<p>기존에는 요소 클릭 시 카메라 이동 없이 즉시 실행</p>
<p><code>BTB_Refactor</code>
<img src="https://velog.velcdn.com/images/purangi_code/post/fe9b33e5-1085-4b7d-aac1-de46c85aa92c/image.gif" alt=""></p>
<p>리마스터링에선 Virtual Camera 추가하여 카메라 확대 및 이동 효과 추가</p>
<p><strong><code>CameraController.cs</code></strong></p>
<pre><code class="language-cs">public class CameraController : Singleton&lt;CameraController&gt;
{
    [SerializeField] CinemachineVirtualCamera zoomCamera;

    [SerializeField] float zoomSpeed;
    private Vector3 originalPosition;
    private Vector3 targetPosition;
    private float originalSize;
    private float targetSize;

    private Coroutine zoomCoroutine;

    private Vector2 minBounds;
    private Vector2 maxBounds;

    private bool isZoomed = false;
    public bool IsZoomed { get { return isZoomed; } }

    private int itemIndex = -1;

    void Start()
    {
        if (zoomCamera == null)
        {
            Debug.LogError(&quot;Virtual Camera is not assigned&quot;);
        }

        //SET original camera transform
        originalPosition = transform.position;
        originalSize = zoomCamera.m_Lens.OrthographicSize;
    }

    public void ZoomCamera(Vector3 _targetPosition, float _targetSize, int _index)
    {
        isZoomed = true;

        if (_index == itemIndex)
        {
            ResetZoom();
            return;
        }

        targetPosition = ClampPosition(_targetPosition);
        targetSize = _targetSize;
        itemIndex = _index;

        zoomCoroutine = StartCoroutine(Zoom());
    }

    public void ResetZoom()
    {
        isZoomed = false;

        targetPosition = originalPosition;
        targetSize = originalSize;
        itemIndex = -1;

        if (zoomCoroutine != null)
        {
            StopCoroutine(zoomCoroutine);
        }

        zoomCoroutine = StartCoroutine(Zoom());
    }

    private IEnumerator Zoom()
    {
        Transform cameraTransform = zoomCamera.transform;

        //position move until target
        while (Vector3.Distance(cameraTransform.position, targetPosition) &gt; 0.1f || Mathf.Abs(zoomCamera.m_Lens.OrthographicSize - targetSize) &gt; 0.1f)
        {
            cameraTransform.position = Vector3.Lerp(cameraTransform.position, targetPosition, zoomSpeed * Time.deltaTime);
            zoomCamera.m_Lens.OrthographicSize = Mathf.Lerp(zoomCamera.m_Lens.OrthographicSize, targetSize, zoomSpeed * Time.deltaTime);

            yield return null;
        }

        cameraTransform.position = targetPosition;
        zoomCamera.m_Lens.OrthographicSize = targetSize;
    }

    private Vector3 ClampPosition(Vector3 position) //Limit the Position
    {
        SetClampBounds();

        float clampedX = Mathf.Clamp(position.x, minBounds.x, maxBounds.x);
        float clampedY = Mathf.Clamp(position.y, minBounds.y, maxBounds.y);

        return new Vector3(clampedX, clampedY, position.z);
    }

    private void SetClampBounds() // SET by SceneIndex
    {
        Scene currentScene = SceneManager.GetActiveScene();

        switch (currentScene.buildIndex)
        {
            case 0: //MainScene
                minBounds = new Vector2(-5.4f, -3f);
                maxBounds = new Vector2(5.4f, 3f);
                break;
        }
    }

}</code></pre>
<p>카메라 컨트롤러 스크립트를 추가하여 카메라 확대 및 초기화, 이동 최대&amp;최소 범위 제한 등의 기능을 구현하였습니다.</p>
<blockquote>
<p>추가할 요소 - 카메라 확대 시 입장하기 버튼 활성화하여 각 인재 방 방문 기능 필요</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 77일차 - Skill 상속 구조 Refactor]]></title>
            <link>https://velog.io/@purangi_code/TIL-77%EC%9D%BC%EC%B0%A8-Skill-%EC%83%81%EC%86%8D-%EA%B5%AC%EC%A1%B0-Refactor</link>
            <guid>https://velog.io/@purangi_code/TIL-77%EC%9D%BC%EC%B0%A8-Skill-%EC%83%81%EC%86%8D-%EA%B5%AC%EC%A1%B0-Refactor</guid>
            <pubDate>Thu, 18 Apr 2024 12:54:01 GMT</pubDate>
            <description><![CDATA[<p>📝 24.04.18</p>
<p>Skill 오브젝트에 들어갈 Skill이라는 클래스 스크립트를 Player Skill과 Enemy Skill이라는 자식 스크립트로 분리해야할 필요를 느껴서 수정했다.</p>
<p><strong>기존의 Skill.cs</strong></p>
<pre><code class="language-cs">using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class Skill : MonoBehaviour
{
    public Animator anim;

    public SkillInfoData data {  get; set; }
    private Player player;

    private Vector3 leftDirection = new Vector3(2f, 2f, 1f);
    private Vector3 rightDirection = new Vector3(-2f, 2f, 1f);

    private void OnEnable()
    {
        player = GameManager.Instance.player;

        if(player != null)
        {
            SetTransform();
            CheckType();
        }
    }

    private void CheckType()
    {
        switch(player.Data.StatusData.JobType)
        {
            case JobType.Archer:
                StartCoroutine(ShootSkill());
                break;
            default:
                StartCoroutine(WaitForAnimationEnd());
                break;
        }
    }

    IEnumerator WaitForAnimationEnd()
    {
        do
        {
            yield return null;
        } while (anim.GetCurrentAnimatorStateInfo(0).normalizedTime &lt; 1);

        gameObject.SetActive(false);
    }

    IEnumerator ShootSkill()
    {
        if(data != null)
        {
            Vector3 originalPosition = transform.position;
            Vector3 targetPosition = originalPosition + (player.Controller.isLeft ? new Vector3(data.Range * -1, 0, 0) : new Vector3(data.Range, 0, 0));

            do
            {
                transform.position = Vector3.MoveTowards(transform.position, targetPosition, Time.deltaTime * 7f);
                yield return null;
            } while (transform.position != targetPosition);

            gameObject.SetActive(false);
        }
    }

    private void SetTransform()
    {
        Vector3 plus = new Vector3(-0.5f, 0, 0);
        if (!player.Controller.isLeft)
        {
            plus.x *= -1f;
            Flip(false);
        }
        else Flip(true);
        transform.position = player.transform.position + plus;
    }

    private void Flip(bool isLeft)
    {
        transform.localScale = isLeft ? leftDirection : rightDirection;
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        IDamageable damageable = collision.gameObject.GetComponent&lt;IDamageable&gt;();

        if(damageable != null)
        {
            damageable.TakeDamage(player.Data.StatusData.Atk + data.Damage);
            gameObject.SetActive(false);
        }
    }
}</code></pre>
<p><strong>리팩토링 Skill.cs</strong></p>
<pre><code class="language-cs">using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class Skill : MonoBehaviour
{
    public Animator anim;

    [SerializeField]
    public SkillInfoData data;

    protected IDamageable damageable;

    protected void CheckType()
    {
        if(data.Range &gt; 0)
        {
            StartCoroutine(ShootSkill());
        } else
        {
            StartCoroutine(WaitForAnimationEnd());
        }
    }

    IEnumerator WaitForAnimationEnd()
    {
        do
        {
            yield return null;
        } while (anim.GetCurrentAnimatorStateInfo(0).normalizedTime &lt; 1);

        gameObject.SetActive(false);
    }

    IEnumerator ShootSkill()
    {
        if(data != null)
        {
            Vector3 originalPosition = transform.position;
            Vector3 targetPosition = originalPosition + GetTargetPosition();

            do
            {
                transform.position = Vector3.MoveTowards(transform.position, targetPosition, Time.deltaTime * 7f);
                yield return null;
            } while (transform.position != targetPosition);

            gameObject.SetActive(false);
        }
    }

    protected virtual void SetTransform() { }

    protected virtual Vector3 GetTargetPosition() { return Vector3.left; }

    protected virtual void OnCollisionEnter2D(Collision2D collision)
    {
        damageable = collision.gameObject.GetComponent&lt;IDamageable&gt;();
    }
}
</code></pre>
<p>대충 가상메서드로 여럿 변경한 것이 주요하고 GetTargetPosition()이라는 새로운 메서드를 만들어서 PlayerSkill과 EnemySkill이 각각 다른 설정을 할 수 있도록 수정했다.</p>
<p><strong>PlayerSkill.cs</strong></p>
<pre><code class="language-cs">using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerSkill : Skill
{
    private Player player;

    private Vector3 leftDirection = new Vector3(2f, 2f, 1f);
    private Vector3 rightDirection = new Vector3(-2f, 2f, 1f);

    private void OnEnable()
    {
        player = GameManager.Instance.player;

        if (player != null)
        {
            SetTransform();
            CheckType();
        }
    }

    protected override void SetTransform()
    {
        Vector3 plus = new Vector3(-0.5f, 0, 0);
        if (!player.Controller.isLeft)
        {
            plus.x *= -1f;
            Flip(false);
        }
        else Flip(true);
        transform.position = player.transform.position + plus;
    }

    private void Flip(bool isLeft)
    {
        transform.localScale = isLeft ? leftDirection : rightDirection;
    }

    protected override void OnCollisionEnter2D(Collision2D collision)
    {
        base.OnCollisionEnter2D(collision);

        if (damageable != null)
        {
            damageable.TakeDamage(player.Data.StatusData.Atk + data.Damage);
            gameObject.SetActive(false);
        }
    }

    protected override Vector3 GetTargetPosition()
    {
        return player.Controller.isLeft ? new Vector3(data.Range * -1, 0, 0) : new Vector3(data.Range, 0, 0);
    }
}
</code></pre>
<p>아직 <code>EnemySkill</code>는 스킬 오브젝트 프리팹 작업이 더 급해서 못만들고 있지만 얼추 <code>GetTargetPosition()</code> 메서드를 적절하게 재정의하고, <code>OnCollisionEnter2D()</code> 메서드의 <code>damage</code>도 다르게 계산하도록 수정해야 할 듯 하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 76일차 - ui 디자인]]></title>
            <link>https://velog.io/@purangi_code/TIL-76%EC%9D%BC%EC%B0%A8-ui-%EB%94%94%EC%9E%90%EC%9D%B8</link>
            <guid>https://velog.io/@purangi_code/TIL-76%EC%9D%BC%EC%B0%A8-ui-%EB%94%94%EC%9E%90%EC%9D%B8</guid>
            <pubDate>Wed, 17 Apr 2024 14:06:51 GMT</pubDate>
            <description><![CDATA[<p>📝 24.04.17</p>
<p>내일배움캠프는 개발자 양성 코스이므로 프로젝트에 함께할 디자이너가 따로 없다.</p>
<p>그래서 직접 디자인도 해야하는데, 아무리 ui 에셋이 잘 구성되어있어도 적절한 이미지를 적절하게 배치하는 것이 너무 어렵다.</p>
<p>그래도 나름 최선을 다해 몇가지 만들고 있다.</p>
<p><img src="https://velog.velcdn.com/images/purangi_code/post/aa03a9f7-9489-47c7-bc43-02a38e6e875d/image.png" alt="">
기존 직업 선택창</p>
<p><img src="https://velog.velcdn.com/images/purangi_code/post/4be61218-b6cc-45aa-9d23-e575d23344d0/image.png" alt=""></p>
<p>수정한 버전</p>
<p><img src="https://velog.velcdn.com/images/purangi_code/post/0519a04f-0993-4b8d-8e7d-c62e1b4f1860/image.png" alt="">
대기 퀘스트 설명 / 보상</p>
<p><img src="https://velog.velcdn.com/images/purangi_code/post/fac01d98-214b-4c8b-9e11-4f97c842ac28/image.png" alt=""></p>
<p>상호작용 표시</p>
<p>가장 중요한 것은 전체적인 통일감이 있는 디자인과 사용자가 보기 편해야 한다는 것이므로 최대한 깔끔하고 보기좋은 디자인을 만들려고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 75일차 - Excel to Json]]></title>
            <link>https://velog.io/@purangi_code/TIL-75%EC%9D%BC%EC%B0%A8-Excel-to-Json</link>
            <guid>https://velog.io/@purangi_code/TIL-75%EC%9D%BC%EC%B0%A8-Excel-to-Json</guid>
            <pubDate>Thu, 11 Apr 2024 12:35:42 GMT</pubDate>
            <description><![CDATA[<p>📝 24.04.11</p>
<p>엑셀 파일을 JSON 파일로 바꾸는 프로그램을 사용했다.</p>
<p>🔗 <strong><a href="https://github.com/coolengineer/excel2json">Excel2Json</a></strong></p>
<p>프로그램을 다운 받고 해당 폴더에 output 폴더를 만든다. </p>
<p>그리고 프로그램 js 폴더와 같은 위치에 양식에 맞춰 작성한 엑셀 파일을 넣고 프로그램을 실행시키면, output 폴더에 json 파일이 생성된다.</p>
<p>해당 json 파일은 Resource 파일에 넣고 스크립트로 불러와서 사용할 수 있다.</p>
<pre><code class="language-cs">using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LevelDatas
{
    public int level;
    public int requiredExp;
    public int atk;
    public int def;
    public int maxHp;
}

public class PlayerLevelDatabase
{
    public List&lt;LevelDatas&gt; levelDatas;
    public Dictionary&lt;int, LevelDatas&gt; levelDic = new();

    public void Initialize()
    {
        foreach (LevelDatas data in levelDatas)
        {
            levelDic.Add(data.level, data);
        }
    }

    public LevelDatas GetLevelDataByKey(int level)
    {
        if (levelDic.ContainsKey(level))
            return levelDic[level];

        return null;
    }
}

public class PlayerDataManager : MonoBehaviour
{
    public PlayerLevelDatabase playerLevelDatabase;

    private void Awake()
    {
        TextAsset LevelJson = Resources.Load&lt;TextAsset&gt;(&quot;JSON/LevelDatas&quot;);

        if (LevelJson != null)
        {
            string json = LevelJson.text;

            playerLevelDatabase = JsonUtility.FromJson&lt;PlayerLevelDatabase&gt;(json);
            playerLevelDatabase.Initialize();
        }
        else
        {
            Debug.Log(&quot;Level JSON NULL&quot;);
        }
    }

    public void SetPlayerLevel()
    {
        Player player = GameManager.Instance.player;

        if (player != null)
        {
            int level = player.Data.StatusData.Level;

            LevelDatas data = playerLevelDatabase.GetLevelDataByKey(level);
            player.Data.StatusData.LoadLevelData(data);
        }

    }
}</code></pre>
<p>형식을 유지하고 컬럼명만 다르게 제작하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 74일차 - Update와 Coroutine]]></title>
            <link>https://velog.io/@purangi_code/TIL-74%EC%9D%BC%EC%B0%A8-Update%EC%99%80-Coroutine</link>
            <guid>https://velog.io/@purangi_code/TIL-74%EC%9D%BC%EC%B0%A8-Update%EC%99%80-Coroutine</guid>
            <pubDate>Tue, 09 Apr 2024 12:12:00 GMT</pubDate>
            <description><![CDATA[<p>📝 24.04.09</p>
<p>어제 기술 면접 문답을 많이 해서 오늘은 생략한다.</p>
<p>오늘 면접 연습을 하면서 여러 피드백을 받았다.</p>
<ol>
<li>자기 소개에는 자기가 왜 게임을 좋아하는지 그래서 어떤 것을 했는지 <strong>나만의 이야기</strong>를 포함해야 한다.</li>
<li>기술 면접은 외워서 대답하는 게 아니라 <strong>이해하는 것</strong>이 중요 - 예를 들어 스택과 힙에 대해 물어보면 구조체나 지역 변수, 동적 배열 리스트, new 키워드 등 예시를 들어서 설명하는 것이 좋음</li>
<li>문제 자체 뿐만 아니라 <strong>꼬리 질문에 대비</strong> 해야 함 - 드로우콜 배칭에 대한 대답만 준비할게 아니라 드로우콜이 뭔지도 알아둬야 함</li>
</ol>
<p>위의 피드백을 바탕으로 기술 면접 문답을 더 정교하게 준비해야겠다.</p>
<br>
---
<br>
오늘은 몬스터 사망 시 아이템 드랍을 가장 주요하게 구현했다.

<p><strong>아이템 드랍 효과</strong> <a href="https://unitybeginner.tistory.com/159">📝</a></p>
<p>위의 포스트를 참고하여 구현하였는데, Update() 사용이 굳이 필요없을 뿐더러 탑다운 게임을 기반으로 만든 위의 스크립트를 플랫포머 게임 기준으로 새로 구현하였다.</p>
<p>또한, 그림자 효과는 필요없으므로 삭제했다.</p>
<pre><code class="language-cs">using System.Collections;
using UnityEngine;

public class Gem : MonoBehaviour
{
    [SerializeField] private int xForce = 5;
    [SerializeField] private int yForce = 15;
    [SerializeField] private int gravity = 25;

    private Vector2 direction;
    private bool isGrounded = true;

    private float maxHeight;
    private float currentHeight;

    private void Start()
    {
        currentHeight = Random.Range(yForce - 1, yForce);
        maxHeight = currentHeight;
        direction = new Vector2(Random.Range(-xForce, xForce), 0);
        Initialize(direction);
        StartCoroutine(Move());
    }

    private IEnumerator Move()
    {
        while (!isGrounded)
        {
            currentHeight += -gravity * Time.deltaTime;
            transform.position += new Vector3(0, currentHeight, 0) * Time.deltaTime;
            transform.position += (Vector3)direction * Time.deltaTime;

            yield return null;
            CheckGroundHit();
        }
    }

    private void Initialize(Vector2 _direction)
    {
        isGrounded = false;
        maxHeight /= 1.5f;
        direction = _direction;
        currentHeight = maxHeight;
    }

    private void CheckGroundHit()
    {
        RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.down, 0.5f, LayerMask.GetMask(&quot;Ground&quot;));
        Debug.Log(hit.collider);
        if (hit.collider != null)
        {
            // 땅에 닿음
            isGrounded = true;
            transform.position = hit.point;
        }
    }
}</code></pre>
<p>땅에 바로 떨어지길 바래서 여러번 튀지 않게 했고, 몬스터가 죽으면 터지는 것처럼 포물선을 그리는 효과만 유지했다.</p>
<p>굳이 꾸준한 이동을 프레임마다 호출할 이유가 없으므로 Update() 대신 코루틴을 통해 이동을 실행하도록 수정했다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 55일차 - 좌표 기반 점프]]></title>
            <link>https://velog.io/@purangi_code/TIL-56%EC%9D%BC%EC%B0%A8-%EC%A2%8C%ED%91%9C-%EA%B8%B0%EB%B0%98-%EC%A0%90%ED%94%84</link>
            <guid>https://velog.io/@purangi_code/TIL-56%EC%9D%BC%EC%B0%A8-%EC%A2%8C%ED%91%9C-%EA%B8%B0%EB%B0%98-%EC%A0%90%ED%94%84</guid>
            <pubDate>Tue, 09 Apr 2024 00:57:44 GMT</pubDate>
            <description><![CDATA[<p>📝 24.03.13</p>
<h3 id="오늘의-질문">오늘의 질문</h3>
<blockquote>
<p><strong>박싱과 언박싱에 대하여 설명해주세요.</strong>
<br> - (꼬리질문) 박싱, 언박싱을 사용할 때 <strong>주의해야 할 점</strong>이 있다면 무엇이 있나요?</p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p><strong>박싱</strong>은 값 타입의 객체를 참조 타입으로 변환하는 작업을, <strong>언박싱</strong>은 이 박싱되어있는 참조 타입 객체 복사본을 다시 값 타입으로 돌리는 작업을 말합니다. 박싱과 언박싱은 객체에 대한 복사본을 생성하는 과정에서의 <strong>버그 발생</strong>을 주의해야 합니다.</p>
</blockquote>
<p>오늘 답변이 검색으로 정확하게 파악할 수 없어서 너무 어려웠다. 박싱과 언박싱이라는 단어 자체도 생소한데 공식 문서에서의 답변도 다소 모호하여 이해하고 내 단어로 정리하기 힘들었다.</p>
<br>
+ 오늘 조에서 모의 면접을 진행했는데, 자기 소개와 지원 동기에서의 부족함을 지적받았다.

<p>자기 소개는 처음부터 래퍼토리를 좀 정리해와야 할 것 같다. 내가 게임 클라이언트라는 분야를 위해 무엇을 준비해왔는지를 녹일 수 있는 답변을 생각해봐야겠다.</p>
<br>

<hr>
<br>

<p>오늘 가장 많은 노력을 한 것은 좌표로 점프 값을 구현하는 것이다.</p>
<pre><code class="language-cs">using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Vector3 currentVelocity = new Vector3(0, 0, 0);
    private Vector3 impact;

    public Vector2 velocity;
    public bool isGrounded { get; set; } = false;

    public Vector3 Movement =&gt; impact + Vector3.up * velocity.y;
    private void FixedUpdate()
    {
        RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector3.down, 0.2f, LayerMask.GetMask(&quot;Ground&quot;));
        Debug.DrawRay(transform.position, Vector3.down, Color.green);
        if (hit.collider != null)
        {
            isGrounded = true;
        }
        else
        {
            isGrounded = false;
        }

        if (velocity.y &lt;= 0f &amp;&amp; isGrounded)
        {
            velocity = Vector2.zero;
        }
        else
        {
            velocity += (Physics2D.gravity * 0.2f) * Time.fixedDeltaTime;
            transform.position += new Vector3(velocity.x, velocity.y);
        }

        impact = Vector3.SmoothDamp(impact, Vector3.zero, ref currentVelocity, 0.3f);
    }
    /* 생략 */

    public void Jump(float _jumpForce)
    {
        velocity.y += _jumpForce;
    }
}</code></pre>
<p><code>rigidbody</code>의 <code>velocity</code>를 <strong>좌표값</strong>을 통해 구현하는 방법이다. 사실 아직도 움직임이 부드럽진 않아서 좀 더 손봐야 하겠지만 어쨌든 문제없이 점프가 된다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 73일차 - 기술 면접 문답 목록2]]></title>
            <link>https://velog.io/@purangi_code/TIL-73%EC%9D%BC%EC%B0%A8-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EB%AC%B8%EB%8B%B5-%EB%AA%A9%EB%A1%9D2</link>
            <guid>https://velog.io/@purangi_code/TIL-73%EC%9D%BC%EC%B0%A8-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EB%AC%B8%EB%8B%B5-%EB%AA%A9%EB%A1%9D2</guid>
            <pubDate>Mon, 08 Apr 2024 14:55:26 GMT</pubDate>
            <description><![CDATA[<p>📝 24.04.08</p>
<h3 id="37-object-pool을-사용하는-이유는-무엇인가요">37. Object pool을 사용하는 이유는 무엇인가요?</h3>
<blockquote>
<p>오브젝트 풀은 성능 향상을 위해 사용합니다. 게임에서 오브젝트를 생성하고 삭제하는 작업은 메모리 사용량이 높아 성능 저하의 원인이 되기 때문에 미리 생성된 객체를 재사용함으로써 성능 향상을 도모할 수 있습니다.</p>
</blockquote>
<h3 id="38-객체를-이동할-때-벡터를-정규화nomarlized-하는-이유에-대해-설명해주세요">38. 객체를 이동할 때 벡터를 정규화(Nomarlized) 하는 이유에 대해 설명해주세요.</h3>
<blockquote>
<p>객체 이동 시 벡터를 정규화하는 가장 큰 이유는 일관성 있는 이동 속도를 갖게하기 위해서입니다. 벡터를 정규화하면 이동 벡터의 크기를 모두 동일하게 1로 통일해주므로 이동에 사용되는 속도를 일정하게 유지할 수 있습니다.</p>
</blockquote>
<h3 id="39-월드-스페이스world-space와-로컬-스페이스local-space의-차이에-대해-설명해주세요">39. 월드 스페이스(World Space)와 로컬 스페이스(Local Space)의 차이에 대해 설명해주세요.</h3>
<blockquote>
<p>월드 스페이스는 전역 좌표 공간으로 씬 전체를 기준으로 게임 오브젝트의 위치와 회전을 나타냅니다. 로컬 스페이스는 부모 게임 오브젝트를 기준으로한 상대적인 좌표 공간으로, 부모 오브젝트가 이동하면 자식 오브젝트의 좌표가 바뀌지 않아도 부모 오브젝트를 따라 이동합니다.</p>
</blockquote>
<h3 id="40-컬링-종류와-사용하는-이유에-대해-설명해주세요">40. 컬링 종류와 사용하는 이유에 대해 설명해주세요.</h3>
<blockquote>
<p>컬링이란 화면에 표시할 필요가 없는 오브젝트들을 추려내는 작업입니다. 게임 엔진에서 가장 자주 사용하는 컬링은 프러스텀 컬링입니다. 카메라 시야에 보이는 오브젝트만 그리고 그외의 오브젝트는 제거하는 방법으로 필요한 작업량을 대폭 줄일 수 있어 사용됩니다. 또다른 컬링 종류로는 오클루전 컬링이 있습니다. 오클루전 컬링은 다른 오브젝트에 의해 숨겨진 오브젝트를 걸러내어 렌더링 프로세스에서 제거하는 방법으로 성능을 향상합니다.</p>
</blockquote>
<h3 id="41-유니티-최적화-기법은-어떤-것들이-있나요">41. 유니티 최적화 기법은 어떤 것들이 있나요?</h3>
<blockquote>
<p>유니티 최적화 기법으로는 메모리 최적화를 위한 오브젝트 풀링, 가비지 컬렉션 혹은 그래픽 최적화를 위한 배칭, 오브젝트 컬링, 그리고  가장 기본적인 스크립트 최적화 등 다양한 기법이 있습니다.</p>
</blockquote>
<p><code>꼬리 질문 a. 최적화를 해본 적이 있나요? 없다면 어떤 최적화가 있는지 설명해주세요.</code></p>
<blockquote>
<p>메모리 최적화를 위해 오브젝트 풀링 기법을 자주 사용하였습니다. 스킬 오브젝트 호출을 오브젝트 풀링 기법으로 사용하여 필요 이상의 오브젝트 생성과 소멸로 인한 메모리 낭비를 최소화했습니다.</p>
</blockquote>
<p><code>꼬리 질문 b. 최적화에서 가장 중요한 부분은 무엇인가요?</code></p>
<blockquote>
<p>최적화의 핵심은 문제 식별이라고 생각합니다. 어느 부분에서 성능 문제가 발생하는지 식별해야 최적화 작업을 시작할 수 있기 때문입니다. 가장 많은 시간이 소요되는 코드 영역을 중점적으로 파악하여 해결할 줄 알아야 합니다.</p>
</blockquote>
<p><code>꼬리 질문 c. 최적화를 위해서 적용해본 텍스쳐 포맷이 있나요?</code></p>
<blockquote>
<p>최적화를 위해 적용해본 텍스쳐 포맷은 없습니다. 하지만 최근 가장 자주 사용되는 텍스쳐 포맷은 ASTC으로, 다양한 해상도와 압축률을 지원하는 모바일 지원 고급 텍스쳐 압축 포맷이라는 것은 압니다.</p>
</blockquote>
<h3 id="42-가비지컬렉터gc란-무엇인가요">42. 가비지컬렉터(GC)란 무엇인가요?</h3>
<blockquote>
<p>가비지 컬렉터는 자동 메모리 관리 시스템입니다. 힙 메모리 영역에서 더 이상 사용되지 않는 메모리를 식별하고 자동으로 회수하여 프로그램 기능을 향상합니다.</p>
</blockquote>
<h3 id="43-어떤-에셋을-사용해-보셨나요-없다면-알고-있는-에셋이-있나요">43. 어떤 에셋을 사용해 보셨나요? 없다면 알고 있는 에셋이 있나요?</h3>
<blockquote>
<p>다양한 에셋을 사용했습니다. 지금 기억나는 에셋은 SPUM 이라는 2D 캐릭터 에셋인데, 피부색, 눈, 머리, 옷, 무기 등 거의 모든 부분을 커스텀한 2D 픽셀 캐릭터를 생성할 수 있게 하는 에셋입니다.</p>
</blockquote>
<h3 id="44-scriptableobject이란-무엇이며-어떻게-사용되나요">44. ScriptableObject이란 무엇이며 어떻게 사용되나요?</h3>
<blockquote>
<p>추후 서술</p>
</blockquote>
<p><code>꼬리 질문 a. ScriptableObject의 특징에 대해 설명해주세요.</code></p>
<blockquote>
</blockquote>
<h3 id="45-unity에서-레이어와-태그의-역할은-무엇이며-어떻게-사용되는지-설명해주세요">45. Unity에서 레이어와 태그의 역할은 무엇이며, 어떻게 사용되는지 설명해주세요.</h3>
<blockquote>
<p>유니티에서 레이어와 태그는 게임 오브젝트를 식별하고 분류하는 데 사용하는 기능입니다. 그 중 레이어는 게임 오브젝트를 서로 다른 그룹으로 분류하는 데 사용됩니다. 예를 들어, 레이어를 분리하여 적, 플레이어, 맵 등의 오브젝트 종류를 구분하고 서로 다른 레이어끼리의 충돌 감지 여부를 구분할 수 있습니다. 태그는 특정 유형의 게임 오브젝트를 식별하고 관리하는 데 사용됩니다. 예를 들어 아이템 태그를 가진 오브젝트와 충돌했을 때만 해당 아이템을 줍게할 수 있게 하는 등 특정 태그와의 충돌에만 특정 행동을 취하도록 스크립트를 작성할 수 있습니다.</p>
</blockquote>
<h3 id="46-find-함수-사용을-자제해야-하는-이유에-대해-설명해주세요">46. Find 함수 사용을 자제해야 하는 이유에 대해 설명해주세요.</h3>
<blockquote>
<p>Find 함수는 성능에 부정적인 영향을 미칠 수 있기 때문입니다. Find 함수는 씬 내의 모든 게임 오브젝트를 검색하여 이름이 일치하는 것을 찾는 함수 이므로, 씬에 많은 수의 게임 오브젝트가 있는 경우 검색량이 많아 매우 큰 성능 저하가 일어날 수 있습니다.</p>
</blockquote>
<h3 id="47-scene-load의-종류를-비교해서-설명해주세요">47. Scene Load의 종류를 비교해서 설명해주세요.</h3>
<blockquote>
<p>SceneManager.LoadScene은 새로운 씬을 로드할 때 사용됩니다. 단일 쓰레드에만 작동하는 씬 로드입니다. SceneManager.LoadSceneAsync는 비동기적으로 씬을 로드할 수 있게 합니다. 씬 로드 상태를 추적할 수 있어 진행 상황을 알 수 있습니다. 따라서 로딩씬을 구현할 때 사용됩니다.</p>
</blockquote>
<h3 id="48-unity의-물리-엔진은-어떻게-동작하며-어떤-요소를-조작할-수-있는지-설명해주세요">48. Unity의 물리 엔진은 어떻게 동작하며, 어떤 요소를 조작할 수 있는지 설명해주세요.</h3>
<blockquote>
<p>유니티의 물리 엔진은 Rigidbody 컴포넌트와 Collider 컴포넌트를 통해 사용할 수 있습니다. Rigidbody는 게임 오브젝트의 물리적인 특성을 부여하는 데 사용되어 질량, 중력 작용 여부, 회전 제어 등을 조작할 수 있습니다. Collider는 게임 오브젝트의 경계를 정의하는 데 사용됩니다. 콜라이더는 다른 콜라이더와의 충돌을 감지할 수 있습니다.</p>
</blockquote>
<h3 id="49-texture-와-sprite-에-대해-설명해주세요">49. Texture 와 Sprite 에 대해 설명해주세요.</h3>
<blockquote>
<p>텍스쳐는 주로 3D 게임 오브젝트의 표면에 적용되는 이미지 데이터입니다. 텍스쳐는 주로 게임 오브젝트의 Material에 할당되어 렌더링됩니다. 스프라이트는 2D 그래픽 오브젝트를 나타냅니다. 일반적으로 유니티에서는 Sprite Renderer 컴포넌트를 통해 화면에 렌더링 됩니다. </p>
</blockquote>
<h3 id="50-프리팹prefab이란-무엇이며-어떻게-사용되나요">50. 프리팹(Prefab)이란 무엇이며, 어떻게 사용되나요?</h3>
<blockquote>
<p>프리팹이란 재사용 가능한 게임 오브젝트의 템플릿이라고 볼 수 있습니다. 반복적으로 사용되는 요소들을 효율적으로 관리하기 위해 사용되는 것으로, 게임 씬에 배치된 오브젝트를 프로젝트 폴더로 드래그하면 프리팹화할 수 있습니다.</p>
</blockquote>
<h3 id="51-디버깅을-어떤-방식으로-진행하는지-설명해주세요">51. 디버깅을 어떤 방식으로 진행하는지 설명해주세요.</h3>
<blockquote>
<p>저는 디버깅에 크게 중단점과 콘솔 출력을 사용합니다. 콘솔창의 로그를 살펴보고 오류 위치에 중단점을 걸어 디버깅 모드로 들어가면, 스크립트의 어떤 위치에서 버그가 발생했는지 확인할 수 있습니다. 만약 이 방법으로도 감지할 수 없는 버그라면 콘솔 출력을 통해 코드의 현재 상태를 추적하여 디버깅합니다.</p>
</blockquote>
<h3 id="52-attribute를-사용한-경험과-그에-대한-설명을-해주세요">52. Attribute를 사용한 경험과 그에 대한 설명을 해주세요.</h3>
<blockquote>
<p>가장 자주 사용한 Attribute는 SerializedField입니다. private 필드를 Inspector 창에 표시할 수 있게 해주는 Attribute로, 실행 중에 값이 제대로 입력되었는지 손쉽게 확인할 수 있어 자주 사용하였습니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 72일차 - 코루틴에 대하여]]></title>
            <link>https://velog.io/@purangi_code/TIL-72%EC%9D%BC%EC%B0%A8-%EC%BD%94%EB%A3%A8%ED%8B%B4%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</link>
            <guid>https://velog.io/@purangi_code/TIL-72%EC%9D%BC%EC%B0%A8-%EC%BD%94%EB%A3%A8%ED%8B%B4%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</guid>
            <pubDate>Fri, 05 Apr 2024 12:15:24 GMT</pubDate>
            <description><![CDATA[<p>📝 24.04.05</p>
<h3 id="오늘의-질문-1">오늘의 질문 1)</h3>
<blockquote>
<p>코루틴(Coroutine)이 무엇이며, 어떤 상황에서 유용하게 사용될 수 있나요?</p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p>코루틴은 작업 병행성을 지원하기 위한 프로그래밍 기법입니다. 코루틴을 사용하면 대기 시간동안 다른 작업이 실행될 수 있도록 하는 비동기 프로그래밍이나 이벤트가 발생할 때마다 동작을 수행해야할 때 유용하게 사용됩니다.</p>
</blockquote>
<p><code>꼬리 질문 : 코루틴을 사용한 경험에 대해 설명해주세요.</code></p>
<h3 id="나의-답변-1">나의 답변</h3>
<blockquote>
<p>스킬 쿨타임을 구현할 때 사용하였습니다. 스킬을 실행한 후, 코루틴을 이용해 쿨타임만큼의 지연시간 동안은 스킬 버튼이 활성화되지 않도록 유지하였다가 쿨타임이 지나면 스킬 버튼이 활성화되도록 코루틴을 구현한 경험이 있습니다.</p>
</blockquote>
<h3 id="오늘의-질문-2">오늘의 질문 2)</h3>
<blockquote>
<p><strong>오브젝트 풀링(Object Pooling)이 무엇이며, 어떻게 구현하는지 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변-2">나의 답변</h3>
<blockquote>
<p>오브젝트 풀링은 리소스를 효율적으로 관리하기 위한 디자인 패턴입니다. 일정 개수의 오브젝트를 생성하여 초기화한 후, 프로그램이 오브젝트를 필요할 때마다 생성해둔 오브젝트를 가져와 사용하다 더이상 필요하지 않게 되면 오브젝트를 다시 반환하는 방법으로 사용됩니다. <br>
유니티에서의 오브젝트 풀링은 사용할 오브젝트들을 리스트에 담아둔 후 프로젝트가 실행하였을 때 사용할 오브젝트들을 Instantiate()함수로 생성합니다. 생성된 오브젝트 중 사용할 오브젝트는 SetActive()를 true로 설정하고 사용되지 않는 오브젝트들은 SetActive()를 false로 설정하여 반환합니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 71일차 - 렌더링 파이프라인]]></title>
            <link>https://velog.io/@purangi_code/TIL-71%EC%9D%BC%EC%B0%A8-%EB%A0%8C%EB%8D%94%EB%A7%81-%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8</link>
            <guid>https://velog.io/@purangi_code/TIL-71%EC%9D%BC%EC%B0%A8-%EB%A0%8C%EB%8D%94%EB%A7%81-%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8</guid>
            <pubDate>Thu, 04 Apr 2024 12:29:48 GMT</pubDate>
            <description><![CDATA[<p>📝 24.04.04</p>
<h3 id="오늘의-질문-1">오늘의 질문 1)</h3>
<blockquote>
<p><strong>유니티 렌더링 파이프라인에 대해 설명해보세요.</strong><br>
    + 꼬리질문 : 랜더링 파이프라인에는 어떤 종류가 있나요?</p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p>유니티 엔진의 렌더링 파이프라인은 게임 오브젝트의 렌더링 과정을 제어하는 시스템입니다. 여기서 렌더링이란 화면에 오브젝트를 그리는 과정을 말합니다. 
<br>유니티 렌더링 파이프라인의 종류로는 총 4가지가 있습니다. 먼저, <strong>Built-in Render Pipeline</strong>이 있습니다. 유니티에서 기본적으로 설정되어있는 렌더 파이프라인입니다. 두번째로 <strong>Universal Render Pipeline</strong>이 있습니다. 경량화되어 그래픽 요구사항이 낮은 게임에 주로 이용됩니다. 세번째로 <strong>High Definition Render Pipeline</strong>이 있습니다. 높은 시각적 품질과 그래픽 효과를 지원하여 PC 및 콘솔 게임 개발에 주로 이용됩니다. 마지막으로 <strong>Scriptable Render Pipeline</strong>은 사용자가 직접 렌더링 파이프라인을 제어하고 정의할 수 있도록 합니다.</p>
</blockquote>
<h3 id="오늘의-질문-2">오늘의 질문 2)</h3>
<blockquote>
<p><strong>드로우콜(Draw Call) 배칭이 무엇인지 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변-1">나의 답변</h3>
<blockquote>
<p>드로우콜 배칭이란 <strong>그래픽 카드에게 렌더링할 요소들을 그룹화하여 한번에 처리하도록 하는 작업</strong>을 의미합니다. 드로우콜 배칭을 통해 유사한 속성을 가진 오브젝트들을 하나의 배치로 그룹화하여 가능한 적은 수의 드로우콜을 생성하면 그래픽 카드 작업의 효율성을 높여 성능을 최적화할 수 있습니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 70일차 - 상속에 대한 고민]]></title>
            <link>https://velog.io/@purangi_code/TIL-70%EC%9D%BC%EC%B0%A8-%EC%83%81%EC%86%8D%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EB%AF%BC</link>
            <guid>https://velog.io/@purangi_code/TIL-70%EC%9D%BC%EC%B0%A8-%EC%83%81%EC%86%8D%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EB%AF%BC</guid>
            <pubDate>Wed, 03 Apr 2024 13:18:00 GMT</pubDate>
            <description><![CDATA[<p>📝 24.04.03</p>
<h3 id="오늘의-질문-1">오늘의 질문 1)</h3>
<blockquote>
<p><strong>유니티로 타이머를 구현하는 알고리즘을 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p>타이머를 구현하기 위해서는 Update() 메서드를 사용합니다. Time.deltaTime이라는 프레임 간 경과 시간을 Update() 메서드에서 지속적으로 누적하여 타이머 시작 시점으로부터의 경과 시간을 측정하는 방법으로 타이머를 구현할 수 있습니다.</p>
</blockquote>
<h3 id="오늘의-질문-2">오늘의 질문 2)</h3>
<blockquote>
<p><strong>Time.deltaTime이란 무엇이며, 사용하는 이유에 대해 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변-1">나의 답변</h3>
<blockquote>
<p>Time.deltaTime이란 <strong>프레임 당 경과 시간을 나타내는 변수</strong>입니다. 이 변수는 이전 프레임에서 현재 프레임까지 걸린 시간으로, 게임이 실행되는 플랫폼에 따라 프레임 속도가 다르기 때문에 이 요소를 일정하게 제어하기 위하여 사용됩니다.</p>
</blockquote>
<br>

<hr>
<br>

<p>부모 클래스를 구현할 때, 어느 부분까지 포함시켜야하는지는 늘 고민이다.</p>
<p>SkillPage를 구현하는데, SetSkillBtn()은 필수로 구현해야 하는 메서드다 보니 추상 메서드로 구현했었다. 그런데 개발하다보니 하위에서 굳이 오버라이드할 필요 없이 그냥 상위 클래스에서 공통으로 구현해도 될 것 같아서 추상 메서드가 아닌 protected void 메서드로 구현했고, 결과적으로 작업량이 훨씬 줄었다.</p>
<p>처음부터 어디까지 상위 클래스에 구현할지, 하위 클래스에서 재정의할지 고민하는 것이 늘 어려운 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 69일차 - Update() 메서드의 사용]]></title>
            <link>https://velog.io/@purangi_code/TIL-69%EC%9D%BC%EC%B0%A8-Update-%EB%A9%94%EC%84%9C%EB%93%9C%EC%9D%98-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@purangi_code/TIL-69%EC%9D%BC%EC%B0%A8-Update-%EB%A9%94%EC%84%9C%EB%93%9C%EC%9D%98-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Tue, 02 Apr 2024 12:24:52 GMT</pubDate>
            <description><![CDATA[<p>📝 24.04.02</p>
<h3 id="오늘의-질문-1">오늘의 질문 1)</h3>
<blockquote>
<p><strong>Update의 종류와 각각 어떤 특징을 가지고 있는지 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p>유니티에서 주로 사용되는 Update 메서드로는 <strong>Update(), FixedUpdate(), LateUpdate()</strong> 세가지가 있습니다. Update()는 매 프레임마다 호출되는 메서드로, 프레임 속도에 따라 호출간격이 변할 수 있어 주로 사용자 입력 처리에 사용됩니다.FixedUpdate() 메서드는 프레임 속도의 변화에 영향을 받지않는 Update() 메서드로, 주로 물리 연산에 사용됩니다. 마지막으로 LateUpdate()는 Update() 메서드가 실행된 후에 호출되는 메서드로, 주로 카메라 추적에 사용됩니다.</p>
</blockquote>
<h3 id="오늘의-질문-2">오늘의 질문 2)</h3>
<blockquote>
<p><strong>서로 다른 성능을 가진 기기에서 Update 사용 시 주의할 점에 대해 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변-1">나의 답변</h3>
<blockquote>
<p>서로 다른 성능의 기기에 대응하기 위해서는 일차적으로 <strong>Update() 메서드에서는 너무 무거운 작업을 하지 않도록</strong> 주의해야 합니다. 만약 꼭 Update() 메서드를 사용해야 한다면 <strong>프레임 속도의 변화로부터 독립적인 로직을 구현하는 것이 중요</strong>합니다.&#39;Time.deltaTime&#39; 을 사용하여 이동이나 애니메이션과 같은 업데이트를 프레임 속도와 상관없이 일관되도록 만드는 것이 좋습니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 68일차 - 유니티 생명 주기와 초기화]]></title>
            <link>https://velog.io/@purangi_code/TIL-68%EC%9D%BC%EC%B0%A8-%EC%9C%A0%EB%8B%88%ED%8B%B0-%EC%83%9D%EB%AA%85-%EC%A3%BC%EA%B8%B0%EC%99%80-%EC%B4%88%EA%B8%B0%ED%99%94</link>
            <guid>https://velog.io/@purangi_code/TIL-68%EC%9D%BC%EC%B0%A8-%EC%9C%A0%EB%8B%88%ED%8B%B0-%EC%83%9D%EB%AA%85-%EC%A3%BC%EA%B8%B0%EC%99%80-%EC%B4%88%EA%B8%B0%ED%99%94</guid>
            <pubDate>Mon, 01 Apr 2024 12:11:47 GMT</pubDate>
            <description><![CDATA[<p>📝 24.04.01</p>
<h3 id="오늘의-질문-1">오늘의 질문 1)</h3>
<blockquote>
<p><strong>MonoBehaviour 클래스의 주요 메서드와 그 기능에 대해 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p>MonoBehaviour 클래스는 <strong>Unity 프로젝트 창에서 C# 스크립트를 생성하면 자동으로 상속되는 클래스</strong>로 <strong>Unity가 제공하는 생명 주기와 관련된 메소드들을 호출</strong>할 수 있습니다. 초기화에 사용되는 Awake()와 Start() 메서드, 업데이트에 사용되는 Update(), FixedUpdate(), LateUpdate() 메서드, 상태 변화에 관련된 메서드들인 OnEnable(), OnDisable(), OnDestroy() 등이 바로 Monobehaviour 클래스의 주요 메서드입니다.</p>
</blockquote>
<h3 id="오늘의-질문-2">오늘의 질문 2)</h3>
<blockquote>
<p><strong>Unity 오브젝트가 다양하게 씬에 올라와 있다면 동시에 시작되고 무엇이 먼저 초기화 되는지 알 수 없을 수 있는데, 프로젝트에서 코드를 만들 때 이에 대해 고민하고 해결해본 경험이 있다면 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-게임">나의 게임</h3>
<blockquote>
<p>프로젝트에서 초기화 시점으로 인해 문제를 겪은 적이 있습니다. GameManager에서 Player를 Awake()에 선언했는데, 다른 오브젝트에서 같은 Awake() 메서드에서 GameManager의 player를 사용하려고 하다 보니 Null 예외 오류가 났었습니다. 처음에는 이를 해결하기 위해 후자의 메서드를 Start() 시점으로 옮겼었습니다. 하지만 고민해본 결과 메서드 실행 시점을 <strong>한 스크립트에서 이벤트 시스템 구독을 통해 시점의 순서를 관리하는 방법이 더 효율적</strong>이라는 결론에 이르러 해당 방법으로 수정하였습니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 67일차 - MVC 모델이란]]></title>
            <link>https://velog.io/@purangi_code/TIL-67%EC%9D%BC%EC%B0%A8-MVC-%EB%AA%A8%EB%8D%B8%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@purangi_code/TIL-67%EC%9D%BC%EC%B0%A8-MVC-%EB%AA%A8%EB%8D%B8%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Fri, 29 Mar 2024 12:03:09 GMT</pubDate>
            <description><![CDATA[<p>📝 24.03.29</p>
<h3 id="오늘의-질문-1">오늘의 질문 1)</h3>
<blockquote>
<p><strong>MVC 모델이란 무엇인지 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p>MVC 모델은 디자인 패턴 중 하나로 <strong>프로젝트를 구성할 때 그 구성 요소를 Model, View, Controller 세 가지 역할로 구분한 패턴</strong>입니다. 여기서 모델은 애플리케이션의 정보와 데이터를 나타내고, 뷰는 데이터를 사용자들이 볼 수 있게 하는 UI 요소를, 컨트롤러는 모델과 뷰를 연결하는 이벤트 처리 역할을 합니다. </p>
</blockquote>
<h3 id="오늘의-질문-2">오늘의 질문 2)</h3>
<blockquote>
<p><strong>Unity 의 생명주기(Unity Life Cycle)에 대해서 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변-1">나의 답변</h3>
<blockquote>
<p>Unity 생명주기는 <strong>Monobehaviour를 상속 받은 클래스를 컴포넌트로 가진 게임 오브젝트들이 생성에서 파괴까지 자동으로 호출되는 내장 메서드들의 호출 주기</strong>를 말합니다. 초기화 작업을 수행하는 데 사용되는 Awake(), 스크립트가 활성화되고 첫 프레임에 호출되는 Start(), 매 프레임마다 호출되는 Update()와 FixedUpdate()와 LateUpdate(),  스크립트가 활성화되거나 비활성화될때 호출되는 OnEnable()과 OnDisable(), 스크립트가 파괴될때 호출되는 OnDestroy() 등의 메서드가 바로 유니티 생명 주기를 관리하는 데 사용되는 내장 메서드입니다.</p>
</blockquote>
<br>

<hr>
<br>

<p><strong>유니티 디버깅 방법</strong>을 드디어 습득했다.</p>
<p>F5로 디버깅 모드 
-&gt; 게임 플레이 하다가 중단점에 도달하면 해당 위치에서 난 문제 확인 
-&gt; 제대로 확인 안되면 F11로 한 단계식 코드 실행 or F10으로 프로시저 단위로 실행</p>
<p>이 방법으로 찾다보면 프로젝트에서 가장 자주 일어나는 NullException을 쉽게 해결할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 66일차 - 디자인 패턴]]></title>
            <link>https://velog.io/@purangi_code/TIL-66%EC%9D%BC%EC%B0%A8-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%9D%98-%EB%8C%80%EC%9D%91</link>
            <guid>https://velog.io/@purangi_code/TIL-66%EC%9D%BC%EC%B0%A8-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%9D%98-%EB%8C%80%EC%9D%91</guid>
            <pubDate>Thu, 28 Mar 2024 12:04:31 GMT</pubDate>
            <description><![CDATA[<p>📝 24.03.28</p>
<h3 id="오늘의-질문-1">오늘의 질문 1)</h3>
<blockquote>
<p><strong>인터페이스와 추상클래스의 차이를 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p>추상 클래스는 <strong>하나 이상의 추상 메서드를 포함할 수 있는 클래스</strong>입니다. 추상 클래스를 상속한 클래스는 <strong>반드시 추상 함수를 재정의</strong>해야 합니다. 인터페이스는 추상 클래스와 달리 메서드를 정의할 수는 없고, <strong>함수 선언만 할 수 있습니다</strong>. 인터페이스에 선언한 모든 함수는 <strong>인터페이스를 상속하는 클래스에서 반드시 구현</strong>해야 합니다.</p>
</blockquote>
<h3 id="오늘의-질문-2">오늘의 질문 2)</h3>
<blockquote>
<p><strong>디자인 패턴(Singleton, Observer 등) 사용하는 이유는 무엇인가요?</strong></p>
</blockquote>
<h3 id="나의-답변-1">나의 답변</h3>
<blockquote>
<p>디자인 패턴을 사용하는 가장 큰 이유는 <strong>이미 효율성이 검증되었기 때문</strong>입니다. 많은 사람들에 의해 이미 <strong>코드의 재사용성이나 유지 보수성, 확장성</strong> 측면에서 효율적인 코드임이 검증이 되었기 때문에 소프트웨어 품질 향상에 도움이 됩니다. 또한, 개발자들끼리 이미 공유되고 있기에 개발자들간의 <strong>소통 향상</strong>에도 도움이 됩니다.</p>
</blockquote>
<p><code>꼬리 질문 a. 프로젝트에 디자인패턴을 적용해 본 경험이 있나요? 왜 그 디자인패턴을 선택해서 구현하였나요?</code></p>
<blockquote>
<p>젬 크로니클 프로젝트에서 <strong>플레이어 캐릭터에 상태 머신 패턴을 적용</strong>했습니다. 플레이어의 특성상 걷기/공격/점프 등의 <strong>다양한 행동 패턴이 동시에 일어나지 않고 각각이 분리되어 작동</strong>하므로 상태 머신을 적용하기에 적합하다고 생각했습니다. 또한, 캐릭터의 행동 패턴을 추가할 경우 상태 머신 디자인 패턴은 이를 확장하기에도 용이하다 생각하여 선택하였습니다.</p>
</blockquote>
<p><code>꼬리 질문 b. Unity를 사용하면서 경험해볼 수 있는 대표적인 디자인패턴이 무엇인지 설명해주세요.</code></p>
<blockquote>
<p>유니티에서 사용하는 가장 대표적인 패턴은 <strong>싱글톤 패턴</strong>이라고 생각합니다. 특정 클래스의 <strong>인스턴스가 오직 하나만 생성되도록 보장하는 패턴</strong>으로, 해당 클래스의 인스턴스를 <strong>전역적으로 접근</strong>할 수 있게 하여 객체 생성 및 메모리 사용을 최적화하는 데 사용됩니다.</p>
</blockquote>
<br>

<hr>
<br>

<p>실수로 생긴 오류를 잡는 것이 세상에서 제일 어려운 것 같다.</p>
<p>상속을 해놓고 base의 함수를 불러오지 않는 등의 행위를 하지 않도록 주의해야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 65일차 - 정보값 활용]]></title>
            <link>https://velog.io/@purangi_code/TIL-65%EC%9D%BC%EC%B0%A8-%EC%A0%95%EB%B3%B4%EA%B0%92-%ED%99%9C%EC%9A%A9</link>
            <guid>https://velog.io/@purangi_code/TIL-65%EC%9D%BC%EC%B0%A8-%EC%A0%95%EB%B3%B4%EA%B0%92-%ED%99%9C%EC%9A%A9</guid>
            <pubDate>Wed, 27 Mar 2024 12:30:31 GMT</pubDate>
            <description><![CDATA[<p>📝 24.03.27</p>
<h3 id="오늘의-질문-1">오늘의 질문 1)</h3>
<blockquote>
<p><strong>상속이란 무엇인지 프로젝트 내에 적용해 본 부분과 함께 예를 들어 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p>상속이란 <strong>기존의 클래스를 확장하거나 재사용하여 새로운 클래스를 생성하는 것</strong>을 말합니다. 제가 사용했던 프로젝트로 예를 들면, 몬스터와 플레이어가 공유하는 스탯들인 공격력, 방어력, 체력 등의 변수를 Status 클래스에 구현하고 PlayerStatus 클래스와 MonsterStatus 클래스에 상속하여 사용한 경험이 있습니다. 이렇게 상속을 활용하면 공통된 변수를 각각 구현할 필요 없이 상위 클래스의 변수를 재사용하여 구현할 수 있습니다. </p>
</blockquote>
<h3 id="오늘의-질문-2">오늘의 질문 2)</h3>
<blockquote>
<p><strong>오버로딩과 오버라이딩의 차이점을 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변-1">나의 답변</h3>
<blockquote>
<p>오버로딩은 <strong>동일한 메서드 이름을 가지고 있지만 매개변수의 개수, 타입 또는 순서가 다른 여러개의 메서드를 정의하는 것</strong>을 의미합니다. 그에 반해 오버라이딩은 <strong>부모 클래스에서 이미 정의된 메서드를 자식 클래스에서 재정의 하는 것을 의미</strong>합니다. 이때 메서드의 이름, 매개변수 및 반환 타입이 모두 동일해야 합니다.</p>
</blockquote>
<p>사실 이 오버로딩과 오버라이딩은 이름만 비슷하다 뿐이지 아예 다른 것이라 차이점이라고 집을만한 것을 잘 모르겠다. </p>
<br>

<hr>
<br>

<p>튜터님의 가르침을 받아 스킬 정보를 주고받는 방식으로 수정하였다. 이 과정에서 </p>
<pre><code class="language-cs">public List&lt;SkillInfoData&gt; skillInfoDatas { get; set; } = new List&lt;SkillInfoData&gt;();</code></pre>
<p>를 선언부 없이 사용하려다가 null 오류가 났었다. 늘 주의해야할 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 64일차 - 불필요한 코드 정리]]></title>
            <link>https://velog.io/@purangi_code/TIL-64%EC%9D%BC%EC%B0%A8-%EB%B6%88%ED%95%84%EC%9A%94%ED%95%9C-%EC%BD%94%EB%93%9C-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@purangi_code/TIL-64%EC%9D%BC%EC%B0%A8-%EB%B6%88%ED%95%84%EC%9A%94%ED%95%9C-%EC%BD%94%EB%93%9C-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 26 Mar 2024 12:51:46 GMT</pubDate>
            <description><![CDATA[<p>📝 24.03.26</p>
<p>코드 구조를 변경하겠다고 마음을 먹을때가 가장 어려운 일 같다. </p>
<p>특히 이번엔 캐릭터 애니메이션 컨트롤러의 구조부터 바꾸는 일이라 더 어렵다.</p>
<p>요약하자면 AttackNumState를 삭제하고 AttackState로 통일하였고, 애니메이션을 3번 반복하면서 매 애니메이션 실행마다 Shoot을 실행하는 방법으로 수정하였다.</p>
<p>그리고 Attack 인풋을 AttackA, AttackS, AttackD 로 따로 분리하여 모두 OnAttack을 구독하는 방식으로 진행하였다.</p>
<p>아직 제대로 구동되는지 확인하지 못해서 추후 수정이 더 필요할 수도 있겠다.</p>
<br>

<hr>
<br>

<p><strong>기술 면접 피드백</strong></p>
<blockquote>
<ol>
<li>경험이 많다는 의미가 없다 -&gt; 경험을 왜 많이 해보았는지 -&gt; 적극성</li>
<li>마감을 급박하게 받아들이려 한다 -&gt; 책임감으로 이어줄 수 있음 -&gt; 좀 더 발전해나갈 수 있다.</li>
</ol>
<p>한 호흡에서 너무 많이 말하려고 함
끝에서 급해지는 걸 고쳐야 함.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 63일차 - 기술 면접 문답 목록]]></title>
            <link>https://velog.io/@purangi_code/TIL-63%EC%9D%BC%EC%B0%A8-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EB%AC%B8%EB%8B%B5-%EB%AA%A9%EB%A1%9D</link>
            <guid>https://velog.io/@purangi_code/TIL-63%EC%9D%BC%EC%B0%A8-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EB%AC%B8%EB%8B%B5-%EB%AA%A9%EB%A1%9D</guid>
            <pubDate>Mon, 25 Mar 2024 12:19:34 GMT</pubDate>
            <description><![CDATA[<p>📝 24.03.25</p>
<h3 id="15-정렬-알고리즘">15. 정렬 알고리즘</h3>
<blockquote>
<p><strong>정렬 알고리즘이란 무엇이며, 사용 이유에 대해 설명해주세요.</strong></p>
</blockquote>
<p><strong>답변</strong></p>
<blockquote>
<p>정렬 알고리즘이란 <strong>데이터들을 번호순이나 사전 순서와 같이 일정한 순서대로 열거하는 알고리즘</strong>입니다. 정렬을 통해 <strong>데이터 처리 및 검색의 효율성</strong>을 높일 수 있으므로 사용됩니다. 따라서 데이터의 크기와 상황에 따라 적절한 정렬 알고리즘을 사용하는 것이 중요합니다.</p>
</blockquote>
<h3 id="16-선택-정렬과-버블-정렬">16. 선택 정렬과 버블 정렬</h3>
<blockquote>
<p><strong>선택 정렬과 버블 정렬에 대해 설명해주시고, 코드를 작성해보세요.</strong></p>
</blockquote>
<p><strong>답변</strong></p>
<blockquote>
<p><strong>선택 정렬</strong>이란 배열에서 최소값(또는 최대값)을 찾아 맨 앞(또는 맨 뒤)와 교환하는 방법으로 정렬하는 알고리즘이고, <strong>버블 정렬</strong>은 서로 인접한 두 원소를 검사하여 정렬하는 알고리즘입니다.</p>
</blockquote>
<p><strong>선택 정렬</strong></p>
<pre><code class="language-cs">for(int i = 0; i &lt; arr.Length - 1; i++)
{
    int minIndex = i; //첫번째 인덱스부터 기준을 잡고 확인

    for (int j = i + 1; j &lt; arr.Length; j++) 
    { //기준 인덱스 뒤의 모든 숫자들 중 가장 최소값을 가진 인덱스 번호 찾기
        if (arr[j] &lt; arr[minIndex])
        {
            minIndex = j;
        }
    }

    //기준 인덱스보다 작은 값의 인덱스가 뒤에 있다면 서로 바꾸기(swap)
    int temp = arr[i]; 
    arr[i] = arr[minIndex];
    arr[minIndex] = temp;
}</code></pre>
<p><strong>버블 정렬</strong></p>
<pre><code class="language-cs">int i, j, temp;

for(i=n-1; i&gt;0; i--){
// 0 ~ (i-1)까지 반복
  for(j=0; j&lt;i; j++){
  // j번째와 j+1번째의 요소가 크기 순이 아니면 교환
    if(list[j]&lt;list[j+1]){
      temp = list[j];
      list[j] = list[j+1];
      list[j+1] = temp;
    }
  }
}</code></pre>
<h3 id="17-스택-힙-메모리">17. 스택, 힙 메모리</h3>
<blockquote>
<p>** 스택, 힙 메모리란 무엇이며 어떤 차이가 있는지 비교해서 설명해주세요.**</p>
</blockquote>
<p><strong>답변</strong></p>
<blockquote>
<p><strong>스택</strong>은 <strong>정적 메모리 할당 영역</strong>으로 함수 호출 및 지역 변수의 저장에 사용되며 <strong>후입선출(LIFO)</strong> 구조를 가지고 있습니다. 그에 반해 <strong>힙</strong>은 <strong>동적 메모리 할당 영역</strong>으로 동적 배열이나 연결 리스트 등의 동적 데이터 구조에 사용됩니다. 그리고 스택과 달리 먼저 들어온 데이터가 먼저 나가는 <strong>선입선출(FIFO)</strong> 구조를 가지고 있습니다.</p>
</blockquote>
<h3 id="18-값-형식과-참조-형식">18. 값 형식과 참조 형식</h3>
<blockquote>
<p><strong>값 형식과 참조 형식의 차이에 대해 설명해주세요.</strong></p>
</blockquote>
<p><strong>답변</strong></p>
<blockquote>
<p><strong>값 형식</strong>은 변수가 직접 해당 데이터를 보유하고 있어, <strong>변수가 할당된 값을 변경할 때 해당 값을 복사하는 구조</strong>입니다. 값 형식은 <strong>스택 메모리 영역</strong>에 저장됩니다. <strong>참조 형식</strong>은 해당 변수가 데이터에 대한 메모리 주소를 보유하고 있어, <strong>변수가 할당된 값을 변경할 때 해당 값을 참조하는 구조</strong>입니다. 참조 형식 변수는 <strong>힙 메모리 영역</strong>에 저장됩니다.</p>
</blockquote>
<h3 id="19-자료구조의-종류">19. 자료구조의 종류</h3>
<blockquote>
<p><strong>자료구조의 종류는 무엇이 있으며 각각 어떤 차이점이 있는지 설명해주세요</strong></p>
</blockquote>
<p><strong>답변</strong></p>
<blockquote>
<p>C#에서 사용되는 자료구조의 종류로는 크기가 고정되어있는 <strong>배열</strong>, 그와 반대로 크기를 동적으로 할당할 수 있어 삽입과 삭제가 용이한 <strong>리스트</strong>, 선입선출 구조의 <strong>큐</strong>, 후입선출 구조의 <strong>스택</strong>, 값만 저장하는 다른 자료구조들과 달리 키와 값을 쌍으로 저장하는 딕<strong>셔너리</strong> 등이 있습니다. </p>
</blockquote>
<p><code>꼬리질문: 위 자료구조는 무조건 좋은가요?</code></p>
<p><strong>답변</strong></p>
<blockquote>
<p>모든 자료구조는 <strong>데이터의 크기나 사용되는 곳</strong>에 따라 적합한 곳이 다릅니다. 따라서 <strong>어떤 자료구조가 해당 알고리즘을 구현하기에 편리한지</strong> 늘 고려하여 설계하는 것이 중요합니다.</p>
</blockquote>
<h3 id="20-객체-지향">20. 객체 지향</h3>
<blockquote>
<p>** 객체지향이란 무엇인지 설명해주세요. **</p>
</blockquote>
<p><strong>답변</strong></p>
<blockquote>
<p><strong>객체 지향 프로그래밍</strong>이란 현실 세계의 사물을 모델링하여 프로그래밍하는 개발 방법론 중 하나입니다.</p>
</blockquote>
<p><code>꼬리질문 a. 객체지향의 특징은 무엇이 있나요?</code></p>
<blockquote>
<p><strong>객체 지향의 특징</strong>으로는 크게 4가지가 있습니다. 데이터와 그 데이터를 처리하는 메서드를 하나의 단위로 묶는 <strong>캡슐화</strong>, 기존 클래스의 속성과 메서드를 자식 클래스에서도 사용할 수 있게 하는 <strong>상속</strong>, 같은 이름의 메서드가 다른 상황에서 다르게 동작할 수 있는 <strong>다형성</strong>, 공통의 속성을 묶어서 클래스로 표현하는 <strong>추상화</strong>가 바로 객체 지향의 주요 특징입니다.</p>
</blockquote>
<p><code>꼬리질문 b. OOP란?</code></p>
<blockquote>
<p><strong>객체 지향 프로그래밍</strong>의 영어 약자입니다.</p>
</blockquote>
<p><code>꼬리질문 c. SOLID 원칙은 무엇인가요?</code></p>
<blockquote>
<p>SOLID 원칙이란 <strong>대표적인 객체 지향 프로그래밍 원칙</strong>입니다. 클래스는 하나의 책임만 가져야 한다는 <strong>단일 책임 원칙</strong>, 확장에 대해 열려 있고 수정에 대해서는 닫혀있어야 한다는 <strong>개방-폐쇄 원칙</strong>, 상위 타입은 하위 타입으로 교체할 수 있어야 한다는 <strong>리스코프 치환 원칙</strong>, 인터페이스는 클라이언트 요구 사항에 따라 적절히 분리되어야 한다는 <strong>인터페이스 분리 원칙</strong>, 추상화에 의존함으로써 구현의 변경이 발생해도 고수준 모듈에는 영향을 주지 않아야 한다는 <strong>의존 역전의 원칙</strong>들이 있습니다. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 62일차 - 콜백 함수]]></title>
            <link>https://velog.io/@purangi_code/TIL-62%EC%9D%BC%EC%B0%A8-%EC%BD%9C%EB%B0%B1-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@purangi_code/TIL-62%EC%9D%BC%EC%B0%A8-%EC%BD%9C%EB%B0%B1-%ED%95%A8%EC%88%98</guid>
            <pubDate>Fri, 22 Mar 2024 12:46:03 GMT</pubDate>
            <description><![CDATA[<p>📝 24.03.22</p>
<h3 id="오늘의-질문">오늘의 질문</h3>
<blockquote>
<p><strong>콜백이란 무엇인가요? 사용해봤는지?</strong></p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p>콜백이란 <strong>특정 이벤트가 발생했을 때 함수나 메서드를 다른 함수나 메서드의 매개변수로 전달하여 호출하도록 하는 프로그래밍 매커니즘</strong>입니다. 유니티 프로젝트에서 Input System사용 시 콜백 함수를 자주 사용해보았습니다. Input System의 Action이 실행되었을 때 실행될 함수들을 콜백 함수로 구현하여 사용했습니다.</p>
</blockquote>
<p>오늘은 중간 발표 준비로 피곤하여 여기서 TIL 작성을 마치겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 61일차 - 람다식이란]]></title>
            <link>https://velog.io/@purangi_code/TIL-61%EC%9D%BC%EC%B0%A8-%EB%9E%8C%EB%8B%A4%EC%8B%9D%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@purangi_code/TIL-61%EC%9D%BC%EC%B0%A8-%EB%9E%8C%EB%8B%A4%EC%8B%9D%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Thu, 21 Mar 2024 12:01:15 GMT</pubDate>
            <description><![CDATA[<p>📝 24.03.21</p>
<h3 id="오늘의-질문">오늘의 질문</h3>
<blockquote>
<p><strong>람다식(Lambda Expression)이 무엇인지 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p>람다식이란 <strong>메서드를 이름과 반환값없이 식 형태로 표현한 것</strong>입니다. 람다식 자체로 메서드의 매개변수로 전달할 수 있어 메서드를 변수처럼 다루는 것이 가능하게 만들어줍니다.</p>
</blockquote>
<br>

<hr>
<br>

<p>무언가를 구현하는 것보다 어려운 것이 오류를 수정하는 것이다. 구현하다보면 구현된 각 부분이 유기적으로 연결되지 않아 생기는 오류가 많다.</p>
<p>지금 내가 마주한 가장 큰 오류가 <strong>다른 상태가 실행중일 때는 이동이 안되는 것</strong>이다. 이것을 어떻게 해결해야 할 지 이미 구현된 부분들을 뜯어보고 고쳐야하는데 아직 감을 잡지 못해서 어렵다.</p>
<p>이로 인한 현재 문제가</p>
<ol>
<li>이동 중 점프는 가능하지만 점프 중 이동 불가능</li>
<li>스킬 사용하면서 이동 불가능</li>
</ol>
<p>이 있으므로 핵심적 문제를 파악해야 할 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 60일차 - 구성의 변경]]></title>
            <link>https://velog.io/@purangi_code/TIL-60%EC%9D%BC%EC%B0%A8-%EA%B5%AC%EC%84%B1%EC%9D%98-%EB%B3%80%EA%B2%BD</link>
            <guid>https://velog.io/@purangi_code/TIL-60%EC%9D%BC%EC%B0%A8-%EA%B5%AC%EC%84%B1%EC%9D%98-%EB%B3%80%EA%B2%BD</guid>
            <pubDate>Wed, 20 Mar 2024 12:57:10 GMT</pubDate>
            <description><![CDATA[<p>📝 24.03.20</p>
<h3 id="오늘의-질문">오늘의 질문</h3>
<blockquote>
<p><strong>&#39;delegate&#39;, &#39;event&#39;, &#39;action&#39;, &#39;func&#39; 간의 차이를 설명해주세요.</strong></p>
</blockquote>
<h3 id="나의-답변">나의 답변</h3>
<blockquote>
<p>delegate, action, func, event 모두 메소드에 대한 참조 변수를 만들기 위해 존재하는 대리자입니다. 이 중 delegate가 가장 기본적인 형태입니다. action과 func은 C#에서 미리 정의된 delegate 유형들로, action은 그 중 매개변수를 받지 않고 값도 반환하지 않는 메서드를 나타냅니다. 그리고 func은 action과 달리 값을 반환하는 메서드를 나타냅니다. 그리고 event는 델리게이트와 거의 유사하지만 delegate와 달리 interface 내부에서 선언할 수 있고, delegate는 interface 내부에서 선언할 수 없습니다.</p>
</blockquote>
<ul>
<li><h3 id="꼬리질문">꼬리질문</h3>
<blockquote>
<p>프로젝트에 적용해 본 경험이 있다면 설명해주세요.</p>
<br>
답변 : 유니티 프로젝트에서 action을 많이 사용하였습니다. 그 중 한 예시로 TimeKeeper라는 프로젝트에서 스테이지를 클리어하였을 때의 action을 만들어 스테이지 클리어 보상을 받고 게임 진행이 멈추는 메소드를 구독하여 사용한 경험이 있습니다.
</blockquote>
</li>
</ul>
<br>

<hr>
<br>

<p>스킬 구현을 플레이어 하위 오브젝트의 애니메이션으로 구성했었다.</p>
<p>하지만 이 경우 캐릭터가 이동하면 스킬도 따라 이동한다는 문제점이 생긴다. 따라서 외부의 Skill 오브젝트를 생성시켜 공격을 주는 방향으로 수정해야하는데 구상이 잘 안되어 여러 자료 조사만 하다 시간이 지났다. 내일부터 본격적으로 구현에 착수해봐야 할 것 같다.</p>
]]></description>
        </item>
    </channel>
</rss>