결과

 

A* 알고리즘 구현을 해보기 위해 준비하다가 , 마우스 클릭으로 쉽게 장애물을 만들고 장애물 경로를 피해 찾아갔으면 좋겠다 싶어서 마우스 클릭으로 장애물을 만드는 기능을 구현했다.

 

RayCast를 활용하여 구현 하였고 해당 기능이 있으면 Play를 하여 내가 원하는 경로를 직접 만들어 줄 수 있는것이 장점이다.

 

 

코드는 생각나는데로 하드 코딩하여 썩 좋은 코드는 아니다.

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

public class GridMapGenerator : MonoBehaviour
{
    [SerializeField] private GameObject obstacle;
    [SerializeField] private GameObject selectAreaPrefab;

    public LayerMask Selectlayer;
    private GameObject selectArea;

    float delayClick = 0.1f;
    float curClickTimer;

    private void Awake()
    {
        selectArea = Instantiate(selectAreaPrefab);
    }

    private void Update()
    {
        curClickTimer += Time.deltaTime;

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);


        if (Physics.Raycast(ray,out RaycastHit hit,1000.0f))
        {
            Debug.DrawLine(ray.origin, hit.point, Color.red);
            
            selectArea.transform.position = new Vector3(Mathf.Round(hit.point.x), 0.1f, Mathf.Round(hit.point.z));

            if (Input.GetMouseButton(0) && curClickTimer > delayClick && LayerMatchCheck(hit.transform.gameObject.layer, Selectlayer))
            {
                curClickTimer = 0;

                GameObject obj = Instantiate(obstacle);
                Vector3 pos = new Vector3(selectArea.transform.position.x, 0, selectArea.transform.position.z);
                obj.transform.position = pos;
            }
        }

       
    }

    private bool LayerMatchCheck(int target , LayerMask layer)
    {
        if(layer == (layer.value | 1 << target ))
        {
            return true;
        }

        return false;
    }
}

https://01149.tistory.com/178

 

Unity :: 셰이더 그래프

셰이더 그래프란?HLSL(High Level Shader Language) 코드 작성 없이 노드 기반으로 셰이더를 만들수 있는 기능입니다. 셰이더 그래프 사용 방법?1. Project 부분에서 해당 경로를 따라가서 셰이더 그래프를

01149.tistory.com


 

1. 포트폴리오 제작 중 

출시 목적으로 스토리 + 카드형 턴제 전투 게임을 개발 중이며 , 현재 대화시스템을 구글 스프레드 시트와 연동하여

테스트 중이다.

해당 작업이 완료되는데로 TIL에 따로 작성할 목적

 

2.내일배움캠프에서 진행되는 바로인턴10기 지원

Unity 클라이언트 프로그래머의 취업문이 좁다보니 , 한달동안 인턴 생활을 하는 제도가 있어

지원서를 작성하여 신청하였다. 지원서에 붙으면 서류 및 과제를 이틀동안 작성하여 제출하여야한다.

작성되어 크니브 스튜디오에 인턴이 되었으면 좋겠다. 

UI가 아닌 오브젝트를 클릭해서 이동하는 것을 구현 하고 싶었다.

 

현재 드래그 이동이 아닌 클릭 후 카드를 움직이는 방식으로 구현하였다.

 

public class TestInputController : MonoBehaviour
{
    [SerializeField] private LayerMask cardLayerMask;
    private GameObject cardObject = null;
    private bool isCardSelect = false;

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            //화면 좌표계에 있기에 월드 좌표로 변환
            Vector2 worldPos = Camera.main.ScreenToWorldPoint(Mouse.current.position.ReadValue());
            RaycastHit2D hit = Physics2D.Raycast(worldPos, Vector2.zero, 0f, cardLayerMask);

            if (!isCardSelect && hit.collider != null)
            {
                Debug.Log(hit.transform.name);
                cardObject = hit.collider.gameObject;
                isCardSelect = true;
            }
            else if (isCardSelect)
            {
                cardObject = null;
                isCardSelect = false;
            }
        }

        if (cardObject != null)
        {
            Vector3 pos = Camera.main.ScreenToWorldPoint(Mouse.current.position.ReadValue());
            pos.z = 0;
            cardObject.transform.position = pos;
        }
    }
}

현재 Update() 문으로 구현을 해서 최적화에 좋지 않을것이다. 

