728x90

모바일 던파 TD분이 오셔서 섹션을 진행, 모바일 던파가 어떤 식으로 제작 되었는지 설명

모바일 던파 개발 배경
PC 던파의 기본 클래스
PC 던파의 기본 클래스들을 그대로 이식

PC 던파의 클래스 구조를 그대로 이식했지만 프레임 저하 등 최적화 문제 발생

코드 구조를 연산과 표현 계층으로 나누었다고 한다.
과정에서 유니티의 기술 활용
PC 던파의 네트워크 - 클라이언트 구조

기존 PC 던파는 P2P 연결을 통하여 던전 플레이를 구현

모바일 던파의 네트워크 - 클라이언트 구조

모바일 환경에서는 다양한 문제 때문에 락스탭 서버를 통하여 던전 플레이를 구현

던파 모바일에서 프레임 동기화 방식 사용
프레임 동기화방식에서 문제되는 것을 해결
전투중 반응 속도 문제

모바일 던파에서 전투 플레이 중 반응 속도 문제를 해결하기 위해 미리 연산 처리된 B와 인풋으로 입력된 A를 보간하여 C를 보여줌

락스탭 서버를 통해서 얻는 이점1
락스탭 서버를 통해서 얻는 이점2
락스탭 서버를 통해서 얻는 이점3
락스탭 서버를 통해서 얻는 이점4

락스탭 서버를 사용하면 기록이 쉬워져 해당 이점들을 얻어서 적용하였다 함

핫픽스 솔루션은 텐센트의 injectFix 사용

핫픽스 솔루션인 injectFix의 사용 과정을 보여줌

 

정리하자면

1. PC던파의 리소스, 코드를 모바일 던파로 이식하는 툴을 개발해 이식

2. 과정에서 유니티의 기술도 사용하면서 모바일 환경에서 개선해야할 문제를 개선

3. 네트워크 방식은 다른 방식을 사용함

4. Logic과 View 계층을 분리함

728x90
728x90

PlayMaker 패키지를 이용해 구성한 FSM 로직이 실제 빌드 런타임에서 실행되지 않는 문제가 발생했습니다.

원인은 Linker Wizard라는 브릿지와 같은 내용이 빌드 단계에서 포함되지 않아 발생하는 문제였습니다.

 

해결 방법

  1. 우선 PlayMaker Ecosystem 페이지에서 EcosystemBrowser 패키지를 다운받은 뒤, 프로젝트에 추가합니다.
    Ecosystem 패키지 업데이트가 2021년도에 되어서 API 업데이트가 발생할 수 있습니다. 가능하면 변경사항들을 미리 백업 해두세요.
  2. Ecosystem 패키지 추가 후, 프로젝트 툴바의 PlayMaker > Addons > Ecosystem > Ecosystem Browser를 통해 Ecosystem 브라우저를 엽니다. 처음 브라우저를 열었을 때에는 disclaimer 페이지가 표시되니, 브라우저의 우측 상단 disclaimer 버튼 또는, 페이지 내용 중 Back to Browser 버튼을 클릭해 검색 페이지로 이동할 수 있습니다.
  3. 브라우저 검색 창에서 Linker Wizard를 검색하고, 해당 이름의 패키지를 찾아 프로젝트에 추가합니다. 해당 단계에서 Linker Wizard 패키지가 추가되고, API 업데이트가 한번 더 발생할 수 있습니다. 마찬가지로 진행 전, 변경사항들을 백업해두세요.
  4. Linker Wizard 패키지 설치 후, 에셋 폴더 내에 Linker Wizard 에셋이 추가된것을 확인할 수 있습니다.
    해당 에셋 선택하면 다음과 같은 인스펙터를 확인할 수 있습니다.
  5. Install Actions > Include Conditional Expression action > Update Linker content를 차례로 클릭합니다.
    이 과정 이후에는 에셋 폴더 아래에 link.xml이라는 파일이 생성된것을 확인할 수 있습니다.

 

PlayMaker FSM에서 Conditional Express Action을 이용하거나, C# Reflection을 이용하는 것으로 보이는 액션을 사용/수정한다면, 빌드 전에 항상 Linker Wizard를 통해 링크 데이터를 업데이트 해주세요.
릴리즈 런타임에서 PlayMaker FSM이 정상적으로 작동하지 않을 수 있습니다.

728x90
728x90
728x90
728x90

Android Resolver를 사용하다 보면 오류가 발생할 때가 있는데

