공부/Unity

24.03.12

월러비 2024. 3. 12. 13:42

0. 생성한 스크립트

  • Structures : 구조체 스크립트
  • Classes : 오버라이드 등 클래스 예제
  • Expression : 프로퍼티 및 식 본문 멤버 사용 예시
  • Inheritance : 상속 예시
  • Generic_Func : 제네릭 함수 예시
  • Generic_Stack : 제네릭 스택 생성

 

1. 프로퍼티

  • 프로퍼티 : 클래스가 구현 또는 검증 코드를 숨기는 동시에 값을 가져오고 설정하는 방법을 공개적으로 노출할 수 있다.
    • get 프로퍼티 : 속성 값을 반환하는 데 사용된다.
    • set 프로퍼티 : 새 값을 할당하는 데 사용된다.
      • 두 프로퍼티중 하나만 사용하여 읽기전용(get만 사용), 쓰기전용(set만 사용)으로 만들 수 있다.
    • value 키워드 : set 또는 init 접근자가 할당하는 값을 정의하는 데 사용된다.
  • 프로퍼티는 변수 바로 밑에 생성하는게 보기 편하다.
  • 멤버 변수 => property => 멤버 함수
  • get : 저장된 값을 쓴다. / set : 값을 저장한다.
private float mpBooster;

public float MpBooster
{
    //get { return mpBooster; }
    //set { mpBooster = value; }

    get => mpBooster;
    set => mpBooster = value;
}

 

2. 생성자

  • 생성자 : 클래스 또는 구조체의 인스턴스가 만들어질 때마다 해당 생성자가 호출된다.
    • 서로 다른 인수를 사용하는 여러 생성자가 있을 수 있다.
  • 객체가 생성될때 자동으로 호출되는 함수
class Character
{
	 //생성자는 객체를 생성할때 반드시 호출되기 때문에 public으로 만들어야한다.
    public Character() //기본 생성자는 특별한 경우가 아닌경우 사용하지 않는다. / 생성자는 오버로딩 가능
    {
        Debug.Log("생성자"); //모노비헤비어 상속이 안되어있는 클래스이기 때문에 print사용이 불가능하다.
    }

    //public Character(string name)
    //{
    //    this.name = name;
    //}

    public Character(string name)
        :this(name, 100, 100) //밑의 매개변수 3개인 생성자를 호출한다.(생성자 2개를 동시에 호출할때 사용한다.)
    {

    }

    public Character(string name, float health, float magician)
    {
        this.name = name;
        this.health = health;
        this.magician = magician;
    }
 }

 

3. new 연산자

  • new 연산자는 새 유형의 인스턴스를 만든다.
    • 생성자 호출
    • 배열 생성 
  • new 키워드를 멤버 선언 한정자 또는 제네릭 형식 제약 조건으로 사용할 수도 있다.
    • var dict = new Dictionary<string, int> {  };
Character player = new Character("Player"); //생성자 / Character() : 생성자를 호출하는 명령이다.

 

new 설명 사진

4. this.변수

  • 클래스의 현재 생성자를 가리키며 확장 메서드의 첫 번째 매개 변수에 대한 한정자로도 사용된다.
    • 클래스 내부의 private 접근지정자 변수에 this를 붙여서 사용할 수 있다.
      • private string name; => this.name = name;
    • 개체를 다른 메서드에 매개변수로 전달한다.
      • CalcTax(this);
  • 멤버변수 즉, 객체의 변수
public Character(string name, float health, float magician)
{
    this.name = name;
    this.health = health;
    this.magician = magician;
}

 

