게임 엔진/Unity

Unity 2일차 - C# 스크립트 기초 -1

FakeZero 2021. 6. 1. 05:32

오늘은 C# 스크립트를 조금 본격적으로 다뤄보도록 하겠습니다....라곤 하지만 사실 C#도 근본적으로 C언어와 다른 것이 없습니다. 그러니 C언어를 이해하고 있다면 C#도 쉽게 이해할 수 있습니다.

그렇다면 이 과정은 사실상 스킵해도 상관이 없는데 왜 강의를 굳이 하는가. 그것은 C# 스크립트를 사용하는데 익숙해지는 것과 우리가 작성한 C# 스크립트가 게임 엔진, 또는 게임에서 어떻게 작동을 하는지 직접 해보기 위해서입니다.

그럼 일단 하나하나 직접 해보도록 하죠.

 


0. 버전 업데이트

시작하기 전에 한 가지 말해둘 것이 있습니다. 아마 강좌를 따라하시다보면 Unity가 업그레이드 되어 버전을 교체해야할 때가 올 수 있습니다. 실제로 제가 첫 강의를 올린지 얼마 지나지 않아 바로 업데이트가 되어버렸더군요.

아무래도 구버전을 쓰기 보다는 새로운 버전을 쓰는 것이 훨씬 실용적이겠죠. 하지만 Unity는 자동으로 업데이트를 해주지 않습니다. 그렇다면 어떻게 업데이트를 해야할까요?

버전을 바꾸는 건 아주 간단합니다. 저번에 설치했던대로 Unity Hub의 설치탭에서 추가 버튼을 누르면 이렇게 Unity 버전을 새로 다운로드 할 수 있습니다. 사진의 최신 버전은 2021.1.9f1 버전이 최신 버전이군요. 저 버전을 선택해서 설치를 진행해주시면 되겠습니다.(저는 이미 설치가 되어있어서 2021.1.9f1 버전이 비활성화 되어 있습니다.)

이렇게 설치가 되었다면 프로젝트 탭으로 가보겠습니다.

프로젝트 탭으로 왔다면 저희가 저번에 생성한 Sample 프로젝트가 보일 것입니다. 하지만 이 프로젝트는 현재 저희가 저번에 진행했던 버전인 2021.1.7f1 버전을 쓰도록 지정되어 있습니다. 이 버전을 2021.1.9f.1 버전으로 바꾸도록 하겠습니다. 방법은 간단합니다.

원하는 프로젝트의 Unity 버전 옆에 있는 역삼각형을 클릭하면 PC에 설치되어 있는 모든 Unity 버전의 목록이 나타납니다. 여기서 저희가 원하는 버전인 2021.1.9f.1 버전을 선택해 보도록 하죠.

이렇게 쉽게 프로젝트의 버전이 바뀌었습니다. 여기까진 문제가 없어보입니다. 다만 프로젝트를 실행할 때 문제가 생깁니다.

버전을 업그레이드한 프로젝트를 실행하려고 하면 이런 창이 나타나게 됩니다. 이 창은 일종의 경고문으로 프로젝트가 이전 버전에서 생성되어서 최신 버전과 호환이 안 되서 프로젝트가 손상될 수 있으니 주의하라는 경고문입니다.

 

당연하게도 프로그램이 업데이트 되면 일부 기능이 삭제되거나 변경되었을 가능성이 있습니다. 그렇게 되면 미리 만들어둔 프로젝트에 영향을 끼칠 수 있습니다.

 

이번 경우에는 버전을 변경할 프로젝트가 매우 단순하기 때문에 그냥 바꿨지만 이미 개발이 상당히 진행되어 있는 상태에서 버전을 업데이트 할 때에는 미리 백업을 진행한 후에 버전을 변경하길 권장드립니다.

 

위 사진과 같은 상태에서 확인버튼을 눌러주면 그대로 Unity가 실행되며 프로젝트가 열람됩니다. 프로젝트 열람후 문제가 발견되지 않으면 이전 버전은 삭제해도 좋습니다.