해당 사진은 구글에서 가져온 오류 이미지

해당 오류가 되면서 Resolve와 빌드가 되지 않는다.

해당 오류를 수정하기 위해서는 Edit > Preferences... 에서 External Tools의 JDK 위치를 확인한 후 경로를 복사한다
(Copy Path)

윈도우 검색 창에 "시스템 환경 변수 편집" 검색 후

환경 변수에 들어가 아래 시스템 변수에 새로 만들기를 통해

변수 이름에는 "JAVA_HOME" 변수 값은 아래 복사한 경로를 붙혀넣고 재부팅하면 문제가 해결된다.

728x90
728x90

2022 이상 버전의 유니티를 열 때 나오는 에러

Restart Unity as a standard user를 클릭하면 계속 알림이 뜨고

I wish to continue at my own risk를 클릭하거나 X를 눌러 닫으면 실행이 된다.

하지만 콘솔창에

Unity is running with Administrator privileges, which is not supported. Unity executes scripts and binary libraries in your project that may originate from third party sources and potentially be harmful to your computer. Unity may also execute scripts and binary libraries that are still under development and not yet fully tested. Running Unity with Administrator privileges may lead to catastrophic consequences, including but not limited to accidental data loss, change of global system settings or even bricking your device.

이런 경고를 보내고 있는데 상당히 거슬린다.

 

해결 방법

윈도우 검색창에 "사용자 계정 컨트롤 설정" or "uac" 검색

해당 설정을 맨 위로 올려주고 재부팅해주면 문제가 해결된다.

참고 영상 : https://www.youtube.com/watch?v=ZG3FjmZKXxQ

728x90
728x90

C#에서 지원하는 Parse는 여러가지가 존재한다.
가장 대표적인 예시는 int->string, string->int 정도가 있는데
int->string은 ToString(), System.Convert.ToString()이 있고
string->int는 int.Parse(), int.TryParse()가 있다.
각각의 속도는 어떨까?

using System;

public class Ex : MonoBehaviour
{
    List<int> integers = new List<int>();
    List<string> strs = new List<string>();
    int LoopCount = 100000;

    void Start()
    {
        for(int i = 0; i < LoopCount; i++)
        {
            integers.Add(i);
            strs.Add(i.ToString());
        }
    }

    void Update()
    {
        for(int i = 0; i < LoopCount; i++)
        {
            string str_1 = integers[i].ToString();
            string str_2 = integers[i].System.Convert.ToString(integers[i]);
            int integer_1 = int.Parse(strs[i]);
            int integer_2;
            int.TryParse(strs[i], out integer_2);
        }
    }
}

속도를 보면 
int->string은 속도가 비슷하거나 뒤죽박죽 하기 때문에 입맛에 따라 쓰면 될 것 같다.
string->int의 경우 int.Parse가 1000회당 0.01ms 정도 느리다. 입맛에 따라 사용해도 되긴 하지만 안전한 코드 사용을 위해 int.TryParse를 사용하는 것을 권장

728x90
728x90

1. 백터의 내적과 외적을 게임에서 사용하는 경우

내적의 활용 - 앞뒤 판별

플레이어의 정면 벡터(forward vector)와 플레이어가 적을 향하는 벡터를 내적하여 나온 스칼라 값이 양수이면 적이 플레이어 방향벡터와 같은 방향(앞)에 있고 음수이면 반대 방향(뒤)에 있음

내적의 활용 - 시야각 판별

플레이어의 시야각 a가 적을 향하는 정면 벡터에서 플레이어가 적을 향하는 벡터까지의 각이 2/a보다 작으면 시야 이내에 있는것을 알 수 있음

외적의 할용 - 좌우 판별

플레이어의 정면 벡터와 플레이어가 적을 향하는 벡터를 외적하여 나온 노말 벡터를 업 벡터와 내적한 스칼라 값이 양수이면 같은 방향에 있고 아니면 다른 방향에 있음

2. Quaternion과 Euler, 짐벌락

Euler : 우리가 흔히 알고있는 x,y,z 3개의 축을 기준으로 회전시키는 각도계

짐벌락 : 같은 방향으로 오브젝트의 두 회전 축이 겹치는 현상

Unity에서는 오일러 앵글이 X,Y,Z 순서대로 계산되고 각 축을 독립적으로 판단해서 짐벌락이 발생하면 한 축에 대해서는 계산이 불가능함 이러한 현상을 해결하기 위해 나온 것이 쿼터니언

