티스토리 뷰

저번글에서는 C# 기본문법에 대해 공부하였습니다. 이번글에서는 클래스와 오브젝트에 대해 공부해보겠습니다.

 

게임속 사물을 오브젝트라고 합니다. 그러한 오브젝트들이 상호작용하여 프로그램을 이룹니다. 이러한 것을 객체 지향 이라 합니다.

객체지향은 독립적이며 스스로 동작하는 여러 객체(오브젝트)가 모여 거대한 프로그램이 완성되는 구조를 만드는 방법입니다. 그리고 그것이 C#스크립트의 클래스가 동작하는 방식입니다. 

 

클래스와 오브젝트는 객체지향의 핵심입니다. 객체 지향은 사람이 현실세상에 보는 방식에 가깝게 프로그램을 완성하는 것입니다. 

 

이 글에서는 클래스와 오브젝트의 개념과 활용하는 방법에 대해 공부해보겠습니다. 

 

1. 클래스와 오브젝트의 개념

클래스는 묘사(추상화) 할 대상과 관련된 코드(변수와 메서드 등)를 묶는 틀입니다. 

class Dog{
  string name;
 
  void Eat(){
  ...
  }
}

 

위 클래스의 변수 name과 Eat() 메서드는 Dog 클래스내에 선언되어 개의 이름과 먹는 동작을 나타냅니다. 즉 ,클래스는 표현하고 싶은 대상을 추상화하여 대상과 관련된 변수와 메서드를 정의하는 틀입니다. 

 

오브젝트는 물건의 설계도인 클래스와 달리 실제로 존재하는 물건(실체)입니다. 

위 Dog 클래스로 진순이(진돗개)와 버디(리트리버)의 오브젝트를 생성했다고 가정한다면 Dog는 실제로 존재하는 오브젝트가 아니지만 Dog클래스를 통해 두 오브젝트를 생성했습니다. 여기서 클래스는 하나만 존재하지만 클래스를 기반으로 생성한 오브젝트는 여러개 있다는 점을 주목합니다.

 

이렇게 클래스라는 틀로 오브젝트를 찍어내 실체화 하는 것인스턴스화 라고 합니다. 이 인스턴스화를 이용해 생성된 오브젝트를 인스턴스라고 합니다.  오브젝트는 인스턴스를 포함하는 개념입니다. 

 

하나의 클래스에서 여러개의 오브젝트를 생성할 수 있지만 오브젝트는 서로 독립적이며 구별 가능한 실체입니다. 즉, 진순이라는 개와 버디라는 개는 지구상에 1마리 뿐입니다. 하지만 똑같은 개에 속합니다. 하지만 진순이와 버디는 서로 독립적인 실체입니다.

 

2. 코딩해보기!

프로젝트를 하나 생성하여 Human이라는 클래스를 만듭니다. project 창에서 create > C# script를 클릭합니다.

여기서 Human 클래스는 사람을 추상화한 클래스입니다. 

생성된 클래스명을 Human으로 바꿉니다.

 

생성한 Human 스크립트 파일을 더블클릭하여 편집기를 실행합니다. 다음과 같이 스크립트를 작성합니다. 

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

public class Human
{
    public string name;
    public int age;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    public void Introduce() {
        Debug.Log("제 이름은 " + name +"이고, 나이는 "+age+"살입니다.");
    
    }
}
  •  MonoBehaviour 클래스를 상속하지 않았기 때문에 Human클래스는 게임오브젝트에 컴포넌트로서 추가할 수 없습니다.
  • MonoBehavior 클래스를 상속한 클래스는 new 연산자로 인스턴스화 할 수 없습니다. 만약, new 연산자로 MonoBehaviour 클래스를 오브젝트로 생성하면 필요한 초기화 과정과 게임오브젝트에 추가되는 과정을 전부 생략하고 즉시 오브젝트가 생성되어 오브젝트가 정상적으로 동작하지 않습니다.
  • 어떤 클래스에 속하며 해당 클래스의 데이터와 행위를 표현하는 요소를 멤버라고 합니다. 여기서 Human클래스에 속한 변수 name,age 와 Introduce() 메서드가 Human의 멤버입니다. 
  • 클래스의 멤버 중에서 변수를 필드라고 부릅니다. Human클래스의 멤버 중에서 변수 name,age가 Human 클래스의 필드입니다. 

 

