06
29

Cpaacity를 먼저 설정했을 때와 그냥 사용했을 때에 차이점을 테스트해봤다.

첫 번째 테스트

리스트에 같은 수의 데이터를 넣고 지우 고를 반복했을 때 걸리는 시간 체크하기. 여기 포인트는 미리 정해놓은 Cpaacity의 크기를 넘지 않을때이다.

 

테스트 코드

	long lPre = System.GC.GetTotalMemory(false);
        int tick1 = Environment.TickCount;
        List<int> list = null;
        if (bCapacity)
            list = new List<int>(10000000);
        else
            list = new List<int>();

        for (int k = 0; k < 10; k++)
        {
            for (int i = 0; i < nCount; i++)
            {
                for (int j = 0; j < nCount; j++)
                {
                    list.Add(i + j);
                }
            }
        }
        int tick2 = Environment.TickCount;
        long lAfter = System.GC.GetTotalMemory(false);

        Debug.LogError(string.Format("Capacity Use : {0} | list Count : {1} / Tick : {2}/ Memory : {3}", 
        			bCapacity, list.Count, tick2 - tick1, lAfter - lPre));

1. Capacity을 사용 안 했을 때.

list Count : 10000000 / Tick : 172/ Memory : 134279168

2. Capacity을 사용했을 때.

 list Count : 10000000 / Tick : 109/ Memory : 40001536


테스트 결과

Capacity를 크기를 미리 설정한 케이스가 시간이나 메모리가 더 적게 발생하는 걸 알 수 있다. 

 


 

두 번째 테스트

재 할당될 때 List의 Capacity변화를 테스트해봤다.

 

테스트 코드

        List<int> list = new List<int>();
        Debug.LogError(list.Capacity);
        list.AddRange(new int[4] { 1, 2, 3, 4 });
        Debug.LogError(list.Capacity);
        list.Add(1);
        Debug.LogError(list.Capacity);

처음에 4개의 데이터를 넣고 그 범위를 초과할 때 Capacity를 로그 찍어봤다.

 

테스트 결과

데이터의 수는 4개에서 5개로 1개 증가했지만 현재 사이즈의 2배만큼 Capacity를 할당된 것을 알 수 있다.

 


오늘 테스트 최종 결과

List에 사용하는 최대 크기를 안다면 Capacity를 미리 설정해두는 것이 좋다. List는 현재 가지고 있는 Count수가 초과될 때 기존의 데이터를 복사한 후 다시 2배 사이즈로 재할당하게 된다(기존의 있던 데이터는 가비지 해제 대상으로 잡히게 된다.) 만약 할당된 Capacity를 현재 데이터의 수만큼 변경하고 싶으면 TrimExcess 을 이용한다.

 

 

'프로그래밍언어 > C#' 카테고리의 다른 글

C#) Async, Await  (0) 2022.08.15
C#) Enum.Parse  (0) 2020.04.17
C#) String null 검사,체크 (널처리)  (0) 2020.04.16
C#) 전처리기 지시자  (0) 2020.04.12
C#) 동적바인딩 / 정적바인딩  (0) 2020.04.08
COMMENT
 
03
11

대리자 대 인터페이스

대리자로 풀 수 있는 문제는 인터페이스로도 해결이 가능하다.

 

 

그럼 어떨 때 대리자를 쓰는 게 더 효율적일까?

내가 보는 책에서는 3가지 정도의 예시를 보여주고 있다.

  1. 인터페이스가 메서드를 하나만 정의할 때

  2. 다중 캐스팅 능력이 필요하다.

  3. 여러 종류의 메서드를 인터페이스를 여러 번 구현해야 한다.

하나씩 살펴보자.

 

1. 인터페이스가 메서드를 하나만 정의할 때 & 3. 여러 종류의 메서드를 인터페이스를 여러 번 구현해야 한다

위 예시처럼  ITransformer인터페이스는 메서드를 하나만 가지고 있다. 이럴 경우 왜 델리게이트 더 좋냐면, 인터페이스 같은 경우 하나의 클래스에서는 하나의 메서드만 넘길 수 있는 반면에 델리게이트로 구현하게 되면 다른 메서드(int로 반환하는 메서드) 면 어떠한 메서드도 넘길 수 있기 때문이다.

델리게이트로 하면  Square 1도 되고~ Square2되지만

 

인터페이스로는

각각 클래스에 인터페이스를 상속받아넘겨야 한다.

 

2. 다중 캐스팅 능력이 필요하다.

하나의 대리자 인스턴스가 여러 개의 메서드를 지칭할 수 있는 델리게이트 기능이 필요하다면. 예를 들어 

예시가 너무 구린데 암튼 이런 식으로 쓸 거라면 델리게이트 고고.

 

 

COMMENT
 
02
19