1. 변수

이제야 겨우 본론으로 돌아갈 수 있겠군요. 그럼 이제부터 C# 스크립트를 본격적으로 사용해봅시다.

 

위에서도 말했듯이 C#도 근본적으로는 C언어와 다른 것이 없습니다. 따라서 프로그램을 짜는 방법 자체는 거의 같다고 해도 무방할 정도로 비슷합니다. 다만 조금씩 차이는 있기 때문에 이번 강의는 그 차이점에 초점을 두어 보시면 될 것 같습니다.

 

준비가 되었다면 프로젝트를 열어 Project창에서 이전 강좌에서 사용한 Test C# 스크립트를 더블 클릭해 비주얼 스튜디오로 스크립트를 수정할 준비를 하도록 합시다.

수정할 준비가 되었다면 이제 기초적인 코딩을 해보도록 합시다.

 

저번에는 콘솔창에 출력하는 법을 배웠으니 이번엔 변수를 배워보도록 합시다. 전에도 말했듯이 C언어와 크게 다르지 않습니다.

데이터형 이름 설명 값의 범위
int 정수형 -2,147,483,648 ~ 2,147,483,647
float 부동소수점형 -3.402823E+38 ~ 3.402823E+38
double 배정도(倍精度)부동소수점형 -1.79769313486232E+308 ~ 1.79769313486232E+308
bool 불형 true 또는 false
char 문자형 텍스트로 사용되는 유니코드 기호
string 문자열형 텍스트

이처럼 변수의 데이터형도 C언어와 별반 다르지 않습니다. 다만 몇가지 다른 점이 있으니 그 점들을 데이터형을 다루면서 설명하도록 하겠습니다.

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

public class Test : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        int age=19;
        string name = "이름";

        Debug.Log(age+"살 "+ name);
    }
}

이번엔 Update 메서드를 사용하지 않으므로 잠시 지워두겠습니다.

위와 같은 프로그램을 이용하면 C언어 때와 똑같이 프로그램이 작동하는 것을 볼 수 있습니다. 이대로 출력이 된다면 Unity의 콘솔 창에는 '19살 이름'이 출력될 것입니다.

 

그렇다면 C언어와 비슷한 것은 알겠는데 다른 점은 무엇일까요.

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

public class Test : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        float H1 = 180.5f;
        double H2 = 180.5;

        Debug.Log(H1);
        Debug.Log(H2);
    }
}

다음과 같이 float 데이터 형을 사용하려면 변수를 지정해줄때 뒤에 f를 붙여서 이 변수가 float형이다! 라는 것을 알려줄 필요가 있습니다. 소수 데이터는 f를 붙이지 않으면 double 데이터 형으로 취급되기 때문입니다.

다음과 같이 f를 생략하게되면 비주얼 스튜디오가 코드가 잘못됬다며 오류를 내보냅니다.

float와 double은 비슷한 데이터 형이지만 구분은 해주어야한다는 것을 알 수 있습니다.

하지만 오해마시길 바랍니다. 데이터 형이 다를 지언정 연산은 똑같이 다 됩니다.

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

public class Test : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        float H1 = 180.5f;
        double H2 = 180.5;
        int H3 = 4;
        double H4;

        H4 = H1 + H2 + H3;

        Debug.Log(H4);
    }
}

위 프로그램을 실행하면 프로그램을 실행하기 전 우리가 예상할 수 있는 값인 365가 그대로 나오는 것을 알 수 있습니다. H1, H2, H3는 데이터형은 다를 지언정 모두 숫자 데이터이기 때문에 연산이 가능한 것입니다.

 

우리 모두가 알듯이 연산은 기본적으로 +(더하기), -(빼기), *(곱하기), /(나누기)를 이용하지만 몇가지 편리한 연산자를 알아보도록 하겠습니다.

int answer = 10;

answer = answer + 5;

