유니티 C# 스크립팅 마스터하기1

칼든개구리·2024년 10월 3일
0
post-thumbnail

유니티의 각 스크립트 파일은 인스턴스화 가능한 주 클래스를 하나씩 정의하고 있는데 이것은 도면이나 설계도에 해당하는 것이다.
클래스는 관련된 변수, 함수, 이벤트의 집합이다. 스크립트는 메시, 오디오 파일과 같은 다른 종류의 유니티 에셋과 동등하게 취급된다.
스크립트를 특정 씬에 추가하기 전까지 스크립트는 Project 패널에 비활성화 상태로 존재하게 된다. 형태를 가진 독립적인 메시 등의 오브젝트와는 달리 스크립트는 완전히 논리적이고 수학적인 것으로서 아직 씬에 추가된 상태가 아니다. 스크립트는 시작적, 청각적 존재감이 없어 직접 보거나 들을 수 없다. 대신 기존의 게임 오브젝트에 이 오브젝트의 동작을 정의하는 컴포넌트로서 추가된다.

특정 오브젝트에 스크립트를 컴포넌트로서 추가해 숨을 불어넣는 과정을 인스턴스화라고 한다.

여러 오브젝트에 하나의 스크립트 파일을 인스턴스화해 모든 오브젝트에 복제된 동작을 갖도록 할 수 있다.
오브젝트에 스크립트 파일을 추가하려면 Project 패널의 스크립트를 씬에 있는 오브젝트로 드래그앤드롭한다.

C#에는 정적 배열동적 배열이 있다. 정적 배열은 메모리에 고정된 최대 항목의 수만큼 사전에 할당하고, 이 용량보다 적은 수의 항목만을 담는 경우일지라도 프로그램 실행 중 배열의 용량은 변하지 않는다. 일정 양의 공간이 낭비될 수 있다.
동적 배열은 필요한 항목의 수에 따라 용량의 확대와 축소가 가능하다. 정적배열이 일반적으로 더 빠르고 성능상 유리하지만 동적 배열이 더 깔끔한 느낌이 들고 메모리 낭비도 피할 수 있다.
반복문에서 각 단계 혹은 주기는 보통 이터레이션으로 불린다. 반복문은 배열의 크기에 의존적이다.

유니티의 여러 클래스와 오브젝트는 ToString함수를 갖고 있다. 이 함수는 int와 같은 오브젝트를 사람이 읽을 수 있는 단어나 상태로 변환해 콘솔이나 디버깅창에 출력하도록 한다.

클래스는 수많은 관련 변수와 함수를 붙여주는 치과 재료같은 역할을 하며, 자신 안에서 모든 내용을 한데 모은 단위라 할 수 있다.
예를 들어 한 게임은 마법사, 오크, 나무, 집, 플레이어, 퀘스트, 인벤토리 아이템, 무기, 마법, 출입구, 다리, 방어막, 등등으로 채워져 있다. 이러한 개체 중 많은 것들이 현실 세계의 것과 유사하다. 하지만 이런 것들은 결정적으로 각각 독립된 개체다. 마법사는 방어막과 다르고, 호위병은 나무와 동떨어져있다. 따라서 이런 것들은 각각의 맞춤 형식을 가진 하나의 개체로서 생각해볼 수 있다. 오크를 예로 들어 이 개체의 속성과 행동 방식을 살펴보자. 오크는 위치와 회전 값, 크기를 가지고 있어 이것들은 각각 변수에 대응하는 것들이다. 오크는 도끼를 사용하는 근거리 공격, 석궁을 사용하는 원거리 공격 등과 같이 다른 종류의 공격 형태를 가질 수 있다. 이런 공격은 함수를 통해 이루어진다. 이런 식으로 변수와 함수의 집합이 의미있는 관계로 합쳐지게 된다. 이렇게 묶는 것을 캡슐화라고 한다.

게임에서 orc 클래스를 오크 개체로 만드는 시나리오를 상상해보자. 개체로 만든 후, 두 가지 업그레이드 형태를 만들기로 한다. 하나는 더 좋은 갑옷과 무기를 갖춘 오크 대장이고 다른 하나는 이름 그대로 마법을 시전하는 오크마법사다. 둘에 추가되는 기능 외에도 보통의 오크가 할 수 있는 모든 행동을 할 수 있다. 이런 것들을 구현하기 위해 공통 코드를 복사해 붙이는 방법으로 orc, orcwarlord, orcmage 세 개의 클래스를 따로 만든다.
오크 대장과 오크 마법사가 보통의 오크와 수많은 공통점을 가짐으로써, 많은 양의 코드가 이것을 구현하기 위해 불필요하게 복사되어 붙여지는 것이 문제이다. 게다가 한 클래스의 복사한 코드에서 버그가 발생되면 다른 클래스에도 이 버그를 고치기 위해 수정된 코드를 붙여넣기 해야한다. 이렇게 하는 대신 개체지향적 개념인 상속을 이용할 수 있다. 상속은 다른 클래스의 기능성을 암시적으로 포함/흡수해 완전히 새로운 클래스를 만드는 개념으로, 기존의 원본 클래스자체에는 영향을 주지 않으면서 새로운 클래스에 원본을 확장할 수 있게끔한다. 또한 원형 클래스를 확장해 새로 만드는 클래스를 서브 클래스, 파생 클래스라고 부른다.