C#의 모든 형식은 실행 시점에서 System.Type의 인스턴스로 표현이 된다. 두 가지 방법으로 Type객체를 얻을 수 있다.

  1. 인스턴스에 대해 GetType을 호출한다.

  2. 형식 이름에 대해 Typeof연산자를 호출한다.

이 두가지의 큰 차이점은 GetType은 실행 시점에서 평가되는 반면에 typeof는 컴파일 시점에서 정적으로 평가된다.(제네릭 형식은 JIT(just-in-time compilation)컴파일러가 결정한다.)

 

1. GetType 

GetType을 실행해 보면 현재 인스턴스의 타입을 가져오고 있다. (자칫 클래스 이름을 가져온다고 생각할 수 있지만 타입이다 타입)

 

그러면 아래 실행결과는 어떤값을 보내줄까?

int형인 x의 타입이니 Int32를 보내준다.

 

Name을 사용하면 타입을 string값으로 받을 수 있다. 

 


 

1. typeof

형식에 대한 System.Type개체를 얻는데 사용된다. 

이렇게 타입형식을 참조할 수 있다.

 

 

이 두개의 차이점은?

이 두개의 실행결과를 예상해 보자. 정답은 위에서부터 각각 true, false, true, true, false다.

첫 번째는 타입을 비교하고 두 번째는 인스턴스를 비교하고 있다. child로 같은 타입이기 때문에 true이다.

두 번째는 Object.Equals를 이용해 인스턴스가 같은지를 비교하고 있다. new를 이용해 새로운 생성자 인스턴스를 리턴해주고 있기 때문에 c와 c2는 같지 않다. 

세 번째는 c와 c2모두 같은 타입이고 typeof은 타입을 반환하기 때문에 '==' 비교는 true를 출력하고 다섯 번째는 다른 타입과 비교를 하고 있어 false를 출력한다.

'프로그래밍언어 > C#' 카테고리의 다른 글