다음과 같이 한 변수에 일정한 수를 더해야할 경우에는 저렇게 표현하면 되지만 더 간단한 표현방법이 있습니다.

int answer = 10;

answer += 5;

이렇게 써도 'answer = answer + 5'와 똑같은 효과를 가질 수 있습니다. 당연히 +(더하기)만 해당하는 내용이 아니라 일정한 수를 다음과 같이 처리해야할 때,

-(빼기)일 땐 -=

*(곱하기)일 땐 *=

/(나누기) 일 땐 /=

이러한 연산자를 통해 일정한 수를 더하거나 빼거나 곱하거나 나눌 수 있습니다.

이 연산자 중 +=, -=는 문자열에도 사용 가능하니 참고바랍니다.

 

한편, 일정하게 더하거나 빼야할 수가 1, 즉, 코드가

int answer1=10;
int answer2=10;

answer1 += 1;
answer2 -= 1;

위와 같이 쓰여야 할 경우, 더욱 간단한 방법이 있습니다.

int answer1=10;
int answer2=10;

answer1++;
answer2--;

위와 같이 ++와 --를 사용하는 것입니다. 사실 위에서 소개한 연산자는 우리가 C언어를 할 때 본적이 있는 연산자입니다. 만약 본적이 없더라도 똑같은 기능 그대로 C언어에서 사용이 가능할 껍니다.

 

+2021.06.08 수정

++와 --를 이용하는 방법에는 두 가지 방법이 있습니다.

위에서 쓴 것처럼

(변수 이름)++;
(변수 이름)--;

를 쓰는 방법이 있고,

++(변수 이름);
--(변수 이름);

이렇게 변수 이름을 뒤에 쓰는 방법이 있습니다.

이 두 가지 방법은 결론적으로는 변수에 1을 더해주는 '결론' 자체는 같지만 '과정'이 좀 다릅니다. 이 차이는 다른 변수에 연산한 값을 대입할 때 확연히 들어납니다.

 

++(또는 --)를 변수 이름의 뒤에 쓸 경우[ex) i++] 처리과정은 다음과 같습니다.

int i=0;
int k = i++;

Debug.Log(i);
Debug.Log(k);

1. i에 0을 대입해서 변수 생성.

2. k라는 변수 생성 후, i의 '초기값', 즉, 0 대입. 그 후에 i에 1을 더함.

3. 현재 i는 1, k는 0으로 출력.

이렇게 ++(또는 --)를 변수 이름의 뒤에 쓸 경우에는 지정한 변수에 1을 더하기 전의 값인 초기값을 넣습니다.

만약 저 과정을 한 후에 한 번더 k = i++;를 쓰게 된다면 이번엔 i는 2, k는 1이 출력될 것 입니다.

 

++(또는 --)를 변수 이름의 앞에 쓸 경우[ex) ++i] 처리과정은 다음과 같습니다.

int i=0;
int k = ++i;

Debug.Log(i);
Debug.Log(k);

1. i에 0을 대입해서 변수 생성.

2. k라는 변수 생성 후, i에 1을 더해서 k에 대입.

3. 현재 i는 1, k는 1로 출력.

이런식으로 ++(또는 --)를 변수 이름 앞에 쓸 경우에는 먼저 변수에 1을 더한 후에 다른 변수에 대입되게 됩니다.

 

결론적으로 두 코드 모두 변수에 1을 더하고 있지만 어느게 더 좋다고 하지는 않겠습니다. 코드란건 필요에 맞게 작성해야하니까요. 다만 이러한 절차가 있다는 것을 꼭 잊지 마시길 바랍니다.

 

마지막으로 하나 더.

string str = "Hello";
int num = 123;
string message = str + num;

Debug.Log(message);

위와 같이 문자열과 숫자를 연결하면 숫자 데이터를 문자열로 취급합니다. 따라서 실제로 message 변수를 출력하게 되면 Hello123이라고 출력되게 됩니다.

 