기본적으로 새로 만드는 모든 유니티 스크립트 파일에는 Monobehaviour에서 파생하는 새로운 클래스가 만들어진다. 새로 만들어지는 모든 스크립트는 Monobehaviour의 모든 기능성을 포함하고 코드를 추가함에 따라 여기에 더 많은 기능을 가지게 된다는 것을 의미한다.

C#에서 다형성을 설명하기 위해 아래 코드를 살펴보자. 이 예제가 곧바로 다형성을 보여주는 것은 아니지만 곧 보게 될 다형성이 유용하게 이용되는 시나리오의 시작점이다. RPC게임에서 NPC의 뼈대가 되는 클래스를 정의했다. 이 클래스는 의도적으로 복잡한 기능을 제외하고 캐릭터의 시작 값을 기록하는 기본적인 변수들만 제공한다. 플레이어가 NPC와 대화할 때 실행될 SayGreeting함수가 클래스에 포함된다는 것이 중요한 부분이다. 이 함수는 콘솔 창에 일반적인 인사 메세지를 출력한다
using UnityEngine;
using System.Collections;

public class MyCharacter
{
public sting CharName="";
public int Health= 100;
public int Strength=100;
public float Speed=10.0f;
public bool isAwake=true;
public virtual void SayGreeting()
{
Debug.Log("Hello,my friend");
}
}
Mycharacter 클래스가 실제로 게임에서 동작한다고 상상해보면 여기에서 다양성과 신뢰성에 연관된 첫 번째 문제가 발생한다.
특히 모든 캐릭터가 MyCharacter로부터 상속되어 SayGreeting이 불릴 때 남자, 여자, 오크 할 것 없이 모두 똑같은 인사말을 전달하게 될 것이다. MyCharacter에서 파생해 각각의 NPC 종류마다 고유한 인사말을 건내도록 하나의 클래스를 추가한다. MyCharacter 클래스에서 SayGreeting함수가 virtual 키워드를 사용해 선언되었기 때문에 이것이 가능해진다. 이렇게 하면 파생된 클래스에서 MyCharacter클래스의 SayGreeting 함수의 동작을 대체하는 것이 가능해진다. 다시말해 파생된 클래스의 SayGreeting 함수가 기본 클래스의 원형 함수의 동작 을 교체한다는 것을 의미한다 .

using UnityEngine;
using System.Collections;

public class MyCharacter
{
public sting CharName="";
public int Health= 100;
public int Strength=100;
public float Speed=10.0f;
public bool isAwake=true;
public virtual void SayGreeting()
{
Debug.Log("Hello,my friend");
}
}
public class ManCharacter: MyCharacter
{
public override void SayGreeting()
{
Debug.Log("Hello i'm man");
}
}
public class WomanCharacter: MyCharacter
{
public override void SayGreeting()
{
Debug.Log("Hello i'm Woman");
}
}
public class OrcCharacter: MyCharacter
{
public override void SayGreeting()
{
Debug.Log("Hello i'm Orc");
}
}

C#에서 보편적으로 널리 사용되는 if-else문을 여러 줄로 나누지 않고 단순하게 축약하는 표기법이 있다. 이 축약형을 ?연산자로 부른다.
-y위치가 100 유닛 초과하면 오브젝트 숨겨야함
bool SouldHideObject= (transform.position.y>100) ? true:false;

유니티 API에 포함된 Monobehaviour 클래스는 대부분 새로 작성하는 클래스의 기본 클래스로서 sendMessage와 BroadcastMessage 메소드를 사용한다. 이 함수들을 사용해 오브젝트에 붙은 모든 컴포넌트의 함수를 이름으로 실행할 수 있다. 일반적으로는 클래스에 접근하기 위해 인스턴스를 가리키는 참조변수가 필요하고 이것을 통해 클래스의 함수를 호출하고 변수에 접근할 수 있게 된다. 하지만 SendMessage와 BroadcastMessage 함수는 실행할 함수의 이름을 문자열의 값으로 지정해 실행할 수 있게 해준다.

profile
메타쏭이

0개의 댓글