5. 식 본문 멤버

  • 식 본문 정의를 사용하면 간결하고 읽기 쉬운 형식으로 멤버의 구현을 제공할 수 있다.
  • 메서드 또는 속성과 같은 지원되는 멤버에 대한 논리가 단일 식으로 구성된 경우 식 본문 정의를 사용할 수 있다.
  • 식 본문 정의는 다음 형식 멤버와 함께 사용할 수 있다.
    • Method
      • public override string ToString() => $"{fname} {lname}".Trim();
    • 읽기 전용 속성
    • 속성
      • get => mpBooster;
    • 생성자
      • public Character(string name) => Name = name;
    • 종료자
    • 인덱
  • =>(return 기호다)
public float MpBooster
{
    //get { return mpBooster; }
    //set { mpBooster = value; }

    get => mpBooster;
    set => mpBooster = value;
}

 

6. static

  • static 한정자를 사용하여 특정 개체가 아니라 형식 자체에 속하는 정적 멤버를 선언할 수 있다.
  • static 한정자를 사용하여 static 클래스를 선언할 수 있다.
    • 클래스, 인터페이스 및 구조체에서 필드, 메서드, 속성, 연산자, 이벤트 및 생성자에 static 한정자를 추가할 수 있다.
    • static 키워드가 클래스에 적용된 경우 클래스의 모든 구성원은 static 이어야 한다.
  • static 한정자를 로컬 함수에 추가할 수 있다.
    • 정적 로컬 함수는 지역 변수 또는 인스턴스 상태를 캡처할 수 없다.
  • 클래스 안에 모든 영역에서 공용으로 단 하나만 사용된다. (데이터영역에 저장된다.)
  • static 생성자는 접근 지정자가 없고 기본적으로 public으로 생각해라
  • 상속 불가능하다.
private static int count;

static 설명 사진

7. 오버라이드

  • 상속된 메서드, 속성, 인덱서 또는 이벤트의 추상 또는 가상 구현을 확장하거나 수정하는 데 필요하다.
  • 오버라이드 메서드는 기본 클래스에서 상속된 멤버의 새 구현을 제공한다.
    • 정적 메서드는 재정의할 수 없다.
    • 오버라이드 선언에서는 virtual 메서드의 액세스 가능성을 변경할 수 없다.
    • 오버라이드 메서드 및 virtual 메서드 둘 다에 동일한 엑세스 수준 한정자(public, protected 등)가 있어야한다.
  • 재정의된 기본 메서드는 virtual, abstraact, override여야한다.
public override string ToString()
{
    return $"{id}, {name}, {health}, {magician}";
}

오버라이딩 설명 사진

8. 상속

  • 상속을 사용하면 다른 클래스에 정의된 동작을 다시 사용, 확장 및 수정하는 새 클래스를 만들 수 있다.
  • 인터페이스 선언은 그 멤버의 기본 구현을 정의할 수 있다.
    • 이러한 구현은 파생된 인터페이스에 의해, 그리고 해당 인터페이스를 구현하는 클래스에 의해 상속된다.
  • 기본 클래스가 메서드를 virtual로 선언하는 경우 자식 클래스가 자체 구현으로 메서드를 어버라이드 할 수 이싿.
    • 기본 클래스가 멤버를 abstract로 선언하는 경우 해당 클래스에서 직접 상속되는 모든 비추상 클래스에서 메서드를 재정의해야한다.
    • 자식 클래스 자체가 abstract인 경우 직접 구현하지 않고 추상 멤버를 상속한다.
  • 상속받은 클래스의 객체 안에 상속받은 부모 클래스의 공간이 따로 있고 그 안에 부모클래스의 변수 공간이 할당되어있다.
  • 함수를 오버라이드하면 자신의 힙(heap)공간 안에 오버라이드한 함수가 따로 저장된다.
    • 이때 부모의 원래의 함수 주소와, 오버라이드한 자식의 함수 주소가 가상의 테이블에 저장된다(가상 테이블)
  • private 변수는 자식도 사용 못하지만, protected는 자식도 사용할 수 있다.
  • 프로퍼티도 상속된다.
  • A oba = new A(); / B obb = new B(); / A obb2 = (A) obb; => 업 캐스팅(이건 무조건 가능한 방법이다)
    • A obb2 = (A) obb; 이렇게하면 B공간에 생성된 부모A 공간에 바로 접근이 가능해진다.
    • C obc = new (C); / B obb3 = (B) obb2; (3교시 녹음 마지막부분 잘 듣자)