이렇게 하면 변수를 다루는 법은 대강 설명한 것 같습니다.


2. 제어문

이번엔 제어문을 사용해 보겠습니다.....라곤 하지만 이 부분은 진짜로 C언어와 전혀 다른 것이 없습니다.

조건문인 if문, 반복문인 for문 등은 전부 사용 가능합니다.

그러니 이번 챕터는 한가지 예제만 보고 넘어 가겠습니다.

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

public class Test : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        int a = 9;

        if(a<10)
        {
            for(int i=0;i<5;i++ )
            {
                Debug.Log(i);
            }
        }
        else
        {
            Debug.Log("123");
        }
    }
}

단숨에 코드가 복잡해진 것 같지만 전혀 그렇지 않습니다. 천천히 분석해보도록 하죠.

 

프로그램이 시작될 때 a라는 변수를 만들어 9라는 값을 저장해 두었습니다. 그 다음엔 if문을 사용해 a의 값을 비교했습니다. a가 10보다 작으면 if블록 안의 실행문을, 그 이외의 값이면 else블록 안의 실행문을 실행하게 되어있습니다.

 

따라서 현재 a는 10보다 작은 9이므로 if블록 안의 for문을 실행하게 됩니다. for문에서는 i라는 변수를 만들어서 0을 대입해 두었습니다. for문이 시작되면 먼저 for블록 안의 실행문이 실행된 다음 i의 값이 1씩 늘어나서 5가 될때까지 반복됩니다. 따라서 결국 출력은 0, 1, 2, 3, 4가 차례대로 출력될 것입니다.

 

만약 a가 10이었다면 Unity의 콘솔 창에는 123만이 출력이 되었을 것입니다.

 

위 코드를 통해 제어문은 C언어랑 완전히 동일하다는 것을 알았을 것입니다. 다만 주의하셔야 하는 점은 C언어를 공부할 때에는 콘솔창을 이용했기에 무한 반복 출력 프로그램을 짜도 문제가 없었지만 Unity에서는 게임 엔진의 콘솔창에서 값을 내보내므로 무한 반복 출력 프로그램을 짜서 실행하게되면 Unity가 멈출 가능성이 있습니다. 이 점은 주의하셔야합니다.

 

제어문은 그다지 다른 것이 없으니 바로 넘어가도록 하겠습니다.


3. 배열

낮선 단어가 등장했습니다. 사실 이 배열이라는 것은 C언어에서도 자주 쓰이는 것입니다. 다만 아직 배열을 모르는 사람들을 위해 배열을 간단히 설명하자면 배열은 데이터의 집합입니다. 예를 들어 학번을 쫙 늘여놓으면 그것은 배열이 됩니다. 배열은 숫자 배열만 있는 것이 아닙니다. 예를 들어 먹고 싶은 과일 이름을 쫙 늘여놓으면 그것도 배열이 됩니다. 이 경우에는 문자열 배열이 됩니다. 전혀 어려운 개념이 아니므로 차차 이해해 봅시다.

 

배열도 일종의 변수에 가까우므로 선언하는 과정이 필요합니다. C#에서 배열은 다음과 같이 선언합니다.

데이터 형[] 배열이름;

예를 들어 int형의 points라는 이름의 배열을 선언하고 싶다면

int[] points;

위와 같이 만들면 됩니다.

 

이렇게 하면 배열을 선언할 수는 있지만 배열의 길이, 즉, 변수를 몇 개 배열하고 싶은지 알 수 없습니다. 따라서 비어있는 배열을 만들때에는 이렇게 합니다.

데이터 형[] 배열 이름 = new 선언한 데이터형[배열 개수];

만약 int형의 points라는 이름의 배열에 데이터를 5개 저장하고 싶다면

int[] points = new int[5];

라고 쓰면 되는 겁니다. 이렇게 배열이 만들어졌다면 배열 안에 있는 값을 바꾸거나 이용해야합니다.

예를 들어봅시다.

 