Quaternion : x,y,z,w로 이루어져 있음 (w = 스칼라)

방향과 회전을 다 표현할 수 있다. 하지만 쿼터니언의 회전은 180보다 큰 값을 표현할 수 없음

3. 머터리얼

머터리얼은 게임 오브젝트의 렌더링 효과를 결정하는 속성을 가진 컴포넌트, 쉐이더와 텍스쳐를 조합하여 오브젝트의 색상, 질감, 광택 등을 제어할 수 있음

4. 프리팹

게임 오브젝트를 미리 만들어 놓고 필요할 때마다 인스턴스화하여 사용할 수 있도록 하는 기능

프로젝트에 저장되어 있으며 필요할 때마다 가져와 사용할 수 있음, 이를 통해 게임 오브젝트의 중복 생성을 줄이고 효율적으로 사용

5. 쉐이더

쉐이더는 그래픽 처리 유닛에서 사용되는 프로그램으로 렌더징 엔진에서 빛, 색상, 질감등의 시각적요소를 계산하는데 사용, 쉐이더를 사용하여 오브젝트의 머터리얼에 적용하여 시각적인 효과 구현

6. 빌드

게임을 실행 가능한 상태로 만드는 작업, 플랫폼별로 빌드하여 사용자에게 제공

7. 콜리더와 리지드바디의 차이

콜리더는 충돌 감지를 위한 컴포넌트, 리지드바디는 물리 엔진과 상호작용하기 위한 컴포넌트

콜리더는 오브젝트가 다른 오브젝트와 충돌하는 것을 감지하고 이에 대한 이벤트 발생, 리지드바디는 물리 엔진에서 오브젝트의 물리적인 움직임을 제어하며 콜리더와 함께 사용하여 오브젝트간 충돌 및 반응 구현

8. 코루틴 vs 인보크

코루틴 : 유니티에서 비동기 처리를 구현하는 기능으로 메서드 실행을 일시 중지하고, 일정 시간이 지난 후에 중지한 부분부터 다시 실행하는 기능, 단일 쓰레드 형식, 오브젝트가 비활성화 되면 호출되지 않음

인보크 : 오브젝트가 비활성화 상태여도 호출, 매개 변수로 넘겨준 시간 만큼 지연 호출

9. 레이 캐스트

광선을 쏘아 해당 위치에 대한 정보를 가져오는 기능

10. 애니메이션 애니메이터

애니메이션은 게임 오브젝트의 동작을 미리 만들어 놓은 애니메이션 클립으로 제어 하는 기능

애니메이터는 애니메이션 클립을 제어하는 기능

11. 생명 주기

주로 물어보는 것들 위주

Reset - Awake - OnEnable - Start - FixedUpdate - OnTrigger - OnCollision - OnMouse - Update - yield null - yield WaitForSeconds - LateUpdate - Scene rendering - OnGUI - OnApplicationPause - OnDisable - OnApplicationQuit - OnDestroy

12. FixedUpdate, Update, LateUpdate

Update : 스크립트가 enabled 상태일때 매 프레임 마다 호출, 물리 효과가 적용되지 않은 오브젝트의 움직임이나 타이머, 키입력에 사용

FixedUpdate : Fixed Timestep에 설정된 값에 따라 일정한 간격으로 호출, 물리 효과가 적용된 오브젝트를 조정할 때 사용

LateUpdate : 모든 Update함수가 호출된 후 마지막으로 호출, 주로 오브젝트를 따라가는 카메라에 사용

13. 드로우 콜

CPU가 GPU에 렌더링 하라고 명령을 보내는 것

14. Rect Transform 컴포넌트 Anchros,Pivot

Anchros : UI의 원점 위치를 정함

Pivot : UI의 기준점을 정함

15. 캔버스

Screen Space - Overlay : UI 요소들이 스크린 상에만 존재, 3D 오브젝트 위에 그려져 덮어짐

Screen Space - Camera : 3D 좌표 상에서 위치값을 가지게 됨, UI요소(캔버스)보다 앞에 오게 배치할수 있음, 파티클이 이에 해당

World Space : UI를 3D 오브젝트 취급, 회전값 위치값 다 가질수 있음, 바닥이나 표면같은 곳, 증강현실 UI

728x90
728x90

1. 인터페이스와 가상 함수, 추상 함수

virtual(가상) 함수 : 하나의 기능을 하는 완전한 클래스, 파생된 클래스에서 상속하여 재정의가 가능하나 필수가 아님