class Character
{
    protected string name;
    public string Name
    {
        get => name;
        set => name = value;
    }

    private float hp;
    public float Hp
    {
        get => hp;
        set => hp = value;
    }

    public Character(string name, float hp)
    {
        this.name = name;
        this.hp = hp;
    }

    public override string ToString() => $"{name}, {hp}";

    public virtual void Move()
    {
        Debug.Log("오른쪽 방향으로 10만큼 이동");
    }
}

class Player : Character
{
    public Player()
        : base("None", -1) //부모 생성자에 넘기는 인자
    {
        Debug.Log(ToString());
    }

    public Player(string name, float hp)
            : base (name, hp)
    {
        Debug.Log(ToString());
    }

    public override void Move()
    {
        base.Move();

        Debug.Log("전진 방향으로 10만큼 이동");
    }
}

Player p = new Player();
Player p2 = new Player("Player2", 100);
p2.Move();

상속 결과
상속과 static 설명 사진

9. 가상화 (virtual 키워드)

  • virtual 키워드는 메서드, 속성, 인덱서 또는 이벤트 선언을 수정하고 파생 클래스에서 재정의하도록 허용하는 데 사용된다.
public virtual void Move()
{
    Debug.Log("오른쪽 방향으로 10만큼 이동");
}

public override void Move()
{
    base.Move();

    Debug.Log("전진 방향으로 10만큼 이동");
}

가상화 결과

 

10. 업 캐스팅 / 다운 캐스팅

  • 업 캐스팅 : 자식 객체에서 부모 객체로 형변환하는 것을 의미한다.
    • 자식 타입의 객체를 부모 타입의 변수로 참조하는 것이다.
    • 단, 자식 타입의 객체의 전부에 접근할 순 없고 부모로부터 상속받은 멤버들만 접근이 가능하다.
  • 다운 캐스팅 : 부모 객체에서 자식 객체로 형변환하는 것을 의미한다.
    • 자식 타입의 객체를 참조하던 부모 타입 변수를 자식 타입으로 형변환해주는 것은 가능하다.
    • 다운 캐스팅은 반드시 명시적 형변환을 해주어야 한다.
    • 부모 타입의 변수가 자식 타입으로 명시적 형변환을 할 땐 문제가 없지만, 같은 부모를 가진 다른 자식 타입으로 명시적 형변환을 할 때에는 런타임 오류가 발생한다.
      • 자식 타입끼리 서로가 공유하지 않는 멤버들이 존재할 수도 있기 때문이다.
      • is 키워드와 as 키워드를 이용하여 형변환할때 해당 객체를 참조하고 있는지 확인할 수 있다.
Character[] characters = new Character[5];
characters[0] = new Player("Player1", 5);
characters[1] = new Character("Character", 2);
characters[2] = new Enemy("Enemy", 7);
characters[3] = new Player("Player2", 4);
characters[4] = new Character("Character2", 9);

업캐스팅 상속 결과
업 캐스팅 / 다운 캐스팅 설명 사진

  • A obb2 = (A) obb; 는 B공간안의 A공간에 접근하는것이다.
  • obb2.b=20;은 성립하지 않는다. => A공간에 접근 한것이지 B의 공간을 사용하는것이 아니기에 b의 공간에 접근하지 못한다.
  • B obb3 = (B) obb2;는 다운 캐스팅으로 A에서 A의 공간을 가지고 있는 B로 이동하는것이기에 가능한 것이다.
  • obb2에서 a=10; , b=20;을 정의했고, obb3.a , obb3.b를 부른다면 이미 정의되어있는것에 10과 20이 들어가있고 접근이 가능하다.