위와 같은 배열이 있다고 했을때 만약 30이라는 값을 꺼내서 쓰고 싶다면

point[2]

위와 같이 쓰면 왼쪽에서 3번째 값인 30을 꺼낸게 됩니다.

왜 왼쪽에서 3번째 값인데 3이 아니라 2를 쓴 것일까요? 그것은 배열은 가장 첫번째 값은 0번째로 지정되기 때문입니다.

때문에 10을 꺼내서 쓰고 싶다면 point[1]이 아닌 point[0]이라고 써야하는 것이죠.

이렇게만 쓰면 잘 이해가 안될 수 있겠군요. 그렇다면 그냥 직접 써보도록 합시다.

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

public class Test : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        int[] points = new int[5];

        points[0] = 10;
        points[1] = 20;
        points[2] = 30;
        points[3] = 40;
        points[4] = 50;
        
        Debug.Log(points[2]);
    }
}

이렇게 하면 위의 사진과 같은 상황이 됩니다. 5개의 빈 자리가 있는 points라는 배열이 선언되었고 그 밑에는 첫번째 자리부터 5번째 자리까지 각 숫자가 들어갔습니다. 여기서 3번째 자리 숫자를 출력하기 위해 'Debug.Log(points[2])'를 쓰면 Unity에서는 30이 출력될 껍니다.

 

이렇게 하면 어느정도 배열에 대한 감이 잡혔을 것 같습니다....만 매번 배열을 이렇게 만들면 굉장히 불편할 것입니다. 따라서 더 간단한 방법이 있습니다.

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

public class Test : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        int[] points = { 10, 20, 30, 40, 50 };

        Debug.Log(points[2]);
    }
}

위와 같이 배열을 선언할 때부터 { }를 이용해 배열에 들어갈 숫자를 지정해주면 바로 배열과 배열에 들어간 데이터가 선언됩니다. 앞으로는 이 방법을 더욱 자주 쓰게 될 것입니다.

 

마지막으로 하나만 더 설명하겠습니다.

배열에는 배열에 들어있는 변수의 개수가 존재하기 때문에 반복문 등의 제어문에서 배열의 길이를 변수의 비교대상으로 삼는 경우가 많습니다. 이 때에 배열의 길이를 나타낼 수 있는 방법이 있습니다.

배열 이름.Length

이 값을 사용하면 배열의 길이를 나타낼 수 있습니다. 여기서 .의 의미는 다음 강좌에서 다시 알려드리도록 하겠습니다. 지금은 이런 표현방식을 통해 배열의 길이를 표현할 수 있다는 것을 알아두도록 하죠.

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

public class Test : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        int[] points = { 10, 20, 30, 40, 50 };

        Debug.Log(points.Length);
    }
}

예를 들어 위와 같이 코드가 짜여져 있을때 points라는 배열의 길이는 5입니다. 따라서 Unity의 콘솔 창에는 5가 출력되게 됩니다.

 

배열의 길이는 굉장히 많이 쓰이는 값중에 하나입니다. 예를 들면 배열의 평균값을 구하려면 배열의 값을 전부 더하고 배열의 길이로 나누면 평균값이 나오겠군요. 이외에도 for문의 조건식에 활용하는등 활용할 방법이 매우 다양합니다.


자, 오늘은 C# 스크립트의 기초를 해보았습니다. 아마 다음 강좌도 기초를 강좌하게 될 껍니다. 게임을 만들러 왔더니 C# 스크립트에서 콘솔창만 다루고 있는게 지루할 수는 있지만 어디에서나 기초가 가장 중요합니다. 이후에 게임을 만들기 위해서는 다 필요한 절차이니 조금만 참아주셨으면 합니다.

C# 스크립트의 기초는 다음 강좌까지만 합니다. 다음 강좌까지만 들으면 드디어 게임 엔진을 본격적으로 다루게 되니 조금만 더 힘내봅시다. 질문이 있으면 댓글로 질문 바랍니다.

 

수고하셨습니다.