abstract(추상) 함수 : 부모 클래스에서 정의만 하고 파생된 클래스에서 상속하여 반드시 재정의를 해야함

interface(인터페이스) : 추상클래스와 비슷하지만 멤버 변수를 사용할 수 없음, 서로 다른 계층이나 타입이더라도 같은 기능을 추가하고 싶을 때 사용 (예시 : 몬스터나 플레이어나 데미지를 입는건 마찬가지이므로 해당 함수를 가진 인터페이스를 사용할 수 있다.)

abstract vs interface

  interface abstract class
접근 지정자 public private, public, protect
구현 구현 불가 구현 가능
속도 상대적으로 느림 상대적으로 빠름
인스턴스화 사용 불가 사용 불가
필드 가질수 없음 필드와 상수 정의 가능
메소드 추상 메소드만 가능 일반 메소드도 있을수 있음
멤버 변수 사용 불가 사용 가능

2. 구조체와 클래스

구조체는 상속 불가, 값 타입, Stack에 할당

클래스는 상속 가능, 참조 타입, Heap에 할당

3. 상속성과 다형성

상속 : 부모 클래스로부터 필드, 메소드 등을 그대로 물려 받아 새로운 파생 클래스를 만드는 것

다형성 : 객체가 여러 형태를 가질수 있음

(예시 : 오버로딩을 통해 같은 이름의 메소드가 매개 변수의 개수나 타입이 다른경우)

public class EX : MonoBehaviour
{
	private void print(int ex)
    {
    	Debug.Log(ex);
    }
    
    private void print(string ex)
    {
    	Debug.Log(ex);
    }
}

 

 

(예시 : 오버라이딩을 통해 부모 클래스로 부터 물려받은 메소드를 재정의하여 사용하는 것)

public class EX : MonoBehaviour
{
	protected virtual void print()
    {
    	Debug.Log("EX Class : !");
    }
    
    protected abstract void printint ();
}

public class EX2 : EX
{
	protected override void print()
    {
    	base.print();
        Debug.Log("EX2 Class : @");
    }
    
    protected override void printint()
    {
    	Debug.Log("EX2 Class : 0");
    }
}

Output :
EX Class : !
EX Class : !
EX2 Class : @
EX2 Class : 0

4. 배열과 리스트

배열은 동적 할당 불가능, List는 동적 할당이 가능

배열은 데이터의 크기가 정해져 있음, 값을 중간에 넣고 뺄 때 크기를 늘리거나 줄이는 작업이 필요해서 많은 연산 필요

리스트는 데이터의 크기가 정해져 있지 않음, 값을 중간에 넣고 뺄 때 자유로움

5. namespace와 partial

클래스이름의 중복 방지 namespace

클래스의 크기가 커서 길어지는 경우 partial로 파일을 분할하여 동일한 클래스로 작성 가능

6. 객체 지향

SOLID (솔리드) 원칙

SRP(Single Responsibility Principle, 단일책임원칙) : 클래스는 하나의 목적만 가져야 하며, 클래스를 변경하는 이유도 하나여야 한다.

OCP(Open-Closed Principle, 개방폐쇠원칙) : 클래스는 확장에는 열려 있고, 변경에는 닫혀 있어야 한다.

LSP(Liskov Substitution Principle, 리스코프치환원칙) : 상위 타입의  객체를 하위 타입으로 바꾸어도 프로그램은 일관되게 동작해야 한다.

ISP(Interface Segregation Principle, 인터페이스분리원칙) : 클라이언트는 이용하지 않는 메소드에 의존하지 않도록 인터페이스를 분리해야 한다.

DIP(Dependency Inversion Principle, 의존역전법칙) : 클라이언트는 추상화(인터페이스)에 의존해야 하며, 구체화(구현된 클래스)에 의존해서는 안된다.

7. 전역변수 vs 지역변수

전역 변수 : Heap 메모리에 저장되며 함수 외부에서 선언, 프로그램이 종료되기 전까지 파괴되지 않음

지역 변수 : Stack 메모리에 저장되며 함수 내부에서 선언, 해당 함수가 종료되면 파괴

8. delegate와 event

delegate : public으로 선언하면 클래스 외부에서 호출 가능, callback의 용도로 사용

event : public으로 선언해도 클래스 외부에서 호출 불가, 객체의 상태 변화나 사건의 발생을 알리는 용도로 사용

9. Boxing(박싱), UnBoxing(언박싱)