11. 제네릭

  • 클래스 또는 메서드가 클라이언트 코드에 의해 선언되고 인스턴스화될 때까지 하나 이상의 형식 지정을 연기하는 클래스 및 메서드를 디자인할 수 있도록한다.
    • 즉, 제네릭 형식 매개 변수 T를 사용하여 자료형을 선택하지 않은채 작성한 다음, 선언할때 해당 자료형을 넣어 선언한다.
    • 제네릭은 컬렉션(배열, 컨테이너) 및 해당 컬렉션에서 작동하는 메서드에서 가장 자주 사용된다.
  • 제네릭 형식을 사용하여 코드 재사용, 형식 안전성 및 성능을 최대화한다.
  • 가장 일반적으로 제네릭은 컬렉션 클래스를 만드는 데 사용된다.
  • 사용자 고유의 제네릭 인터페이스, 클래스, 메서드, 이벤트 및 대리자를 만들 수 있다.
private void Swap<T>(ref T a, ref T b)
{
    T temp = a;
    a = b;
    b = temp;
}

int val1 = 10;
int val2 = 20;
Swap<int>(ref val1, ref val2);
print($"{val1}, {val2}");

string val3 = "abc";
string val4 = "def";
Swap<string>(ref val3, ref val4);
print($"{val3}. {val4}");

제네릭 결과
제네릭 설명 사진

11-2 제네릭 스택 구현

class Stack<T>
{
    private int top = -1;
    private T[] values;

    public const int MaxCount = 10; //const : 상수 => 절대 변하지 않는 수, 반드시 초기화 시켜야한다.

    public Stack()
    {
        values = new T[MaxCount];
    }

    public void push(T value)
    {
        if(top +1 >= MaxCount)
        {
            throw new System.Exception("스택 꽉참");
        }

        values[++top] = value;
    }

    public T Pop()
    {
        if (Empty())
        {
            throw new System.Exception("스택 비어있음");
        }

        T value = values[top--];

        return value;
    }

    public T Front()
    {
        return values[top];
    }

    public bool Empty()
    {
        return top < 0 ? true : false;
    }
}

Stack<int> stack = new Stack<int>();
stack.push(9);
stack.push(20);
stack.push(10);
stack.push(50);
stack.push(4);
stack.push(3);

while (stack.Empty() == false)
{
    print(stack.Pop());
}

for(int i = 0; i < 11; i++)
{
    stack.push(i);
}

제네릭 스택 결과
제네릭 스택 설명 사진

12. const 

  • 상수(const)는 컴파일 시간에 변경할 수 없는 값이다.
  • 열거형 형식을 사용하여 정수 계열 기본 제공 형식(int, uint, long 등)에 대한 명명된 상수를 정의할 수 있다.
  • 상수는 선언될 때 초기화되어야한다.
  • 상수에 액세스할 때에는 클래스이름.상수명 으로 사용해야한다.
public const int MaxCount = 10; //const : 상수 => 절대 변하지 않는 수, 반드시 초기화 시켜야한다.

 

13. SerializeField

  • private 접근 지정자는 선언된 클래스 또는 구조체의 본문 내에서만 액세스할 수 있지만, [SerializeField]를 앞에 붙인다면 인스펙터 창에서는 접근가능하게 만들어주는 명령어다.
    • 직렬화 : 추상적인 데이터를 전송 가능하고 저장 가능한 형태로 바꾸는 것을 의미한다.
    • 간단하게, 유니티가 private 필드를 직렬화(serialization)하도록 설정하는 것이다.
[SerializeField]
private GameObject _prefab;

serializeField 결과

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

24.03.14  (3) 2024.03.14
24.03.13  (0) 2024.03.13
24.03.11  (0) 2024.03.11
24.03.08  (1) 2024.03.08
24.03.07  (0) 2024.03.07