20200224[C#] 제네릭 제약_1  (0) 2020.02.24
20200220[C#] 제네릭  (0) 2020.02.20
20200218[C#] Object형식, 박싱 언박싱  (0) 2020.02.18
20200217[C#] 생성자와 상속  (0) 2020.02.17
20200214[C#] 상속된 멤버 숨기기  (0) 2020.02.14
COMMENT
 
02
04

공통 언어 런타임 CLR

 마이크로 소프트 이니셔티브에서 제공하는 가상 머신의 구성요소이다. 프로그램 코드를 위한 실행 환경을 정의하는 마이크로소프트의 공통 언어 기반(CLI)표준의 기능이다. C#이나 VB닷넷과 같은 언어로 프로그래밍하며, 해당 언어의 컴파일러가 소스 코드를 공통 중간 언어(IL) 코드로 변환한다. 

CLR은 관리되는 코드(managed code)를 실행하기 위한 런타임이다. C#은 여러 관리되는 언어중 하나인데, 관리되는 언어로 작성한 소스코드를 컴파일 하면 관리되는 코드가 생성된다. 관리되는 코드를 실행 파일또는 라이브러리(.dll)형태로 만들고 그것을 형식 정보, 즉 메타자료와 함께 하나의 패키지로 묶은 것을 어셈블리라고 한다. 어셈블리를 적재 할 때 CLR은 IL코드를 해당 컴퓨터(x86 등) 고유의 기계어 코드로 변환한다. 이러한 변환을  담당하는 것이 CLR의 JIT(Just - in - time)컴파일러이다. 어셈블리는 원래의 원본 언어의 구성을 거의 그대로 유지하기 때문에, 코드를 조사하기 쉽고 심지어 동적으로 생성하기도 쉽다.

위캐백과

 

 

1.이니셔티브 : 우선권, 주도권, 스스로 상황 판단을하고, 남들이 움직이기 전에 먼저 움직일 수 있는 능력

2.CLI : Command-Line user Interface또는 Character User Interface

COMMENT
 
10
02

같은 클래스로 인스턴스를 new로 생성하게 되면  

1번을 제외하고 2~4번은 false

참조형 변수의 주소값을 비교하는 object.ReferenceEquals

즉, 관리 힙에 할당된 객체의 참조 주소 값을 비교해 '같음 여부'를 판단하기 때문에, object.ReferenceEquals '값 형식'의 인스턴스에 사용해서는 안됨

값형식을 넣으면 오류는 안나지만 false를 반환

object.ReferenceEquals의 값을 넣게되면 매개변수타입이 object형식이라 박싱과정이 거친다. 그러면 힙메모리에 값이 할당되게 된다. 결국 스택에 있는 서로다른 주소값이 생기기 떄문에 항상 false를 반환하게된다.

 

 

 

COMMENT
 
09
24

abstract :

상속 제한 : sealed키워드와 반대로 무조건 상속해서 쓰라는 의미 

메서드 오버 라이딩 제한 : 이 메서드는 반드시 오브 라이딩해달라는 의미

 

as :

객체를 캐스팅 할 때 사용되는 연산자로, 캐스팅에 성공하면 캐스트 결과를 리턴하고 실패하면 null을 리턴

 

is :

캐스팅이 가능하면 true, 아니면 false를 리턴

 

base :

해당 키워드를 사용하는 부모 클래스를 가리키는 것

 

const :

상수 필드 또는 지역 상수를 선언할 때 사용한다. 변수가 아니며, 한번 값이 할당되면 이후 변경이 불가능

 

readonly :

성수를 선언할 때 사용, 선언 시 선언할 때 값을 할당하지 않아도 됨, const와 다르게 생성자에서 한번 더 값 변경이 가능하다.

 

continue :

반복문에서 continue키워드 선언 이후 부분은 넘기고 다음 반복문부터 시작하도록 한다.

 

decimal :

고정 소수점 방식이며 연산 속도가 빠르고 수의 정확성이 높은 데신 큰 수를 저장할 때 메모리를 많이 먹게 된다. 16byte

 

double:

부동소수점 방식이며 decimal보다 정확성은 떨어지지만 작은 메모리 공간에 큰 소수를 저장이 가능하다.

 

event :

public이어도 자신이 선언되어 있는 클래스의 외부에서는 호출이 불가능, 객체의 상태 변화나 사건의 발생을 알리는 용도로 사용

 

delegate:

메서드 참조를 포함하고 있는 영역

 

size of :

지정된 형식의 변수에서 사용하는 바이트 수를 반환한다.

 

COMMENT
 
08
28

 디자인 패턴 

싱글톤 패턴

같은 인스턴스를 여러 개 만들지 않고, 최초 한번만 메모리를 할당하고 그 메모리에 인스턴스를 만들어서 사용하는 패턴이다. 어디서든지 접근하기 쉽다.

 

구현방법

가장 기본적인 싱글턴 구현 방법이다. 인스턴스를 요청하기 전까지는 객체를 생성하지 않는다.

늦은 초기화(Lazy initialization) : 멀티스레드 환경에서는 동시에 Instance을 호출하게 되면 둘 이상 객체가 만들어질 위험이 있다.

 

정적 초기화

이른 초기화(Eager initialization) 

로딩 때 생성되므로 스레딩에 안전한 대신 미리 생성하므로 안 쓰는 경우에 메모리 낭비가 될 수 있음

 

멀티스레드에서 교착상태를 피하기 위한 싱글턴

교착상태를 피하기 위해 이중 검사 잠금

lock키워드 설명 : http://www.csharpstudy.com/Threads/lock.aspx

 

싱글턴 문제점

개방 폐쇄 원칙(OCP)을 위배될 수 있다. (객체 지향 설계 원칙)

커플링이 심해질 수 있음 => 한 곳에서 변경이 다른 부분에 영향을 미치게 될 확률이 커짐

 

학습 참고 사이트

 

COMMENT
 
08
22

파란색 : 풀면서 어려웠던 부분 or 고려해야 될 부분

빨간색 : 해결방법

초록색 : 느낀점

문제


우선 문제를 봤을 때 고려할 부분으로는 1,2,3학생 답 배열의 담겨있는 수들의 규칙이다.   

 

 

내 풀이


학생 답 각각 배열을 생성하고 문제에서 보여주는 값들 중 다시 반복이 되는 수 전까지 담아준다.  

int[] st1 = new int[5] { 1, 2, 3, 4, 5 }

int[] st2 = new int[8] { 2, 1, 2, 3, 2, 4, 2, 5 }

int[] st3 = new int[10] { 3, 3, 1, 1, 2, 2, 4, 4, 5, 5 }

그리고 정답배열을 순회하면서 학생 배열과 비교하고 학생배열의 값과 같다면 정답카운트인 score 배열의 값을 변경 시켜주도록 한다.  (코드는 5,8,10으로 나누었지만 확장성으로 st1.Length으로 나누어도 된다)

제한조건으로 최고점자가 동률이 나오면 오름차순으로 모두 출력해주어야 하기 때문에 for문을 통해 최대값을 구하고 그 값과 같은 배열만 list에 담도록 했다. 

 

다른 사람의 풀이


우선 차이점으로 학생배열을 2차원 배열로 만들고, 이중for문을 통해 if문 한개로 모든 학생배열을 순회하는 방식으로 정답카운트를 체크하고 있다. 그리고 배열.Max()함수를 통해 최대값을 찾고 그 리스트를 리턴하는 방식이다

내 코드처럼 각각 배열을 3개 생성하지 않고, 이차원배열로 생성했으며, if문으로 각자 배열을 매직넘버인 1,2,3를 넣어서 순회하는 것이 아닌 이중포문으로 한번에 비교를 한다는점에서 더 효율적인 풀이법인 것같다.


 

 

COMMENT
 
06
30

문제점 : 빨간색 / 해결방법 : 파란색 / 느낀 점 : 녹색 

 

C#기본 문법이긴 하지만 그래도 컴파일 오류이기 때문에 포스팅했다.

 

우선 파셜 클래스의 대해서 알아보자  

파셜 클래스?

동일한 클래스명을 두고 이를 partial로 선언하는데, 컴파일러는 나중에 이를 합쳐 하나의 클래스로 인식한다.

 

그럼 언제 쓸까?

한 클래스에 여러 내용들이 있을 때, 또는 특징을 분할하여 가독성을 높이거나 여러 사람이 한 클래스를 작성할 때 사용하기도 한다고 한다.

 

 

나는 Character를 상속받는 Monster클래스를 세팅/행동으로 클래스 기능으로 두 개로 나누었다.

 

 

문제점 :  오류의 원인은 파셜로 만든 두 클래스가 다른 부모클래스를 상속받고 있었다.

 해결방법 : 같은 부모를 상속받도록 Character로 수정하니 해결됐다.

 

+) 파셜은 클래스만 아니라 인터페이스,구조체도 가능하다.

 

느낀 점 : 파셜클래스는 기존에도 사용했지만 다시 한번 찾아보게 되었다. 인터페이스나 구조체도 사용이 가능하다는 것도 알게 되었다. 

COMMENT
 
02
10

boxing/unboxing


박싱/언박싱?


내가 알고 있는 박싱/언박싱은 자료의 형변환이 일어날때

값 형식을 참조형식으로 박싱

참조형식을 값형식으로 언박싱이다 라는정도인데 메모리영역에서 어떻게 일어나는지 알아보았다.


박싱

값 형식을 참조 형식으로 변환되는 것을 말한다. 

static void Main(string[] args)

{ int i = 93; object s = i; //박싱 }

int i 는 93이라는 값을 받고, object s는 i의 값을 받고있다.

값 형식인 정수형 자료 int를 object(참조형식)객체로 할당하게 되면 박싱이 일어나게 된다.


=> 스택에 있는 데이터가 힙으로 복사 된 것이다.


Stack에 있는 93이라는 정수형 자료가 Heap영역으로 복사되고, 이영역을 객체 변수 s가 가리키게 된다.



언 박싱

참조 형식을 값 형식으로 변환하는 것,

static void Main(string[] args) { int i = 93; object s = i; int j = (int)s; //언 박싱(명시적 변환) }

s를 int로 값 형식으로 변환한다. 

박싱된 객체인 s를 다시 값 형식으로 변환하면 언박싱이 일어난다.


=> 힙에 있는 데이터가 스택으로 복사된다.



언 박싱이 가능한 객체

값 형식을 박싱하여 생성된 객체이어야만 가능

static void Main(string[] args) { short i = 93; object s = i; int j = (int)s; //언 박싱 불가 }

short타입을 박싱한 객체를 int타입으로 언 박싱은 불가능

해당 타입보다 작은 범위로 변환 불가능



높은 비용의 박싱/언박싱

박싱과 언박싱은 많은 시간이 소모된다고 한다. 되도록 제네릭을 사용해서 박싱과 언박싱이 일어나지 않도록 구성하도록 하는게 좋다.


박싱의 과정 : 

1. 값 타입을 힙에 생성하기 위해 메모리를 힙 영역에 생성

2. 값을 힙 영역에 할당된 메모리로 복사

3. 참조할 변수에 할당된 메모리 주소를 할당


언박싱의 과정 :

1. 박싱값인지 확인

2. 박싱된 값이라면 값 타입 변수에 복사

3. 박싱한 메모리와 언박싱한 메모리 2개 존재 ( 가비지 발생 )



학습참고 : http://www.mkexdev.net/Article/Content.aspx?parentCategoryID=1&categoryID=5&ID=671

 https://grayt.tistory.com/87 [IT's me]

https://hongjinhyeon.tistory.com/90


COMMENT
 
01
16

스태틱Static 변수


스태틱 변수는 객체를 선언만 해도 메모리가 할당되며 일반적인 변수들이 객체가 새로 생성될 때 메모리가 초기화 되는 것과 다르게 해당 객체를 계속 반복적으로 생성해도 메모리가 유지 된다는 특징이 있다. 

테스트를 해봤다

        public class Myclass

        { 

        private static int stNum= 0;

        private int num = 0;


        public Myclass()

        {

                stNum++;

                num++;

        }

     

        public void Showtest()

        {

            Console.WriteLine("stNum: {0},  num : {1}", stNum, num);

        }


    }

        static void Main(string[] args)

        {

            for (int i = 0; i < 5; i++)

            {

                Myclass test = new Myclass();

                test.Showtest();

            }

        }

    }


일반 변수인 num의 값은 변하지 않지만 Static으로 선언한 stNum은 메모리를 초기화 하지 않고 계속 더해 지고 있다. 

=> static 필드는 프로그램 실행 후 해당 클래스가 처음으로 사용될 때 한번 초기화되어

 계속 동일한 메모리를 사용하게 된다. 






스태틱Static 메소드



Static메소드는 객체가 메모리를 할당 받기 전에 호출이 되기 때문에 객체 생성 후 메모리 할당을 받는 일반 변수에 접근이 불가능하다. 인스턴스 메소드와 다르게 클래스로 객체를 따로 생성하지 않고 [클래스명.메서드명]이런식으로 호출하게 된다.

호출 시 일반 인스턴스 메서드와 달리 클래스로 부터 객체를 생성하지 않고 직접 호출한다. 



일반 인스턴스 메서드는 클래스로부터 객체를 생성하고 메서드를 호출해야하지만

static메서드는 [클래스명.메서드명]으로 메서드를 호출한다.


static메소드 내부에서 객체 멤버를 호출 할 수없다.

인스턴스 메서드는 스태틱메서드 멤버를 참조가 가능하지만 스태틱메서드는 다른 멤버 참조가 불가능하다.






스태틱Static 클래스



Static 클래스는 모든 클래스 멤버가 static 멤버로 되어 있으며, 클래스명 앞에 static이 붙는다.

다른 일반 클래스와 다르게 static생성자를 갖는다. 이 생성자는 보통 static필드를 초기화 할 때 사용한다.


테스트를 해보았다.



static 멤버 호출


객체 생성 불가

static는 인스턴스화 하지 않는 클래스이기 때문에 객체생성이 불가능하다.


 

스태틱객체는 프로그램이 종료되기 전까지 메모리를 해제하지 않고 객체를 생성하지 않고도 멤버에 접근이 가능하다는 장점 (특징)을 잘 활용해야 할 것같다. 하지만 단점으로 여러군데서 스태틱 멤버를 동시에 참조하게 될 경우와 객체 지향에 벗어난 개념이 되어 안좋다는 시선도 있다고 한다. 다른 장단점을 알아 볼 필요가 있겠다.



 참조 : http://www.csharpstudy.com/csharp/CSharp-static.aspx 사이트

http://ronniej.sfuh.tk/ , http://mygumi.tistory.com/253 ,http://blog.acronym.co.kr/347 블로그 





'프로그래밍언어 > C#' 카테고리의 다른 글

C#) 델리게이트 #2  (0) 2019.01.24
C#) 델리게이트(delegate) #1  (0) 2019.01.23
C#) 스택(Stack), 힙(Heap) 메모리구조  (0) 2019.01.15
C#)기본 개념 interface 인터페이스  (0) 2018.12.20
C#) continue , break 키워드  (0) 2018.11.14
COMMENT
 
01
15

스택(Stack), 힙(Heap) 메모리구조


우리가 어떤 동작을 할때(프로그램을 키거나) 운영체제는 그동작을 할 수 있게 메모리공간을 할당해준다.

그 할당해주는 메모리구조중 스택과 힙에 대해서 알아보자


스택 Stack 

프로그램은 함수의 호출로써 작동되는데 함수는 다른 함수를 호출하고 그 함수는 또 다른 함수를 호출하게된다. 함수들은 자신을 호출한 함수에게 결과를 반환한다.  함수 호출을 스택구조로 메모리에 차곡차곡  쌓고 처리가 끝나면 메모리에서 해제된다.

스택 메모리는 영역은 값 형식이다.

int a = 100;

int b = a;

b = 200;

a = 100;

a를 100으로 초기화하고 b는 a값을 넣어준다.

그리고 다시 b에는 200을 넣어주고 a는 100을 넣어준다.

결국은 a와 b는 마지막에 넣은100,200이 값이 되는것을 알 수있다.

스택메모리는 변수가 할당되었던 위치에 값만 변경되는것이다.

그리고 ,스택은 함수 호출 시 생성되는 지역 변수와 매개 변수가 저장되는 영역이며 함수 호출이 완료되면 해제한다.


힙 Heap

스택과 다르게 관리가 가능한(=사용자가 직접) 데이터 외에 다른 형태의 데이터를 관리하기 위한 빈 공간이라 생각하자

이 빈 공간은 동적생성된 변수를 관리 하기 위한 공간이다. 

힙 메모리 영역은 참조 형식이다.

Program p1 = new Program();

p1.value =200;

Program p2 = p1;

p2.value  = 100;

p를 동적 생성하고 값을 100을 넣어준다.

그리고 p2에 p1객체를 넣는다. 이 과정은 Stack에서의 복사가 이루어 진것이다.

p1이 참조하고있는 주소가 1000이라고 하면 p2 주소도 1000을 참조하게 된 것이다.

당연히 주소1000은 200을 참조하고 있으니 p2도 200을 참조하게 된다.

스택메모리에는 주소1000이 저장되고 힙메모리에는 값 200을 갖게된다.

네 번째줄  코드에서는 다시 100을 넣는다. 

당연히 같은 주소를 갖고있으니 p1,p2는 둘다 100을 값을 갖게 된다.

추가적인 특징으로 스택에는 메모리가 해제되는 시점이 있지만 힙에는 딱히 정해진 시점이 없다.

가비지콜렉터가 알아서 할당을 해제하기 때문이다. 

new로 동적 생성한 객체는 메모리는 힙에 만들어 지는 것과 동시에 가비지 콜렉터가 관리 되어 크게 신경쓸 필요는 없지만

가비지 콜렉터가 있으면 성능상으로 좋지 않다고 한다.


ref를 이용한 참조타입과 값타입 차이




COMMENT
 
01
04

 마우스로 캐릭터 방향 바꾸기



스크립트 작성

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

        Plane GroupPlane = new Plane(Vector3.up, Vector3.zero);

float rayLength;

        if(GroupPlane.Raycast(camearRay, out rayLength))

        {

            Vector3 pointTolook = camerRay.GetPoint(rayLength);

            transform.LookAt(new Vector3(pointTolook.x, transform.position.y, pointTolook.z));

        }


코드분석

Ray cameraRay = Camera.main.ScreenPointToRay(Input.mousePosition); : 마우스의 위치를 ScreenPointToRay를 이용해 카메라로 부터의 스크린의 점을 통해 레이를 반환한다.

Plane  GroupPlane = new Plane(Vector3.up, Vector.zero); : 월드 좌표로 하늘방향에 크기가 1인 단위 백터와 원점을 갖는다.

if(GroupPlane.Raycast(cameraRay, out rayLength) ; : 레이가 평면과 교차했는지 여부를 체크한다.

Vector3 pointTolook = camerRay.GetPoint(rayLenghth); : rayLenghth거리에 위치값을 반환한다.

transform.LookAt ~~: 위에서 구한 pointTolook 위치값을 캐릭터가 바라 보도록 한다.

Plane GroupPlane  = new Plane(Vector3.up, Vector.zero); 그냥 쓸수 없고 이렇게 하는 이유는??

유니티에서 Plane을 만드는 생성자는 3가지로 오버로딩 되어있다.(= 평면을 만들 수 있는 조건)

평면을 결정하는 최소 조건!

  1. 한 직선 위에 있지 않은 세 점
  2. 한 직선과 그 직선 위에 있지 않은 한 점
  3. 한 점에서 만나는 두 직선
  4. 서로 평행한 두 직선

첫 번째 사용

normal은 평면의 수직 방향을 얘기한다. 벡터는 방향과 크기를 가지고있지만 특정 위치를 나타내지는 않는다.
그래서 위치를 표현 할 수 있는 점이나, 거리를 인자로 받아야한다. 
1) public Plane(Vector3 inNormalVector3 inPoint);
노멀위치부터 한점의 위치,
2) public Plane(Vector3 inNormal, float d);
노멀위치로 부터 길이(d : 원점으로 부터의 거리)
3) public Plane(Vector3 a, Vector3 b, Vector3 c);
평면을 만드는 조건 :  한직선위에 있지 않는 세점

학습참고 평면조건 https://docs.unity3d.com/ScriptReference/Plane-ctor.html

COMMENT
 
01
02

Fade(In,Out)


(fadeIn 효과)


위 그림처럼 게임 시작 시 알파값을 조절해 fadeIn 효과를 연출할 수 있다.


1) Image 생성

Canvas -> UI -> Image를 생성한 뒤 Color

까맣게 만들어 준다.

2) 스크립트 생성

public class FadeIn : MonoBehaviour

{

    public float FadeTime = 2f; // Fade효과 재생시간

    Image fadeImg;

    float start;

    float end;

    float time = 0f;

    bool isPlaying = false;


    void Awake()

    {

        fadeImg = GetComponent<Image>();

        InStartFadeAnim();

    }

    public void OutStartFadeAnim()

    {

        if(isPlaying == true) //중복재생방지

        {

            return;

        }

start = 1f;

         end = 0f;

        StartCoroutine("fadeoutplay");    //코루틴 실행

    }

public void InStartFadeAnim()

    {

        if (isPlaying == true) //중복재생방지

        {

            return;

        }

        StartCoroutine("fadeIntanim");

    }

    IEnumerator fadeoutplay()

    {

        isPlaying = true;


        Color fadecolor = fadeImg.color;

        time = 0f;

        color.a = Mathf.Lerp(start, end, time);


            while (fadecolor .a > 0f)

            {

                time += Time.deltaTime / FadeTime;

                fadecolor .a = Mathf.Lerp(start, end, time);

                fadeImg.color = fadecolor ;

                yield return null;

            }

            isPlaying = false;

    }

코드분석

while(color.a > 0f) {    } :  이미지 색상의 알파값이 0으로 가까워 질 수록 투명해짐(이미지 색상이 약해짐?)

time += Time.deltaTime / FadeTime; : 지정한 시간만큼 효과를 주기 위해 1초를 나눠줌

fadecolor.a = Math.Lerp(start, end, time); : start와 end 중간값을 리턴

yield return null; :  다음 프레임까지 대기


Math.Lerp(start, end, time);

선형 보간을 할때 사용.

시작과 끝을 알고 정해진 시간동안 진행되야될 경우에 사용 
0일경우 시작값을, 1일 경우 끝 값을 반환하는데,

0.4일경우 시작값 40%,끝 값 60%값을 반환해서 자연스러운 연출이 가능하다.

(매 프레임 마다 증가하는 time값과 감소하는 알파값을 Debug.log를 찍어봤다)

Math.Lerp를 사용하면 time값에 따라 0에서 1로 갈수록 점점 큰 약한 알파값을 반환함으로서 자연스럽게 연출이 가능해진다.

FadeOut

같은 코드로 start값과 end값 그리고 while조건문 값만 수정하면 연출이 가능하다.



이 블로그에 더 자세히 나와있음 : http://ronniej.sfuh.tk/%EC%BD%94%EB%A3%A8%ED%8B%B4coroutine%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-fade-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98-%EB%A7%8C%EB%93%A4%EA%B8%B0/

COMMENT
 
12
27


코루틴 Coroutine 


유니티 Update( )함수는 게임의 지속적인 변화를 주거나 게임의 진행되는 매순간 체크(사용자의 입력 등)해야할 경우 사용하게 된다.

하지만 특정행동을 5초 동안 취해야 할 경우,  초당60~80(프레임)번 호출 되는 Update함수 안에서는 제어 하기가 힘들다. 

그리고 플레이하는 디바이스마다 각각 다른 프레임이 나오기 때문에 구현 자체가 더더욱 힘들다.


그래서 C#과 유니티에서는 코루틴이라는 것을 제공한다.

유니티에서 사용할 것이기 때문에 유니티 코루틴을 알아보도록 하자


사용법 

StartCoroutine

void 함수명( ) //Update안에 있는

{

     StartCoroutine( 코루틴 함수 이름( ) );  

}

IEnumerator

    public IEnumerator 코루틴 함수 이름( ) //코루틴 사용

    {

            Debug.log(코루틴 대기);   

 yield return new WaitForFixedUpdate();

            Debug.log(코루틴 완료);

    }

 코드분석

우선 StartCoroutine( ) 괄호안에 코루틴으로 IEnumerator 개채명, 지정한 함수이름을 써준다.

yield라는 것은 반복자의 IEnumerator객체에 값을 전달하거나, 반복의 종료를 알리기 위해 사용한다.

WaitForFixedUpdate( );  다음 FixedUpdate 물리 프레임 전까지 대기

(코루틴 예외 :  함수안에서 만 사용, 알수 없는 이름의 함수(람다)에서는 에러)

코루틴용 데이터엔진이 수행하는 기능
yield return null다음 프레임까지 대기
yield return new WaitForSeconds(float)지정된 초 만큼 대기
yield return new WaitForFixedUpdate()다음 물리 프레임까지 대기
yield return new WaitForEndOfFrame()모든 렌더링작업이 끝날 때까지 대기
yield return StartCoRoutine(string)다른 코루틴이 끝날 때까지 대기
yield return new WWW(string)웹 통신 작업이 끝날 때까지 대기
yield return new AsyncOperation

비동기 작업이 끝날 때까지 대기




참고 : https://docs.unity3d.com/kr/530/Manual/Coroutines.html





COMMENT
 
12
22

The Animation View






하이라키창에서 움직일 오브젝트를 선택하고



애니메이션 창에서  AddProperty를 필요한 속성을 추가한다.



왼쪽에는 속성과 값을 설정할 수있고 오른쪽에는 원하는 시간대에 설정값을 넣어 애니메이션 만들 수 있다.



첫 번째는 원하는 시간대로 이동

두 번째는 프레임 설정(숫자가 낮으면 느려짐)



  

녹화 버튼을 누르면 빨갛게 변한다. 추가 하고싶은 요소를 추가한다.

현재는 위치와 회전값만 프로퍼티로 추가 했기 때문에 Position과 Rotation만 색이 변한 걸 볼 수 있다.

(녹화 버튼을 누른 상태에 값을 주어야함)


게임신에서 움직여도 되지만 정확한 값을 넣기 위해 인스펙창을 통해 설정한다.






The Animator Component




Controlle : 유니티가 생성한 에셋으로 하나 이상의 상태 머신이 포함되어있다.

상태머신? 씬이 실행될 때 어느 애니메이션이 재생될 것인지 결정한다.

Avater : 3D휴머노이드를 임포트할 때 유니티가 생성하는 에셋이다.

모델과 애니메이터를 이어주는 접착제? 같은 역할이라고 생각하면 된다.


Apply RootMotion : 애니메이션이 게임 오브젝트의 트랜스폼에 영향을 줄 수 있는지 여부를 결정한다.

UnCheck하게 되면 애니메이션은 작동하지만 이동하지는 않는다.



Culling Mode : 렌더링 상태가 아닐때 애니메이션이 재생될 것인지 아닌지를 정할 수 있다.

(비용절약) 화면에 보이지 않으면 애니메이션은 작동하지 않는다.



The Animator Controller


Parameters옆의 + 아이콘을 클릭하면

Float, Int, Bool,Trigger

애니메이션의 퀄리티나 조건을 나타낸다.


Animator Window 살펴보기

애니메이터 창에서 애니메이터컨트롤러 상태를 설정할 수가 있다.


처음 생성된 상태는 기본상태(주황색)로 된다.

(기본을 변경하고 싶으면 원하는 상태에서 마우스 오른쪽 -> Set As Default)


상태 편집은 클릭하면 인스펙터창에서 할 수 있다.

맨위 는 이름과 태그로 코드로 참조 가능하며 어떤 상태에 있는 동안 원하는 동작을 수행하게 할 수 있다.


speed  : 일반 애니메이션 속도의 비해 얼마나 빠르게 재생되는지를 참조

Mirror : 애니메이션의 좌우가 반전

Foot IK : 체크하면 애니메이션이 발 미끄러짐이 감소하거나 제거 된다.

Transitions : 다른 상태로 트랜지션할 수있는 상태를 표시,설정


트랜지션 상태 (흰 화살표)

마우스 오른쪽 -> Make Transitions으로 설정



style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;">트랜지션 상태 설정하기

디버그용

Mute : 현재 상태에 연결된 트랜지션을 비활성화 한다.

Solo : 같은 상태에 연결된 모든 트랜지션을 고려하여 그 중에서 Solo가 표기 되지 않은 모든 트랜지션을 비활성화한다.

Conditions : 설정한 파라미터(bool,Int,flat)를 통해 다른 상태로 이동하는 조건을 설정 할 수 있다.


예를 들어 일정 속도값이 생기면 걷는 동작을 취하도록 하려면

void Update()

{

float h = Input.GetAxis("Horizontal");

anim.SetFloat("speed", v);

}

스크립트 작성후 컴포넌트 해주고


애니메이터윈도우에

파라미터 speed를 생성하고


Idle -> Walk

(스크립트로 제어할것이기 때문에 Has Exit Time 언체크!)

speed값이 0.1이 넘으면 걷기 애니메이션이 작동하도록 설정해준다.  



Walk -> Idle

speed값이 0이면 다시 Idle 상태로 돌아 가기 위해 Less는 ‘0’으로 설정한다.



니메이터 윈도우에 Base Layer를 보면 현재 어떤 상태인지 볼 수있다.

Parameters에서는 키보드 위 방향을 누르면 speed 값이 올라가는 걸 볼 수 있다.

COMMENT
 
12
20

인터페이스 interface


 클래스를 만들 때 사용하는 규약?



기본구조

interface [인터페이스 이름]

{

}



생성위치

인터페이스는 클래스와 동급의 카테고리이다. 그렇기 때문에 클래스를 생성하는 위치라면 어디든지 만들 수 있다.



예제를 보면서 이해하자



1) 인터페이스 생성

interface IBasic

{

int TestInstanceMethod( );

int TestProperty{  get; set ;}

}

메서드에 내부 구현을 입력할 수 없다.

속성에도 마찬가지로 내부 구현을 입력할 수 없다.


2) 인터페이스 상속

class TestClass : IBasic

{


}

static void Main(string[] args)

{

}


3) 인터페이스 구현

'Ctrl' + '.' 누르면 자동완성 

class TestClass : IBasic

{

public int TestInstanceMethod( )

{

throw new NotImplementedException( );

}

public int TestProperty

{

get

{

throw new NotImplementedException( );

}

set

{

throw new NotImplementedException( );

}

}

}

클래스에서 이후에 구현해준다.



4) 인터페이스 다중 상속

class Program

{


class Parent{ }

class Child : Parent, IDisposable, IComparable

{

public void Dispose( )

{

throw new NotImplementedException( );

}


public int CompareTo(object obj)

{

throw new NotImplementedException( );

}

}

//한 개의 클래스와 두 개의 인터페이스를 상속받는다.


이렇게 상속되면 다음과 같이 세종류로 자료형 변환이 가능해진다.

Child child = new Child( );

Parent ChildAsParent = new Child( );

IDisposable childAsDisposable = new Child( );

IComparable childAsComparable = new Child( );






COMMENT
 
1