공부/Unity

24.03.25

월러비 2024. 3. 25. 23:06

새로 생성한 스크립트

  • Player : 수정
  • IDamage : 수정
  • Player_AnimEvent : 수정 / Movement 클래스에서 Stop과 Move 함수 받아서 공격시 움직임 막기 등
  • Movement : 에트리뷰트 사용한 움직임 / speed 상태 변경을 enum으로 사용하는 예시
  • Test_Object : 스크립트나 그걸 가진 게임오브젝트 찾기 / 리플렉션 / 복사생성자 / 얕은 복사 ‘ 깊은 복사 / explicit operator 사용 / 업 다운 캐스팅 / try - catch - finally 간단 사용 예시

타격감을 구성하는 요소

  • 애니메이션 : 피격 모션
  • 사운드
  • 이펙트
  • 카메라 효과 : 카메라 흔들림
  • 진동(PC에서는 구현 못함)
  • Hit Stop
    • 피격시 경직
    • 피격 직전 슬로우모션

프로그래밍의 역사

  • 절차지향(구조적) → 정보공학(데이터중심) → 객체지향(클래스, 또는 인터페이스 중심) → CBD(컴포넌트 중심)
    • 객체지향 : GameObject / CBD : Transform ‘ Rigidbody ‘ Animator …
    • 간단한 물리 기능 및 대상의 정보 전달(협업시 다른사람에게 공개해줘야 할(해줘도 될) 부분) : 컴포넌트로 해결 / 상세한 기능(피격, 프로그램 상에 필요한 기능) : 인터페이스로 해결

에트리뷰트

  • 에트리뷰트 : 클래스의 추가적인 속성을 정할때 쓰는 기능
    • RequireComponent) : 얘는 반드시 포함해야합니다 를 가리킬때 사용한다.
    • [RequireComponent(typeof(Animator))] [SerializeField]
    • 이게 사용된 스크립트를 오브젝트에 넣는다면 typeof에 적힌 컴포넌트가 없다면 자동으로 생성된다.

애트리뷰티 설명

SerializeField private, protected 변수를 인스펙터에 표시
Serializable 커스텀 클래스를 인스펙터에 표시
Header 변수위에 타이틀을 설정해 카테고리 분류 가능, 인스펙터 외관 정리에 사용
HideInInspector public 변수를 인스펙터에서 숨길 수 있다.
RqruireComponent 필수 컴포넌트를 추가 할 수 있다.
Range int, float 변수를 슬라이드바로 표시하고 범위를 제한함
Space 변수와 변수 사이에 간격 주가
CreateAssetMenu ScriptableObject Asset을 생성할때 사용하는 메뉴를 추가 할 때 사용
MenuItem 임의의 함수 (static) 실행을 메뉴 항목으로 추가
ContextMenu 임의의 함수 (non-static) 실행을 컴포넌트 톱니 메뉴에 추가
AddComponentMenu 인스펙터의 AddComponent 메뉴 항목으로 컴포넌트를 추가 할때 사용
ExecuteInEditMode 에디터가 플레이 모드가 아니더라도 컴포넌트가 동작하도록 할떄 사용
Multiline string 변수를 여러줄 입력 가능하게 만들때 사용
TextArea Multiline과 비슷, 폭에 맞춰 자동으로 줄바꿈과 슬라이드바 표시
Tooltip 인스펙터에 표시되는 변수에 설명을 추가 할때 사용

클래스에 기본적으로 생성되는 요소

  • 기본생성자
  • 대입 연산자(=)
  • 최상위 클래스인 오브젝트 클래스로부터 받는 4가지 함수
    • bool Equals(object obj); ⇒ ==연산이 기본적으로 Equals를 호출한다.
    • int GetHashCode() ⇒ Equals를 호출할때 매개변수에 들어오는 변수를 해쉬 코드로 읽어 비교한다. / 이 해쉬코드와 비교하는 변수의 해쉬코드가 같다면 두 변수는 같은 변수다.
    • Type GetType() ⇒ 리플렉션 기능을 한다. , 비교하는 변수의 타입을 가져와 자료형을 탐색한다.
    • string ToString()

리플렉션

  • 컴파일 시에 알 수 없었던 타입이나 멤버들을 찾아내고 사용할 수 있게 해주는 메커니즘이다.
    • 즉, 객체의 이름, 모든 멤버, 이벤트 목록 등등 객체의 정보들을 런타임 중에 가져와 분석하고 사용할 수 있다.
  • C++에는 없고 C#에만 있는 기능이다.