Boxing : 값 타입의 객체를 참조 타입으로 변환하는 작업 → Stack에 있던 값 타입의 객체를 Heap으로 이동할 때 복사가 일어난다. → Heap 영역에 복사된 영역을 참조 타입이 가르키게 된다(주소값 할당)

UnBoxing : 객체 타입의 객체를 값 타입으로 변환하는 작업 → Heap 영역에 있던 데이터를 Stack 영역으로 복사

10. object 타입에 value 타입을 대입하면

value 타입을 참조 타입으로 박싱한다. Stack영역에 있던 value를 Heap으로 복사 후 주소값을 할당

11. 세대별 GC(Garbage Collection)

0세대 : GC를 한번도 겪지 않은 갓 생성된 객체

1세대 : GC를 1회 겪은 객체

2세대 : GC를 2회 겪은 객체

세대가 낮은 메모리부터 해제를 해준 다음 메모리 컴펙션

2세대 GC를 할 시 Full Garbage Collection이라 하고 전체 Heap에 대하여 GC하는 것을 의미

세대를 나누는 근거는?

최근에 생성된 객체일수록 생명주기가 짧을 가능섶이 높고 오래된 객체일수록 생명주기가 길 가능성이 높음

최근에 생성된 객체끼리는 서로 연관성이 높을 수 있으며 비슷한 시점에 자주 액세스 됨

일부분 Heap에 대해 GC하는 것이 전체 GC를 하는것 보다 빠름

12. LOH, SOH

LOH : Large Object Heap 으로 CLR(Common Language Runtime)에서 용량이 큰(83kb이상) 객체에 사용되는 Heap

SOH : 그 이하에 평소에 사용되는 Heap

LOH는 GC시 2세대로 간주, 메모리 해제 후 메모리 컴펙션을 진행하지 않으므로 메모리 내부 단편화가 발생할 수 있음

13. Call by Value vs Call by Reference

Call By Value : 인자로 받은 값을 복사하여 처리, 넘어온 값을 증가시키거나 감소시켜도 원래의 값 보존, 값을 복사하여 사용하기 때문에 메모리 사용량이 상대적으로 늘어나 느림

Call By Reference : 인자로 받은 값의 주소를 참조하여 처리, 넘온 값을 참조하여 직접 값에 영향을 미침, 값을 참조하여 사용하기 때문에 메모리 사용량이 상대적으로 적어 빠름

14. 프로세스, 쓰레드

프로세스 : 메모리에 올라와 실행되고 있는 프로그램의 인스턴스

운영체제로부터 독립된 메모리 영역을 할당받음, 서로 독립적이라 통신이 어려움 1개 이상의 쓰레드를 가지고 있음

쓰레드 : 프로세스 내에서 할당받은 자원을 이용해 동작하는 실행 단위

쓰레드는 프로세스 내에서 Stack영역만 할당 받고 Code, Data, Heap 영역은 서로 공유, 프로세스의 자원을 공유하기 때문에 다른 쓰레드에 의한 결과를 즉시 확인 가능(통신이 쉬움)

멀티 프로세스 : 하나의 프로그램을 여러 개의 프로세스로 구성하여 1개의 작업을 처리하도록 하는 것

하나의 프로세스가 죽어도 다른 프로세스에 영향이 없음

멀티 쓰레드 : 하나의 프로그램을 여러 개의 쓰레드로 구성하여 1개의 작업을 처리하도록 하는 것

자원을 공유하기 때문에 효율적으로 사용 가능, 하나의 쓰레드의 문제가 생기면 전체 프로세스가 영향을 받음, 하나의 자원에 여러 쓰레드가 동시에 접근하면 동기화 문제가 발생할 수 있음

15. 데드락(교착상태)

한정된 자원을 여러 프로세스가 사용하고자 할 때 발생하는 상황으로 프로세스가 자원을 얻기위해 영구적으로 기다리는 상태

A라는 자원을 가진 프로세스1(P1)이 B라는 자원을 가진 프로세스2(P2)의 B가 필요하고 P2는 A가 필요할 때 데드락 발생,

뮤텍스나 세마포어 등으로 문제를 예방

16. 싱글톤 패턴 사용 이유

싱글톤 패턴 : 단 하나의 인스턴스만 생성하여 사용하는 디자인 패턴

사용하는 이유 : 단 하나의 인스턴스만 생성하는 것을 보증하고 싶은 경우 (GameManager), 메모리 낭비 방지, 인스턴스가 메모리에 올라와 있으면 언제든지 사용할수 있기 때문

728x90

+ Recent posts