Human이라는 클래스를 생성했지만 아무런 일도 일어나지 않습니다. Human클래스는 실체(오브젝트)가 아니기 때문입니다. 

 

Human클래스를 기반으로 Human 오브젝트를 만드는 Company 스크립트를 작성합니다. 위 방법으로 Company 스크립트를 생성하고 다음과 같이 소스를 입력합니다. 

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

public class Company : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Human mina = new Human();
        mina.name = "신민아";
        mina.age = 23;

        mina.Introduce();

    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
  • new 연산자는 클래스로부터 인스턴스를 생성합니다.
  • Human() 메서드는 Human 클래스의 생성자입니다. 생성자는 오브젝트를 생성할때 실행되며, 오브젝트가 생성될때 어떻게 초기화할지 정의하기 위해 사용하는 특수한 메서드입니다.

완성된 스크립트를 동작하려면 게임 오브젝트를 만들어 스크립트를 오브젝트에 연결해야합니다. 빈 게임오브젝트를 생성하고 작성한 Compay 스크립트를 붙입니다.

 

Hiearchy창에서 Create > Create Empty를 눌러 빈 게임오브젝트를 생성합니다.

 

생성한 GameObject를 클릭하여 확성화된 Inspector창에 Project창내의 Company 스크립트를 선택하여 드래그앤 드롭합니다.

플레이버튼을 눌러 콘솔창의 로그를 확인합니다.

3. 접근제한자

접근제한자란 클래스 멤버의 공개 여부를 정하는 키워드입니다. 자주 사용하는 접근 제한자는 다음과 같습니다.

  • public : 클래스 외부에서 멤버에 접근 가능 
  • private : 클래스 내부에서만 접근 가능 (기본값)
  • protected : 클래스 내부와 파생 클래스에서만 멤버에 접근가능

즉, Company 클래스에서 Human 클래스의 멤버 name, age, Introduce() 에 접근 가능했던것은 접근 제한자를 human으로 선언했기 떄문입니다. 만약 클래스의 멤버를 private으로 선언하였다면 외부클래스에서 접근 불가능합니다.  

 

4. 참조타입

string name ="마시멜로";
int year = 2019;

위와 같이 name,int 등의 new 키워드를 사용하지 않고 변수에 바로 값을 할당할 수 있는 변수가 있습니다. 

Human human = new Human();

 반면에 new 연산자를 사용하여야지 사용가능한 변수가 있는데 이 클래스로 만든 변수는 참조 타입으로 실체화된 오브젝트가 아닙니다. 

참조타입의 변수는 선언하는것만으로는 오브젝트가 생성되지 않기 때문에 new 를 사용해 오브젝트를 개별적으로 생성해야 합니다.

 즉 , human 변수는 오브젝트가 아니라 오브젝트를 가리키는 참조값을 저장하는 변수입니다.

 void Start()
    {
        Human mina = new Human();
        mina.name = "민아";
        mina.age = 23;

        Human junewoo = new Human();
        junewoo.name = "준우";
        junewoo.age = 26;

        junewoo = mina;
        junewoo.name = "윤경";

        mina.Introduce();
        junewoo.Introduce();
    }

 

실행결과

 

결과값이 예상과는 달리 출력되어 당황하였을 것입니다. 이것은 참조타입은 오브젝트의 주소값을 저장하는 변수라는 것을 다시한번 기억하고 다음의 과정을 차례대로 보도록 합시다.

 

과정 1. 인스턴스화 

        Human mina = new Human();
        mina.name = "민아";
        mina.age = 23;

        Human junewoo = new Human();
        junewoo.name = "준우";
        junewoo.age = 26;

 

과정 2. 참조값 변경

 junewoo = mina;

여기서 junewoo 가 가르키던 오브젝트는 아무도 가리키지 않는 상태로 남겨져 있고, junewoo 변수는 mina 변수와 같은 오브젝트를 가리킵니다. 이 아무도 가리키지 않는 오브젝트는 가비지 컬렉터거 자동으로 파괴하여 정리합니다.

 