private void Reflection()
{
    //GameObject.Find("Paladin"); //팔라딘을 찾는 기능
    Enemy enemy = GameObject.FindObjectOfType<Enemy>();
    //print(enemy != null ? "T" : "F"); //enemy 스크립트를 찾는 코드, 있으면 T 없으면 F 출력
    //print(enemy.gameObject.name); //에너미가 들어간 오브젝트 이름 출력

    //enemy 타입을 추적하는 코드
    Type type = enemy.GetType();
    MemberInfo[] members = type.GetMembers();

    foreach (MemberInfo info in members)
    {
        print($"{info.Name}, {info.MemberType}");
    }
}

 

복사 생성자

  • 복사 생성자 (C#에서는 기본 복사 생성자가 생성되지 않기에 직접 기본 복사 생성자를 생성해야한다.)
    • 동일한 클래스의 객체를 매개변수로 사용하는 경우 복사 생성자라고 한다.
    public Copy_Character(int hp, int speed) //매개변수가 들어간 생성자를 만들면 
    {
        Hp = hp;
        Speed = speed;
    
        ItemList = new int[3];
        ItemList[0] = 10;
    }
    
    public Copy_Character(Copy_Character character) //복사 생성자
    {
        this.Hp = character.Hp;
        this.Speed = character.Speed;
        //this.ItemList = character.ItemList; //얕은 복사
        this.ItemList = (int[])character.ItemList.Clone(); //아이템 리스트를 복사해라 라는 함수 //깊은 복사
    
        Debug.Log("Copy_Character");
    }
    
  • 복사 생성자 필요성
    • 깊은 복사를 위해 사용한다.
    • 객체를 다른 객체에 복사하고 싶을 때마다 복사 생성자를 사용할 수 있다.

앝은 복사 문제

class A{
	int[] a = new int[3];
	A(A copy){
		this.a = copy.a;
		}
	}
A ob = new A();
A ob2 = new A(ob);
ob.a[0] = 100;
  • 복사 생성자를 사용하여 매개변수로 들어간 객체의 값을 변경하면 복사 생성자의 객체도 값이 바뀌는 문제다.
  • 정리
    • copy.a의 값이 담긴 주소가 ob2에 저장된다.
    • 즉, 값이 담긴 주소를 저장한다.

깊은 복사 문제

class A{
	int[] a = new int[3];
	A(A copy){
		this.a = copy.a; => Clone()사용
			//(int[])character.ItemList.Clone()
		}
	}
A ob = new A();
A ob2 = new A(ob);
ob.a[0] = 100;
  • Clone함수는 값이 담긴 공간의 주소와 똑같은 공간을 만들고 복사한 공간의 주소를 준다.
    • 즉, 복사하는 주소의 공간을 똑같이 만드는 기능이다.
  • 정리
    • Clone함수가 새 공간을 만들고 넣은 값을 복사해서 새 공간의 주소에 넣는다.
    • 즉, 값 자체를 복사한다.

람다식

  • 함수의 축약형을 쓰겠다는 기능이다.

⇒ 연산자

  • 2가지의 의미를 가진다.
    • 람다(LinQ)
    • 식 본문 멤버 : 식 본문을 ⇒ 이후에 나오는 내용으로 정의하겠다는 의미다.
      public void Print(string s)
      {
      	print(s);
      }
      -> 
      public void Print(string s) => print(s);
      
    • private int number; private int Number { set => number = value; get => number; }

try - catch - finally 예외처리

  • try : 실행할 코드를 작성한다.
  • catch : 예외가 발생했을때 처리하는 실행문을 넣는다.
  • finally : 예외가 발생했을때도 반드시 실행되어야하는 기능을 작성한다.
try
{
    Copy_Character2 mario2 = (Copy_Character2)o; //
    print("예외발생"); //출력 안나옴 이유 : 바로 위에서 예외가 나오면 바로 catch영역으로 넘어가기 때문이다.
}
catch(Exception e) //무슨 에러가 날지 모를떄 사용한다.
{
    print(e.Message);
}
finally //예외가 발생해도 반드시 필요한 코드를 실행시킬때 사용하는 함수
{
    print("예외처리 완료");
}

is - as 예외 발생 처리수단\

  • 명시적 캐스팅 보단 as사용
    1. 가독성이 좋다.
    2. cast보다 as가 빠르다. (녹음 41분 들어보자)
      1. 명시적 캐스팅은 캐스팅 연산자를 모두 체크해 본다,.(캐스팅 연산자 콜이 있다)
        1. 캐스팅 연산자 콜을 해서 하나하나 확인한다.
      2. as는 변환하고자하는 타입만 확인한다.(캐스팅 연산자 콜이 없다)
        1. 바뀔수 있는지만 확인.
    3. 항상 동일한 결과를 보장한다
      1. 명시적 캐스팅은 캐스팅 연산자 오버로딩이 가능하기 때문이다.

'공부 > Unity' 카테고리의 다른 글

24.03.27  (1) 2024.03.27
24.03.26  (0) 2024.03.26
24.03.22  (1) 2024.03.22
24.03.21  (0) 2024.03.21
24.03.20  (1) 2024.03.20