1.마우스 클릭 Class를 생성후, event를 등록시켜서 필요할때만 호출 시키는 형식으로 리팩토링이 필요하다. 

2.InputSystem을 활용하여 event로 연동 시킨다.

 

이 두가지 방법 중 하나를 택해서 진행하게 될것같다. 

 

Card Class 안에 IPointerHandler를 상속시켜 쉽게 진행 할 수도 있었겠지만, 

Card에는 카드가 게임에서 사용되는 효과,연출이 담겨 있어야 되고 

Card를 조작하는 것은 InputController에서 담당을 해야 SRP(단일 책임 원칙)을 지킬 수 있을것 같아

이렇게 구현 하였다. 

 

 if (Input.GetMouseButtonDown(0))
        {
            //화면 좌표계에 있기에 월드 좌표로 변환
            Vector2 worldPos = Camera.main.ScreenToWorldPoint(Mouse.current.position.ReadValue());
            RaycastHit2D hit = Physics2D.Raycast(worldPos, Vector2.zero, 0f, cardLayerMask);

이부분은 InputManager 와 InputSystem 둘다 사용 중이기에 하나를 택해서 바꿔서 진행해야 된다. 

 

InputSystem의 현재 마우스 좌표를 반환하는 메서드, 반환값은 Vector2
Layer를 Card로 선언하여 RayCastHit를 이용하여 체크후 이동시킨다.

 

https://github.com/lostwaltz/PossibleDefense

 

GitHub - lostwaltz/PossibleDefense

Contribute to lostwaltz/PossibleDefense development by creating an account on GitHub.

github.com

 

해당 프로젝트에서 발생한 트러블 슈팅 중의 하나인

<타워 이동시 기존에 있던 타일 데이터가 초기화 되지 않는 이슈> 가 있었는데 , 발표 자료에만 작성이 되어있어

블로그에 기록 하려고 한다. 

 

발표에서 사용했던 자료

문제원인

1.타워가 원하는 타일로 이동 후 기존 타일의 데이터를 따로 가지고 있지 않아


타일 데이터가 타워가 없는데도 있다고 판정을 함
2.해당 문제로 인하여 타워 소환 및 타워 판매시에 데이터가 꼬여버림
 

문제원인

1.BaseSlimeTower 에 프로퍼티로 설치 가능한 타워의 Index를 저장하고
필요할때마다 불러서 값을 수정해주기로 변경

다음 프로젝트시 적용

1. Tile 코드를 작성하면서 Inventory와 유사한 방식이였던것을 알아서


다음 프로젝트 진행 시 Tile처럼 데이터를 보관할 일이 생기면 event를
활용해야 된다고 생각함

 


타워의 데이터 대신에 Index(int) 자료값을 사용하여 , 메모리를 최적화 하였습니다. 

최종 프로젝트를 진행하면서 느낀 것이 하나 있다.

DB를 관리하면서 너무 불편했던 경험이 있다.

GitHub를 이용해서 데이터 관리를 하니 데이터가 변경 되었을때 해당 작업자가 상위 브런치에 Merge를 해야만

변경된 데이터를 확인할수가 있어서 너무 불편했었다. 

 

해당 프로젝트에서는 메인 기획자라고 할 사람이 없었지만 , 내가 회사에 취직했을때는 기획자가 데이터 값을 변동만하면 바로 적용 하게 해야할 필요를 느꼇다.

 

구글 스프레드 시트를 이용하여 온라인으로 외부 데이터를 읽어오는 방식이다.

현재 방법은 구글 스프레드 시트 API를 이용하지 않는 방법으로 간단한 프로젝트를 구성할때 좋은 방식이다. 

 

 

 

해당 구글 스프레드 시트에 데이터를 기입하자.

 

구글 스프레드시트에 데이터를 기입하고 [공유] 버튼을 눌러 링크를 활성화 하자.

 

공유에 있는 링크를 가져오자

 

이렇게 가져온 링크를 밑에 스크립트 코드에 붙여 넣는다. 

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

//복사해온 URL : URL주소

//1.복사해 온 주소에서 끝에 있는 "edit?usp=sharing" 삭제한다.
//2.삭제 한 주소에 다음을 추가한다 "export?format=tsv&range=A2:E";
//2-1. 설명 : 모드와 포맷 그리고 시트의 범위를 뜻함, =A2:E 를 엑셀 연산식에 적용시 범위를 알수 있음 

//사용할 URL :  URL주소 + export?format=tsv&range=A2:E


public class GoogleSheetDBLoader : MonoBehaviour 
{
    private string sheetData; // URL에서 불러온 데이터를 저장하는 변수
    private readonly string googleSheetURL = "사용할 URL";

    public string SheetData { get => sheetData; set => sheetData = value; }

    IEnumerator Start()
    {
        //UnityWebRequest 인스턴스 리소스 해제를 위한 using
        using(UnityWebRequest www = UnityWebRequest.Get(googleSheetURL))
        {
            yield return www.SendWebRequest();

            if(www.isDone)
            {
                sheetData = www.downloadHandler.text;
            }
        }

        DisplayText();
    }

    public void DisplayText()
    {
        //Split 함수로 데이터 처리하기
        string[] rows = sheetData.Split('\n'); //행 데이터 (카드의 데이터 모음)

        string str = "";
        for (int j = 0; j < rows.Length; j++)
        {
            string[] columns = rows[j].Split('\t'); // 열 데이터 (카드의 데이터 중 하나)

            //첫번째 행의 카드 데이터를 출력한다.
            for (int i = 0; i < columns.Length; i++)
            {
                str += columns[i] + " ";
            }

            str += "\n";
        }

        Debug.Log(str);
    }
}

 

이렇게하면 해당 스크립트에 범위에 표시된 데이터를 다 문자열로 파싱해온다.

 

범위는 추가되는 URL의 ( A2:E ) 이 부분을 수정해서 사용하면된다.

물론 이 코드는 확장성에서 많이 떨어지는 부분이 있기에 나중에 프로젝트가 커지면 API를 사용하는게 더 효율적일것이다. 

URL에 추가할때 해당 빨간상자 친 부분을 수정해주면된다.

 

 

불러온 구글 스프레드 시트 데이터가 출력된다.

 

해당 기능을 이용하여 나중에 게임에 DB를 구성하여 사용 할수 있을것이다. 

C# 질문

더보기

 

21 인터페이스와 추상클래스의 차이는 무엇인가요? 인터페이스는 행동에 대한 추상화가 필요할때 사용됩니다.
예상이 되지 않는 행동일때 많이 사용되며
A has B관계로 고양이 =/=걷다 이지만 , 고양이는 걷는 행동을 할 수 있습니다.

추상클래스는 구체적인 추상화가 필요할때 사용됩니다.
필드,메서드 를 부모,자식 사이에서 공통적으로 사용할때 많이 사용됩니다.
A is B관계로 , 고양이 = 동물 , 강아지 = 동물
22 가비지 컬렉터란 무엇인가요? GC란 Heap 영역에서 참조가 끊겨 사용하지 않는 데이터들을 수집하여
처리해주는 기능입니다.
23 가비지 컬렉터의 장점과 단점에 대해 설명해주세요. GC의 장점은 프로그래머가 신경을 덜 써도 되기에 실수 발생률을 줄여줍니다.
메모리의 할당 해지는 런타임시 매우 중요합니다.
즉, 프로그래머가 놓친 부분을 GC가 자동으로 다 처리해주는 것이 장점입니다.

단점으로는 GC는 처리비용이 높기에 결국 너무 의존해서는 안됩니다.
GC는 프로그래머가 원하는 호출시점을 알 수 없기에 런타임 되고 있는
프로그램이 어느순간 렉을 먹거나 하는 경우입니다.
24 가비지 컬렉터의 세대 개념에 대해 설명해주세요. GC의 세대 개념은 Java는 .NET에서 사용되는 개념입니다.
GC는 일반적으로 <세가지 세대>로 메모리를 나눕니다

0세대는 객체가 생성되면 할당됩니다.
1세대는 GC가 동작한뒤 사용되고 있는 0세대 객체들이 1세대로 승격합니다.
똑같은 동작을 반복하게 되고 1세대에서 살아남은 객체들은 2세대로 승격하게
됩니다.

즉, 2세대는 가장 큰 메모리 공간을 차지하게되며 계속 쌓이게 되면 오버헤드
문제점을 일으킬수도 있습니다.

크기가 큰 객체는 LOH(라지 오브젝트 heap)에 할당되에
일반적인 세대 기반 수집과는 다른방식으로 처리됩니다.
25 박싱, 언박싱을 사용할 때 주의해야 할 점은 무엇일까요? 박싱,언박싱은 결국 형변환의 일종이기에 박싱을 한 필드(변수)가 언박싱 될때
다른 자료형으로 변환시 잘못된 데이터가 들어가는 경우를 주의해야 합니다.
null값이 들어가게 될수도 있다.
이러한 단점을 방지하기 위해 제네릭을 사용 할 수 있습니다.
26 오브젝트 풀을 사용하면 메모리 관리에 도움이 되는 이유가 무엇일까요? 오브젝트를 Inisiate/Destroy를 반복하게 될경우 오브젝트의 생성/파괴시
처리비용이 높으며 , 파괴는 즉 GC의 수집량을 늘리는 상황이 됩니다.

즉 오브젝트 풀링을 사용하여 런타임시에 사용할 오브젝트를 미리 할당해놓고
사용하게되면 필요없는 생성/파괴가 일어나지 않기에 메모리 관리에 도움이
됩니다./
27 제네릭이란 무엇인가요? 제네릭이란 일반화로 , 클래스를 자료형에 상관없이 사용할때,
즉,다양한 데이터 타입으로 재사용 할수 있는 기술이며
자주 사용되는 Class를 변수처럼 사용하기 위한 용도로 보면됩니다.

28 람다식(Lambda Expression)이 무엇인지 설명해주세요. 람다식은 이름없는 함수로도 불리며,
원하는 호출시점에서 편하게 생성하여 사용 할 수 있는 기능이다.
단점으로는 이름이 없기에 다른 곳에서 호출하지 못하여 재사용성이 떨어지는
단점이 있다.
29 LINQ란 무엇인가요? LINQ를 설명하기전에 쿼리에 대해 알아야합니다.
쿼리는 DB에 정보를 요청하는 행위 ,즉 데이터를 필터링,정렬,조회 등등할때
사용되는 단어입니다.

LINQ는 .NET 프레임워크에 내장된 기능이며
사용하면 좀더 SQL, 컬렉션, XML, 엔티티 프레임워크 등의 데이터에
접근하여 쉽게 관리 할 수 있습니다.

하지만 LINQ의 단점으로는 간단한 데이터 조회시에는 괜찮지만
데이터가 복잡해지고 양이 많아지게 되면 퍼포먼스나 코드 가독성 면으로
떨어질수 있습니다.
30 리플렉션(Reflection)이 뭔지, 사용을 해봤다면 어떤 이유에서 사용했는지 설명해주세요. 리플렉션은 .NET에서 런타임에 메타데이터를 사용하여 클래스,메서드,
프로퍼티 등에 접근하고 조작할 수 있는 기능을 말합니다.

보통 코드를 빌드 과정에서 컴파일시에 해당 프로그램에 사용되는 자료형이
선언이 되는데, 해당 동작은 그 과정을 위반하고 런타임 중에 동적으로 생성하는것이다.

즉, 이러한 동작이 처리비용이 높고 , 컴파일 타임의 안정성을 저해하기 때문에
사용에 매우 신중을 가해야 된다고 생각합니다.

 

유니티 질문

더보기

 

1 Unity 생명주기(Unity Life Cycle)에 대해서 설명해주세요. Monobehaviour를 상속한 Class의
함수 호출 시점을 나타낸 것이다. 즉, 이 생명주기 함수들로
Class의 초기화,생성,업데이트,파괴를 할 수 있는것입니다.
2 MonoBehaviour 클래스의 주요 메서드와 그 기능에 대해 설명해주세요. 주요 메서드로 Awake와 Start,Update가 있습니다.
물론 이 밖에도 주요 메서드들은 더 있지만 이 3가지를
주로 사용하였기에 설명해보겠습니다.

2-1 MonoBehaviour 클래스에서 Start와 Awake의 차이점은 무엇이며,
이를 적절히 사용하는 방법에 대해 설명해주세요
Awkae와 Start의 주요 차이점은 호출 시점입니다.
Awake는 오브젝트가 활성화되자마자 호출됩니다.
Start는 오브젝트가 활성화 된 이후 첫 번쨰 프레임 업데이터 전에
호출됩니다. 즉, Awake보다 뒷 시점에 호출이 됩니다.

Awake는 스크립트간의 참조, 즉 초기화를 하기위해
주로 사용합니다.

Start는 Awake에서 초기화가 되고 난 후의 동작을 할때
주로 사용 하였습니다.
3 Update, FixedUpdate, LateUpdate의 차이점에 대해 설명해주세요. Update는 매 프레임마다 호출되는 메서드입니다.
FixedUpdate는 물리연산에 처리되는 메서드로 프레임률에 상관없이
일정한 간격으로 호출 됩니다.
LateUpdate는 프레임 종료직전에 한번 호출하게 되는 메서드입니다.
4 Time.deltaTime이란 무엇이며, 사용하는 이유에 대해 설명해주세요. deltaTime이란 프레임과 프레임 사이의 시간을 측정한것입니다.
이 델타타임이 필요한 이유는 기기의 성능에 따라 게임 플레이가
다른것을 보여주면 안되기 때문입니다.

간단히 말하면 핑이 튄다, 핑이 높다라는 표현이며 이 델타타임을 이용하여
기기성능에 상관없이 유저들에게 똑같은 게임 플레이를 제공 할 수 있습니다.
5 코루틴의 동작원리와 사용해본 예시를 함께 설명해주세요. 코루틴은 비동기라고 생각하지만 아닙니다. 메인 쓰레드에서 동작하며
비동기적으로 일시적으로 중단/재개 할수있는 기능입니다.

코루틴을 시작하게되면 메인 로직 동작중에 코루틴 시점이 오면
코루틴 함수가 동작하고 종료되면 다시 원복하여 메인 로직을
동작하게 하는 원리입니다.

사용해본 예시로 , Update 처럼 매 프레임을 체크할 필요는 없
6 Invoke와 코루틴의 차이에 대해 설명해주세요. Invoke는 인자값을 사용 할 수 없지만 코루틴은 인자값을 사용 할수 있습니다.
즉 , 간단한 시간 지연 함수 호출시에는 Invoke가 좋지만 , 로직 및 구조가
복잡해지고 확장성을 챙겨야 되는경우에는 코루틴이 적합하다고 생각합니다.
7 코루틴과 멀티쓰레딩은 어떤 차이가 있는지 설명해주세요. 코루틴은 메인스레드에서 동작하며 비동기적으로 동작하는거고
멀티쓰레딩은 스레드를 여러개 생성하여 비동기로 동작합니다.
즉, 여러 로직(렌더링,서버)를 병렬로 작업하여 효율성을 증가합니다.
8 유니티 최적화 기법은 어떤 것들이 있나요? 여러장의 스프라이트를 하나의 파일로 관리하는 스프라이트 아틀라스 및
거리에 따른 렌더링 최적화 기법인 LOD 기법 , 카메라의 영역에 있지 않으면
렌더링하지 않는 오클루전 컬링 기법 등을 알고 있습니다.
8-1 최적화를 해본 적이 있나요? 없다면 어떤 최적화가 있는지 설명해주세요. 2D 슈팅게임을 만들며 , 플레이어 캐릭터 및 적,투사체의 Sprite리소스를 Sprite
아틀라스로 만들어 사용했던 적이 있습니다. 해당 기능을 사용하여
기존에 Sprite를 사용했던것보다 SpriteAtala를 사용하여 드로우콜을 최적화한
경험이 있습니다.
8-2 최적화에서 가장 중요한 부분은 무엇인가요? 해당 최적화에서 중요한 부분은 DrawCall를 최소한으로
호출하는것입니다. 렌더링이 아주 큰 처리비용을 가지고 있기에
최소한의 DrawCall을 사용해야됩니다.
8-3 최적화를 위해서 적용해본 텍스쳐 포맷이 있나요? 텍스쳐 포맷은 따로 사용해본적은 없습니다. 하지만 필요로 해야되는 기능이기에
꼭 익혀서 자신의 것으로 만들어놓겠습니다.
9 드로우콜에 대해서 설명하고, 최적화하는 방식에 대해 알고 있는 것이 있으면 설명하세요. 드로우 콜은 CPU가 현재 프레임에 무엇을 그릴지 결정하고
GPU에 그리게하는 것입니다.

제가 아는 최적화 방식은 LOD(Level of Detail) 기법이 있습니다.
GPU는 하나의 폴리곤을 그리기 위해 가까이 있든 멀리있든 해당 메쉬의 크기에 맞춰
그리게 됩니다. 하지만 이렇게되면 쿼드오버드로우 현상이 발생하게 되고 멀리 조그만한
점을 그리기 위해 4개의 픽셀을 사용하게되는 비효율적인 상황이 나옵니다.

즉 멀리있는 폴리곤은 그리지 않는것이 LOD 기법의 특징입니다.
10 Find 함수 사용을 자제해야 하는 이유에 대해 설명해주세요. FInd 함수는씬에 존재하는 모든 오브젝트를 탐색하기에
시간 복잡도 및 처리 비용이 매우 높기 때문입니다. 대처법으로는 하이어라키에
자식 오브젝트로 부모오브젝트가 필요한것을 배치하거나 컴포넌트를 사용하는
방법이 있습니다.

면접 자기 소개 작성

 

더보기

안녕하십니까, 소통을 중시하는 클라이언트 프로그래머 [송명성]입니다. 
제 열정과 노력으로 이 분야에서 역량을 키우고 있습니다.

2020년부터 2년간 공장 라인설비 회사에서 엔지니어로 근무하며 공장 라인 출장 업무를 주로 담당했습니다. 
이를 통해 문제 해결 능력과 관계자와의 원활한 소통 능력을 키울 수 있었습니다. 
이 경험은 이후 게임 개발 프로젝트에서도 팀원들과 협업하고 소통하는 데 큰 도움이 될 것입니다.

2022년부터는 본격적으로 프로그래머가 되기 위한 여정을 시작했습니다. 부산 아텐츠 게임아카데미에서 C/C++, 자료구조, 
컴퓨터 그래픽스를 배우며 기초를 다졌고, Unity를 활용해 2D 슈팅 게임을 모작하며 실제 개발 경험을 쌓았습니다. 
이를 통해 기초적인 게임 개발 과정과 Unity 엔진의 활용법을 익혔습니다.

2024년 8월에는 대전 인디게임잼에 프로그래머로 참가하여 **<마지막 빵>**이라는 스토리 어드벤처 게임을 개발했습니다. 
여기서 전체기획과 프로그래머로써 Scene 간 데이터 전달 파트를 맡으며, 제한된 시간 안에 팀원들과 협업하며 결과물을 만들어내는 
경험을 했습니다. 
하지만 당시 제 실력과 협업 능력의 부족함을 느껴, 이를 보완하고자 내일배움캠프 유니티 6기에 지원하게 되었습니다.

캠프에서는 매주 진행되는 미니 프로젝트의 리더를 맡으며 개발 실력뿐만 아니라 팀원들과의 소통, 리소스 분배, 일정 관리 능력을 키웠습니다. 
현재는 최종 프로젝트로 2.5D 방치형 게임을 개발하고 있으며, 이 게임은 itch.io에 배포할 예정입니다. 
이 과정에서 Unity 엔진을 심도 있게 다뤄보고, 팀원들과의 협업을 통해 하나의 완성된 게임을 만들어가는 기쁨을 느끼고 있습니다.

이러한 경험들을 통해 저는 단순히 개발 역량뿐만 아니라, 협업과 커뮤니케이션 능력을 갖춘 개발자로 성장하고 있습니다. 감사합니다.
앞으로도 제가 가진 열정과 팀워크 능력을 바탕으로 더 많은 도전을 통해 성장해 나가고 싶습니다. 감사합니다.

자기소개 나열식은 좋지 않다. -> 서사 얘기는 좋지 않다.
자기 소개 :: 듣는사람 입장에서 이사람이 나를 어떡해 기억할 수있지??

팀원과의 프로젝트에서 소통 및 갈등,트러블슈팅 등을 스토리텔링 서사를 풀어야된다. 

 


면집 질문 준비

C#의 event란 무엇인가요? Delegate 기반으로 구현된 대리자이며 ,
객체 간 비동기 통신을 가능하게 해줍니다.
event에 메서드를 첨삭하는것은 내부/외부에서도 가능하지만
event를 실행시키는 것은 내부에서만 가능합니다.
event는 Observer패턴과 동작방식이 유사합니다.

장점으로는 발행자와 구독자 간의 느슨한 결합으로
모듈화 및 유연성을 장점으로 가지고 있습니다.
Unity에서 사용하는 델리게이트 혹은 이벤트에는 어떤 것이 있나요? Unity의 Button 컴포넌트, InputSystem의 키 맵핑시
동작방식을 event로 선언할 수 있으며 , 여러 콜백 메서드가
있습니다.
참조 형식과 값 형식에 대해 설명해주세요. 값 형식의 Stack에서 생성되는 데이터들을 의미합니다.
흔히 사용되는 int,float,struct,,enum이 여기에 속합니다.

참조 형식은 Heap영역에 생성되는 데이터들을 의미하며
Heap영역의 데이터들은 Stack영역에 있는 데이터들을
참조를 하여 사용하게 됩니다.

그러기 때문에 참조 형식의 데이터는 변경이 되어도
다른 값형식의 변수에서 변경된 값을 가져오게 됩니다.
메모리에서 스택과 힙의 차이점에 대해 설명해주세요. 스택은 함수내에서 선언시나 변수 할당시 메모리가 생성이되며
함수가 종료될때 스택 영역의 데이터는 삭제됩니다.

힙은 new키워드나 Unity 에서 Instaniate를 통해 생성이 가능하고
참조를 끊을수는 있지만 heap에 저장된 메모리는 GC를 통해서만
삭제가 가능합니다.
1번과 2번 질문의 답안을 기반으로 struct와 class의 차이점에 대해 설명해주세요. 구조체는 Stack 영역에 저장되며 , 매개변수 없는 생성자를
작성할 수 없습니다. (C# 10 이상 예외)

클래스는 Heap 영역에 저장되며 매개변수 없는 생성자를
명시적으로 작성해서 사용합니다.
얕은 복사와 깊은 복사의 차이점은 무엇인가요? 얕은 복사는 데이터의 주소를 복사해 가는것이기에
외부에서 데이터가 변경 되는경우 원본 데이터가 변경이 됩니다.

깊은 복사는 데이터 그 자체를 복사하는것이기에
데이터가 변경되어도 원본 데이터는 유지를 하고 있습니다.
박싱과 언박싱이 일어나는 과정을 메모리 관점에서 설명해주세요. 우선 C#에서 박싱 언박싱을 하기위해서는
참조형식의 변수인 object가 필요합니다.
object 변수는 모든 데이터의 부모이기에 형변환이
가능하기 때문입니다.

박싱할 변수를 object 변수에 대입 하게되면
Stack 영역에 참조할 object 변수가 생성되고
Heap 영역에 object 에 박싱한
자료의 데이터가 저장되어있습니다.

언박싱은 heap영역에 존재하는
object 변수의 데이터를 Stack으로 복사하여
언박싱 할 변수에 생성하게 됩니다. 이
때 언박싱한 데이터는 독립적인 데이터가 됩니다.
클래스를 다른 클래스로 상속하기 위한 방법은 무엇인가요? 상속할 클래스 명 뒤에 세미콜론 과 부모클래스명 을 입력합니다.
클래스 상속에서 다이아몬드 문제(diamond problem)가 발생하는 이유와 이를 해결하는 방법에 대해 설명해주세요. C#에서는 Class간의 다중상속을 지원하지 않습니다.
C++ 에서는 Class간의 다중상속을 지원하기에 다이아몬드 문제가
발생 할수 있습니다.

다이아몬드 문제가 발생하는 이유는 두개의 자식클래스에서
동일한 부모 클래스를 상속 받은뒤 , 다른 클래스가 두개의 자식클래스를
둘다 상속 하고 있는경우 발생하게 됩니다,

부모의 있는 메서드나 필드에 접근하려고 할때
두 자식 클래스 호출이 애매모호 해짐

유니티<C#>에서는 해당 문제를 대처하기위해 다중 상속을 interface에만
지원을 해놓았습니다. 인터페이스는 구현체를 포함하지 않으므로
다이아몬드 문제와 같은 모호성 문제가 발생하지 않습니다.

C++ 에서는 가상 상속을 이용하여 다이아몬드 문제를 방지가 가능합니다.
인터페이스란 무엇인가요? 인터페이스란 ,일종의 행동의 약속이라고 볼수있습니다.
행동 즉, 메서드를 인터페이스에 정의하면 인터페이스를 상속한
클래스들은 반드시 해당 메서드를 재정의 해야됩니다.

 

Heap 영역은 답변시 완전이진트리 키워드가 나와야한다.

https://github.com/lostwaltz/PossibleDefense

 

GitHub - lostwaltz/PossibleDefense

Contribute to lostwaltz/PossibleDefense development by creating an account on GitHub.

github.com

 

일주일간 4명의 팀원과 진행한 모바일 3D 타워 디펜스 게임에 프로토타입을 개발하였다.

결과물은 만족 스럽게 나왔으나 코드 작성시에 하드코딩이 좀 많았던것 같아 회고를 해보려고 한다. 

 

해당 파트에서 나는 Stage에 관련된 파트를 담당했다.

 

Stage에서 필요한 기능들은

-Stage에 사용될 Tile 관리

-Tile에 설치될 타워 관리 (설치 및 판매)

-해당 Stage에서 사용될 타워 업그레이드

-Stage에서 사용되는 골드 재화

-로비 -> 게임 -> 로비 로 이동시의 Data 유지와 Scene 연결

요약하면 이정도가 될것같다. 

 

해당 기능들을 크게 키워드로 해서 Class로 기능을 분리해서 작업해야 가독성이 오르는데

이번에는 하드코딩도 많고 팀원끼리 소통을 그렇게 많이 했는데도 변수명을 정하지 않았던점이 문제였던것 같다.

GameScene에서 사용된 오브젝트들과 컴포넌트들인데, 전혀 가독성이 없고 코드가 일관성이 없어 보기 힘들다.

1번 문제점 :

UI매니저가 없기에 우선 UI를 만들어두자 하고 작업을 진행하였고 Refactoring 하는 과정에서

UI매니저를 작성하여 UI매니저에 집어넣고 꺼내쓰는 식으로 사용 했어야 됬는데 결국에는 UI매니저를 사용하기 위해 UIBase 인터페이스 자체도 작성하지 않아 결국에는 동적생성을 하지 못해 이런식으로 사용하게 되었다.

 

1번 문제의 대처점 : 첫 작업시에 프레임워크 작업을 진행하고 , 해당 매니저들을 미리 작성해놓아야한다.

그러기에 팀원과 회의를 정말 많이 해야된다. 

 

2번 문제점 :

3번과 연관되는 문제점이긴한데 SpawnManager가 있지만 이 Manager는 EnemySpanwManager이다.

이름이 직관적이지 않아 직접 열어봐야만 알수있고 BulletObjectPool은 하이어라키에있고

Tile ObjectPool은 왜 Stageamanager의 안에 있는지 의문이다. ( ObjectPoolLegacy가 Tile ObjectPool)

즉, Class 및 오브젝트의 이름이 직관성 없기때문에 발생했던 문제다.

 

2번 문제의 대처점 : 해당 오브젝트 명 컴포넌트 명을 정확하게 구체적으로 작성해서 사용 할것 

 

3번 문제점

위에서 말한 큼직큼직한 기능들을 키워드 삼아서 Class별로 분리해서 컴포넌트처럼 붙여 사용하거나 따로 오브젝트화 시켰어야했는데 StageManager에 관련없는 기능을 다 넣어서 사용 한것이 문제가 되었다.

 

정말 하드코딩하고 Inspector에 다 때려 밖은 상태 절대 이렇게 작업하면 안된다.

 

StageManager의 Inspector에서 보면 밑에 컴포넌트로 부착한것들을 전부 등록하여 사용하고있다.

물론 내부에서도 해당 컴포넌트들이 비면 null체크를 해서 컴포넌트를 호출해서 사용하고 있지만

이런 Inspector 구조는 가독성이 떨어지기에이런식으로 Inspctor에 정리없이 사용하면 안될것 같다. 

또한 Scene 전환시에도 Missing이 일어날 확률이 높다.

 

3번 문제의 대처점 : Inspector에서는 최소한으로 등록하여 사용하고 내부적으로 동적생성하게 코드를 구현해야 되며 UI매니저를 사용하여 UI를 원하는 시점에서 꺼내 쓸수 있게 구현 해야된다.

 

 

p.s 코드 구조를 잡지 않고 자료구조를 막 사용한 나쁜 예시

이 코드는 제출하기 직전에 급하게 만든 코드라 최적화를 생각하지 못했다.

타일을 선택할떄마다 타일 선택 정보를 초기화 해주는 코드인데 맨처음 작성시 자료구조를 List를 쓴것부터가 문제의 시작이였고 해당 문제를 해결하려면 TowerTiled을 딕셔너리로 변경해서 사용할수있게 구조를 바꿧어야 했다. 

 

 

그래도 해당 프로젝트에서는 오전 / 오후 / 저녁으로 자기의 코드리뷰와 프로젝트 진척도를 회의하는 시간을 계속 가져왔고

작업량이 없어도 무조건 코드리뷰를 하게 하였다. 그러면서 서로 문제점이 있는부분을 서로 보완해주고 서로에 대한 정보공유를하면서 정말 실력이 많이 늘었다. 

 

다음 프로젝트에서도 팀원과의 소통 및 회의/회고를 적극 권장해야겠다.

+ Recent posts