과정 3. 값 변경

 junewoo.name = "윤경";

이렇게 변수에 실체가 아니라 실체로 향하는 참조가 할당되고, 변수에 접근하면 참조를 통해 실체에 접근하는 변수를 참조 타입이라고 합니다.  즉, 오브젝트는 하나지만 그것을 여러개의 참조변수가 동시에 가리킬 수 있습니다.

 

모든 변수가 참조로 동작하는 것은 아닙니다. 내장변수는 참조로 동작하지 않습니다. 이런 타입을 값 타입이라고 합니다. 참조타입 변수는 값(실체)으로 향하는 참조를 저장하고, 값 타입의 변수는 해당 변수 공간에 값 자체를 저장합니다. 

참조타입 값타입

class 타입

유니티의 모든 컴포넌트

MonoBehaviour를 상속받는 클래스 

C# 내장 변수

(bool, int, float, char, double, string...)

struct (구조체) 타입 - Vector3, Color....

 

5. 변수로 컴포넌트 사용하기

변수의 참조값으로 실체에 접근하는 참조타입 덕분에 변수로 씬에 있는 게임 오브젝트와 컴포넌트에 접근하고 이들 제어 할 수 있습니다. 유니티 에디터에서 작성한 변수로 게임오브젝트를 제어해봅니다.

 

1) Hierachy창에서 Create -> 3D Object -> Cube 클릭

2) 중력과 물리적인 힘을 받도록 리지드바디 컴포넌트 추가가 필요합니다.

하이어아키창에서 큐브를 선택하고 inspector 창 하단의 Add Component 클릭 -> Physics > Rigidbody 클릭

3) Rigidbody 타입의 변수는 Rigidbody 오브젝트 그자체는 아니지만 실제 Rigidbody 컴포넌트를 가리킬 수 있습니다. 따라서, 해당 변수로 실제 리지드바디 컴포넌트에 접근해 조정 가능합니다. Cube 오브젝트에 연결된 Rigidbody 컴포넌트에 접근하고 힘을 추가하는 C# Script를 작성해봅니다.

 

프로젝트창에서 Create>C# Script 클릭하여 생성된 스크립트 명을 Jumper로 변경한 후 스크립트를 더블클릭하여 실행합니다.

4) 스크립트를 다음과 같이 작성합니다.

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

public class Jumper : MonoBehaviour
{
    public Rigidbody rigidbody;
    // Start is called before the first frame update
    void Start()
    {
        rigidbody.AddForce(0, 500, 0);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

- rigidbody 변수는 public으로 선언되어 외부에서 접근 가능하도록 합니다.

 

5) 코드편집창 저장 후  최소화하거나 닫습니다. 유니티 에디터창으로 돌아가 Cube 오브젝트에 작성한 스크립트를 연결합니다.

project창의 Jumper스크립트를 Cube오브젝트에 드래그앤드롭합니다. 연결이 완료되면 Inspector창에 아래 그림과 같이 Jumper스크립트가 연결된 것을 확인할 수 있습니다.  

6) 플레이모드를 누르면 콘솔창에 에러메세지가 출력됩니다. 메시지내용을 보면 rigidbody변수에 아직 참조를 할당하지 않았다는 내용입니다. 다시 플레이 버튼을 눌러 플레이 모드를 해제합니다.

6) 컴포넌트를 변수에 연결해야합니다. 스크립트의 public 변수로 선언되었기때문에 Rigidbody라는 변수가 표시되는데 할당값이 None으로 나타납니다. 아직 어떠한 오브젝트도 가리키고 있지 않다는 내용입니다. 따라서 인스펙터창에서 실제 오브젝트인 리지드바디 컴포넌트를 연결해야합니다. 

Inspector창에서 Rigidbody 컴포넌트를 변수 None 부분에 드래그앤 드롭합니다.

6) 다시 플레이버튼을 눌러 실행하면 정상적으로 큐브가 1회 점프하는것을 볼 수 있습니다. 

 

이상 클래스와 오브젝트의 개념을 공부하고, 게임오브젝트의 컴포넌트를 코드로 제어해보았습니다.

 

수고하셨습니다!

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크